private void createCategoricalLegendItems(
      PlotInstance plotInstance,
      Set<PlotDimension> dimensionSet,
      LegendItemCollection legendItemCollection,
      Iterable<Double> values) {
    createDimensionTitleLegendItem(plotInstance, dimensionSet, legendItemCollection);

    PlotConfiguration plotConfig = plotInstance.getCurrentPlotConfigurationClone();

    Shape defaultShape = new Ellipse2D.Float(-5f, -5f, 10f, 10f);
    Color defaultOutlineColor = PlotConfiguration.DEFAULT_OUTLINE_COLOR;
    ColorProvider colorProvider = null;
    ShapeProvider shapeProvider = null;
    SizeProvider sizeProvider = null;

    DefaultDimensionConfig dimensionConfig =
        (DefaultDimensionConfig) plotConfig.getDimensionConfig(dimensionSet.iterator().next());
    DimensionConfigData dimensionConfigData =
        plotInstance.getPlotData().getDimensionConfigData(dimensionConfig);
    for (PlotDimension dimension : dimensionSet) {
      if (dimension == PlotDimension.COLOR) {
        colorProvider = dimensionConfigData.getColorProvider();
      } else if (dimension == PlotDimension.SHAPE) {
        shapeProvider = dimensionConfigData.getShapeProvider();
      } else if (dimension == PlotDimension.SIZE) {
        sizeProvider = dimensionConfigData.getSizeProvider();
      }
    }

    // initialize size scale for legend
    ContinuousSizeProvider legendSizeProvider = null;
    if (sizeProvider != null) {
      double minScalingFactor = sizeProvider.getMinScalingFactor();
      double maxScalingFactor = sizeProvider.getMaxScalingFactor();
      double minLegendScalingFactor = MIN_LEGEND_ITEM_SCALING_FACTOR;
      double maxLegendScalingFactor = MAX_LEGEND_ITEM_SCALING_FACTOR;
      if (minScalingFactor > maxScalingFactor) {
        double tmp = minScalingFactor;
        minScalingFactor = maxScalingFactor;
        maxScalingFactor = tmp;
        minLegendScalingFactor = MAX_LEGEND_ITEM_SCALING_FACTOR;
        maxLegendScalingFactor = MIN_LEGEND_ITEM_SCALING_FACTOR;
      }
      legendSizeProvider =
          new ContinuousSizeProvider(
              minScalingFactor,
              maxScalingFactor,
              minLegendScalingFactor,
              maxLegendScalingFactor,
              false);
    }

    for (Double value : values) {
      // configure shape and stroke
      Shape shape = defaultShape;
      BasicStroke outlineStroke;
      Color outlineColor = new Color(0, 0, 0, 0);
      if (shapeProvider != null) {
        shape = shapeProvider.getShapeForCategory(value);
        outlineStroke = DEFAULT_OUTLINE_STROKE;
        outlineColor = defaultOutlineColor;
      } else {
        outlineStroke = new BasicStroke();
        if (colorProvider != null) {
          shape = UNDEFINED_SHAPE;
        } else {
          shape = UNDEFINED_SHAPE_AND_COLOR;
        }
      }

      // configure fill paint
      Paint paint = UNDEFINED_COLOR_PAINT;
      if (colorProvider != null) {
        paint = colorProvider.getColorForValue(value);
      }

      double scalingFactor = 1;
      if (sizeProvider != null) {
        // scale shape according to sizeProvider
        scalingFactor = sizeProvider.getScalingFactorForValue(value);
        // scale shape to fit into legend
        scalingFactor = legendSizeProvider.getScalingFactorForValue(scalingFactor);
        AffineTransform transformation = new AffineTransform();
        transformation.scale(scalingFactor, scalingFactor);
        shape = transformation.createTransformedShape(shape);
      }

      String label = dimensionConfigData.getStringForValue(value);
      if (label == null) {
        label = "";
      }

      CustomLegendItem legendItem =
          new CustomLegendItem(label, null, null, null, shape, paint, outlineStroke, outlineColor);
      legendItemCollection.add(legendItem);
    }
  }
  /**
   * Creates a continuous legend item for one item in dimensionSet, i.e. dimensionSet must be a set
   * containing exactly one value.
   *
   * @param dateFormat format used to format minValue and maxValue as dates, or null if they should
   *     be displayed numerically instead of as dates
   * @throws ChartPlottimeException
   */
  private LegendItem createContinuousLegendItem(
      PlotInstance plotInstance,
      Set<PlotDimension> dimensionSet,
      double minValue,
      double maxValue,
      DateFormat dateFormat) {
    PlotConfiguration plotConfiguration = plotInstance.getCurrentPlotConfigurationClone();
    PlotDimension dimension = dimensionSet.iterator().next();
    DefaultDimensionConfig dimensionConfig =
        (DefaultDimensionConfig) plotConfiguration.getDimensionConfig(dimension);
    DimensionConfigData dimensionConfigData =
        plotInstance.getPlotData().getDimensionConfigData(dimensionConfig);
    // String label = dimensionConfig.getLabel();
    // if(label == null) {
    // label = I18N.getGUILabel("plotter.unnamed_value_label");
    // }
    String label = "";

    if (dimension == PlotDimension.COLOR) {
      ColorProvider colorProvider = dimensionConfigData.getColorProvider();
      if (!colorProvider.supportsNumericalValues()) {
        throw new RuntimeException(
            "Color provider for continuous legend item does not support numerical values.");
      }

      // shape dimensions
      final int width = 50;
      final int height = 10;

      // create item paint

      // first disable logarithmic scale on color provider ( -> linear gradient in legend)
      // ContinuousColorProvider continuousColorProvider = null;
      // if (dimensionConfig.isLogarithmic() && colorProvider instanceof
      // ContinuousColorProvider) {
      // continuousColorProvider = (ContinuousColorProvider)colorProvider;
      // continuousColorProvider.setLogarithmic(false);
      // }

      // calculate gradient
      float fractions[] = new float[width];
      Color colors[] = new Color[width];
      for (int i = 0; i < width; ++i) {

        float fraction = i / (width - 1.0f);
        double fractionValue;
        if (colorProvider instanceof ContinuousColorProvider
            && ((ContinuousColorProvider) colorProvider)
                .isColorMinMaxValueDifferentFromOriginal(
                    ((ContinuousColorProvider) colorProvider).getMinValue(),
                    ((ContinuousColorProvider) colorProvider).getMaxValue())) {
          fractionValue =
              ((ContinuousColorProvider) colorProvider).getMinValue()
                  + fraction
                      * (((ContinuousColorProvider) colorProvider).getMaxValue()
                          - ((ContinuousColorProvider) colorProvider).getMinValue());
        } else {
          fractionValue = minValue + fraction * (maxValue - minValue);
        }
        colors[i] = colorProvider.getColorForValue(fractionValue);
        fractions[i] = fraction;
      }
      LinearGradientPaint shapeFillPaint =
          new LinearGradientPaint(
              new Point(0, 0), new Point(width, 0), fractions, colors, CycleMethod.REPEAT);

      // reset color provider to logarithmic if necessary
      // if (continuousColorProvider != null && dimensionConfig.isLogarithmic()) {
      // continuousColorProvider.setLogarithmic(true);
      // }

      // create item shape
      Rectangle itemShape = new Rectangle(width, height);

      if (colorProvider instanceof ContinuousColorProvider) {
        return createFlankedShapeLegendItem(
            label,
            ((ContinuousColorProvider) colorProvider).getMinValue(),
            ((ContinuousColorProvider) colorProvider).getMaxValue(),
            itemShape,
            shapeFillPaint,
            true,
            dateFormat);
      } else {
        return createFlankedShapeLegendItem(
            label, minValue, maxValue, itemShape, shapeFillPaint, true, dateFormat);
      }
    } else if (dimension == PlotDimension.SHAPE) {
      // shape provider probably never supports numerical values
      return null;
    } else if (dimension == PlotDimension.SIZE) {
      SizeProvider sizeProvider = dimensionConfigData.getSizeProvider();

      if (!sizeProvider.supportsNumericalValues()) {
        throw new RuntimeException(
            "Size provider for continuous legend item does not support numerical values.");
      }

      double minScalingFactor = sizeProvider.getMinScalingFactor();
      double maxScalingFactor = sizeProvider.getMaxScalingFactor();
      ContinuousSizeProvider legendSizeProvider =
          new ContinuousSizeProvider(
              minScalingFactor,
              maxScalingFactor,
              MIN_LEGEND_ITEM_SCALING_FACTOR,
              MAX_LEGEND_ITEM_SCALING_FACTOR,
              false);

      int legendItemCount = 4;
      Area composedShape = new Area();
      Shape originalShape = UNDEFINED_SHAPE;
      if (dimensionSet.contains(PlotDimension.SIZE) && dimensionSet.size() == 1) {
        originalShape = UNDEFINED_SHAPE_AND_COLOR;
      }
      double maxHeight = originalShape.getBounds().getHeight() * MAX_LEGEND_ITEM_SCALING_FACTOR;
      for (int i = 0; i < legendItemCount; ++i) {
        double fraction =
            minScalingFactor
                + ((double) i / legendItemCount * (maxScalingFactor - minScalingFactor));
        double legendScalingFactor = legendSizeProvider.getScalingFactorForValue(fraction);

        double composedWidth = composedShape.getBounds().getWidth();

        AffineTransform t = new AffineTransform();
        t.scale(legendScalingFactor, legendScalingFactor);
        Shape shape = t.createTransformedShape(originalShape);

        t = new AffineTransform();
        double shapeWidth = shape.getBounds().getWidth();
        double shapeHeight = shape.getBounds().getHeight();
        t.translate(composedWidth + shapeWidth * .1, (maxHeight - shapeHeight) / 2.0);
        t.translate(-shape.getBounds().getMinX(), -shape.getBounds().getMinY());
        shape = t.createTransformedShape(shape);
        composedShape.add(new Area(shape));
      }

      return createFlankedShapeLegendItem(
          label, minValue, maxValue, composedShape, UNDEFINED_COLOR_PAINT, false, dateFormat);

    } else {
      throw new RuntimeException(
          "Unsupported dimension. Execution path should never reach this line.");
    }
  }