I have an XYPlot on which are series and a couple of dynamically added shape annotations with no fill (hence each of the series points are visible). Is it possible to display the series tool tips(that show the coordinate of the series point over which the mouse pointer is currently pointing to) over the annotations? Or how can I re-arrange the elements in order to make the tooltip visible.
I suspect you are adding the shape annotations to the plot, where they are drawn last. Instead, add them to the renderer in Layer.BACKGROUND. As shown below, the circle does not obscure the tool tip at (20, 20). Note also how (10, 10) is not affected by the line annotation, while (30, 30) is obscured by the arc.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.util.Random;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.XYLineAnnotation;
import org.jfree.chart.annotations.XYShapeAnnotation;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.Layer;
/**
* #see http://stackoverflow.com/questions/6797012
* #see http://stackoverflow.com/questions/6604211
*/
public class ArcTest {
private static final Random r = new Random();
private static final Color blue = Color.blue;
private static final BasicStroke stroke = new BasicStroke(2.0f);
private static final double PI = 180d;
private static final int X = 8;
private static final int Y = 0;
private static final int W = 6 * X;
private static final int H = 3 * X;
public static void main(String[] args) {
JFreeChart chart = ChartFactory.createXYLineChart(
"ArcTest", "X", "Y", createDataset(),
PlotOrientation.VERTICAL, true, true, false);
XYPlot plot = chart.getXYPlot();
XYLineAndShapeRenderer renderer =
(XYLineAndShapeRenderer) plot.getRenderer();
renderer.setBaseShapesVisible(true);
Ellipse2D.Double circle = new Ellipse2D.Double(X, X, 20, 20);
renderer.addAnnotation(new XYShapeAnnotation(
circle, stroke, blue), Layer.BACKGROUND);
XYLineAnnotation line = new XYLineAnnotation(X, Y, X, H, stroke, blue);
plot.addAnnotation(line);
Arc2D.Double arc = new Arc2D.Double(X, Y, W, 2 * H, PI, PI, Arc2D.OPEN);
plot.addAnnotation(new XYShapeAnnotation(arc, stroke, blue));
ChartFrame frame = new ChartFrame("Test", chart);
frame.pack();
frame.setVisible(true);
}
private static XYDataset createDataset() {
XYSeriesCollection result = new XYSeriesCollection();
XYSeries series = new XYSeries("ArcTest");
series.add(0, 0);
series.add(10, 10);
series.add(20, 20);
series.add(30, 30);
series.add(W, W);
result.addSeries(series);
return result;
}
}
Related
Starting from the code below , is there a way to add graduation to plot ?
the aim is to obtain a plot like posted.
i found addannotation for linechart plot but not for polar ...
Thank you
package jfreechart;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
public class JFreeChartPolarChartExample2 extends JFrame {
private static final long serialVersionUID = 1L;
public JFreeChartPolarChartExample2(String applicationTitle) {
super(applicationTitle);
XYSeriesCollection dataSet1 = new XYSeriesCollection();
JFreeChart jfreeChart = ChartFactory.createPolarChart(null, dataSet1, true, true, false);
final XYSeries series = new XYSeries(" serie1");
series.add(10, 0.90);
series.add(100, 0.10);
series.add(195, 0.50);
series.add(295, 0.50);
dataSet1.addSeries(series);
PolarPlot polarPlot = (PolarPlot) jfreeChart.getPlot();
ChartPanel chartPanel = new ChartPanel(jfreeChart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 500));
setContentPane(chartPanel);
}
public static void main(String[] args) {
JFreeChartPolarChartExample2 chart = new JFreeChartPolarChartExample2(null);
chart.pack();
chart.setVisible(true);
}
}
On an XYPlot, I want the coordinates of mouse displayed as hint near to mouse, but only when (the mouse) move on chart! In another words, when the crosshair moves to another point, the positioning of the coordinate values would move too, following the crosshair.
Also 1 horizontal line and 1 vertical line will be drawn, that intersects specifically at the point that mouse is over on.
Is this possible?
Until now I can get the coordinates and printed on console using ChartMouseListener and chartMouseMoved method.
This is my project and how I want to be the chart with mouse.
JFreeChart has quite flexible support for crosshairs. To do what you described I would use an Overlay on the ChartPanel, and update the crosshairs from your ChartMouseListener. Here is a self-contained example (which I'll add to the collection of demos that we ship with the JFreeChart Developer Guide):
package org.jfree.chart.demo;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.panel.CrosshairOverlay;
import org.jfree.chart.plot.Crosshair;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleEdge;
/**
* A demo showing crosshairs that follow the data points on an XYPlot.
*/
public class CrosshairOverlayDemo1 extends JFrame implements ChartMouseListener {
private ChartPanel chartPanel;
private Crosshair xCrosshair;
private Crosshair yCrosshair;
public CrosshairOverlayDemo1(String title) {
super(title);
setContentPane(createContent());
}
private JPanel createContent() {
JFreeChart chart = createChart(createDataset());
this.chartPanel = new ChartPanel(chart);
this.chartPanel.addChartMouseListener(this);
CrosshairOverlay crosshairOverlay = new CrosshairOverlay();
this.xCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.xCrosshair.setLabelVisible(true);
this.yCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.yCrosshair.setLabelVisible(true);
crosshairOverlay.addDomainCrosshair(xCrosshair);
crosshairOverlay.addRangeCrosshair(yCrosshair);
chartPanel.addOverlay(crosshairOverlay);
return chartPanel;
}
private JFreeChart createChart(XYDataset dataset) {
JFreeChart chart = ChartFactory.createXYLineChart("Crosshair Demo",
"X", "Y", dataset);
return chart;
}
private XYDataset createDataset() {
XYSeries series = new XYSeries("S1");
for (int x = 0; x < 10; x++) {
series.add(x, x + Math.random() * 4.0);
}
XYSeriesCollection dataset = new XYSeriesCollection(series);
return dataset;
}
#Override
public void chartMouseClicked(ChartMouseEvent event) {
// ignore
}
#Override
public void chartMouseMoved(ChartMouseEvent event) {
Rectangle2D dataArea = this.chartPanel.getScreenDataArea();
JFreeChart chart = event.getChart();
XYPlot plot = (XYPlot) chart.getPlot();
ValueAxis xAxis = plot.getDomainAxis();
double x = xAxis.java2DToValue(event.getTrigger().getX(), dataArea,
RectangleEdge.BOTTOM);
double y = DatasetUtilities.findYValue(plot.getDataset(), 0, x);
this.xCrosshair.setValue(x);
this.yCrosshair.setValue(y);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
CrosshairOverlayDemo1 app = new CrosshairOverlayDemo1(
"JFreeChart: CrosshairOverlayDemo1.java");
app.pack();
app.setVisible(true);
}
});
}
}
I'm a beginner in JFreeChart. I want to change the x axis values of this chart to milliseconds, with 5 ms intervals. I've tried
axis.setTickUnit(new DateTickUnit(DateTickUnitType.MILLISECOND, 5));
but I keep having a compilation error. I found somme suggestions in the net, but nothing worked for me. Also, is there any way to set a maximum value for the x axis, like 300 ms.
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.axis.DateTickUnitType;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.category.IntervalCategoryDataset;
import org.jfree.data.gantt.GanttCategoryDataset;
import org.jfree.data.gantt.Task;
import org.jfree.data.gantt.TaskSeries;
import org.jfree.data.gantt.TaskSeriesCollection;
import org.jfree.data.time.SimpleTimePeriod;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
public class Gantt extends ApplicationFrame {
private static final long serialVersionUID = 1L;
public Gantt(final String title) {
super(title);
final GanttCategoryDataset dataset = createDataset();
final JFreeChart chart = createChart(dataset);
// add the chart to a panel...
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}
public static GanttCategoryDataset createDataset() {
final TaskSeries s1 = new TaskSeries("P0");
final Task t4 = new Task("P0", new SimpleTimePeriod(5, 50));
final Task st41 = new Task("1", new SimpleTimePeriod(5, 10));
// st41.setPercentComplete(1.0);
final Task st42 = new Task("2", new SimpleTimePeriod(20, 30));
final Task st43 = new Task("3", new SimpleTimePeriod(40, 50));
t4.addSubtask(st41);
t4.addSubtask(st42);
t4.addSubtask(st43);
s1.add(t4);
final TaskSeries s2 = new TaskSeries("P1");
final Task t2 = new Task("P", new SimpleTimePeriod(0, 10));
final Task st21 = new Task("11", new SimpleTimePeriod(5, 10));
final Task st22 = new Task("21", new SimpleTimePeriod(20, 30));
final Task st23 = new Task("31", new SimpleTimePeriod(35, 90));
t2.addSubtask(st21);
t2.addSubtask(st22);
t2.addSubtask(st23);
s2.add(t2);
final TaskSeriesCollection collection = new TaskSeriesCollection();
collection.add(s1);
collection.add(s2);
return collection;
}
/* private static Date date(final int day, final int month, final int year) {
final Calendar calendar = Calendar.getInstance();
calendar.set(year, month, day);
final Date result = calendar.getTime();
return result;
*/
private JFreeChart createChart(final GanttCategoryDataset dataset) {
final JFreeChart chart = ChartFactory.createGanttChart(
"Gantt ", // chart title
"PRO", // domain axis label
"TIME", // range axis label
dataset, // data
true, // include legend
true, // tooltips
false // urls
);
CategoryPlot plot = chart.getCategoryPlot();
DateAxis axis = (DateAxis) plot.getRangeAxis();
//axis.setTickUnit(new DateTickUnit(DateTickUnitType.MILLISECOND, 10));
axis.setDateFormatOverride(new SimpleDateFormat("S"));
return chart;
}
public static void main(final String[] args) {
final Gantt demo = new Gantt("Gantt");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
Some possibilities to consider:
Specify the units in the corresponding axis label when creating the chart.
"TIME (ms)", // range axis label
Use setDateFormatOverride() to change the format of the axis labels, e.g. three-digit values.
DateAxis axis = (DateAxis) plot.getRangeAxis();
axis.setDateFormatOverride(new SimpleDateFormat("SSS"));
Use setMaximumDate(), if warranted.
axis.setMaximumDate(new Date(300));
I want to make two ring charts that look like the following:
But the RingPlot doesn't seem very customizable. The best I could come up with is this:
Any chance of doing what I want with JFreeChart?
JFreeChart can do most things, this should get you started (I'll probably incorporate the center text feature into the upcoming 1.0.18 release so that the subclassing isn't necessary):
package org.jfree.chart.demo;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PiePlotState;
import org.jfree.chart.plot.RingPlot;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.jfree.text.TextUtilities;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.HorizontalAlignment;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.RefineryUtilities;
import org.jfree.ui.TextAnchor;
/**
* A simple demonstration application showing how to create a ring chart using
* data from a {#link DefaultPieDataset}.
*/
public class RingChartDemo1 extends ApplicationFrame {
private static final long serialVersionUID = 1L;
static class CustomRingPlot extends RingPlot {
private Font centerTextFont;
private Color centerTextColor;
public CustomRingPlot(PieDataset dataset) {
super(dataset);
this.centerTextFont = new Font(Font.SANS_SERIF, Font.BOLD, 24);
this.centerTextColor = Color.LIGHT_GRAY;
}
#Override
protected void drawItem(Graphics2D g2, int section,
Rectangle2D dataArea, PiePlotState state, int currentPass) {
super.drawItem(g2, section, dataArea, state, currentPass);
if (currentPass == 1 && section == 0) {
Number n = this.getDataset().getValue(section);
g2.setFont(this.centerTextFont);
g2.setPaint(this.centerTextColor);
TextUtilities.drawAlignedString(n.toString(), g2,
(float) dataArea.getCenterX(),
(float) dataArea.getCenterY(),
TextAnchor.CENTER);
}
}
}
/**
* Default constructor.
*
* #param title the frame title.
*/
public RingChartDemo1(String title) {
super(title);
setContentPane(createDemoPanel());
}
/**
* Creates a sample dataset.
*
* #return A sample dataset.
*/
private static PieDataset createDataset() {
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setValue("A", new Double(210));
dataset.setValue("B", new Double(150));
return dataset;
}
/**
* Creates a chart.
*
* #param dataset the dataset.
*
* #return A chart.
*/
private static JFreeChart createChart(PieDataset dataset) {
CustomRingPlot plot = new CustomRingPlot(dataset);
JFreeChart chart = new JFreeChart("Custom Ring Chart",
JFreeChart.DEFAULT_TITLE_FONT, plot, false);
chart.setBackgroundPaint(new GradientPaint(new Point(0, 0),
new Color(20, 20, 20), new Point(400, 200), Color.DARK_GRAY));
// customise the title position and font
TextTitle t = chart.getTitle();
t.setHorizontalAlignment(HorizontalAlignment.LEFT);
t.setPaint(new Color(240, 240, 240));
t.setFont(new Font("Arial", Font.BOLD, 26));
plot.setBackgroundPaint(null);
plot.setOutlineVisible(false);
plot.setLabelGenerator(null);
plot.setSectionPaint("A", Color.ORANGE);
plot.setSectionPaint("B", new Color(100, 100, 100));
plot.setSectionDepth(0.05);
plot.setSectionOutlinesVisible(false);
plot.setShadowPaint(null);
return chart;
}
/**
* Creates a panel for the demo (used by SuperDemo.java).
*
* #return A panel.
*/
public static JPanel createDemoPanel() {
JFreeChart chart = createChart(createDataset());
chart.setPadding(new RectangleInsets(4, 8, 2, 2));
ChartPanel panel = new ChartPanel(chart);
panel.setMouseWheelEnabled(true);
panel.setPreferredSize(new Dimension(600, 300));
return panel;
}
/**
* Starting point for the demonstration application.
*
* #param args ignored.
*/
public static void main(String[] args) {
RingChartDemo1 demo = new RingChartDemo1("JFreeChart: Ring Chart Demo 1");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
I have a JFree XY Line chart which always starts at x = 0. Then based on user defined settings from a properties file, the application increments based on that number (this represents the time in minutes).
For example, x = 0 to start the user defined setting is 5 so the scale goes 0, 5, 10, 15, 20…, or the user setting is 3 so it goes 0, 3, 6, 9, 12… Pretty simple.
The issue I am having is the way in which the graph starts. If I start at 0, then 0 is in the middle of the graph rather than at the bottom left with -0.0000005, -0.000004, -0.000003… 0.000000 , 0.000001 , 0.000002… 0.000005
How can I just manually add the scale at the bottom, i.e. define it should be increments of 2 and then maintain it?
You should use NumberAxis, which contains a lot of methods to define the scale of your chart.
Example :
// Create an XY Line chart
XYSeries series = new XYSeries("Random Data");
series.add(1.0, 500.2);
series.add(10.0, 694.1);
XYSeriesCollection data = new XYSeriesCollection(series);
JFreeChart chart = ChartFactory.createXYLineChart("XY Series Demo", "X", "Y", data,
PlotOrientation.VERTICAL,
true, true, false);
// Create an NumberAxis
NumberAxis xAxis = new NumberAxis();
xAxis.setTickUnit(new NumberTickUnit(2));
// Assign it to the chart
XYPlot plot = (XYPlot) chart.getPlot();
plot.setDomainAxis(xAxis);
Based on this example, here's an sscce that uses setTickUnit() to adjust the domain axis tick unit dynamically, starting from the value 5.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/** #see https://stackoverflow.com/a/14167983/230513 */
public class SSCCE {
private static final int COUNT = 100;
private static final int UNITS = 5;
private static final Random r = new Random();
public static void main(String[] args) {
XYSeries series = new XYSeries("Data");
for (int i = 0; i < COUNT; i++) {
series.add(i, r.nextGaussian());
}
XYSeriesCollection data = new XYSeriesCollection(series);
final JFreeChart chart = ChartFactory.createXYLineChart("TickUnits",
"X", "Y", data, PlotOrientation.VERTICAL, true, true, false);
XYPlot plot = (XYPlot) chart.getPlot();
final NumberAxis xAxis = (NumberAxis) plot.getDomainAxis();
xAxis.setTickUnit(new NumberTickUnit(UNITS));
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("TickUnitDemo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new ChartPanel(chart));
final JSpinner spinner = new JSpinner(
new SpinnerNumberModel(UNITS, 1, COUNT, 1));
spinner.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
JSpinner s = (JSpinner) e.getSource();
Number n = (Number) s.getValue();
xAxis.setTickUnit(new NumberTickUnit(n.intValue()));
}
});
JPanel p = new JPanel();
p.add(new JLabel(chart.getTitle().getText()));
p.add(spinner);
f.add(p, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}