/// <summary>
        /// Creates a filler series for the given chart to provide padding between bars in a bar graph.
        /// Preconditions: Chart must be bar graph and have more than one desired series of data (columnValueCounters.Count > 1).
        /// </summary>
        private void CreateFillerChartSeries(Chart chart, string fillerName, List <string> xValues)
        {
            Series filler = new Series("filler" + fillerName);

            //Need to set 0 for the y-value corresponding to each xValue to make sure this series does not actually show up in the chart.
            foreach (string xValue in xValues)
            {
                filler.Points.AddXY(xValue, 0);
            }
            filler.Enabled           = true;
            filler.IsVisibleInLegend = false;
            filler.SetCustomProperty("PointWidth", "0.1");
            chart.Series.Add(filler);
        }
 /// <summary>
 /// Configures all style settings for an individual bar chart data series.
 /// </summary>
 private void FinalizeBarChartSeries(Chart chart, Series series, List <ColumnValueCounter> columnValueCounters, Color color, DocumentManipulation.TextReplacementOptions options)
 {
     series.ChartType         = SeriesChartType.Column;
     series["PieLabelStyle"]  = "Outside";
     series.Color             = color;
     series.IsVisibleInLegend = true;
     //Set series label style
     series.CustomProperties    = "BarLabelStyle = Top";
     series.CustomProperties    = "LabelStyle = Top";
     series.Font                = new System.Drawing.Font("Calibri", 16);
     series.IsValueShownAsLabel = true;
     if (options.isPercentage)
     {
         foreach (DataPoint point in series.Points)
         {
             if (!point.YValues[0].ToString().Contains('.'))
             {
                 point.Label = point.YValues[0].ToString() + ".0";
             }
         }
     }
     series.SmartLabelStyle.Enabled = false;
     series.SmartLabelStyle.AllowOutsidePlotArea = LabelOutsidePlotAreaStyle.Partial;
     //When we are plotting more than one column at a time, there will be filler series' in between each data series.
     //Increase the width of the columns to account for the decreased width that gets automatically applied to them because of this.
     if (columnValueCounters.Count > 1)
     {
         //Set width for multiple series case
         series.SetCustomProperty("PointWidth", "1");
     }
     else
     {
         //Set width for single series case
         series.SetCustomProperty("PointWidth", "0.3");
     }
     chart.Series.Add(series);
 }
    protected virtual void CalculateHistogram(Series series, DataRow row) {
      series.Points.Clear();
      if (!row.Values.Any()) return;
      int bins = row.VisualProperties.Bins;

      double minValue = row.Values.Min();
      double maxValue = row.Values.Max();
      double intervalWidth = (maxValue - minValue) / bins;
      if (intervalWidth < 0) return;
      if (intervalWidth == 0) {
        series.Points.AddXY(minValue, row.Values.Count);
        return;
      }

      if (!row.VisualProperties.ExactBins) {
        intervalWidth = HumanRoundRange(intervalWidth);
        minValue = Math.Floor(minValue / intervalWidth) * intervalWidth;
        maxValue = Math.Ceiling(maxValue / intervalWidth) * intervalWidth;
      }

      double intervalCenter = intervalWidth / 2;

      double min = 0.0, max = 0.0;
      if (!Double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue) && !Content.VisualProperties.XAxisMinimumAuto)
        min = Content.VisualProperties.XAxisMinimumFixedValue;
      else min = minValue;
      if (!Double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue) && !Content.VisualProperties.XAxisMaximumAuto)
        max = Content.VisualProperties.XAxisMaximumFixedValue;
      else max = maxValue + intervalWidth;

      double axisInterval = intervalWidth / row.VisualProperties.ScaleFactor;

      var area = chart.ChartAreas[0];
      area.AxisX.Interval = axisInterval;

      series.SetCustomProperty("PointWidth", "1"); // 0.8 is the default value

      // get the range or intervals which define the grouping of the frequency values
      var doubleRange = DoubleRange(min, max, intervalWidth).Skip(1).ToList();

      // aggregate the row values by unique key and frequency value
      var valueFrequencies = (from v in row.Values
                              where !IsInvalidValue(v)
                              orderby v
                              group v by v into g
                              select new Tuple<double, double>(g.First(), g.Count())).ToList();

      // shift the chart to the left so the bars are placed on the intervals
      if (valueFrequencies.First().Item1 < doubleRange.First())
        series.Points.Add(new DataPoint(min - intervalWidth, 0));

      // add data points
      int j = 0;
      foreach (var d in doubleRange) {
        double sum = 0.0;
        // sum the frequency values that fall within the same interval
        while (j < valueFrequencies.Count && valueFrequencies[j].Item1 < d) {
          sum += valueFrequencies[j].Item2;
          ++j;
        }
        string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)
                              ? "X"
                              : Content.VisualProperties.XAxisTitle;
        string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)
                              ? "Y"
                              : Content.VisualProperties.YAxisTitle;
        series.Points.Add(new DataPoint(d - intervalCenter, sum) {
          ToolTip =
            xAxisTitle + ": [" + (d - intervalWidth) + "-" + d + ")" + Environment.NewLine +
            yAxisTitle + ": " + sum
        });
      }
    }
    private void ConfigureSeries(Series series, DataRow row) {
      RemoveCustomPropertyIfExists(series, "PointWidth");
      series.BorderWidth = 1;
      series.BorderDashStyle = ChartDashStyle.Solid;
      series.BorderColor = Color.Empty;

      if (row.VisualProperties.Color != Color.Empty)
        series.Color = row.VisualProperties.Color;
      else series.Color = Color.Empty;
      series.IsVisibleInLegend = row.VisualProperties.IsVisibleInLegend;

      switch (row.VisualProperties.ChartType) {
        case DataRowVisualProperties.DataRowChartType.Line:
          series.ChartType = SeriesChartType.FastLine;
          series.BorderWidth = row.VisualProperties.LineWidth;
          series.BorderDashStyle = ConvertLineStyle(row.VisualProperties.LineStyle);
          break;
        case DataRowVisualProperties.DataRowChartType.Bars:
          // Bar is incompatible with anything but Bar and StackedBar*
          if (!chart.Series.Any(x => x.ChartType != SeriesChartType.Bar && x.ChartType != SeriesChartType.StackedBar && x.ChartType != SeriesChartType.StackedBar100))
            series.ChartType = SeriesChartType.Bar;
          else {
            series.ChartType = SeriesChartType.FastPoint; //default
            row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
          }
          break;
        case DataRowVisualProperties.DataRowChartType.Columns:
          series.ChartType = SeriesChartType.Column;
          break;
        case DataRowVisualProperties.DataRowChartType.Points:
          series.ChartType = SeriesChartType.FastPoint;
          break;
        case DataRowVisualProperties.DataRowChartType.Histogram:
          series.ChartType = SeriesChartType.Column;
          series.SetCustomProperty("PointWidth", "1");
          if (!series.Color.IsEmpty && series.Color.GetBrightness() < 0.25)
            series.BorderColor = Color.White;
          else series.BorderColor = Color.Black;
          break;
        case DataRowVisualProperties.DataRowChartType.StepLine:
          series.ChartType = SeriesChartType.StepLine;
          series.BorderWidth = row.VisualProperties.LineWidth;
          series.BorderDashStyle = ConvertLineStyle(row.VisualProperties.LineStyle);
          break;
        default:
          series.ChartType = SeriesChartType.FastPoint;
          break;
      }
      series.YAxisType = row.VisualProperties.SecondYAxis ? AxisType.Secondary : AxisType.Primary;
      series.XAxisType = row.VisualProperties.SecondXAxis ? AxisType.Secondary : AxisType.Primary;
      if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
      else series.LegendText = row.Name;

      string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)
                      ? "X"
                      : Content.VisualProperties.XAxisTitle;
      string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)
                            ? "Y"
                            : Content.VisualProperties.YAxisTitle;
      series.ToolTip =
        series.LegendText + Environment.NewLine +
        xAxisTitle + " = " + "#INDEX," + Environment.NewLine +
        yAxisTitle + " = " + "#VAL";
    }