Personal tools
You are here: Home Products Openchart2 Documentation Tutorial #3: Scatter Plot Application
Document Actions

Tutorial #3: Scatter Plot Application

A more complex example showcasing the scatter plot capabilities of Openchart2

Introduction

The last tutorial showed the ease at which Openchart2 can be integrated into Swing applications.  This example takes one step further, showing how charts can be made dynamic using certain data models.

Step 1: Create the Swing Dialog

First we need to create a Swing dialog with some basic controls.  Like the last tutorial, we'll use a simple menu with only a single option in the file menu, "Exit."  We'll also set a standard BorderLayout to manage our content pane in the dialog.  These simple steps are left to the reader. 

Step 2: Construct the Chart

For this relatively complex application, we'll isolate the chart building into a private method.  To encapsulate the necessary code, create a function as follows:

    private ChartPanel getChartPanel() {
       
        // Create the panel if necessary
        if(chartPanel == null) {

...
[ Necessary chart building code ]
...
        }
        return chartPanel;
    }

The next steps for building the chart are similar to previous examples.  We'll construct our data model using a MultiScatterDataModel.   This type of data model allows multiple scatter data sets to be plotted simultaneously, each with differing independent axes.  The model constructor appears below:

    MultiScatterDataModel model = new MultiScatterDataModel();

Notice that no data has been passed into the constructor.  The MultiScatterDataModel object allows data to be added and removed dynamically.  For this example, we'll start with 3 data series:

    for(int i=0;i<INITIAL_LENGTHS.length;i++) {
        // Generate random xy pairs
        double[][] xy = getRandomSeries(INITIAL_LENGTHS[i]);
      
        // Add the data to the model
        model.addData(xy, "Series "+Integer.toString(i+1));
      
        // Set to markers only
        model.setSeriesLine("Series "+Integer.toString(i+1), false);
        model.setSeriesMarker("Series "+Integer.toString(i+1), true);
    }

The code above generates and adds three series to our data model.  The custom class we've created for this example includes a private method named getRandomSeries() that generates an #-by-2 array of random values between 0 and 100, where # is specified when the method is called.  This 2D array can then be passed to the MultiScatterDataModel's addData() method, which includes the passed data into the data model.

After we add each series, the series properties are set.  MultiScatterDataModel stores information about how each series should be drawn.  This type of data model always defaults to drawing lines connecting each xy data point in order.  In the example above, the line drawing is disabled and the marker drawing is enabled.  Each series in the MultiScatterDataModel can be addressed by the series name.

Now that the model is built, the standard set of chart-building calls still remain.  Code for constructing the coordinate system and the chart panel appears below:

    // Create an associated coordinate system object
    CoordSystem coord = new CoordSystem(model);
      
    // Generate the chart panel
    chartPanel = new ChartPanel(model,"Random Data");
           
    // Add the coordinate system to the chart
    chartPanel.setCoordSystem(coord);

Now the proper renderer must be added to the newly created panel.  When using a MultiScatterDataModel, the MultiScatterChartRenderer should be used to take full advantage of the data model's capabilities.  The renderer is constructed as shown:

MultiScatterChartRenderer renderer = new MultiScatterChartRenderer(coord,model);

Because scatter plots can often contain enormous amounts of data, the MultiScatterChartRenderer object offers a buffering feature to improve plotting speed.  Normally Openchart2 transforms data from data-space to graphics-space every time a redraw occurs.  This feature ensures proper redraws if the drawn data is dynamic.  If the data is static, however, it may be beneficial to perform the transform from data-space to graphics-space only once.  MultiScatterChartRenderer offers this feature since large amounts of data may be plotted at once.  In our example, we are going to be dealing with dynamic data, so this buffering of transformed points will lead to problems.  Below we explicitly disable the buffering feature (although it is disabled by default):

    renderer.setAllowBuffer(false);

Finally, the renderer must be added to the chart panel.  Similar to other examples, we'll add our only renderer at a z-position of zero:

    chartPanel.addChartRenderer(new MultiScatterChartRenderer(coord,model), 0);

Our chart is now constructed and can be added directly to our dialog panel.  Like the previous tutorial, we'll add the panel to the dialog's content pane at the center BorderLayout position.

Step 3: Add Some Dynamic Behavior

To make this example interesting, some dynamic behavior can now be integrated into our Swing application.  During dialog construction, lets create another panel containing two buttons: "Add" and "Remove."  Assign our custom class as their action listener.  The code appears below:

    // Create a panel of buttons on the bottom
    b_add = new JButton("Add Series");
    b_remove = new JButton("Remove Series");
    b_add.addActionListener(this);
    b_remove.addActionListener(this);

    JPanel buttons = new JPanel();
    buttons.add(b_add);
    buttons.add(b_remove);

These two buttons will provide our application with the ability to add and remove series from the chart.  Add this panel to our main content pane at the south BorderLayout position.

The actionPerformed method can handle both buttons (as well as our "Exit" menu item).  The code appears below:

    public void actionPerformed(java.awt.event.ActionEvent e) {
        // If this was our exit button responding, dispose of the dialog
        if(e.getSource() == m_exit)
            dispose();
        else if(e.getSource() == b_add)
            addSeries();
        else if(e.getSource() == b_remove)
            removeSeries();
    }

We need two more methods, one for adding series, the other for removing series.  Let's handle adding a new series first.

To add a series, we'll again generate a random data set using the getRandomSeries() method already discussed.  For the purposes of this example, we'll further randomize the series length. The calls to build the data are simply:

    int length = 15+(int)(Math.random()*20.0);
    double[][] data = getRandomSeries(length);

This data is then added to our existing data model.  Like our original chart-building code, we'll add the data to the model and set the properties accordingly:

    model.addData(data, "Series "+Integer.toString(series_count+1));
           
    // Set to markers only
    model.setSeriesLine("Series "+Integer.toString(series_count+1), false);
    model.setSeriesMarker("Series "+Integer.toString(series_count+1), true);

We've now added data to the model, but we need to request a redraw to force the chart to update.  Finish the addition with the simple call:

    getChartPanel().repaint();

Removing data is even easier.  The remove button in this case will simply remove the last series added.  To remove the last data set added, use the following code:

    int series_count = model.getDataSetNumber();
    model.removeData(series_count-1);

The data is now removed from the chart.  Note that the addData() and removeData() methods are unique to the MultiScatterDataModel and not generic across all Openchart2 model types.

Conclusion

This example showed the dynamic abilities of Openchart2.  The complete source listing provides further dynamic behavior.  If you download the complete code, you'll notice that some precautions have been added to limit the number of series that can be added and removed.  The chart title will change depending on which limit, upper or lower, is reached.  This example provides a starting point for those who wish to integrate an Openchart2 plot with dynamic behavior into any Swing application.

Source Code: Download!


Related content
Advertisements
« July 2010 »
Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: