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 CustomLegendItem createValueSourceLegendItem(
      PlotConfiguration plotConfig, ValueSource valueSource) {

    Set<PlotDimension> dimensions = new HashSet<PlotDimension>();
    for (PlotDimension dimension : PlotDimension.values()) {
      switch (dimension) {
        case DOMAIN:
        case VALUE:
          break;
        default:
          if (valueSource.useSeriesFormatForDimension(plotConfig, dimension)) {
            dimensions.add(dimension);
          }
      }
    }
    if (dimensions.isEmpty()) {
      return null;
    }

    SeriesFormat format = valueSource.getSeriesFormat();
    String description = "";
    String toolTipText = "";
    String urlText = "";
    boolean shapeVisible = true;
    Shape shape;
    boolean shapeFilled = true;
    Paint fillPaint = UNDEFINED_COLOR_PAINT;
    boolean shapeOutlineVisible = true;
    Paint outlinePaint = PlotConfiguration.DEFAULT_OUTLINE_COLOR;
    Stroke outlineStroke = DEFAULT_OUTLINE_STROKE;
    boolean lineVisible =
        format.getLineStyle() != LineStyle.NONE
            && format.getSeriesType() == SeriesFormat.VisualizationType.LINES_AND_SHAPES;

    // configure fill paint and line paint
    Paint linePaint;
    String label = valueSource.toString();
    if (label == null) {
      label = "";
    }
    if (dimensions.contains(PlotDimension.COLOR)) {
      Color color = format.getItemColor();
      fillPaint = format.getAreaFillPaint(color);
      linePaint = fillPaint;
    } else {
      if (format.getAreaFillStyle() == FillStyle.NONE) {
        fillPaint = new Color(0, 0, 0, 0);
        linePaint = fillPaint;
      } else if (format.getAreaFillStyle() == FillStyle.SOLID) {
        fillPaint = UNDEFINED_COLOR_PAINT;
        linePaint = UNDEFINED_LINE_COLOR;
      } else {
        fillPaint = format.getAreaFillPaint(UNDEFINED_COLOR);
        linePaint = fillPaint;
      }
    }

    VisualizationType seriesType = valueSource.getSeriesFormat().getSeriesType();
    if (seriesType == VisualizationType.LINES_AND_SHAPES) {
      if (dimensions.contains(PlotDimension.SHAPE)) {
        shape = format.getItemShape().getShape();
      } else if (dimensions.contains(PlotDimension.COLOR)) {
        shape = UNDEFINED_SHAPE;
      } else {
        shape = UNDEFINED_SHAPE_AND_COLOR;
      }

      if (dimensions.contains(PlotDimension.SIZE)) {
        AffineTransform transformation = new AffineTransform();
        double scalingFactor = format.getItemSize();
        transformation.scale(scalingFactor, scalingFactor);
        shape = transformation.createTransformedShape(shape);
      }
    } else if (seriesType == VisualizationType.BARS) {
      shape = BAR_SHAPE;
    } else if (seriesType == VisualizationType.AREA) {
      shape = AREA_SHAPE;
    } else {
      throw new RuntimeException("Unknown SeriesType. This should not happen.");
    }

    // configure line shape
    float lineLength = 0;
    if (lineVisible) {
      lineLength = format.getLineWidth();
      if (lineLength < 1) {
        lineLength = 1;
      }
      if (lineLength > 1) {
        lineLength = 1 + (float) Math.log(lineLength) / 2;
      }

      // line at least 30 pixels long, and show at least 2 iterations of stroke
      lineLength = Math.max(lineLength * 30, format.getStrokeLength() * 2);

      // line at least 2x longer than shape width
      if (shape != null) {
        lineLength = Math.max(lineLength, (float) shape.getBounds().getWidth() * 2f);
      }
    }

    // now create line shape and stroke
    Shape line = new Line2D.Float(0, 0, lineLength, 0);
    BasicStroke lineStroke = format.getStroke();
    if (lineStroke == null) {
      lineStroke = new BasicStroke();
    }

    // unset line ending decoration to prevent drawing errors in legend
    {
      BasicStroke s = lineStroke;
      lineStroke =
          new BasicStroke(
              s.getLineWidth(),
              BasicStroke.CAP_BUTT,
              BasicStroke.JOIN_ROUND,
              s.getMiterLimit(),
              s.getDashArray(),
              s.getDashPhase());
    }

    return new CustomLegendItem(
        label,
        description,
        toolTipText,
        urlText,
        shapeVisible,
        shape,
        shapeFilled,
        fillPaint,
        shapeOutlineVisible,
        outlinePaint,
        outlineStroke,
        lineVisible,
        line,
        lineStroke,
        linePaint);
  }