How to add text/image on time series jfree chart - java

Requirement: i need to display toolTip(No data available) and image on time series chart which have null data ie; Image 2 on gray color area.
Problem:I am not able to get it.
Image With some data ie; series1.addOrUpdate(absoluteMSecond, data[i]);
Image with null data ie; series1.addOrUpdate(absoluteMSecond, null);
COde:
import java.util.Calendar;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
public class TextOnJFreeChart extends ApplicationFrame {
public TextOnJFreeChart(final String title) {
super(title);
final XYDataset data = createDataset();
final JFreeChart chart = createChart(data);
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}
private JFreeChart createChart(final XYDataset data) {
final JFreeChart chart = ChartFactory.createTimeSeriesChart("Text/ToolTip Trying Demo", "X", "Y", data, true, true, true);
final XYPlot plot = chart.getXYPlot();
plot.getRenderer().setToolTipGenerator(StandardXYToolTipGenerator.getTimeSeriesInstance());
plot.setNoDataMessage("Hai it is ok if i get this message.......");
final DateAxis domainAxis = new DateAxis("Time");
domainAxis.setUpperMargin(0.50);
plot.setDomainAxis(domainAxis);
final ValueAxis rangeAxis = plot.getRangeAxis();
rangeAxis.setUpperMargin(0.30);
rangeAxis.setLowerMargin(0.50);
return chart;
}
private XYDataset createDataset() {
final TimeSeriesCollection result = new TimeSeriesCollection();
result.addSeries(createSupplier1Bids());
return result;
}
private TimeSeries createSupplier1Bids()
{
double[] data = {200.0, 195.0, 190.0, 188.0, 185.0, 180.0};
long timeStamp = System.currentTimeMillis();
Millisecond absoluteMSecond = getTimeInMillisecondFormat(timeStamp, 0L);
final TimeSeries series1 = new TimeSeries("Supplier 1", Millisecond.class);
for(int i = 0; i < data.length; i++)
{
absoluteMSecond = getTimeInMillisecondFormat(timeStamp + i * 1000, 0L);
//series1.addOrUpdate(absoluteMSecond, data[i]);
series1.addOrUpdate(absoluteMSecond, null);
}
return series1;
}
public Millisecond getTimeInMillisecondFormat(long timeStamp, long startTime)
{
try
{
long diff = timeStamp - startTime;
Calendar calender = Calendar.getInstance();
calender.setTimeInMillis(diff);
Millisecond elapsedMSecond = new Millisecond(calender.getTime());
return (elapsedMSecond);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
public static void main(final String[] args) {
final TextOnJFreeChart demo = new TextOnJFreeChart("Text/ToolTip Trying Demo");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
Thanks in advance

You can specify the desired image to the plot's setBackgroundImage() method, mentioned here and here.
The implementation of getToolTipText() in ChartPanel will return null if the dataset is empty, but you can override the method to return a suitable alternative string.

Related

How to change from line chart to bar chart

I have this line chart and want to make it a bar chart, but I'm new to Java and am not knowing if it possible since the x-axis is TimeSeries. This is the code I have that visualizes the line chart:
public class Time {
private static Time INSTANCE;
public static boolean isInitialized = false;
private Marker marker;
private Long markerStart;
private Long markerEnd;
private XYPlot plot;
long last_lowerBound;
long last_upperBound;
#Inject
public Time() {
}
Composite comp;
TimeSeriesCollection dataset;
ChartPanel panel;
JFreeChart chart;
protected Point endPoint;
#PostConstruct
public void postConstruct(Composite parent) {
comp = new Composite(parent, SWT.NONE | SWT.EMBEDDED);
Frame frame = SWT_AWT.new_Frame(comp);
JApplet rootContainer = new JApplet();
TimeSeries series = new TimeSeries("Timeline");
dataset = new TimeSeriesCollection();
String plotTitle = "";
String xaxis = "Time";
String yaxis = "Docs";
PlotOrientation orientation = PlotOrientation.VERTICAL;
boolean show = false;
boolean toolTips = true;
boolean urls = false;
chart = ChartFactory.createTimeSeriesChart(plotTitle, xaxis, yaxis, dataset, show, toolTips, urls );
// get a reference to the plot for further customisation...
plot = chart.getXYPlot();
plot.setBackgroundPaint(Color.white);
plot.setDomainGridlinePaint(Color.gray);
plot.setRangeGridlinePaint(Color.gray);
plot.setOutlinePaint(Color.white);
plot.getRangeAxis().setLabel("");
plot.getDomainAxis().setLabel("");
ValueAxis y_axis = plot.getRangeAxis(); // Y
ValueAxis x_axis = plot.getDomainAxis(); // X
Font font = new Font("Veranda", Font.PLAIN, 12);
y_axis.setTickLabelFont(font);
x_axis.setTickLabelFont(font);
x_axis.setTickLabelPaint(Color.black);
y_axis.setTickLabelPaint(Color.black);
plot.getDomainAxis().setAxisLineVisible(false);
final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
// renderer.setSeriesLinesVisible(0, false);
renderer.setSeriesShapesVisible(0, false);
plot.setRenderer(renderer);
Should I only update this line: chart = ChartFactory.createTimeSeriesChart(plotTitle, xaxis, yaxis, dataset, show, toolTips, urls ); or I should change it completely?
I tried changing this part like this but it doesn't show anything:
dataset = new TimeSeriesCollection();
String plotTitle = "";
String xaxis = "Time";
String yaxis = "Docs";
PlotOrientation orientation = PlotOrientation.VERTICAL;
boolean show = false;
boolean toolTips = true;
boolean urls = false;
chart = ChartFactory.createBarChart(plotTitle, xaxis, yaxis, (CategoryDataset) dataset, orientation, show, toolTips, urls);
chart.setBackgroundPaint(null);
chart.setBackgroundImageAlpha(0.0f);
CategoryPlot plot = (CategoryPlot) chart.getPlot();
plot.setRangeGridlinesVisible(false);
plot.setDomainGridlinesVisible(false);
plot.setOutlineVisible(false);
plot.setRangeZeroBaselineVisible(false);
plot.setDomainGridlinesVisible(false);
plot.setBackgroundPaint(COLOR_INVISIBLE);
plot.setBackgroundImageAlpha(0.0f);
BarRenderer renderer = (BarRenderer) plot.getRenderer();
renderer.setSeriesPaint(0, AttributeGuiTools.getColorForValueType(Ontology.NOMINAL));
renderer.setBarPainter(new StandardBarPainter());
renderer.setDrawBarOutline(true);
renderer.setShadowVisible(false); } }
Any help would be highly appreciated!
Given a suitable XYDataset, such as IntervalXYDataset, you can replace ChartFactory.createTimeSeriesChart() with ChartFactory.createXYBarChart(), which provides for an optional DateAxis. The example below uses the same dataset to create both charts.
IntervalXYDataset dataset = createDataset();
f.add(createPanel(ChartFactory.createXYBarChart("Data", "Time", true, "Value", dataset)));
f.add(createPanel(ChartFactory.createTimeSeriesChart("Data", "Time", "Value", dataset)));
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickMarkPosition;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.axis.DateTickUnitType;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.Year;
import org.jfree.data.xy.IntervalXYDataset;
/**
* #see https://stackoverflow.com/a/54362133/230513
* #see https://stackoverflow.com/a/42612723/230513
*/
public class Test {
public static void main(String[] args) {
EventQueue.invokeLater(new Test()::display);
}
private void display() {
JFrame f = new JFrame("Data");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(0, 1));
IntervalXYDataset dataset = createDataset();
f.add(createPanel(ChartFactory.createXYBarChart("Data", "Time", true, "Value", dataset)));
f.add(createPanel(ChartFactory.createTimeSeriesChart("Data", "Time", "Value", dataset)));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private ChartPanel createPanel(JFreeChart chart) {
final XYPlot plot = chart.getXYPlot();
final DateAxis domainAxis = (DateAxis) plot.getDomainAxis();
domainAxis.setTickUnit(new DateTickUnit(DateTickUnitType.YEAR, 1));
domainAxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
domainAxis.setDateFormatOverride(new SimpleDateFormat("yyyy"));
return new ChartPanel(chart) {
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 250);
}
};
}
private IntervalXYDataset createDataset() {
TimeSeries series = new TimeSeries("Value");
Calendar c = Calendar.getInstance();
for (int i = 0; i < 7; i++) {
series.add(new Year(c.getTime()), i + 1);
c.add(Calendar.YEAR, 1);
}
return new TimeSeriesCollection(series);
}
}

how to import and plot CSV in Java with timestamp

Hi Currently I am trying to import the CSV file into the Java to plot the data, basically, I can import successfully but it does not work in my CSV because it has the time format as: HH:mm:ss MM-dd-yy
The data is as follow:
2016-05-15 00:00:00 0
2016-05-15 00:00:00 0
2016-05-15 00:00:00 5.44852
2016-05-15 00:00:01 0
2016-05-15 00:00:01 0
2016-05-15 00:00:01 5.26064
the code is as follow:
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.text.SimpleDateFormat;
import org.jfree.chart.axis.DateAxis;
import org.jfree.data.time.Minute;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
import au.com.bytecode.opencsv.CSVReader;
public class Test extends ApplicationFrame{
/**
*
*/
private static final long serialVersionUID = 1L;
XYSeriesCollection dataset;
JFreeChart chart;
final ChartPanel chartPanel;
final int chartWidth = 560;
final int chartHeight = 367;
CSVReader reader;
String[] readNextLine;
XYSeries series;
public Test(String applicationTitle) throws IOException {
super(applicationTitle);
dataset = createDataset();
chart = createChart(dataset);
chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(chartHeight,
chartWidth));
this.add(chartPanel);
}
public XYSeriesCollection createDataset() throws NumberFormatException,
IOException {
dataset = new XYSeriesCollection();
try {
reader = new CSVReader(new FileReader("/usr/csv_dump.csv"),'\t');
// Read the header and chuck it away
readNextLine = reader.readNext();
// Set up series
final XYSeries seriesX = new XYSeries("X");
final XYSeries seriesY = new XYSeries("Y");
final XYSeries seriesZ = new XYSeries("Z");
while ((readNextLine = reader.readNext()) != null) {
// add values to dataset
double Time = Double.valueOf(readNextLine[0]);
double X = Long.valueOf(readNextLine[1]);
double Y = Long.valueOf(readNextLine[2]);
double Z = Long.valueOf(readNextLine[3]);
seriesX.add(Time, X);
seriesY.add(Time, Y);
seriesZ.add(Time, Z);
}
System.out.println(seriesX.getMaxX() + "; " + seriesX.getMaxY());
dataset.addSeries(seriesX);
dataset.addSeries(seriesY);
dataset.addSeries(seriesZ);
} catch (FileNotFoundException e) {
System.out.println("File not found!");
}
return dataset;
}
public JFreeChart createChart(XYDataset dataset)
throws NumberFormatException, IOException {
chart = ChartFactory.createXYLineChart("Acceleration vs Time", // chart
// title
"Time", // domain axis label
"Acceleration", // range axis label
dataset, // data
PlotOrientation.VERTICAL, // the plot orientation
true, // legend
true, // tooltips
false); // urls
return chart;
}
public static void main(String[] args) throws IOException {
System.out.println("In here, to create a Test");
final Test demo = new Test("Test XY Line chart");
System.out.println("Created, pakcking");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
but I don't know how to put the time format in this code. Thank you for anyone who can help me with it.
In this simpler example,
Use SimpleDateFormat to parse dates of the given format.
Use ChartFactory.createTimeSeriesChart() to create a time series chart; it will use a DateAxis for the domain.
Data:
2016-05-15 00:00:00, 20
2016-05-15 00:01:01, 21
2016-05-15 00:02:02, 42
Code:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
public class Test extends ApplicationFrame {
public Test(String applicationTitle) throws IOException {
super(applicationTitle);
this.add(new ChartPanel(createChart(createDataset())));
}
public XYSeriesCollection createDataset() {
final XYSeries series = new XYSeries("X");
try {
BufferedReader in = new BufferedReader(new FileReader("data.txt"));
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String s = null;
while ((s = in.readLine()) != null) {
String[] a = s.split(",");
Date d = f.parse(a[0]);
int v = Integer.valueOf(a[1].trim());
series.add(d.getTime(), v);
}
} catch (IOException | ParseException e) {
e.printStackTrace(System.err);
}
return new XYSeriesCollection(series);
}
public JFreeChart createChart(XYDataset dataset)
throws NumberFormatException, IOException {
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"Acceleration vs Time", "Time", "Acceleration", dataset,
true, true, false);
return chart;
}
public static void main(String[] args) throws IOException {
final Test demo = new Test("Test Time Series Chart");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}

How to convert MySQL Timestamp to JFreeChart TimeSeries Graph X Axis values?

I have gone through several questions on StackOverflow but Still I am unable to convert properly timestamp from mysql database to TimeSeries Graph using JfreeCharts. I tried converting to milliseconds or using XYplot but it's not working.
import java.awt.Color;
import java.text.SimpleDateFormat;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.Day;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.Month;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.RefineryUtilities;
//Part of my sql code
import java.sql.*;
import java.text.SimpleDateFormat;
public class Graph1 extends ApplicationFrame {
#SuppressWarnings("deprecation")
static TimeSeries s1 = new TimeSeries("Value", Month.class);
public Graph1(String title) {
super(title);
XYDataset dataset = createDataset();
JFreeChart chart = createChart(dataset);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
chartPanel.setMouseZoomable(true, false);
setContentPane(chartPanel);
}
private static JFreeChart createChart(XYDataset dataset) {
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"Sensor Data Values", // title
"Time", // x-axis label
"Value", // y-axis label
dataset, // data
true, // create legend?
true, // generate tooltips
false // generate URLs?
);
chart.setBackgroundPaint(Color.white);
XYPlot plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);
plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
plot.setDomainCrosshairVisible(true);
plot.setRangeCrosshairVisible(true);
XYItemRenderer r = plot.getRenderer();
if (r instanceof XYLineAndShapeRenderer) {
XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r;
renderer.setBaseShapesVisible(true);
renderer.setBaseShapesFilled(true);
}
DateAxis axis = (DateAxis)plot.getDomainAxis();
axis.setDateFormatOverride(new SimpleDateFormat("dd-MM-yyyy HH-mm-ss"));
return chart;
}
private static XYDataset createDataset()
{
Connection conn = null;
Statement stmt = null;
try
{
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/agriculture","root","root");
stmt = conn.createStatement();
String sql;
sql = "select date_time,data_value from sensor_data order by date_time desc limit 10";
ResultSet rs = stmt.executeQuery(sql);
while(rs.next())
{
Timestamp now = rs.getTimestamp("date_time");
double value = rs.getInt("data_value");
//SimpleDateFormat df = new SimpleDateFormat("YYYY.MM.dd HH:mm:ss");
//String s = df.format(now);
//System.out.print("Time: " + s);
//System.out.print(", Value: " + value + "\n");
s1.add(new Millisecond(now), value);
}
rs.close();
stmt.close();
conn.close();
}
catch(SQLException se)
{
se.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
try
{
if(stmt!=null)
stmt.close();
}
catch(SQLException se2)
{
}
try
{
if(conn!=null)
conn.close();
}
catch(SQLException se)
{
se.printStackTrace();
}//end finally try
}//end try
TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(s1);
//dataset.setDomainIsPointsInTime(true);
return dataset;
}
public static JPanel createDemoPanel()
{
JFreeChart chart = createChart(createDataset());
return new ChartPanel(chart);
}
public static void main(String[] args) {
Graph1 demo = new Graph1("Time Series Demo 1");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
Database Screenshot
Graph Screenshot
The problem is that you're using a deprecated TimeSeries constructor. You've told it to accept values of type Month.class, but you're adding values of type Millisecond.class.
I'm not sure what the MySQL driver does with datetime values retrieved using getTimestamp(), but the complete h2 example below works.
import java.awt.Dimension;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Graph extends JFrame {
public Graph(String title) {
super(title);
JFreeChart chart = createChart(createDataset());
ChartPanel chartPanel = new ChartPanel(chart) {
#Override
public Dimension getPreferredSize() {
return new Dimension(650, 400);
}
};
chartPanel.setMouseZoomable(true, false);
add(chartPanel);
}
private JFreeChart createChart(XYDataset dataset) {
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"Sensor Data Values", "Time", "Value", dataset, true, true, false);
XYPlot plot = (XYPlot) chart.getPlot();
plot.setDomainCrosshairVisible(true);
plot.setRangeCrosshairVisible(true);
XYItemRenderer r = plot.getRenderer();
if (r instanceof XYLineAndShapeRenderer) {
XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r;
renderer.setBaseShapesVisible(true);
renderer.setBaseShapesFilled(true);
}
DateAxis axis = (DateAxis) plot.getDomainAxis();
axis.setDateFormatOverride(new SimpleDateFormat("dd-MMM-yyyy HH:mm"));
return chart;
}
private static XYDataset createDataset() {
TimeSeries series = new TimeSeries("Value");
try {
Connection conn = DriverManager.getConnection("jdbc:h2:mem:test", "", "");
Statement st = conn.createStatement();
st.execute("create table sensor(when datetime, value integer)");
PreparedStatement ps = conn.prepareStatement(
"insert into sensor values (?, ?)");
Calendar c = Calendar.getInstance();
for (int i = 0; i < 10; i++) {
ps.setTimestamp(1, new Timestamp(c.getTimeInMillis()));
ps.setInt(2, i * i + 1);
ps.execute();
c.add(Calendar.HOUR_OF_DAY, 1);
}
st = conn.createStatement();
String sql;
sql = "select when, value from sensor order by when desc";
ResultSet rs = st.executeQuery(sql);
while (rs.next()) {
Timestamp time = rs.getTimestamp("when");
int value = rs.getInt("value");
series.add(new Millisecond(time), value);
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
TimeSeriesCollection dataset = new TimeSeriesCollection(series);
return dataset;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Graph demo = new Graph("Time Series Demo 1");
demo.setDefaultCloseOperation(EXIT_ON_CLOSE);
demo.pack();
demo.setLocationRelativeTo(null);
demo.setVisible(true);
}
});
}
}

Dynamic Time Series Stacked Area Chart in Java

My requirement is to create a dynamic time series stacked area chart in a java desktop app. Something like this example, but i want Stacked Area chart. I have found lot of examples of stacked area chart but they all are based on static data.
Here is the modified version of this example for dynamic time series stacked area chart.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.axis.DateTickUnitType;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.SeriesRenderingOrder;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StackedXYAreaRenderer;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimePeriod;
import org.jfree.data.time.TimeTableXYDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
public class DTSCTest extends ApplicationFrame {
private static final String TITLE = "Dynamic Series";
private static final String START = "Start";
private static final String STOP = "Stop";
private static final float MINMAX = 100;
private static final int COUNT = 15;
private static final int FAST = 1000;
private static final int SLOW = FAST * 5;
private static final Random random = new Random();
private Timer timer;
private static final String SERIES1 = "Positive";
private static final String SERIES2 = "Negative";
public DTSCTest(final String title) {
super(title);
final TimeTableXYDataset dataset = new TimeTableXYDataset();
JFreeChart chart = createAreaChart(dataset);
final JButton run = new JButton(STOP);
run.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (STOP.equals(cmd)) {
timer.stop();
run.setText(START);
} else {
timer.start();
run.setText(STOP);
}
}
});
final JComboBox combo = new JComboBox();
combo.addItem("Fast");
combo.addItem("Slow");
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if ("Fast".equals(combo.getSelectedItem())) {
timer.setDelay(FAST);
} else {
timer.setDelay(SLOW);
}
}
});
this.add(new ChartPanel(chart), BorderLayout.CENTER);
JPanel btnPanel = new JPanel(new FlowLayout());
btnPanel.add(run);
btnPanel.add(combo);
this.add(btnPanel, BorderLayout.SOUTH);
timer = new Timer(FAST, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
TimePeriod period = new Second();
dataset.add(period, randomValue(), SERIES1);
dataset.add(period, randomValue(), SERIES2);
if(dataset.getItemCount() > COUNT) {
TimePeriod firstItemTime = dataset.getTimePeriod(0);
dataset.remove(firstItemTime, SERIES1);
dataset.remove(firstItemTime, SERIES2);
}
}
});
}
private float randomValue() {
float randValue = (float) (random.nextGaussian() * MINMAX / 3);
return randValue < 0 ? -randValue : randValue;
}
private JFreeChart createAreaChart(final TimeTableXYDataset dataset) {
final JFreeChart chart = ChartFactory.createStackedXYAreaChart(
"Live Sentiment Chart", "Time", "Sentiments", dataset, PlotOrientation.VERTICAL, true, true, false);
final StackedXYAreaRenderer render = new StackedXYAreaRenderer();
render.setSeriesPaint(0, Color.RED);
render.setSeriesPaint(1, Color.GREEN);
DateAxis domainAxis = new DateAxis();
domainAxis.setAutoRange(true);
domainAxis.setDateFormatOverride(new SimpleDateFormat("HH:mm:ss"));
domainAxis.setTickUnit(new DateTickUnit(DateTickUnitType.SECOND, 1));
XYPlot plot = (XYPlot) chart.getPlot();
plot.setRenderer(render);
plot.setDomainAxis(domainAxis);
plot.setSeriesRenderingOrder(SeriesRenderingOrder.FORWARD);
plot.setForegroundAlpha(0.5f);
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setNumberFormatOverride(new DecimalFormat("#,###.#"));
rangeAxis.setAutoRange(true);
return chart;
}
public void start() {
timer.start();
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
DTSCTest demo = new DTSCTest(TITLE);
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
demo.start();
}
});
}
}

JFreeChart timeseries is not refreshing

I have developed a timeseries JFreeChart by using code from this thread.
I want to add this to my main panel, which contains four other panels. So I created a method
package com.garnet.panel;
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.*;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.DynamicTimeSeriesCollection;
import org.jfree.data.time.Second;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.RefineryUtilities;
public class PrepareChart {
private static final String TITLE = "Dynamic Series";
private static final int COUNT = 2 * 60;
private Timer timer;
private static float lastValue = 49.62f;
ValueAxis axis;
DateAxis dateAxis;
public JFreeChart chart;
public PrepareChart() {
super();
final DynamicTimeSeriesCollection dataset = new DynamicTimeSeriesCollection(1, COUNT, new Second());
// Get the calender date time which will inserted into time series chart
// Based on time we are getting here we disply the chart
Calendar calendar = new GregorianCalendar();
int date = calendar.get(Calendar.DAY_OF_MONTH);
int month = calendar.get(Calendar.MONTH);
int year = calendar.get(Calendar.YEAR);
int hours = calendar.get(Calendar.HOUR_OF_DAY);
int minutes = calendar.get(Calendar.MINUTE);
int seconds = calendar.get(Calendar.SECOND);
System.out.println("In caht constructor methoed");
dataset.setTimeBase(new Second(seconds, minutes-2, hours, date, month, year));
dataset.addSeries(gaussianData(), 0, "Currency Rate");
chart= createChart(dataset);
timer = new Timer(969, new ActionListener() {
float[] newData = new float[1];
#Override
public void actionPerformed(ActionEvent e) {
newData[0] = randomValue();
System.out.println("In caht timer methoed");
dataset.advanceTime();
dataset.appendData(newData);
}
});
}
private float randomValue() {
double factor = 2 * Math.random();
if (lastValue >51){
lastValue=lastValue-(float)factor;
}else {
lastValue = lastValue + (float) factor;
}
return lastValue;
}
// For getting the a random float value which is supplied to dataset of time series chart
private float[] gaussianData() {
float[] a = new float[COUNT];
for (int i = 0; i < a.length; i++) {
a[i] = randomValue();
}
return a;
}
// This methode will create the chart in the required format
private JFreeChart createChart(final XYDataset dataset) {
final JFreeChart result = ChartFactory.createTimeSeriesChart(TITLE, "hh:mm:ss", "Currency", dataset, true, true, false);
final XYPlot plot = result.getXYPlot();
plot.setBackgroundPaint(Color.BLACK);
plot.setDomainGridlinePaint(Color.WHITE);
plot.setRangeGridlinePaint(Color.WHITE);
plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
plot.setDomainCrosshairVisible(true);
plot.setRangeCrosshairVisible(true);
XYItemRenderer r = plot.getRenderer();
if (r instanceof XYLineAndShapeRenderer) {
XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r;
renderer.setBaseShapesVisible(true);
renderer.setBaseShapesFilled(true);
renderer.setBasePaint(Color.white);
renderer.setSeriesPaint(0,Color.magenta);
}
dateAxis= (DateAxis)plot.getDomainAxis();
DateTickUnit unit = null;
unit = new DateTickUnit(DateTickUnitType.SECOND,30);
DateFormat chartFormatter = new SimpleDateFormat("HH:mm:ss");
dateAxis.setDateFormatOverride(chartFormatter);
dateAxis.setTickUnit(unit);
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
rangeAxis.setRange(lastValue-4, lastValue+4);
return result;
}
public void start(){
timer.start();
}
public JPanel getChartPanel(){
EventQueue.invokeLater(new Runnable() {
public void run() {
PrepareChart chart = new PrepareChart();
System.out.println("In caht getter methoed");
chart.start();
}
});
return new ChartPanel(chart);
}
}
I am calling this code inside one of my panel constructors like this:
public class ChartPanel extends JPanel{
private Dimension dim;
private PrepareChart chart;
public JPanel jChart;
public ChartPanel(){
dim = super.getToolkit().getScreenSize();
this.setBounds(2,2,dim.width/4,dim.height/4);
chart = new PrepareChart();
jChart =chart.getChartPanel();
this.add(jChart);
}
But when I add this panel to the frame, the graph is not changing dynamically.
OK, I think I have spotted your problem, but I can't be completely sure without seeing how you use all this code.
Your main issue lies here:
public JPanel getChartPanel(){
EventQueue.invokeLater(new Runnable() {
public void run() {
PrepareChart chart = new PrepareChart();
System.out.println("In caht getter methoed");
chart.start();
}
});
return new ChartPanel(chart);
}
In your Runnable, you recreate a new instance of PrepareChart and you start it. This does not make any sense:
Your enclosing PrepareChart instance is never started (hence you don't see it updated dynamically)
The instance you create in your runnable cannot be reached by anyone/anything so that instance if lost forever in the AWT event-queue.
So instead, I would only be using the following:
public JPanel getChartPanel() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
start();
}
});
return new ChartPanel(chart);
}
This is a small main method that I wrote which seemed to do the trick.
public static void main(String[] args) {
PrepareChart prepareChart = new PrepareChart();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(prepareChart.getChartPanel());
frame.pack();
frame.setVisible(true);
}
Consider renaming your class ChartPanel because it is conflicting with the names of JFreeChart which is confusing. Also, I don't see the use of it since you could perform all that directly on the ChartPanel returned by PrepareChart.
Btw, it is quite odd to put the call to start() in a getter-method.

Categories