private JPanel createDemo() {
    upper = new DefaultChartModel();
    lower = new DefaultChartModel();
    splineChartModel = new DefaultChartModel();
    chart = new Chart();
    demoPanel = new JPanel();
    demoPanel.setPreferredSize(new Dimension(500, 500));
    demoPanel.setLayout(new BorderLayout());

    assert xPoints.length == lowerPoints.length && lowerPoints.length == upperPoints.length;

    for (int i = 0; i < xPoints.length; i++) {
      lower.addPoint(xPoints[i], lowerPoints[i]);
      upper.addPoint(xPoints[i], upperPoints[i]);
    }

    Range<?> xRange = lower.getXRange();
    Range<Double> yRange = new CombinedNumericRange().add(lower.getYRange()).add(upper.getYRange());

    Axis xAxis = new Axis(xRange);
    Axis yAxis = new Axis(yRange);

    chart.setXAxis(xAxis);
    chart.setYAxis(yAxis);

    chart.setShadowVisible(false);

    PointStyle pointStyle = new PointStyle(Color.green.darker(), PointShape.SQUARE);
    ChartStyle chartStyle = new ChartStyle();
    chartStyle.setPointStyle(pointStyle);
    chartStyle.setLinesVisible(false);
    chartStyle.setPointsVisible(true);

    chart.addModel(lower, chartStyle);
    chart.addModel(upper, chartStyle);

    // ChartStyle averageChartStyle = new ChartStyle(Color.blue, false, true);
    ChartStyle splineChartStyle = new ChartStyle();
    splineChartStyle.setLinesVisible(true);
    LineStyle lineStyle = new LineStyle();
    lineStyle.setColor(Color.blue);
    lineStyle.setWidth(1);
    splineChartStyle.setLineStyle(lineStyle);

    final AnnotatedChartModel[] baseModels = new AnnotatedChartModel[] {lower, upper};

    averageModel = new AverageChartModel(baseModels);
    // chart.addModel(averageModel, averageChartStyle);

    chart.addModel(splineChartModel, splineChartStyle);
    computeSpline(averageModel, splineChartModel);

    demoPanel.add(chart, BorderLayout.CENTER);

    chart.addMouseListener(
        new MouseListener() {
          public void mouseClicked(MouseEvent e) {

            if (e.getClickCount() == 2 && nearestModel != null && _nearestPoint != null) {
              ((DefaultChartModel) nearestModel).removePoint(_nearestPoint);
              ((DefaultChartModel) nearestModel).update();
              computeSpline(averageModel, splineChartModel);
            }
          }

          public void mouseEntered(MouseEvent e) {}

          public void mouseExited(MouseEvent e) {}

          public void mousePressed(MouseEvent e) {
            Point p = e.getPoint();
            Double minDistance = null;
            for (ChartModel model : baseModels) {
              PointSelection nearest = chart.nearestPoint(p, model);
              Chartable chartable = nearest.getSelected();
              double distance = nearest.getDistance();
              if (minDistance == null || distance < minDistance) {
                _nearestPoint = chartable;
                nearestModel = model;
                minDistance = distance;
              }
            }
          }

          public void mouseReleased(MouseEvent e) {}
        });
    chart.addMouseMotionListener(
        new MouseMotionListener() {
          public void mouseDragged(MouseEvent e) {
            if (nearestModel != null) {
              Point p = e.getPoint();
              Point2D realPoint = chart.calculateUserPoint(p);
              if (realPoint != null) {
                ((ChartPoint) _nearestPoint).setY(new RealPosition(realPoint.getY()));
              }
              // TODO: Should not have to call an update() method!
              ((DefaultChartModel) nearestModel).update();
              computeSpline(averageModel, splineChartModel);
            }
          }

          public void mouseMoved(MouseEvent e) {}
        });
    return demoPanel;
  }