Today we are going to write
a code to draw a dynamic timeseries-cum-line chart in java. The only difference between simple and
dynamic chart is that a dynamic event is used to create a new series and update
the graph. In out example we are using timer which automatically calls a
funtion after every 1/4 th second and graph is updated with random data. Let's
try with the code :
Note : I had tried my best to
provide complete documentation along with code. If at any time anyone have any
doubt or question please post in comments section.
DynamicLineAndTimeSeriesChart.java
import
java.awt.BorderLayout;
import
java.awt.Color;
import
java.awt.event.ActionEvent;
import
java.awt.event.ActionListener;
import
javax.swing.Timer;
import
javax.swing.JPanel;
import
org.jfree.chart.ChartFactory;
import
org.jfree.chart.ChartPanel;
import
org.jfree.chart.JFreeChart;
import
org.jfree.chart.axis.ValueAxis;
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;
/**
* An example to show how we can create a
dynamic chart.
*/
public class
DynamicLineAndTimeSeriesChart extends ApplicationFrame implements
ActionListener {
/** The time
series data. */
private
TimeSeries series;
/** The most
recent value added. */
private double
lastValue = 100.0;
/** Timer to refresh graph after every 1/4th
of a second */
private Timer
timer = new Timer(250, this);
/**
* Constructs a new dynamic chart
application.
*
* @param title the frame title.
*/
public DynamicLineAndTimeSeriesChart(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);
timer.setInitialDelay(1000);
//Sets
background color of chart
chart.setBackgroundPaint(Color.LIGHT_GRAY);
//Created
JPanel to show graph on screen
final
JPanel content = new JPanel(new BorderLayout());
//Created
Chartpanel for chart area
final
ChartPanel chartPanel = new ChartPanel(chart);
//Added
chartpanel to main panel
content.add(chartPanel);
//Sets the size of whole window (JPanel)
chartPanel.setPreferredSize(new
java.awt.Dimension(800, 500));
//Puts the
whole content on a Frame
setContentPane(content);
timer.start();
}
/**
* Creates a sample chart.
*
* @param dataset the dataset.
*
* @return A sample chart.
*/
private
JFreeChart createChart(final XYDataset dataset) {
final JFreeChart result =
ChartFactory.createTimeSeriesChart(
"Dynamic Line And TimeSeries
Chart",
"Time",
"Value",
dataset,
true,
true,
false
);
final XYPlot plot = result.getXYPlot();
plot.setBackgroundPaint(new
Color(0xffffe0));
plot.setDomainGridlinesVisible(true);
plot.setDomainGridlinePaint(Color.lightGray);
plot.setRangeGridlinesVisible(true);
plot.setRangeGridlinePaint(Color.lightGray);
ValueAxis xaxis = plot.getDomainAxis();
xaxis.setAutoRange(true);
//Domain axis would show data of 60 seconds
for a time
xaxis.setFixedAutoRange(60000.0); // 60
seconds
xaxis.setVerticalTickLabels(true);
ValueAxis
yaxis = plot.getRangeAxis();
yaxis.setRange(0.0, 300.0);
return result;
}
/**
* Generates an random entry for a
particular call made by time for every 1/4th of a second.
*
* @param e
the action event.
*/
public void
actionPerformed(final ActionEvent e) {
final double factor = 0.9 +
0.2*Math.random();
this.lastValue = this.lastValue *
factor;
final Millisecond now = new
Millisecond();
this.series.add(new Millisecond(),
this.lastValue);
System.out.println("Current Time
in Milliseconds = " + now.toString()+", Current Value :
"+this.lastValue);
}
/**
* Starting point for the dynamic graph
application.
*
* @param args ignored.
*/
public static
void main(final String[] args) {
final DynamicLineAndTimeSeriesChart
demo = new DynamicLineAndTimeSeriesChart("Dynamic Line And TimeSeries
Chart");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
OUTPUT :
Thanks!!!!!!!!!!! Enjoy Programming :)
Can We have a scroller to see the previously plotted points.
ReplyDeleteYes sure you can do it.
ReplyDeleteFollowing is the procedure to achieve this functionality.
1) Add slider to main panel.
2) Get minimum value of domain axis.
3) Set interval for domain axis for which you wanna show values, for example in this example i can opt for 60 or 120 seconds.
4) Write a state change function which will trigger on change of slider or scroller value. Set domain axis minimum and maximum limit as per the slider value.
That's it.
As reference you can also use following link, a very good example of scrollbar implementation.
http://stackoverflow.com/questions/3231840/jfreechart-scroll-xybarchart-horizontally-chart-translation-and-navigation
Hi Shiv.. Can u please help me in ploting some values which i'l be retrieving dynamicaly from Database.
ReplyDeleteI had used line chart.
These values are on X-axis. I plotted the first 10 values. Then For dynamicity, I was adding a new(11th) value and deleting the first one. So looked like a moving chart.
It worked fine. But the problem is, I am unable to see the previous data plotted.
I am new to JFreeChart.
Please help me.
have you tried slider as per my previous comment?
ReplyDeleteyes i added the slider in the above code. But dint added anything in state change.
ReplyDeleteCoz I found that you are giving the X axis value as time.
I m realy confused.
Pleas guide me how can i do same as you have done above.
Thanks.
hmm...I have to gone through your code. Can you please post your code here.
ReplyDeletepublic class LineChartApplet extends JApplet
ReplyDelete{
private static final long serialVersionUID = 1L;
final CategoryDataset dataset = new DefaultCategoryDataset();
public void init()
{
this.setSize(600, 270);
final JFreeChart chart = createChart(dataset);
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(
new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}
private JFreeChart createChart(final CategoryDataset dataset)
{
final JFreeChart chart = ChartFactory.createLineChart(
"RPM", // chart title
"X", // domain axis label
"Y", // range axis label
dataset, // data
PlotOrientation.VERTICAL, // orientation
true, // include legend
true, // tooltips
false // urls
);
final Shape[] shapes = new Shape[3];
int[] xpoints;
int[] ypoints;
// right-pointing triangle
xpoints = new int[] {-3, 3, -3};
ypoints = new int[] {-3, 0, 3};
shapes[0] = new Polygon(xpoints, ypoints, 3);
// vertical rectangle
shapes[1] = new Rectangle2D.Double(-2, -3, 3, 6);
// left-pointing triangle
xpoints = new int[] {-3, 3, 3};
ypoints = new int[] {0, -3, 3};
shapes[2] = new Polygon(xpoints, ypoints, 3);
final DrawingSupplier supplier =
new DefaultDrawingSupplier(
DefaultDrawingSupplier.DEFAULT_PAINT_SEQUENCE,
DefaultDrawingSupplier.DEFAULT_OUTLINE_PAINT_SEQUENCE,
DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE,
DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
shapes
);
final CategoryPlot plot = chart.getCategoryPlot();
plot.setDrawingSupplier(supplier);
chart.setBackgroundPaint(Color.lightGray);
// set the stroke for each series...
plot.getRenderer().setSeriesStroke(
0,
new BasicStroke(
2.0f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND,
1.0f, new float[] {10.0f, 6.0f}, 0.0f
)
);
plot.getRenderer().setSeriesStroke(
1,
new BasicStroke(
2.0f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND,
1.0f, new float[] {6.0f, 6.0f}, 0.0f
)
);
plot.getRenderer().setSeriesStroke(
2,
new BasicStroke(
2.0f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND,
1.0f, new float[] {2.0f, 6.0f}, 0.0f
)
);
// customise the renderer...
final LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
renderer.setItemLabelsVisible(false);
// customise the range axis...
final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
rangeAxis.setAutoRangeIncludesZero(false);
rangeAxis.setUpperMargin(0.12);
return chart;
}
public void SetLine(double rpm , int xAxisVal , int columnKey)
{
((DefaultCategoryDataset)dataset).removeValue("rpm", columnKey);
((DefaultCategoryDataset)dataset).addValue(rpm , "rpm" , new Integer(xAxisVal));
}
public void SetLine(double rpm , int xAxisVal)
{
((DefaultCategoryDataset)dataset).addValue(rpm , "rpm" , new Integer(xAxisVal));
}
}
/*
The last two functions are for adding values.
the first one is to add one value and remove the first one.
and the second method is only for adding the value
*/
@Mukesh : After going through your code i think your x-axis values fall between -3 to 3. Right? If yes then it's difficult to move backward using any logic :(
ReplyDelete@Shiv : Can u please explain why it is so..
ReplyDeleteIf it is not at all possible den can u please give me other solution. And can your example serve my purpose.
Thanks.
Because your x-axis values are between -3 to 3. But i'm not able to get then how your graph is moving because if at x=-3 you are having another value then it will overwrite the previous one. Can you please send your chat screenshot on dirtyhandsphp@gmail.com
ReplyDeleteHi shiv. I have send you the screenshot on the given mailid.
ReplyDeleteCan your example serve my purpose i.e. can I I/P (x,y) values.
Mukesh : Got your email. Now everything is clear. You are using Linechart to draw your graph and my example is based on TimeSeriesChart. As per your requirements you have to work with LineChart only (Because on x-axis you are using values instead of time). So this example won't meet your purpose. But for your help I am sending an example that would for sure will work for you. Check your email.
ReplyDeleteShiv Modi can you please send me that example.
DeleteEmail->mayurkaushal29gmail.com
Thanks in advance
thanx.. i'l check it and will tell you if any problem..
ReplyDeletefine
ReplyDeletehi Modi...I need a line chart in that the x axis is continuously moving with respect to the time interval of every min and y value update is get from the another one class.So can you help me for that application.
DeleteHi Bala, For that you have to make few changes.
Deleteset timer as one minute as you want the chart to be updated after every minute
/** Timer to refresh graph after every 60 seconds */
private Timer timer = new Timer(60000, this);
//Use first parameter as minute instead of milliseconds
this.series.add(new Minute(), this.lastValue);
and
//Domain axis would show data of 60 minutes for a time
//it would show graph of 1 hour
xaxis.setFixedAutoRange(3600000.0); // 60 minutes
Please let me know if it helped?
hi i need a dynamic line chart in web page.Can u help me.Its in simple JSP not with servlet.Only with simple beans.The updated value comes in separate class..I wrote the code that code get the value for every 5 min.And its updated in one table shown in the JSP.I m struct in the moving Graph.Pls help.If u hav any code mail 2 my id pls.kishorekumar224@gamil.com
DeleteI think following page can solve your problem
Deletehttp://www.jfree.org/phpBB2/viewtopic.php?t=9621
Are you interested in part time (freelance) projects?
ReplyDeleteYes sure.
DeleteHi Shiv,
ReplyDeleteI get following exception while running your code.
Exception in thread "main" java.lang.NoClassDefFoundError: org/jfree/ui/ApplicationFrame
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Caused by: java.lang.ClassNotFoundException: org.jfree.ui.ApplicationFrame
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
... 12 more
I didn't have jfreechart. So I downloaded jcommon-1.0.18.jar and jfreechart-1.0.0.jar and compiled the code as:
javac -classpath jfreechart-1.0.0.jar:jcommon-1.0.18.jarDynamicLineAndTimeSeriesChart.java
Have you imported all the packages mentioned in example?
Deleteshiv, i need a chat exactly like this;
ReplyDeletewith timeseries chart, 3 lines starts from right and goes to left in every 5 seconds. need multiple lines on the go :) my mail: ersi_n@yahoo.com thanks if u help me..
Hi Ersin, It's too late, but have you done with the issue?
DeleteHi Shiv,
ReplyDeleteCan u give me an example of Linechart in Jfreechart with smooth sinewave like curves??
I am not able to find any example of it.
Its really very urgent.
hello , thanks for the code it's really helpful
ReplyDeletei have a question , is it possible to change range axis from left to right
Hi Osam, such comments encourage me to share more...thanks. Ofcourse, you can use setRangeAxisLocation() function to achieve it.
ReplyDeleteHi, i need to generate a line chart for the values retreived from the database? How can i do it.. Please can you modify the code.
ReplyDeleteHello,
ReplyDeleteFirst of all I would like to thank you for this exemple. However, I would like to know how to make the lines look like curves because all what I'm getting is straight lines groupped together, I've tried to use plot.setRenderer(new XYSplineRenderer()); but i'm not getting the curve.. Maybe i'm placing it at the wrong place from the code. Do you have any suggestion plz?
Thank you in advance
Hi Steve, It's great that this example helped you. I worked on jfreecharts a long back so don't remember that in deep but you can check some examples here: http://www.massapi.com/class/xy/XYSplineRenderer.html
DeleteMay be it can solve your problem. Kindly let me know if it worked or not..
Shiv, thanks for sharing the knowledge.
ReplyDeleteThumbs up!!! :)
DeleteHello guys, Thank you for this code. I've a problem, how do i add multiple series? Help me soon, Thanks!
ReplyDeleteThanks Likith. You have to create multiple TimeSeries objects instead of one. I think you can get help from following link: https://codedump.io/share/7Wp5zHoazLL/1/how-to-draw-three-lines-on-dynamic-jfreechart
DeleteThanks Shiv sir, now how do I retrieve it from the database à nd then plot each second??
DeleteThank you very much in advance!
Hey, I am new to JFreeChart and Swing but I have understood your code. I want to read data from ethernet port and keep on updating the char every 5 seconds. How can i do that. I would be thankful for ur time and help :)
ReplyDelete