Usage
This page provides a quick howto for JChart2D. Additional information may be found at the documentation page.
Demo
Before you start you might want to take a look at JChart2D's realtime performance. This may be done on the applet page or by downloading the binary jar file, let's say jchart2d-3.2.2.jar. The jar file is contained in the distributed binary zip file. You have to deflate it using a zip program (google helps).
- Download the file to a directory <dir>.
- Open a command window. For windows you may start -> execute -> type "cmd" or start -> execute -> type "command". Linux users will know.
- Ensure, you have a java runtime environment installed. On your command window type "java". If unsuccessful you should download and install the Java Runtime Environment from http://www.oracle.com/technetwork/java/javase/downloads/index.html. If you don't want to start developing in Java, the JRE link on that page is sufficient. After this procedure reopen the command window and type "java" again. It should work. If not set the bin subdirectory of the JRE installation to the PATH environment variable (for linux via the export command, for windows under start -> settings -> system -> advanced). If the PATH variable had to be set under windows you have to reopen the command window again before testing whether the "java" command works.
Now go to <dir> via the "cd" command and type.
java -jar jchart2d-3.2.2.jarThe showcase example chart starts.
The Showcase application allows to interact with the data collection (start/stop) and to save the Chart2D's graphics to an image file in a format that is supported by your Java Runtime Environment. The sourcecode may be viewed from cvs here.
Another example with multithreaded traces may be viewed by typing:
java -cp jchart2d-3.2.2.jar info.monitorenter.gui.chart.demos.MultiTracingYou may resize the window and see how the scaling takes advantage of more space. The command looks different to the first. This is because the first command tells java to look into the jar file for a file META-INF/manifest.mf in which the name of the entry point (main class) is written. The 2nd command tells plain-forward which class to start.
If you want to use all features of JChart2D enabled (e.g. eps export) you have to include all libraries (*.jar files) from the
binary distribution zip file in the class path of the java process.
For Windows type:
java -cp jchart2d-3.2.2.jar;xmlgraphics-commons-1.3.1.jar;jide-oss-2.9.7.jar info.monitorenter.gui.chart.demos.MultiTracingFor Linux type:
java -cp jchart2d-3.2.2.jar:xmlgraphics-commons-1.3.1.jar:jide-oss-2.9.7.jar info.monitorenter.gui.chart.demos.MultiTracing
Design
The framework is quite small, simple but clever. The javavdoc documentation may look overwhelming at first sight, but the things that have to be touched at startup are few.
Before describing the framework itself, an abstract introduction to
the concept shall be given.
Within JChart2D a chart is an instance that renders traces. It may render
only one trace or more. Traces consist of points or tuples, that are
nothing more than two doubles x,y that represent a location in a two
dimensional coordinate system. The chart ensures, that every point of
every trace it owns is displayed. It does this by finding the minimum maximum
bounds of both dimensions x and y and scales every point into it's
display size.
A trace itself may only be contained in one chart [caused by synchronization requirements].
It has it's own color, name and
policy of ordering the points that are added to it.
It even has a trace painter that allows different graphical representation
of the data points. By default a trace painter that interconnects the
data points with lines is used but dots, circles and filled polygon
is currently supported.
The interaction needed for rendering is a chain: The application code that
uses the API just adds a point to a trace. The trace then notifies it's chart
that it has changed. The chart then keeps this change in mind and will rescale and
repaint in the next painting cycle. Nothing more has to be done at runtime by the user code
than simply adding points to traces.
The following diagram is simplified and only displays the methods, that have to be invoked to set up a chart.
Chart2DThe most important component is the Chart2D class. It is a JComponent [not shown] and therefore may be used within swing applications as any other component. You can add it to the component hierarchy of your user interface implementation. It does nothing more than render the data of it's contained ITrace2D implementations. Towards the ITrace2D implementations it plays the role of an "event receiver". It's interface ITrace2DListener is used by the ITrace2D implementations to notify the chart about changed points.More information is given in the description of the class.
ITrace2DThese are collections of Point2D instances. They are instantiated and added to a Chart2D instance. Then new Point2D instances may be added. The ITrace2D implementation will notify the Chart2D instance about changes. You can define it's label, it's unit, color... . Some methods of the interface are services for the Chart2D, which uses them for rendering and calculations. There are several different implementations. For the right choice read "Choosing the right trace".More information is given in the description of the class.
TracePoint2DA simple data type that contains the two double values that define a location in a two dimensional coordinate system. Instances are created by the application code, that uses the JChart2D API. The Chart2D uses two package friendly members to cache values scaled between 0.0 and 1.0. It is possible to alter the values inside [setLocation(double,double)] which will notify the corresponding ITrace implementation [if the TracePoint2D has been added to an ITrace already] and the Chart2D will be informed too in order to repaint. |
Minimal Code
For playing around with the demo code provided I recommend to use an IDE like eclipse. Put the jar file from the binary zip download into the classpath of your IDE. Under eclipse this is done by copying the file in your eclipse workspace/<projectname> directory and then choosing:
Project -> properties -> Java Build Path -> Add Jar
Static example
The follwing code shows the minimal effort to set up a static Chart2D and let it be displayed. The values will not be changed at runtime.
package info.monitorenter.gui.chart.demos; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Random; import javax.swing.JFrame; import info.monitorenter.gui.chart.Chart2D; import info.monitorenter.gui.chart.ITrace2D; import info.monitorenter.gui.chart.traces.Trace2DSimple; public class MinimalStaticChart { private MinimalStaticChart() { super(); } public static void main(String[]args){ // Create a chart: Chart2D chart = new Chart2D(); // Create an ITrace: ITrace2D trace = new Trace2DSimple(); // Add the trace to the chart. This has to be done before adding points (deadlock prevention): chart.addTrace(trace); // Add all points, as it is static: Random random = new Random(); for(int i=100;i>=0;i--){ trace.addPoint(i,random.nextDouble()*10.0+i); } // Make it visible: // Create a frame. JFrame frame = new JFrame("MinimalStaticChart"); // add the chart to the frame: frame.getContentPane().add(chart); frame.setSize(400,300); // Enable the termination button [cross on the upper right edge]: frame.addWindowListener( new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } } ); frame.setVisible(true); } }
This example does not look very amazing. You could additionally set the color of the
trace, background color of the Chart2D, set a label to the trace,... See the Javadoc documentation
for things one could do.
Please don't copy & paste this example as is if you are planning to integrate the
chart in a complex user interface. For those tasks one way could be to configure
the chart within the UI top-level class. But this wouldn't be clean. I suggest to add
a method "setChart(Char2D)" to your UI top-level class, configure the chart with
traces and other things outside and then add it to your UI.
Dynamic example
This example is more advanced and shows the strong side of JChart2D. A chart is created that will receive new points at runtime and update itself. Note, that for traces that continuously receive new values a limited amount of points has to be chosen: The Trace2DLtd implementation is based on a ringbuffer and guarantees, that no java.lang.OutOfMemoryError will happen. Also it is helpful for performance: The more points have to be rendered, the more calculations have to be done.
In this example a timer is used to simulate that points are added over time from a separate Thread. In your application most often you have a separate polling Thread that collects the data to plot (e.g. from a database or a serial port ("Observer pattern")). Or some event listener which will be called from a separate thread (e.g. a web request, database trigger... ("Reactor pattern")). So don't copy the timer stuff unless you need a polling thread that observes external data structures.
package info.monitorenter.gui.chart.demos; import info.monitorenter.gui.chart.Chart2D; import info.monitorenter.gui.chart.IAxis; import info.monitorenter.gui.chart.ITrace2D; import info.monitorenter.gui.chart.traces.Trace2DLtd; import info.monitorenter.gui.chart.views.ChartPanel; import java.awt.Color; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Timer; import java.util.TimerTask; import javax.swing.JFrame; /** * Demonstrates minimal effort to create a dynamic chart. * * @author Achim Westermann * */ public class MinimalDynamicChart { public static void main(String[]args){ // Create a chart: Chart2D chart = new Chart2D(); // Create an ITrace: // Note that dynamic charts need limited amount of values!!! ITrace2D trace = new Trace2DLtd(200); trace.setColor(Color.RED); // Add the trace to the chart. This has to be done before adding points (deadlock prevention): chart.addTrace(trace); // Make it visible: // Create a frame. JFrame frame = new JFrame("MinimalDynamicChart"); // add the chart to the frame: frame.getContentPane().add(chart); frame.setSize(400,300); // Enable the termination button [cross on the upper right edge]: frame.addWindowListener( new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } } ); frame.setVisible(true); /* * Now the dynamic adding of points. This is just a demo! * * Use a separate thread to simulate dynamic adding of date. * Note that you do not have to copy this code. Dynamic charting is just about * adding points to traces at runtime from another thread. Whenever you hook on * to a serial port or some other data source with a polling Thread (or an event * notification pattern) you will have your own thread that just has to add points * to a trace. */ Timer timer = new Timer(true); TimerTask task = new TimerTask(){ private double m_y = 0; private long m_starttime = System.currentTimeMillis(); /** * @see java.util.TimerTask#run() */ @Override public void run() { // This is just computation of some nice looking value. double rand = Math.random(); boolean add = (rand >= 0.5) ? true : false; this.m_y = (add) ? this.m_y + Math.random() : this.m_y - Math.random(); // This is the important thing: Point is added from separate Thread. trace.addPoint(((double) System.currentTimeMillis() - this.m_starttime), this.m_y); } }; // Every 20 milliseconds a new value is collected. timer.schedule(task, 1000, 20); } /** Defcon. */ private MinimalDynamicChart() { // nop } }
Choosing the right trace
There are several implementations of the interface which differ in the policy of ordering or accepting the points. The proper one has to be chosen according to the characteristics of data and the process of adding it.
Type | Acceptance | Ordering | Note |
---|---|---|---|
Trace2DSimple | Accepts every new point. | As added. | Not intended for continuous add operations: Memory will be exceeded. |
Trace2DLtd | Accepts every new point, but oldest one is dropped, if internal maximum amount is exceeded. | As added. | Based on a fast ringbuffer. |
Trace2DBijective | Accepts every new point, but potentially contained points with the same x value are removed. | As added. | Based on a LinkedList. |
Trace2DLtdReplacing | Accepts the data of every new point. Potentially contained points with the same x value get updated with the y value. | Points with unique x values are ordered as added. Points with x values already contained replace the old point at it's position. | Based on a ringbuffer (subclass of Trace2DLtd), worst case for addPoint of O(n), where n is the amount of points in the trace. This happens often, when no x values recur. |
Trace2DSorted | Accepts the data of every new point. Potentially contained points with the same x value get updated with the y value. | Ordered by ascending x values. | No same x value will occur. Removal policy for recurring x values as Trace2DLtdReplacing. Based on a TreeSet. |