private static void configureBarRenderer(
      BarRenderer renderer, ValueSource valueSource, PlotInstance plotInstance) {
    StandardBarPainter barPainter = new StandardBarPainter();
    renderer.setBarPainter(barPainter);
    renderer.setGradientPaintTransformer(null);

    ValueSourceData valueSourceData = plotInstance.getPlotData().getValueSourceData(valueSource);
    int seriesCount = valueSourceData.getSeriesCount();
    DimensionConfig domainConfig = valueSource.getDomainConfig();
    DimensionConfig colorDimensionConfig =
        plotInstance.getCurrentPlotConfigurationClone().getDimensionConfig(PlotDimension.COLOR);
    SeriesFormat seriesFormat = valueSource.getSeriesFormat();

    // Loop all series and set series format.
    // Format based on dimension configs will be set later on in initFormatDelegate().
    for (int seriesIdx = 0; seriesIdx < seriesCount; ++seriesIdx) {
      // configure series paint if necessary
      if (!SeriesFormat.calculateIndividualFormatForEachItem(domainConfig, colorDimensionConfig)) {
        renderer.setSeriesPaint(seriesIdx, seriesFormat.getAreaFillPaint());
      }

      // configure general style of the bars
      renderer.setShadowVisible(false);
      renderer.setSeriesOutlinePaint(seriesIdx, PlotConfiguration.DEFAULT_SERIES_OUTLINE_PAINT);
    }
    renderer.setDrawBarOutline(true);
  }
  public static DefaultStatisticalCategoryDataset createDefaultStatisticalCategoryDataset(
      ValueSource valueSource, PlotInstance plotInstance) throws ChartPlottimeException {
    ValueSourceData valueSourceData = plotInstance.getPlotData().getValueSourceData(valueSource);
    assertMaxValueCountNotExceededOrThrowException(valueSourceData);
    GroupCellSeriesData dataForAllGroupCells = valueSourceData.getSeriesDataForAllGroupCells();
    DefaultStatisticalCategoryDataset dataset = new DefaultStatisticalCategoryDataset();
    DefaultDimensionConfig domainConfig = valueSource.getDomainConfig();
    DimensionConfigData domainConfigData =
        plotInstance.getPlotData().getDimensionConfigData(domainConfig);

    // Loop all group cells and add data to dataset
    for (GroupCellKeyAndData groupCellKeyAndData : dataForAllGroupCells) {
      GroupCellKey groupCellKey = groupCellKeyAndData.getKey();
      GroupCellData groupCellData = groupCellKeyAndData.getData();
      String seriesName =
          generateSeriesName(
              valueSource, groupCellKey, plotInstance.getCurrentPlotConfigurationClone());

      Map<PlotDimension, double[]> mainSeriesData =
          groupCellData.getDataForUsageType(SeriesUsageType.MAIN_SERIES);
      double[] xValues = mainSeriesData.get(PlotDimension.DOMAIN);
      double[] yValues = mainSeriesData.get(PlotDimension.VALUE);
      double[] yErrorValues = valueSourceData.getAbsoluteUtilityValues(groupCellKeyAndData, true);
      if (yErrorValues == null) {
        throw new ChartPlottimeException(
            "undefined_series", valueSource.toString(), SeriesUsageType.INDICATOR_1);
      }

      // this dataset does not support unsymmetric errors
      if (groupCellData.getDataForUsageType(SeriesUsageType.INDICATOR_2) != null) {
        throw new ChartPlottimeException(
            "unsymmetric_utility_not_supported", valueSource.toString());
      }

      int rowCount = xValues.length;

      // Loop all rows and add data to series
      double xValue;
      double yValue;
      double yErrorValue;
      String xString;
      for (int row = 0; row < rowCount; ++row) {
        xValue = xValues[row];
        xString = domainConfigData.getStringForValue(xValue);
        yValue = yValues[row];
        yErrorValue = yErrorValues[row] - yValue;

        dataset.add(yValue, yErrorValue, seriesName, xString);
      }
    }
    return dataset;
  }
  /**
   * Same as {@link #createDefaultMultiValueCategoryDataset(ValueSource, PlotConfiguration)}, but
   * instead of storing only the values it stores pairs in the lists, where the first value is the
   * data value, and the second value holds the index of the value in the series in valueSource.
   *
   * <p>Must be used for the FormattedScatterRenderer.
   *
   * @throws ChartPlottimeException
   */
  public static DefaultMultiValueCategoryDataset createAnnotatedDefaultMultiValueCategoryDataset(
      ValueSource valueSource, PlotInstance plotInstance) throws ChartPlottimeException {
    ValueSourceData valueSourceData = plotInstance.getPlotData().getValueSourceData(valueSource);
    assertMaxValueCountNotExceededOrThrowException(valueSourceData);
    GroupCellSeriesData dataForAllGroupCells = valueSourceData.getSeriesDataForAllGroupCells();
    DefaultMultiValueCategoryDataset dataset = new DefaultMultiValueCategoryDataset();
    DefaultDimensionConfig domainConfig = valueSource.getDomainConfig();
    DimensionConfigData domainConfigData =
        plotInstance.getPlotData().getDimensionConfigData(domainConfig);

    // Loop all group cells and add data to dataset
    for (GroupCellKeyAndData groupCellKeyAndData : dataForAllGroupCells) {
      // the DefaultMultiValueCategoryDataset expects a List of values for each domain value. This
      // map
      // maps domain values to lists and is filled while we iterate through all data value below.
      Map<Double, List<Pair<Double, Integer>>> valueListsForDomainValues =
          new HashMap<Double, List<Pair<Double, Integer>>>();
      for (Double value : domainConfigData.getDistinctValues()) {
        valueListsForDomainValues.put(value, new LinkedList<Pair<Double, Integer>>());
      }

      GroupCellKey groupCellKey = groupCellKeyAndData.getKey();
      GroupCellData groupCellData = groupCellKeyAndData.getData();
      String seriesName =
          generateSeriesName(
              valueSource, groupCellKey, plotInstance.getCurrentPlotConfigurationClone());

      Map<PlotDimension, double[]> mainSeriesData =
          groupCellData.getDataForUsageType(SeriesUsageType.MAIN_SERIES);
      double[] xValues = mainSeriesData.get(PlotDimension.DOMAIN);
      double[] yValues = mainSeriesData.get(PlotDimension.VALUE);
      int rowCount = xValues.length;

      // Loop all rows and add data into map
      double xValue;
      double yValue;
      String xString;
      for (int row = 0; row < rowCount; ++row) {
        xValue = xValues[row];
        yValue = yValues[row];
        Pair<Double, Integer> valueRowNumberPair = new Pair<Double, Integer>(yValue, row);
        valueListsForDomainValues.get(xValue).add(valueRowNumberPair);
      }

      for (Double value : domainConfigData.getDistinctValues()) {
        xString = domainConfigData.getStringForValue(value);
        dataset.add(valueListsForDomainValues.get(value), seriesName, xString);
      }
    }
    return dataset;
  }
  private static void configureXYDifferenceRenderer(
      FormattedXYDifferenceRenderer renderer,
      ValueSource valueSource,
      PlotConfiguration plotConfiguration) {
    renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
    SeriesFormat seriesFormat = valueSource.getSeriesFormat();
    DimensionConfig domainConfig = valueSource.getDomainConfig();
    DimensionConfig colorDimensionConfig =
        plotConfiguration.getDimensionConfig(PlotDimension.COLOR);
    DimensionConfig shapeDimensionConfig =
        plotConfiguration.getDimensionConfig(PlotDimension.SHAPE);

    int seriesCount = 1; // valueSource.getSeriesDataForAllGroupCells().groupCellCount();

    // Loop all series and set series format.
    // Format based on dimension configs will be set later on in initFormatDelegate().
    for (int seriesIdx = 0; seriesIdx < seriesCount; ++seriesIdx) {
      // configure linestyle
      if (seriesFormat.getLineStyle() == LineStyle.NONE) {
      } else {
        renderer.setSeriesStroke(seriesIdx, seriesFormat.getStroke(), false);
      }

      // configure series shape if necessary
      if (!SeriesFormat.calculateIndividualFormatForEachItem(domainConfig, shapeDimensionConfig)) {
        if (seriesFormat.getItemShape() != ItemShape.NONE) {
          renderer.setSeriesShape(seriesIdx, seriesFormat.getItemShape().getShape());
        } else {
        }
      }

      // configure series color if necessary
      if (!SeriesFormat.calculateIndividualFormatForEachItem(domainConfig, colorDimensionConfig)) {
        Color itemColor = seriesFormat.getItemColor();
        Color halfTransparentPaint =
            DataStructureUtils.setColorAlpha(itemColor, itemColor.getAlpha() / 2);

        renderer.setSeriesPaint(0, halfTransparentPaint);
        renderer.setSeriesFillPaint(0, halfTransparentPaint);
        renderer.setPositivePaint(halfTransparentPaint);
        renderer.setNegativePaint(
            new Color(
                255 - itemColor.getRed(),
                255 - itemColor.getGreen(),
                255 - itemColor.getBlue(),
                itemColor.getAlpha() / 2));
      }
      renderer.setSeriesOutlinePaint(seriesIdx, PlotConfiguration.DEFAULT_SERIES_OUTLINE_PAINT);
    }
  }
  private static void configureXYLineAndShapeRenderer(
      XYLineAndShapeRenderer renderer, ValueSource valueSource, PlotInstance plotInstance) {
    renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
    SeriesFormat seriesFormat = valueSource.getSeriesFormat();
    DimensionConfig domainConfig = valueSource.getDomainConfig();
    DimensionConfig colorDimensionConfig =
        plotInstance.getCurrentPlotConfigurationClone().getDimensionConfig(PlotDimension.COLOR);
    DimensionConfig shapeDimensionConfig =
        plotInstance.getCurrentPlotConfigurationClone().getDimensionConfig(PlotDimension.SHAPE);
    ValueSourceData valueSourceData = plotInstance.getPlotData().getValueSourceData(valueSource);

    int seriesCount = valueSourceData.getSeriesDataForAllGroupCells().groupCellCount();

    // Loop all series and set series format.
    // Format based on dimension configs will be set later on in initFormatDelegate().
    for (int seriesIdx = 0; seriesIdx < seriesCount; ++seriesIdx) {
      // configure linestyle
      if (seriesFormat.getLineStyle() == LineStyle.NONE) {
        renderer.setSeriesLinesVisible(seriesIdx, false);
      } else {
        renderer.setSeriesLinesVisible(seriesIdx, true);
        renderer.setSeriesStroke(seriesIdx, seriesFormat.getStroke(), false);
      }

      // configure series shape if necessary
      if (!SeriesFormat.calculateIndividualFormatForEachItem(domainConfig, shapeDimensionConfig)) {
        if (seriesFormat.getItemShape() != ItemShape.NONE) {
          renderer.setSeriesShapesVisible(seriesIdx, true);
          renderer.setSeriesShape(seriesIdx, seriesFormat.getItemShape().getShape());
        } else {
          renderer.setSeriesShapesVisible(seriesIdx, false);
        }
      }

      // configure series color if necessary
      if (!SeriesFormat.calculateIndividualFormatForEachItem(domainConfig, colorDimensionConfig)) {
        Color itemColor = seriesFormat.getItemColor();
        renderer.setSeriesPaint(seriesIdx, itemColor);
        renderer.setSeriesFillPaint(seriesIdx, itemColor);
      }
      renderer.setSeriesOutlinePaint(seriesIdx, PlotConfiguration.DEFAULT_SERIES_OUTLINE_PAINT);
      renderer.setUseOutlinePaint(true);
    }
  }
  private static void configureLineAndShapeRenderer(
      LineAndShapeRenderer renderer, ValueSource valueSource, PlotInstance plotInstance) {
    ValueSourceData valueSourceData = plotInstance.getPlotData().getValueSourceData(valueSource);
    int seriesCount = valueSourceData.getSeriesCount();
    SeriesFormat seriesFormat = valueSource.getSeriesFormat();
    DimensionConfig domainConfig = valueSource.getDomainConfig();
    DimensionConfig colorDimensionConfig =
        plotInstance.getCurrentPlotConfigurationClone().getDimensionConfig(PlotDimension.COLOR);
    DimensionConfig shapeDimensionConfig =
        plotInstance.getCurrentPlotConfigurationClone().getDimensionConfig(PlotDimension.SHAPE);

    renderer.setDefaultEntityRadius(4);

    // loop all series and set series format
    for (int seriesIdx = 0; seriesIdx < seriesCount; ++seriesIdx) {
      // configure linestyle
      if (seriesFormat.getLineStyle() != LineStyle.NONE) {
        renderer.setSeriesLinesVisible(seriesIdx, true);
        renderer.setSeriesStroke(seriesIdx, seriesFormat.getStroke(), false);
      } else {
        renderer.setSeriesLinesVisible(seriesIdx, false);
      }

      // configure series shape if necessary
      if (!SeriesFormat.calculateIndividualFormatForEachItem(domainConfig, shapeDimensionConfig)) {
        if (seriesFormat.getItemShape() != ItemShape.NONE) {
          renderer.setSeriesShapesVisible(seriesIdx, true);
          renderer.setSeriesShape(seriesIdx, seriesFormat.getItemShape().getShape());
        } else {
          renderer.setSeriesShapesVisible(seriesIdx, false);
        }
      }

      // configure series color if necessary
      if (!SeriesFormat.calculateIndividualFormatForEachItem(domainConfig, colorDimensionConfig)) {
        Color itemColor = seriesFormat.getItemColor();
        renderer.setSeriesPaint(seriesIdx, itemColor);
      }
      renderer.setSeriesOutlinePaint(seriesIdx, PlotConfiguration.DEFAULT_SERIES_OUTLINE_PAINT);
      renderer.setUseOutlinePaint(true);
    }
  }
  private static void configureScatterRenderer(
      ScatterRenderer renderer, ValueSource valueSource, PlotInstance plotInstance)
      throws ChartPlottimeException {
    ValueSourceData valueSourceData = plotInstance.getPlotData().getValueSourceData(valueSource);
    int seriesCount = valueSourceData.getSeriesCount();
    SeriesFormat seriesFormat = valueSource.getSeriesFormat();
    DimensionConfig domainConfig = valueSource.getDomainConfig();
    DimensionConfig colorDimensionConfig =
        plotInstance.getCurrentPlotConfigurationClone().getDimensionConfig(PlotDimension.COLOR);
    DimensionConfig shapeDimensionConfig =
        plotInstance.getCurrentPlotConfigurationClone().getDimensionConfig(PlotDimension.SHAPE);

    renderer.setDefaultEntityRadius(4);

    // loop all series and set series format
    for (int seriesIdx = 0; seriesIdx < seriesCount; ++seriesIdx) {
      // lines are not supported in a ScatterRenderer, but this is already checked in
      // JFreeChartPlotEngine.getWarnings().

      // configure series shape if necessary
      if (!SeriesFormat.calculateIndividualFormatForEachItem(domainConfig, shapeDimensionConfig)) {
        //				if(seriesFormat.getItemShape() != ItemShape.NONE) {
        renderer.setSeriesShape(seriesIdx, seriesFormat.getItemShape().getShape());
        //				} else {
        //					throw new ChartPlottimeException("unsupported_item_shape", valueSource.toString(),
        // seriesFormat.getItemShape());
        //				}
      }

      // configure series color if necessary
      if (!SeriesFormat.calculateIndividualFormatForEachItem(domainConfig, colorDimensionConfig)) {
        Color itemColor = seriesFormat.getItemColor();
        renderer.setSeriesPaint(seriesIdx, itemColor);
      }
      renderer.setSeriesOutlinePaint(seriesIdx, PlotConfiguration.DEFAULT_SERIES_OUTLINE_PAINT);
      renderer.setUseOutlinePaint(true);
      renderer.setDrawOutlines(true);
      renderer.setUseSeriesOffset(false);
    }
  }
  public static CategoryDataset createDefaultCategoryDataset(
      ValueSource valueSource,
      PlotInstance plotInstance,
      boolean fillWithZero,
      boolean allowValuesLessThanZero)
      throws ChartPlottimeException {
    ValueSourceData valueSourceData = plotInstance.getPlotData().getValueSourceData(valueSource);
    assertMaxValueCountNotExceededOrThrowException(valueSourceData);
    GroupCellSeriesData dataForAllGroupCells = valueSourceData.getSeriesDataForAllGroupCells();
    DefaultDimensionConfig domainConfig = valueSource.getDomainConfig();
    DimensionConfigData domainConfigData =
        plotInstance.getPlotData().getDimensionConfigData(domainConfig);
    DefaultCategoryDataset dataset = new DefaultCategoryDataset();

    for (GroupCellKeyAndData groupCellKeyAndData : dataForAllGroupCells) {

      GroupCellKey groupCellKey = groupCellKeyAndData.getKey();
      GroupCellData groupCellData = groupCellKeyAndData.getData();

      // create series name
      GroupCellKey groupCellKeyClone = (GroupCellKey) groupCellKey.clone();
      String seriesName =
          generateSeriesName(
              valueSource, groupCellKeyClone, plotInstance.getCurrentPlotConfigurationClone());

      Map<PlotDimension, double[]> dataForUsageType =
          groupCellData.getDataForUsageType(SeriesUsageType.MAIN_SERIES);
      double[] xValues = dataForUsageType.get(PlotDimension.DOMAIN);
      double[] yValues = dataForUsageType.get(PlotDimension.VALUE);

      int rowCount = xValues.length;
      for (int row = 0; row < rowCount; ++row) {
        double xValue = xValues[row];

        String xString = null;
        xString = domainConfigData.getStringForValue(xValue);
        Double y = yValues[row];
        if (!allowValuesLessThanZero && y < 0) {
          throw new ChartPlottimeException("illegal_zero_value", valueSource.toString());
        }

        if (xString != null) {
          dataset.addValue(y, seriesName, xString);
        }
      }
      if (fillWithZero) {
        for (int row = 0; row < rowCount; ++row) {
          double xValue = xValues[row];

          String xString = null;
          xString = domainConfigData.getStringForValue(xValue);
          Number value = dataset.getValue(seriesName, xString);
          if (value == null || Double.isNaN(value.doubleValue())) {
            dataset.addValue(0, seriesName, xString);
          }
        }
      }
    }

    return dataset;
  }
  /**
   * Creates a dataset which supports custom intervals on both axes.
   *
   * <p>Expects a grouping on the domain axis.
   *
   * @throws ChartPlottimeException
   */
  public static DefaultIntervalXYDataset createDefaultIntervalXYDataset(
      ValueSource valueSource, PlotInstance plotInstance, boolean createRangeIntervals)
      throws ChartPlottimeException {
    ValueSourceData valueSourceData = plotInstance.getPlotData().getValueSourceData(valueSource);
    assertMaxValueCountNotExceededOrThrowException(valueSourceData);

    GroupCellSeriesData dataForAllGroupCells = valueSourceData.getSeriesDataForAllGroupCells();

    DefaultIntervalXYDataset intervalDataset = new DefaultIntervalXYDataset();

    DefaultDimensionConfig domainConfig = valueSource.getDomainConfig();
    DimensionConfigData domainConfigData =
        plotInstance.getPlotData().getDimensionConfigData(domainConfig);

    // Loop all group cells and add data to dataset
    for (GroupCellKeyAndData groupCellKeyAndData : dataForAllGroupCells) {

      GroupCellKey groupCellKey = groupCellKeyAndData.getKey();
      GroupCellData groupCellData = groupCellKeyAndData.getData();

      // create series name
      GroupCellKey groupCellKeyClone = (GroupCellKey) groupCellKey.clone();
      groupCellKeyClone.removeRangeForDimension(
          PlotDimension.DOMAIN); // legend does not need X-group
      String seriesName =
          generateSeriesName(
              valueSource, groupCellKeyClone, plotInstance.getCurrentPlotConfigurationClone());

      List<ValueRange> domainValueGroups = domainConfigData.getGroupingModel();

      // Loop all rows and add data to series.
      // Remember that by definition one row in the groupCellData corresponds
      // to one group in xValueGroups (if the x-axis is grouped, which should
      // always be the case in this function).
      final int domainValueIdx = 0;
      final int domainLowerIdx = 1;
      final int domainUpperIdx = 2;
      final int rangeValueIdx = 3;
      final int rangeLowerIdx = 4;
      final int rangeUpperIdx = 5;
      Map<PlotDimension, double[]> dataForMainSeries =
          groupCellData.getDataForUsageType(SeriesUsageType.MAIN_SERIES);

      int rowCount = dataForMainSeries.get(PlotDimension.DOMAIN).length;
      double[] domainValues = dataForMainSeries.get(PlotDimension.DOMAIN);
      double[] rangeValues = dataForMainSeries.get(PlotDimension.VALUE);
      double[] upperErrorValues = null;
      double[] lowerErrorValues = null;

      upperErrorValues = valueSourceData.getAbsoluteUtilityValues(groupCellKeyAndData, true);
      lowerErrorValues = valueSourceData.getAbsoluteUtilityValues(groupCellKeyAndData, false);
      if (createRangeIntervals && upperErrorValues == null) {
        throw new ChartPlottimeException(
            "undefined_series", valueSource.toString(), SeriesUsageType.INDICATOR_1);
      }

      double[][] series = new double[6][rowCount];
      Iterator<ValueRange> domainGroupIterator = null;
      if (domainValueGroups != null) {
        domainGroupIterator = domainValueGroups.iterator();
      }

      double domainLower;
      double domainUpper;
      double domainValue;
      double rangeValue;
      double rangeUpper;
      double rangeLower;
      for (int row = 0; row < rowCount; ++row) {
        domainValue = domainValues[row];
        domainLower = domainValue;
        domainUpper = domainValue;
        if (domainGroupIterator != null) {
          ValueRange currentDomainGroup = domainGroupIterator.next();
          if (currentDomainGroup.definesUpperLowerBound()) {
            domainLower = currentDomainGroup.getLowerBound();
            domainUpper = currentDomainGroup.getUpperBound();
          }
        }
        rangeValue = rangeValues[row];
        rangeUpper = upperErrorValues != null ? upperErrorValues[row] : Double.NaN;
        rangeLower = lowerErrorValues != null ? lowerErrorValues[row] : Double.NaN;

        series[domainValueIdx][row] = domainValue;
        series[domainLowerIdx][row] = domainLower;
        series[domainUpperIdx][row] = domainUpper;
        series[rangeValueIdx][row] = rangeValue;
        series[rangeLowerIdx][row] = rangeLower;
        series[rangeUpperIdx][row] = rangeUpper;
      }

      intervalDataset.addSeries(seriesName, series);
    }
    return intervalDataset;
  }