Skip to main content

How to draw Dynamic Line or Timeseries Chart in Java using jfreechart library?


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 :)

 

Comments

  1. Can We have a scroller to see the previously plotted points.

    ReplyDelete
  2. Yes sure you can do it.

    Following 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

    ReplyDelete
  3. Hi Shiv.. Can u please help me in ploting some values which i'l be retrieving dynamicaly from Database.

    I 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.

    ReplyDelete
  4. have you tried slider as per my previous comment?

    ReplyDelete
  5. yes i added the slider in the above code. But dint added anything in state change.

    Coz 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.

    ReplyDelete
  6. hmm...I have to gone through your code. Can you please post your code here.

    ReplyDelete
  7. public class LineChartApplet extends JApplet
    {
    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
    */

    ReplyDelete
  8. @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
  9. @Shiv : Can u please explain why it is so..

    If it is not at all possible den can u please give me other solution. And can your example serve my purpose.

    Thanks.

    ReplyDelete
  10. 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

    ReplyDelete
  11. Hi shiv. I have send you the screenshot on the given mailid.

    Can your example serve my purpose i.e. can I I/P (x,y) values.

    ReplyDelete
  12. 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.

    ReplyDelete
    Replies
    1. Shiv Modi can you please send me that example.
      Email->mayurkaushal29gmail.com
      Thanks in advance

      Delete
  13. thanx.. i'l check it and will tell you if any problem..

    ReplyDelete
  14. Replies
    1. hi 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.

      Delete
    2. Hi Bala, For that you have to make few changes.

      set 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?

      Delete
    3. 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

      Delete
    4. I think following page can solve your problem

      http://www.jfree.org/phpBB2/viewtopic.php?t=9621

      Delete
  15. Are you interested in part time (freelance) projects?

    ReplyDelete
  16. Hi Shiv,
    I 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


    ReplyDelete
    Replies
    1. Have you imported all the packages mentioned in example?

      Delete
  17. shiv, i need a chat exactly like this;
    with 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..

    ReplyDelete
    Replies
    1. Hi Ersin, It's too late, but have you done with the issue?

      Delete
  18. Hi Shiv,
    Can 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.

    ReplyDelete
  19. hello , thanks for the code it's really helpful
    i have a question , is it possible to change range axis from left to right

    ReplyDelete
  20. Hi Osam, such comments encourage me to share more...thanks. Ofcourse, you can use setRangeAxisLocation() function to achieve it.

    ReplyDelete
  21. Hi, 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.

    ReplyDelete
  22. Hello,

    First 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

    ReplyDelete
    Replies
    1. 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
      May be it can solve your problem. Kindly let me know if it worked or not..

      Delete
  23. Shiv, thanks for sharing the knowledge.

    ReplyDelete
  24. Hello guys, Thank you for this code. I've a problem, how do i add multiple series? Help me soon, Thanks!

    ReplyDelete
    Replies
    1. Thanks 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

      Delete
    2. Thanks Shiv sir, now how do I retrieve it from the database ànd then plot each second??
      Thank you very much in advance!

      Delete
  25. 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

Post a Comment

Thanks for your valuable comments.

Popular posts from this blog

Odoo/OpenERP: one2one relational field example

one2one relational field is deprecated in OpenERP version>5 but you can achieve the same using many2one relational field. You can achieve it in following two ways : 1) using many2one field in both the objects ( http://tutorialopenerp.wordpress.com/2014/04/23/one2one/ ) 2)  using inheritance by deligation You can easily find the first solution with little search over internet so let's start with 2nd solution. Scenario :  I want to create a one2one relation between two objects of openerp hr.employee and hr.employee.medical.details What I should do  i. Add _inherits section in hr_employee class ii. Add field medical_detail_id in hr_employee class class hr_employee(osv.osv):     _name = 'hr.employee'     _inherits = {' hr.employee.medical.details ': "medical_detail_id"}     _inherit = 'hr.employee'         _columns = {             ...

pyodbc.OperationalError: ('08001', '[08001] [Microsoft][ODBC Driver 17 for SQL Server]

Recently, I faced this error in our Docker-Container environment. All the necessary packages were already installed but still, I was facing this clueless error. I search a bit and after an hour and so I found the exact reason and solution for this error. To know more about this error in detail. Please follow this Github thread. https://github.com/mkleehammer/pyodbc/issues/610 https://github.com/mkleehammer/pyodbc/issues/610#issuecomment-587523802 Solution: It's because the   server's certificate has too weak a key. In case you are using Linux env directly/not the Docker one.  Just edited /etc/ssl/openssl.cnf and change these 2 lines. MinProtocol = TLSv1.0 CipherString = DEFAULT@SECLEVEL=1 In case you are also using a container, please add these three lines to your Docker file. RUN chmod +rwx /etc/ssl/openssl.cnf RUN sed -i ' s/TLSv1.2/TLSv1/g ' /etc/ssl/openssl.cnf RUN sed -i ' s/SECLEVEL=2/SECLEVEL=1/g ' /etc/ssl/openssl.cnf Thanks!! Enjoy Programming! Refer...