JFreeChart: custom chart with tooltip on mouseover - java

I have requirement to show a XyLineChart with adding data dynamically. I have used the chart Customizer to read data from db with some additional logic and adding that to chart. But I am not able to create tool tip on mouse over for each data points on chart. following is my code for Customizer.
What is the correct way to create Tool tip on Mouse over?
public class MyChartCustomizer extends JRAbstractChartCustomizer{
#Override
public void customize(JFreeChart chart, JRChart jrChart) {
XyPlot plot= chart.getXyPlot;
XYSeriesCollection ds = (XYSeriesCollection) plot.getDataset();
XYSeries x1 = new XYSeries("C 1", true, true);
x1.add(10,20);
XYBarRenderer ren = (XYBarRenderer) plot.getRenderer();
plot.setRenderer(ren);
ren.setSeriesToolTipGenerator(0, new XYToolTipGenerator() {
#Override
public String generateToolTip(XYDataset arg0, int arg1, int arg2) {
return "C 1";
}
});
ren.setToolTipGenerator(new XYToolTipGenerator() {
#Override
public String generateToolTip(XYDataset arg0, int arg1, int arg2) {
return "C 1";
}
});
chart.fireChartChanged();
}
}
}

Thank you, Petter and Trashgod helping me out to find the solution for this issue.
The actual issue is, if we add the new data using customizer then the new data point get display on the graph but respected tool tip does not get generated and the map used for tooltip will not be updated on html code. Since I have to use jasper server as per requirement I implemented following work around other way will be simply generate chart image with map using jfreechart API and display on the jsp page(no need for report design....)..
Following is the way I Implemented this.
I used the following code to generate the same chart which jasperserver/jasper studio create the chart. this gives me same chart which internally get created and I create the map for tooltips and passing it as parameter to browser and using javascript function inserting the new map html code with the chart image.
XYSeriesCollection xyDataSet = new XYSeriesCollection();
JFreeChart chart = ChartFactory.createXYLineChart(
cur_chart.getTitle(),
cur_chart.getxLabel(), cur_chart.getyLabel(),
xyDataSet,
PlotOrientation.VERTICAL,
true,
true,
false);
String chartId = null;
for ( Object tt : chart.getSubtitles()){
if (tt instanceof TextTitle){
chartId= ((TextTitle) tt).getText();
}
}
XYPlot plot = chart.getXYPlot();
//following code to set font size and color is required so that same chart with matching tooltip pixels can we generated.
LegendItemCollection legends = plot.getLegendItems();
List<JRSeriesColor> colors = new ArrayList<JRSeriesColor>();
System.out.println("Customizer: "+ chartId);
NumberAxis xAxis = (NumberAxis) plot.getDomainAxis();
NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
Color trans = new Color(0xFF, 0xFF, 0xFF, 0);
chart.setBackgroundPaint(trans);
plot .setBackgroundPaint(trans);
chart.getLegend().setBackgroundPaint(trans);
chart.setTitle(cur_chart.getTitle());
Font font3 = new Font("Dialog", Font.PLAIN, 10);
plot.getDomainAxis().setLabelFont(font3);
plot.getRangeAxis().setLabelFont(font3);
plot.getDomainAxis().setLabelPaint(Color.BLACK);
plot.getRangeAxis().setLabelPaint(Color.BLACK);
//some more code to add real time data to XyDataset,
ToolTipTagFragmentGenerator tooltipConstructor = new ToolTipTagFragmentGenerator() {
public String generateToolTipFragment(String arg0) {
String toolTip = " title = \"" + arg0.replace("\"", "") + "\"";
return (toolTip);
}
};
URLTagFragmentGenerator urlConstructor = new URLTagFragmentGenerator() {
public String generateURLFragment(String arg0) {
String address = " href=\"ControllerAddress\\methodName?"
+ arg0.replace("\"", "") + "\"";
return (address);
}
};
ChartRenderingInfo info = new ChartRenderingInfo(
new StandardEntityCollection());
// BufferedImage bi chart.createBufferedImage(272, 178, info);
TextTitle tt = new TextTitle("chart1");
tt.setFont(font3);
chart.addSubtitle(tt);
ChartUtilities.saveChartAsPNG(new File("/tmp/test.png"), chart, 500, 250, info);
String map = ChartUtilities.getImageMap(cur_chart.getName(), info, tooltipConstructor, urlConstructor);

Related

cannot access setDomainAxis() method in my JFreeChart plot

I have generated a few charts, as per an assignment, and for data analysis I would like the domain axis to scale to my specifications, rather than to automatically fit the data in each series.
I found a solution here, which seemed very simple to follow: JFReeChart x axis scale
However, after I create my plot, with the code below, it seems like the method does not exist.
Is the method setDomainAxis() one that is included in the libraries or do I have to create it myself? Or have I violated some fundamental rule of java that has nothing to do with JFreeChart? I am a beginner java programmer, so please inform your answer accordingly. Thanks!
Here is my XYPlot class:
public class XYPlot extends JFrame {
private String title;
private String xAxis;
private String yAxis;
private XYSeriesCollection dataset;
public XYPlot(String header, String graphTitle, String xax, String yax) {
super(header);
xAxis = xax;
yAxis = yax;
title = graphTitle;
XYPlot myPlot;
// dataset = dat;
}
public void setTit(String newTitle){
title = newTitle;
}
public void setXAxis(String X){
xAxis = X;
}
public void setYAxis(String Y){
xAxis = Y;
}
public void passData(XYSeriesCollection data){
dataset = data;
}
public void createChart(XYSeriesCollection dataIn){
final JFreeChart chart = ChartFactory.createXYLineChart(
title,
xAxis,
yAxis,
dataIn
);
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(1200, 800));
setContentPane(chartPanel);
}
And here is the implementation of the plot in my main program:
public static void seriesPlotter(XYSeriesCollection dataset, String title, String header, String xAxis, String yAxis) {
XYPlot myPlot = new XYPlot(header, title, xAxis, yAxis);
myPlot.createChart(dataset);
NumberAxis domain = new NumberAxis();
domain.setTickUnit(1);
myPlot.setDomainAxis(domain);
myPlot.pack();
myPlot.setVisible(true);
}
Your fragment's use of XYPlot is inconsistent with the API. In particular, there is no such constructor, and there is no method named createChart(). Verify that you are using the current version, 1.0.19, available here.
The methods of ChartFactory are an excellent guide to creating a chart from individual subcomponents. As a concrete example, ChartFactory.createXYLineChart() is recapitulated here. Note how the axes are passed to the XYPlot constructor, obviating the need to invoke setDomainAxis() explicitly. In outline,
// axes
NumberAxis domain = new NumberAxis(xAxis);
NumberAxis range = new NumberAxis(yAxis);
// renderer
XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
// plot
XYPlot plot = new XYPlot(dataset, domain, range, renderer);
// chart
JFreeChart chart = new JFreeChart(
title", JFreeChart.DEFAULT_TITLE_FONT, plot, false);
Maybe you could take a second look after I edit to add the additional code.
Your XYPlot is a JFrame which has no setDomainAxis() method; rename your class to avoid the conflict, e.g. MyXYPlot.
Let your renamed class have a member variable to hold a reference to the org.jfree.chart.plot.XYPlot and add a method to update the name.
XYPlot myPlot;
…
public void setDomainAxisName(String name){
myPlot.getDomainAxis().setLabel(name);
}
There's no reason to extend JFrame.
My technical vocabulary is nil.
Experimenting with JFreeChart is an excellent opportunity to learn.

How to save/restore the views in eclipse e4

I have two sections. In the left section I am using checkbox tableviewer for displaying list of file names. The right section is for showing graphs(I am using JFreechart). I have a handler which is used for dynamically adding tabs to the right side section. IF I am in first tab and made some checkbox selections in left side tableviewer ,the graph is displayed in right side. When I create a new tab(right side) , the left side tableviewer should reset.
When I select the first tab again and I want to see the previous selection in left side section.Can anyone please give some ideas how to save/restore the views based on the tab change?
Left side section code for file viewer:
#PostConstruct
public void createComposite(Composite parent) {
parent.setLayout(new GridLayout(1, false));
tableViewer = new CheckboxTableViewer(parent, SWT.BORDER);
tableViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));
}
public void setTableInput(File[] selectedFiles) {
tableViewer.setContentProvider(ArrayContentProvider.getInstance());
tableViewer.setLabelProvider(new FileLabelProvider());
prevSelectedFiles = selectedFiles;
tableViewer.setInput(selectedFiles);
tableViewer.addCheckStateListener(new ICheckStateListener() {
#Override
public void checkStateChanged(CheckStateChangedEvent event) {
filesSelected = tableViewer.getCheckedElements();
// some code to display graph
}}}
Right side code(Graph)
#PostConstruct
public void postConstruct(final Composite parent) {
final JFreeChart chart = createChart(dataset, title);
new ChartComposite(parent, SWT.NONE, chart, true);
}
private JFreeChart createChart(TimeSeriesCollection dataset, String string) {
final JFreeChart chart = ChartFactory.createTimeSeriesChart(
"REPORT GENERATION", "TimeStamp", "ms", dataset, true, true,
false);
chart.setBackgroundPaint(Color.WHITE);
final XYPlot plot = (XYPlot) chart.getPlot();
plot.setDataset(0, dataset);
plot.setBackgroundPaint(Color.WHITE);
plot.setDomainGridlinePaint(Color.BLACK);
plot.setRangeGridlinePaint(Color.BLACK);
Shape shape = new Ellipse2D.Double(-2.0, -2.0, 4.0, 4.0);
XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot
.getRenderer();
renderer.setSeriesShape(0, shape);
renderer.setSeriesShape(1, shape);
renderer.setSeriesShape(2, shape);
renderer.setBaseShapesVisible(true);
renderer.setSeriesOutlinePaint(0, Color.GRAY);
renderer.setSeriesOutlinePaint(1, Color.GRAY);
renderer.setSeriesOutlinePaint(2, Color.GRAY);
renderer.setUseFillPaint(true);
renderer.setSeriesFillPaint(0, Color.red);
renderer.setSeriesFillPaint(1, Color.green);
renderer.setSeriesFillPaint(2, Color.blue);
renderer.setSeriesPaint(0, Color.red);
renderer.setSeriesPaint(1, Color.green);
renderer.setSeriesPaint(2, Color.blue);
NumberAxis yaxis = (NumberAxis) plot.getRangeAxis();
yaxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
yaxis.setAutoRangeIncludesZero(false);
plot.setRangeAxis(yaxis);
DateAxis axis = (DateAxis) plot.getDomainAxis();
axis.setAutoTickUnitSelection(true);
// axis.setTickUnit(new DateTickUnit(DateTickUnitType.SECOND,120));
axis.setDateFormatOverride(new SimpleDateFormat("HH:mm:ss"));
// DateAxis.createStandardDateTickUnits();
axis.setTickMarksVisible(true);
axis.setTickLabelsVisible(true);
return chart;
}
public void setValue(ArrayList<TreeMap<Timestamp, Long>> statisticalValues, String protocolName, String statistics) {
// //System.out
// .println("setting the value for timeseries-->" + i);
TimeSeries ts = null;
for (TreeMap<Timestamp, Long> entries : statisticalValues) {
ts = new TimeSeries(protocolName + "_" + statistics,
Second.class);
for (Entry<Timestamp, Long> seriesData : entries.entrySet()) {
ts.addOrUpdate(new Second(seriesData.getKey()),
seriesData.getValue());
}
}
dataset.addSeries(ts);
}
The handler responsible for dynamic creation of tab(Grapgh part):
public class DynamicPartsHandler {
#Execute
public void execute(EPartService partService, EModelService modelService,
MApplication application,Shell shell) {
String partName = "Graph";
MPart part = partService
.createPart("com.wincor.commtrace.project.partDescriptor.1");
MPartStack stack = (MPartStack) modelService.find(
"com.wincor.commtrace.project.partstack.2", application);
stack.getChildren().add(part);
part.setLabel(partName);
part.setVisible(true);
part.setCloseable(true);
partService.showPart(part, PartState.ACTIVATE);
}
}
Thanks in advance

draw a multiple plot with JFreechart (bar, XY)

Hello i have to make a program to display power curves, and therefore i need to display three different plots on one window.
The different kind of plots are XY (just points), bar, and XY with lines.
My problem(s) : somehow i can get only two of the charts to get drawn AND i can't change the colors of the single chart correctly.
EDIT : When i put as comment the declaration of the third chart, the second one finally gets drawn. Is it impossible to draw three charts ?
Any help will be greatly appreciated, thanks ;)
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.axis.ValueAxis;
import org.jfree.chart.plot.DatasetRenderingOrder;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
public class OverlaidPlot extends ApplicationFrame
{
final XYSeries series0 = new XYSeries("Graph0");
final XYSeries series1 = new XYSeries("Graph1");
final XYSeries series2 = new XYSeries("Graph2");
public OverlaidXYPlotDemo(final String title)
{
super(title);
final JFreeChart chart = createOverlaidChart();
final ChartPanel panel = new ChartPanel(chart, true, true, true, true, true);
panel.setPreferredSize(new java.awt.Dimension(800, 600));
setContentPane(panel);
}
public void addElem0(double x, double y)
{
this.series0.add(x, y);
}
public void addElem1(double x, double y)
{
this.series1.add(x, y);
}
public void addElem2(double x, double y)
{
this.series2.add(x, y);
}
private JFreeChart createOverlaidChart()
{
final NumberAxis domainAxis = new NumberAxis("Speed (m/s)");
final ValueAxis rangeAxis = new NumberAxis("Power (kw)");
// create plot ...
final IntervalXYDataset data0 = createDataset0();
final XYItemRenderer renderer0 = new XYBarRenderer(0.20);
// change "new XYBarRenderer(0.20)" to "StandardXYItemRenderer()" if you want to change type of graph
final XYPlot plot = new XYPlot(data0, domainAxis, rangeAxis, renderer0);
// add a second dataset and renderer...
final IntervalXYDataset data1 = createDataset1();
final XYLineAndShapeRenderer renderer1 = new XYLineAndShapeRenderer(false, true);
// arguments of new XYLineAndShapeRenderer are to activate or deactivate the display of points or line. Set first argument to true if you want to draw lines between the points for e.g.
plot.setDataset(1, data1);
plot.setRenderer(1, renderer1);
// add a third dataset and renderer...
final IntervalXYDataset data2 = createDataset2();
final XYLineAndShapeRenderer renderer2 = new XYLineAndShapeRenderer(true, true);
// arguments of new XYLineAndShapeRenderer are to activate or deactivate the display of points or line. Set first argument to true if you want to draw lines between the points for e.g.
plot.setDataset(1, data2);
plot.setRenderer(1, renderer2);
plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
NumberAxis domain = (NumberAxis) plot.getDomainAxis();/*
domain.setRange(0.00, 30);*/
domain.setTickUnit(new NumberTickUnit(0.5));
domain.setVerticalTickLabels(true);
// return a new chart containing the overlaid plot...
return new JFreeChart("Test", JFreeChart.DEFAULT_TITLE_FONT, plot, true);
}
private IntervalXYDataset createDataset0()
{
// create dataset 0...
final XYSeriesCollection coll0 = new XYSeriesCollection(series0);
return coll0;
}
private IntervalXYDataset createDataset1()
{
// create dataset 1...
final XYSeriesCollection coll1 = new XYSeriesCollection(series1);
return coll1;
}
private IntervalXYDataset createDataset2()
{
// create dataset 2...
final XYSeriesCollection coll2 = new XYSeriesCollection(series2);
return coll2;
}
}
You have two datasets at the same index within the plot - make sure you're setting each dataset to a unique index:
plot.setDataset(2, data2);
plot.setRenderer(2, renderer2);
After changing this, I ran your example with some test data and was able to see all three data sets plotted.

JFreeChart Bar chart Design Change

I am looking for a way to change the design of the Bar chart in JFreechart. Here is my excel graph. How can I change the jfreechart barchart in the below design format?
The following code can generate a similar chart. Does it suffice?
public class BarExample {
public static void main(String arg[]) throws IOException {
DefaultCategoryDataset dataSet = new DefaultCategoryDataset();
dataSet.setValue(2, Integer.valueOf(1), Integer.valueOf(5));
dataSet.setValue(7, Integer.valueOf(1), Integer.valueOf(10));
dataSet.setValue(4, Integer.valueOf(1), Integer.valueOf(15));
dataSet.setValue(9, Integer.valueOf(1), Integer.valueOf(20));
dataSet.setValue(6, Integer.valueOf(1), Integer.valueOf(25));
JFreeChart chart = ChartFactory.createBarChart
("Chart", "Number of Days", "Number of ECR", dataSet,
PlotOrientation.VERTICAL, false, true, false);
CategoryPlot plot = chart.getCategoryPlot();
// Reduce margin between bars
plot.getDomainAxis().setCategoryMargin(0.0);
// Reduce left and right margin
plot.getDomainAxis().setLowerMargin(0.0);
plot.getDomainAxis().setUpperMargin(0.0);
FileOutputStream outputStream = new FileOutputStream(
new File("chart.png"));
ChartUtilities.writeChartAsPNG(outputStream, chart, 1024, 768);
}
}

Save/Load jFreechart TimeSeriesCollection chart from XML

I'm working with this exemple wich put rondom dynamic data into a TimeSeriesCollection chart.
My problem is that i can't find how to :
1- Make a track of the old data (of the last hour) when they pass the left boundary (because the data points move from the right to the left ) of the view area just by implementing a horizontal scroll bar.
2- Is XML a good choice to save my data into when i want to have all the history of the data?
public class DynamicDataDemo extends ApplicationFrame {
/** The time series data. */
private TimeSeries series;
/** The most recent value added. */
private double lastValue = 100.0;
public DynamicDataDemo(final String title) {
super(title);
this.series = new TimeSeries("Random Data", Millisecond.class);
final TimeSeriesCollection dataset = new TimeSeriesCollection(this.series);
final JFreeChart chart = createChart(dataset);
final ChartPanel chartPanel = new ChartPanel(chart);
final JPanel content = new JPanel(new BorderLayout());
content.add(chartPanel);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(content);
}
private JFreeChart createChart(final XYDataset dataset) {
final JFreeChart result = ChartFactory.createTimeSeriesChart(
"Dynamic Data Demo",
"Time",
"Value",
dataset,
true,
true,
false
);
final XYPlot plot = result.getXYPlot();
ValueAxis axis = plot.getDomainAxis();
axis.setAutoRange(true);
axis.setFixedAutoRange(60000.0); // 60 seconds
axis = plot.getRangeAxis();
axis.setRange(0.0, 200.0);
return result;
}
public void go() {
final double factor = 0.90 + 0.2 * Math.random();
this.lastValue = this.lastValue * factor;
final Millisecond now = new Millisecond();
System.out.println("Now = " + now.toString());
this.series.add(new Millisecond(), this.lastValue);
}
public static void main(final String[] args) throws InterruptedException {
final DynamicDataDemo demo = new DynamicDataDemo("Dynamic Data Demo");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
while(true){
demo.go();
Thread.currentThread().sleep(1000);
}
}
}
The example uses the default values specified in TimeSeries for the maximum item age and count. You'll want to change them to suit your requirements.
XML is fine, but it's voluminous for high rates; plan accordingly.
See also this example that uses javax.swing.Timer to avoid blocking the event dispatch thread.

Categories