如何根据我的系列值获得次轴的比例?

How Do I Get The Scale of The Secondary Axis to be Based on My Series Values?

我正在使用 System.Web.UI.DataVisualization。 Charting 在 MVC 中创建图表。

我有一个图表显示 StackedColumn100 SeriesChartType 中的值,相应的 y 轴值位于左侧的主 y 轴上。

由于它是 100% 堆积柱系列,因此主要 y 轴的比例从 0 到 100。

然后我以线 SeriesChartType 的形式添加了一个二级系列,绑定到二级轴(在右侧)。我希望此轴根据系列中的值调整其比例,但事实并非如此。无论这个系列的最高值是多少,次要 y 轴也有 0 到 100 之间的刻度。

如果我通过以下方式手动设置次要 y 轴的最大值: chart.ChartAreas[0].AxisY2.Maximum = 20;。它有效,但我不想这样做,因为根据所使用的搜索条件,最大值可能会有很大差异。

我真的试图为此找到解决方案,但我做不到。根据文档和样本,比例似乎应该基于系列值,但我不明白它是如何工作的。任何帮助将不胜感激!

下面是重现问题的独立测试函数。我使用以下行从我的视图中调用该函数:

<p><img src="@Url.Action("CreateChart_TestSecondaryAxis")" /> </p>

public FileResult CreateChart_TestSecondaryAxis()
        {
            System.Web.UI.DataVisualization.Charting.Chart chart = new System.Web.UI.DataVisualization.Charting.Chart();
            chart.Width = 800;
            chart.Height = 400;
            chart.BackColor = Color.FromArgb(211, 223, 240);
            chart.BorderlineDashStyle = ChartDashStyle.Solid;
            chart.BackSecondaryColor = Color.White;
            chart.BackGradientStyle = GradientStyle.TopBottom;
            chart.BorderlineWidth = 1;
            chart.Palette = ChartColorPalette.BrightPastel;
            chart.BorderlineColor = Color.FromArgb(26, 59, 105);
            chart.RenderType = RenderType.BinaryStreaming;
            chart.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
            chart.AntiAliasing = AntiAliasingStyles.All;
            chart.TextAntiAliasingQuality = TextAntiAliasingQuality.Normal;

            ChartArea chartArea = new ChartArea();
            chartArea.Name = "TestSecondaryAxis";
            chartArea.BackColor = Color.Transparent;
            chartArea.AxisX.IsLabelAutoFit = false;
            chartArea.AxisY.IsLabelAutoFit = false;
            chartArea.AxisX.LabelStyle.Font =
               new Font("Verdana,Arial,Helvetica,sans-serif",
                        8F, FontStyle.Regular);
            chartArea.AxisY.LabelStyle.Font =
               new Font("Verdana,Arial,Helvetica,sans-serif",
                        8F, FontStyle.Regular);
            chartArea.AxisY.LineColor = Color.FromArgb(64, 64, 64, 64);
            chartArea.AxisX.LineColor = Color.FromArgb(64, 64, 64, 64);
            chartArea.AxisY.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 64);
            chartArea.AxisX.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 64);

            chartArea.AxisX.Title = "Airport";
            chartArea.AxisY.Title = "LandingConf";
            chartArea.AxisY.TextOrientation = TextOrientation.Rotated270;
            chartArea.AxisX.LabelStyle.IsEndLabelVisible = true;
            chart.ChartAreas.Add(chartArea);

            Series seriesPrimaryAxisConf3 = new Series();
            seriesPrimaryAxisConf3.Name = "Conf 3";
            seriesPrimaryAxisConf3.IsValueShownAsLabel = false;
            seriesPrimaryAxisConf3.Color = Color.Blue;
            seriesPrimaryAxisConf3.ChartType = SeriesChartType.StackedColumn100;
            seriesPrimaryAxisConf3.BorderWidth = 2;
            seriesPrimaryAxisConf3.ChartArea = "TestSecondaryAxis";
            DataPoint point;


            for (int i = 1; i < 11; i++)
            {
                point = new DataPoint();
                point.AxisLabel = "Airport" + i.ToString();
                point.YValues = new double[] { i };

                seriesPrimaryAxisConf3.Points.Add(point);
            }

            chart.Series.Add(seriesPrimaryAxisConf3);

            Series seriesPrimaryAxisConfFull = new Series();
            seriesPrimaryAxisConfFull.Name = "Conf Full";
            seriesPrimaryAxisConfFull.IsValueShownAsLabel = false;
            seriesPrimaryAxisConfFull.Color = Color.Red;
            seriesPrimaryAxisConfFull.ChartType = SeriesChartType.StackedColumn100;
            seriesPrimaryAxisConfFull.BorderWidth = 2;
            seriesPrimaryAxisConfFull.ChartArea = "TestSecondaryAxis";


            for (int i = 1; i < 11; i++)
            {
                point = new DataPoint();
                point.AxisLabel = "Airport" + i.ToString();
                point.YValues = new double[] { 11-i };

                seriesPrimaryAxisConfFull.Points.Add(point);
            }

            chart.Series.Add(seriesPrimaryAxisConfFull);

            Series seriesSecondaryAxisNoOfFlights = new Series();
            seriesSecondaryAxisNoOfFlights.Name = "NoOfFLights";
            seriesSecondaryAxisNoOfFlights.IsValueShownAsLabel = false;
            seriesSecondaryAxisNoOfFlights.Color = Color.Red;
            seriesSecondaryAxisNoOfFlights.ChartType = SeriesChartType.Line;
            seriesSecondaryAxisNoOfFlights.BorderWidth = 2;
            seriesSecondaryAxisNoOfFlights.ChartArea = "TestSecondaryAxis";


            for (int i = 1; i < 11; i++)
            {
                point = new DataPoint();
                point.AxisLabel = "Airport" + i.ToString();
                point.YValues = new double[] { i };

                seriesSecondaryAxisNoOfFlights.Points.Add(point);
            }

            chart.Series.Add(seriesSecondaryAxisNoOfFlights);
            chart.Series["NoOfFLights"].YAxisType = AxisType.Secondary;
            chart.ChartAreas["TestSecondaryAxis"].AxisY2.LineColor = Color.Transparent;
            chart.ChartAreas["TestSecondaryAxis"].AxisY2.MajorGrid.Enabled = false;
            chart.ChartAreas["TestSecondaryAxis"].AxisY2.MajorTickMark.Enabled = false;

            MemoryStream ms = new MemoryStream();
            chart.SaveImage(ms);
            return File(ms.GetBuffer(), @"image/png");
        }

MSChart 是一个很好的控件,但不幸的是 Microsoft 总是未能 正确地记录它。

随着 MSDN 的最新变化,事情变得 变得更糟 ,所以我实际上无法指出适用于各种 ChartTypes 的规则.

在你的情况下,我扣除了这个(相当古怪的)规则:

To attach a non 100%-series to an indepently scaled secondary y-axis it must be the first series but the stacked series still must be added first.

所以,如果你想得到这样的结果:

..您需要调整代码。以下是所需的更改和补充......:

首先我们必须插入线系列在前面但是在之后已添加 stack100 系列..:[=​​18=]

chart.Series.Insert(0, seriesSecondaryAxisNoOfFlights);  // instead of adding it

接下来我们需要 owner-draw 行,否则它会 burried 在列下面。

像这样编写 PostPaint 事件:

private void Chart_PostPaint(object sender, ChartPaintEventArgs e)
{
    Chart chart = sender as Chart;  //*
    Series s = chart.Series[0];  // make sure to pick the right one!

    Axis ax = chart.ChartAreas[0].AxisX;
    Axis ay = chart.ChartAreas[0].AxisY2;  // !!

    var pts = s.Points.Select(x => 
        new PointF((float)ax.ValueToPixelPosition(x.XValue),
                   (float)ay.ValueToPixelPosition(x.YValues[0])));

    using (Pen pen = new Pen(s.Color, s.BorderWidth))
            e.ChartGraphics.Graphics.DrawLines(pen, pts.ToArray());
}

为此系列需要有效 x-values。所以添加这一行:

point.XValue = i;  // set both x and y-values!

我还对轴定位添加了一些微调:

ChartArea ca = chart.ChartAreas["TestSecondaryAxis"];
ca.AxisY.Maximum = 100;
ca.AxisX.Minimum = 0.5;
ca.AxisX.IntervalOffset = 0.5;