JCCKit logo

2.2 Example: Lorenz Attractor

The applet Lorenz (see the Examples page) shows trajectories of the famous Lorenz equations in an animated way. It is an example of the usage of point-to-point hints (see Chapter 1.3 Curves, Points, and Hints).

The overridden applet method init() is similar as in the example AnimatedChart (click here to see the complete code):

public class Lorenz extends Applet {
  private double[] _x = new double[3];
  private double[][] _walk = new double[50][2];
  private int _walkIndex;
  private DataPlot _dataPlot;
  private Thread _animationThread;
  public void init() { 
    GraphicsPlotCanvas plotCanvas 
        = createPlotCanvas("true".equals(getParameter("graphics2D")));
    _dataPlot = new DataPlot();
    _dataPlot.addElement(new DataCurve(""));
    setLayout(new BorderLayout());
    add(plotCanvas.getGraphicsCanvas(), BorderLayout.CENTER);
    add(createControlPanel(), BorderLayout.SOUTH);

  private GraphicsPlotCanvas createPlotCanvas(boolean graphics2D) { ... }

  private Panel createControlPanel() { ... }

  private void reset() { ... }
Highlighted code uses JCCKit.

First, createPlotCanvas() creates a GraphicsPlotCanvas (or a Graphics2DPlotCanvas depending on the applet parameter named graphics2D). Next, a DataPlot object with an empty DataCurve is created. The method reset() replaces the empty curve by an initial curve with 50 identical points. After the DataPlot has been connected to the PlotCanvas the applet panel will be filled with the view of the PlotCanvas and the control panel with the buttons.

The state of the Lorenz equation is stored in the array _x. The array _walk holds two variables from the current state as well as from the 49 previous states. The _walkIndex points onto the current state inside _walk.

Here is the code for configuration and creation of the PlotCanvas:

private GraphicsPlotCanvas createPlotCanvas(boolean graphics2D) {
  Properties props = new Properties();
  ConfigParameters config = new ConfigParameters(new PropertiesBasedConfigData(props));
  props.put("foreground", "0xffffff");
  props.put("background", "0");
  props.put("plot/legendVisible", "false");
  props.put("plot/coordinateSystem/xAxis/minimum", "-20");
  props.put("plot/coordinateSystem/xAxis/maximum", "20");
  props.put("plot/coordinateSystem/xAxis/ticLabelFormat", "%d");
  props.put("plot/coordinateSystem/yAxis/axisLabel", "z");
  props.put("plot/coordinateSystem/yAxis/minimum", "0");
  props.put("plot/coordinateSystem/yAxis/maximum", "50");
  props.put("plot/coordinateSystem/yAxis/ticLabelFormat", "%d");
  props.put("plot/curveFactory/definitions", "curve");
            "0.0 0.0 0.018");
  props.put("plot/curveFactory/curve/withLine", "false");
  props.put("plot/curveFactory/curve/symbolFactory/size", "0.015");
  return graphics2D ? new Graphics2DPlotCanvas(config) : new GraphicsPlotCanvas(config);
The animation is started after the start button has been hit. It runs inside the _animationThread which calls next():
private void next() {
  _walk[_walkIndex][0] = _x[0];
  _walk[_walkIndex][1] = _x[2];
  _walkIndex = (_walkIndex + 1) % _walk.length;

private void integrate() { ... }
private void updateCurve() {
  DataCurve curve = new DataCurve("trajectory");
  for (int i = 0; i < _walk.length; i++) {
    int index = (_walkIndex + i) % _walk.length;
    curve.addElement(new DataPoint(_walk[index][0], _walk[index][1]));
  _dataPlot.replaceElementAt(0, curve);
The method integrate() calculates the state for the next time step. We are not going into the details of the numerical integration of the differential equations. x and z of the state will be stored in _walk at the _walkIndex. After a cyclical increment of _walkIndex the curve will be updated. First, a new DataCurve instance is created which will be filled with all points from _walk. Then, the old curve will be replaced by the new one. Behind the scene, the view will be automatically updated.