private void adjustPlotAxes() {
   if (!axisAdjusting) {
     axisAdjusting = true;
     try {
       xAxisRangeControl.adjustAxis(chart.getXYPlot().getDomainAxis(), 0);
       yAxisRangeControl.adjustAxis(chart.getXYPlot().getRangeAxis(), 2);
     } finally {
       axisAdjusting = false;
     }
   }
 }
  private void updateUIState() {
    if (!isInitialized) {
      return;
    }

    xAxisRangeControl
        .getBindingContext()
        .setComponentsEnabled(
            PROPERTY_NAME_MARK_SEGMENTS,
            profileData != null && profileData.getShapeVertices().length > 2);
    xAxisRangeControl.setComponentsEnabled(profileData != null);
    yAxisRangeControl.setComponentsEnabled(profileData != null);
    adjustPlotAxes();

    if (dataSourceConfig.computeInBetweenPoints) {
      chart.getXYPlot().setRenderer(deviationRenderer);
    } else {
      chart.getXYPlot().setRenderer(pointRenderer);
    }

    chart
        .getXYPlot()
        .getRangeAxis()
        .setLabel(
            StatisticChartStyling.getAxisLabel(getRaster(), DEFAULT_SAMPLE_DATASET_NAME, false));

    boolean markSegments =
        (Boolean)
            (xAxisRangeControl
                .getBindingContext()
                .getPropertySet()
                .getValue(PROPERTY_NAME_MARK_SEGMENTS));
    if (markSegments && profileData != null && profileData.getNumShapeVertices() > 1) {
      final int[] shapeVertexIndexes = profileData.getShapeVertexIndexes();
      removeIntervalMarkers();
      for (int i = 0; i < shapeVertexIndexes.length - 1; i++) {
        if (i % 2 != 0) {
          final IntervalMarker marker =
              new IntervalMarker(shapeVertexIndexes[i], shapeVertexIndexes[i + 1]);
          marker.setPaint(new Color(120, 122, 125));
          marker.setAlpha(0.3F);
          chart.getXYPlot().addDomainMarker(marker, Layer.BACKGROUND);
          intervalMarkers.add(marker);
        }
      }
    } else {
      removeIntervalMarkers();
    }

    pointDataSourceEnablement.apply();
    dataFieldEnablement.apply();
  }
 private void adjustAxisControlComponents() {
   if (!axisAdjusting) {
     axisAdjusting = true;
     try {
       if (xAxisRangeControl.isAutoMinMax()) {
         xAxisRangeControl.adjustComponents(chart.getXYPlot().getDomainAxis(), 0);
       }
       if (yAxisRangeControl.isAutoMinMax()) {
         yAxisRangeControl.adjustComponents(chart.getXYPlot().getRangeAxis(), 2);
       }
     } finally {
       axisAdjusting = false;
     }
   }
 }
 private void updateScalingOfYAxis() {
   final boolean logScaled =
       (Boolean)
           yAxisRangeControl
               .getBindingContext()
               .getBinding(PROPERTY_NAME_LOG_SCALED)
               .getPropertyValue();
   final XYPlot plot = chart.getXYPlot();
   plot.setRangeAxis(
       StatisticChartStyling.updateScalingOfAxis(logScaled, plot.getRangeAxis(), true));
 }
  private void updateDataSet() {
    if (!isInitialized) {
      return;
    }

    dataset.removeAllSeries();

    double dx = 0.5 * dataSourceConfig.boxSize;

    if (profileData != null) {
      final float[] sampleValues = profileData.getSampleValues();
      final float[] sampleSigmas = profileData.getSampleSigmas();
      XYIntervalSeries series =
          new XYIntervalSeries(
              getRaster() != null ? getRaster().getName() : DEFAULT_SAMPLE_DATASET_NAME);
      for (int x = 0; x < sampleValues.length; x++) {
        final float y = sampleValues[x];
        final float dy = sampleSigmas[x];
        series.add(x, x - dx, x + dx, y, y - dy, y + dy);
      }
      dataset.addSeries(series);

      if (dataSourceConfig.useCorrelativeData
          && dataSourceConfig.pointDataSource != null
          && dataSourceConfig.dataField != null) {

        XYIntervalSeries corrSeries =
            new XYIntervalSeries(
                getCorrelativeDataLabel(
                    dataSourceConfig.pointDataSource, dataSourceConfig.dataField));
        int[] shapeVertexIndexes = profileData.getShapeVertexIndexes();
        SimpleFeature[] simpleFeatures =
            dataSourceConfig.pointDataSource.getFeatureCollection().toArray(new SimpleFeature[0]);

        if (shapeVertexIndexes.length == simpleFeatures.length) {
          int fieldIndex =
              getAttributeIndex(dataSourceConfig.pointDataSource, dataSourceConfig.dataField);
          if (fieldIndex != -1) {
            for (int i = 0; i < simpleFeatures.length; i++) {
              Number attribute = (Number) simpleFeatures[i].getAttribute(fieldIndex);
              if (attribute != null) {
                final double x = shapeVertexIndexes[i];
                final double y = attribute.doubleValue();
                corrSeries.add(x, x, x, y, y, y);
              }
            }
            dataset.addSeries(corrSeries);
          }
        } else {
          System.out.println("Weird things happened:");
          System.out.println("  shapeVertexIndexes.length = " + shapeVertexIndexes.length);
          System.out.println("  simpleFeatures.length     = " + simpleFeatures.length);
        }
      }

      profilePlotDisplay.restoreAutoBounds();
      xAxisRangeControl
          .getBindingContext()
          .setComponentsEnabled(
              PROPERTY_NAME_MARK_SEGMENTS, profileData.getShapeVertices().length > 2);
    }
  }
  protected JPanel createMiddlePanel(BindingContext bindingContext) {
    final JLabel boxSizeLabel = new JLabel("Box size: ");
    final JSpinner boxSizeSpinner = new JSpinner();
    final JCheckBox computeInBetweenPoints = new JCheckBox("Compute in-between points");
    final JCheckBox useCorrelativeData = new JCheckBox("Use correlative data");

    correlativeFieldSelector = new CorrelativeFieldSelector(bindingContext);
    final PropertyDescriptor boxSizeDescriptor =
        bindingContext.getPropertySet().getProperty("boxSize").getDescriptor();
    boxSizeDescriptor.setValueRange(new ValueRange(1, 101));
    boxSizeDescriptor.setAttribute("stepSize", 2);
    boxSizeDescriptor.setValidator(
        new Validator() {
          @Override
          public void validateValue(Property property, Object value) throws ValidationException {
            if (((Number) value).intValue() % 2 == 0) {
              throw new ValidationException("Only odd values allowed as box size.");
            }
          }
        });
    bindingContext.bind("boxSize", boxSizeSpinner);
    bindingContext.bind("computeInBetweenPoints", computeInBetweenPoints);
    bindingContext.bind("useCorrelativeData", useCorrelativeData);
    EnablePointDataCondition condition = new EnablePointDataCondition();
    pointDataSourceEnablement = bindingContext.bindEnabledState("pointDataSource", true, condition);
    dataFieldEnablement = bindingContext.bindEnabledState("dataField", true, condition);

    bindingContext.addPropertyChangeListener(
        new PropertyChangeListener() {
          @Override
          public void propertyChange(PropertyChangeEvent evt) {
            updateDataSource();
            updateDataSet();
            updateUIState();
          }
        });

    JPanel dataSourceOptionsPanel = GridBagUtils.createPanel();
    GridBagConstraints dataSourceOptionsConstraints =
        GridBagUtils.createConstraints("anchor=NORTHWEST,fill=HORIZONTAL,insets.top=2");
    GridBagUtils.addToPanel(
        dataSourceOptionsPanel,
        boxSizeLabel,
        dataSourceOptionsConstraints,
        "gridwidth=1,gridy=0,gridx=0,weightx=0,insets.left=4");
    GridBagUtils.addToPanel(
        dataSourceOptionsPanel,
        boxSizeSpinner,
        dataSourceOptionsConstraints,
        "gridwidth=1,gridy=0,gridx=1,weightx=1,insets.left=0");
    GridBagUtils.addToPanel(
        dataSourceOptionsPanel,
        computeInBetweenPoints,
        dataSourceOptionsConstraints,
        "gridwidth=2,gridy=1,gridx=0,weightx=2");
    GridBagUtils.addToPanel(
        dataSourceOptionsPanel,
        useCorrelativeData,
        dataSourceOptionsConstraints,
        "gridy=2,insets.top=16");
    GridBagUtils.addToPanel(
        dataSourceOptionsPanel,
        correlativeFieldSelector.pointDataSourceLabel,
        dataSourceOptionsConstraints,
        "gridy=3,insets.top=0,insets.left=4");
    GridBagUtils.addToPanel(
        dataSourceOptionsPanel,
        correlativeFieldSelector.pointDataSourceList,
        dataSourceOptionsConstraints,
        "gridy=4,insets.left=4");
    GridBagUtils.addToPanel(
        dataSourceOptionsPanel,
        correlativeFieldSelector.dataFieldLabel,
        dataSourceOptionsConstraints,
        "gridy=5,insets.left=4");
    GridBagUtils.addToPanel(
        dataSourceOptionsPanel,
        correlativeFieldSelector.dataFieldList,
        dataSourceOptionsConstraints,
        "gridy=6,insets.left=4");

    xAxisRangeControl
        .getBindingContext()
        .bind(PROPERTY_NAME_MARK_SEGMENTS, new JCheckBox("Mark segments"));
    yAxisRangeControl
        .getBindingContext()
        .bind(PROPERTY_NAME_LOG_SCALED, new JCheckBox("Log10 scaled"));

    JPanel displayOptionsPanel = GridBagUtils.createPanel();
    GridBagConstraints displayOptionsConstraints =
        GridBagUtils.createConstraints("anchor=SOUTH,fill=HORIZONTAL,weightx=1");
    GridBagUtils.addToPanel(
        displayOptionsPanel, xAxisRangeControl.getPanel(), displayOptionsConstraints, "gridy=0");
    GridBagUtils.addToPanel(
        displayOptionsPanel,
        xAxisRangeControl
            .getBindingContext()
            .getBinding(PROPERTY_NAME_MARK_SEGMENTS)
            .getComponents()[0],
        displayOptionsConstraints,
        "gridy=1");
    GridBagUtils.addToPanel(
        displayOptionsPanel, yAxisRangeControl.getPanel(), displayOptionsConstraints, "gridy=2");
    GridBagUtils.addToPanel(
        displayOptionsPanel,
        yAxisRangeControl
            .getBindingContext()
            .getBinding(PROPERTY_NAME_LOG_SCALED)
            .getComponents()[0],
        displayOptionsConstraints,
        "gridy=3");

    JPanel middlePanel = GridBagUtils.createPanel();
    GridBagConstraints middlePanelConstraints =
        GridBagUtils.createConstraints("anchor=NORTHWEST,fill=HORIZONTAL,insets.top=2,weightx=1");
    GridBagUtils.addToPanel(middlePanel, dataSourceOptionsPanel, middlePanelConstraints, "gridy=0");
    GridBagUtils.addToPanel(
        middlePanel, new JPanel(), middlePanelConstraints, "gridy=1,fill=VERTICAL,weighty=1");
    GridBagUtils.addToPanel(
        middlePanel,
        displayOptionsPanel,
        middlePanelConstraints,
        "gridy=2,fill=HORIZONTAL,weighty=0");

    return middlePanel;
  }
  @Override
  protected void initComponents() {
    getAlternativeView().initComponents();
    dataset = new XYIntervalSeriesCollection();
    this.chart =
        ChartFactory.createXYLineChart(
            CHART_TITLE,
            "Path in pixels",
            DEFAULT_SAMPLE_DATASET_NAME,
            dataset,
            PlotOrientation.VERTICAL,
            true,
            true,
            false);
    final XYPlot plot = chart.getXYPlot();

    deviationRenderer = new DeviationRenderer();
    deviationRenderer.setUseFillPaint(true);
    deviationRenderer.setBaseToolTipGenerator(new XYPlotToolTipGenerator());
    deviationRenderer.setSeriesLinesVisible(0, true);
    deviationRenderer.setSeriesShapesVisible(0, false);
    deviationRenderer.setSeriesStroke(0, new BasicStroke(1.0f));
    deviationRenderer.setSeriesPaint(0, StatisticChartStyling.SAMPLE_DATA_PAINT);
    deviationRenderer.setSeriesFillPaint(0, StatisticChartStyling.SAMPLE_DATA_FILL_PAINT);

    pointRenderer = new XYErrorRenderer();
    pointRenderer.setUseFillPaint(true);
    pointRenderer.setBaseToolTipGenerator(new XYPlotToolTipGenerator());
    pointRenderer.setSeriesLinesVisible(0, false);
    pointRenderer.setSeriesShapesVisible(0, true);
    pointRenderer.setSeriesStroke(0, new BasicStroke(1.0f));
    pointRenderer.setSeriesPaint(0, StatisticChartStyling.SAMPLE_DATA_PAINT);
    pointRenderer.setSeriesFillPaint(0, StatisticChartStyling.SAMPLE_DATA_FILL_PAINT);
    pointRenderer.setSeriesShape(0, StatisticChartStyling.SAMPLE_DATA_POINT_SHAPE);

    configureRendererForCorrelativeData(deviationRenderer);
    configureRendererForCorrelativeData(pointRenderer);

    plot.setNoDataMessage(NO_DATA_MESSAGE);
    plot.setAxisOffset(new RectangleInsets(5, 5, 5, 5));
    plot.setRenderer(deviationRenderer);

    final AxisChangeListener axisListener =
        new AxisChangeListener() {
          @Override
          public void axisChanged(AxisChangeEvent event) {
            adjustAxisControlComponents();
          }
        };

    final ValueAxis domainAxis = plot.getDomainAxis();
    final ValueAxis rangeAxis = plot.getRangeAxis();
    // allow transfer from bounds into min/max fields, if auto min/maxis enabled
    domainAxis.setAutoRange(true);
    rangeAxis.setAutoRange(true);

    domainAxis.addChangeListener(axisListener);
    rangeAxis.addChangeListener(axisListener);

    intervalMarkers = new HashSet<IntervalMarker>();

    xAxisRangeControl = new AxisRangeControl("X-Axis");
    yAxisRangeControl = new AxisRangeControl("Y-Axis");

    final PropertyChangeListener changeListener =
        new PropertyChangeListener() {
          @Override
          public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getPropertyName().equals(PROPERTY_NAME_MARK_SEGMENTS)) {
              updateDataSet();
            }
            if (evt.getPropertyName().equals(PROPERTY_NAME_LOG_SCALED)) {
              updateScalingOfYAxis();
            }
            updateUIState();
          }
        };
    xAxisRangeControl.getBindingContext().addPropertyChangeListener(changeListener);
    xAxisRangeControl
        .getBindingContext()
        .getPropertySet()
        .addProperty(Property.create(PROPERTY_NAME_MARK_SEGMENTS, false));
    xAxisRangeControl
        .getBindingContext()
        .getPropertySet()
        .getDescriptor(PROPERTY_NAME_MARK_SEGMENTS)
        .setDescription("Toggle whether to mark segments");

    yAxisRangeControl.getBindingContext().addPropertyChangeListener(changeListener);
    yAxisRangeControl
        .getBindingContext()
        .getPropertySet()
        .addProperty(Property.create(PROPERTY_NAME_LOG_SCALED, false));
    yAxisRangeControl
        .getBindingContext()
        .getPropertySet()
        .getDescriptor(PROPERTY_NAME_LOG_SCALED)
        .setDescription("Toggle whether to use a logarithmic axis");

    dataSourceConfig = new DataSourceConfig();
    final BindingContext bindingContext =
        new BindingContext(PropertyContainer.createObjectBacked(dataSourceConfig));

    JPanel middlePanel = createMiddlePanel(bindingContext);
    createUI(createChartPanel(chart), middlePanel, bindingContext);

    isInitialized = true;

    updateComponents();
  }