C# 如何在MSChart左侧或右侧添加更多不同比例的Y轴

C# 如何在MSChart左侧或右侧添加更多不同比例的Y轴,c#,winforms,mschart,yaxis,C#,Winforms,Mschart,Yaxis,我想为具有不同比例的图表添加3个Y轴 我想得到一个x轴和不同的y轴。我做了下面的代码,但我想显示一个y轴像在我附加的第二张图片 到目前为止,我的C#代码: private void checkBoxUseMultipleYAxis_CheckedChanged(object sender, EventArgs e) { if (checkBoxUseMultipleYAxis.Checked) { // Set custom

我想为具有不同比例的图表添加3个Y轴

我想得到一个x轴和不同的y轴。我做了下面的代码,但我想显示一个y轴像在我附加的第二张图片

到目前为止,我的C#代码:

   private void checkBoxUseMultipleYAxis_CheckedChanged(object sender, EventArgs e)
    {
        if (checkBoxUseMultipleYAxis.Checked)
        {
            // Set custom chart area position
            chart1.ChartAreas["ChartArea1"].Position = new ElementPosition(25, 10, 68, 85);
            chart1.ChartAreas["ChartArea1"].InnerPlotPosition = new ElementPosition(10, 0, 90, 90);``



            // Create extra Y axis for second and third series
            CreateYAxis(chart1, chart1.ChartAreas["ChartArea1"], chart1.Series["Current"], 13, 8);
            CreateYAxis(chart1, chart1.ChartAreas["ChartArea1"], chart1.Series["Capacity"], 22, 8);
        }
        else
        {
            // Set default chart areas
            chart1.Series["Current"].ChartArea = "ChartArea1";
            chart1.Series["Capacity"].ChartArea = "ChartArea1";

            // Remove newly created series and chart areas
            while (chart1.Series.Count > 3)
            {
                chart1.Series.RemoveAt(3);
            }
            while (chart1.ChartAreas.Count > 1)
            {
                chart1.ChartAreas.RemoveAt(1);
            }

            // Set default chart are position to Auto
            chart1.ChartAreas["ChartArea1"].Position.Auto = true;
            chart1.ChartAreas["ChartArea1"].InnerPlotPosition.Auto = true;

        }
    }
 public void CreateYAxis(Chart chart, ChartArea area, Series series, float axisOffset, float labelsSize)
    {
        // Create new chart area for original series
        ChartArea areaSeries = chart.ChartAreas.Add("ChartArea_" + series.Name);
        areaSeries.BackColor = Color.Transparent;
        areaSeries.BorderColor = Color.Transparent;
        areaSeries.Position.FromRectangleF(area.Position.ToRectangleF());
        areaSeries.InnerPlotPosition.FromRectangleF(area.InnerPlotPosition.ToRectangleF());
        areaSeries.AxisX.MajorGrid.Enabled = false;
        areaSeries.AxisX.MajorTickMark.Enabled = false;
        areaSeries.AxisX.LabelStyle.Enabled = false;
        areaSeries.AxisY.MajorGrid.Enabled = false;
        areaSeries.AxisY.MajorTickMark.Enabled = false;
        areaSeries.AxisY.LabelStyle.Enabled = false;
        areaSeries.AxisY.IsStartedFromZero = area.AxisY.IsStartedFromZero;


        series.ChartArea = areaSeries.Name;

        // Create new chart area for axis
        ChartArea areaAxis = chart.ChartAreas.Add("AxisY_" + series.ChartArea);
        areaAxis.BackColor = Color.Transparent;
        areaAxis.BorderColor = Color.Transparent;
        areaAxis.Position.FromRectangleF(chart.ChartAreas[series.ChartArea].Position.ToRectangleF());
        areaAxis.InnerPlotPosition.FromRectangleF(chart.ChartAreas[series.ChartArea].InnerPlotPosition.ToRectangleF());

        // Create a copy of specified series
        Series seriesCopy = chart.Series.Add(series.Name + "_Copy");
        seriesCopy.ChartType = series.ChartType;
        foreach (DataPoint point in series.Points)
        {
            seriesCopy.Points.AddXY(point.XValue, point.YValues[0]);
        }

        // Hide copied series
        seriesCopy.IsVisibleInLegend = false;
        seriesCopy.Color = Color.Transparent;
        seriesCopy.BorderColor = Color.Transparent;
        seriesCopy.ChartArea = areaAxis.Name;

        // Disable drid lines & tickmarks
        areaAxis.AxisX.LineWidth = 0;
        areaAxis.AxisX.MajorGrid.Enabled = false;
        areaAxis.AxisX.MajorTickMark.Enabled = false;
        areaAxis.AxisX.LabelStyle.Enabled = false;
        areaAxis.AxisY.MajorGrid.Enabled = false;
        areaAxis.AxisY.IsStartedFromZero = area.AxisY.IsStartedFromZero;
        areaAxis.AxisY.LabelStyle.Font = area.AxisY.LabelStyle.Font;

        // Adjust area position
        areaAxis.Position.X -= axisOffset;
        areaAxis.InnerPlotPosition.X += labelsSize;

    }
    };


这是一个有趣的问题,有一段非常复杂的代码,它解决了一个我从未注意到的问题

让我们先谈谈基本知识

在图表中,可以向同一区域添加多个系列的数据。只要y值的范围大致相同,通常就没有问题。但如果不是,y轴将缩放,以便所有值都适合图表区域。这意味着那些小范围的序列将被压扁。以下是一个例子:

除了无法读取的y值之外,除了橙色系列,我们还看到只有一个轴标题;如果适用于所有系列,则ok;但如果不是这样,最好不要说

(有时,将y轴设置为对数会有所帮助,但通常这只会使事情变得混乱,根本没有帮助。)

这需要更多的轴。事实上,有一个额外的轴内置的,就在那里只是为了提问:每个图表区域的左侧可以有一个主y轴,右侧可以有另一个,称为“
轴2

您可以启用它并将一个系列关联到它:

chart1.ChartAreas[0].AxisY2.Enabled = AxisEnabled.True;
chart1.Series[1].YAxisType = AxisType.Secondary;
这很好,效果很好。但我们的示例需要2个以上的y轴。。这正是您找到的代码所提供的

让我们先来看看reults:

这很好;现在,我们可以看到范围从
0-30
0-120
-20-30
以及最后的
0-1200
之间的差异

但当所有轴都添加到左侧时,它们离绘图区域越来越远。这就是你的问题

我发现扩展您找到的代码比从头开始编写更好的版本更容易。这意味着代码的大多数问题仍然存在:

  • 未模块化
  • 例程依赖于“神奇”值
  • 通过反复试验找到这些值是乏味的
我在
CreateYAxis
方法中添加了两个参数;一个设置添加的轴区域的宽度,另一个切换将它们添加到左侧或右侧

让我们先看看结果:

现在更改代码:

public void CreateYAxis(Chart chart, ChartArea area, Series series, 
                        float axisX, float axisWidth, float labelsSize, bool alignLeft)
{

    chart.ApplyPaletteColors();  // (*)

    // Create new chart area for original series
    ChartArea areaSeries = chart.ChartAreas.Add("CAs_" + series.Name);
    areaSeries.BackColor = Color.Transparent;
    areaSeries.BorderColor = Color.Transparent;
    areaSeries.Position.FromRectangleF(area.Position.ToRectangleF());
    areaSeries.InnerPlotPosition.FromRectangleF(area.InnerPlotPosition.ToRectangleF());
    areaSeries.AxisX.MajorGrid.Enabled = false;
    areaSeries.AxisX.MajorTickMark.Enabled = false;
    areaSeries.AxisX.LabelStyle.Enabled = false;
    areaSeries.AxisY.MajorGrid.Enabled = false;
    areaSeries.AxisY.MajorTickMark.Enabled = false;
    areaSeries.AxisY.LabelStyle.Enabled = false;
    areaSeries.AxisY.IsStartedFromZero = area.AxisY.IsStartedFromZero;
    // associate series with new ca
    series.ChartArea = areaSeries.Name;

    // Create new chart area for axis
    ChartArea areaAxis = chart.ChartAreas.Add("CA_AxY_" + series.ChartArea);

    areaAxis.BackColor = Color.Transparent;
    areaAxis.BorderColor = Color.Transparent;
    RectangleF oRect = area.Position.ToRectangleF();
    areaAxis.Position = new ElementPosition(oRect.X, oRect.Y, axisWidth, oRect.Height);
    areaAxis.InnerPlotPosition
            .FromRectangleF(areaSeries.InnerPlotPosition.ToRectangleF());

    // Create a copy of specified series
    Series seriesCopy = chart.Series.Add(series.Name + "_Copy");
    seriesCopy.ChartType = series.ChartType;
    seriesCopy.YAxisType = alignLeft ? AxisType.Primary : AxisType.Secondary;  // (**)

    foreach (DataPoint point in series.Points)
    {
        seriesCopy.Points.AddXY(point.XValue, point.YValues[0]);
    }
    // Hide copied series
    seriesCopy.IsVisibleInLegend = false;
    seriesCopy.Color = Color.Transparent;
    seriesCopy.BorderColor = Color.Transparent;
    seriesCopy.ChartArea = areaAxis.Name;

    // Disable grid lines & tickmarks
    areaAxis.AxisX.LineWidth = 0;
    areaAxis.AxisX.MajorGrid.Enabled = false;
    areaAxis.AxisX.MajorTickMark.Enabled = false;
    areaAxis.AxisX.LabelStyle.Enabled = false;

    Axis areaAxisAxisY = alignLeft ? areaAxis.AxisY : areaAxis.AxisY2;   // (**)
    areaAxisAxisY.MajorGrid.Enabled = false;
    areaAxisAxisY.IsStartedFromZero = area.AxisY.IsStartedFromZero;
    areaAxisAxisY.LabelStyle.Font = area.AxisY.LabelStyle.Font;

    areaAxisAxisY.Title = series.Name;
    areaAxisAxisY.LineColor =  series.Color;    // (*)
    areaAxisAxisY.TitleForeColor = Color.DarkCyan;  // (*)

    // Adjust area position
    areaAxis.Position.X = axisX;
    areaAxis.InnerPlotPosition.X += labelsSize;
}
我添加了一些代码,使轴具有系列颜色。(*) 当为false时,
alignLeft
将拾取次轴而不是主轴。(**)

在checkbox事件中调用方法时使用必要的数字

以下是我截图中使用的行和数字:

首先是正常的

// Set custom chart area position
ChartArea ca = chart1.ChartAreas["ChartArea1"];
ca.Position = new ElementPosition(23, 10, 77, 85);
ca.InnerPlotPosition = new ElementPosition(12, 0, 67, 90);

 // Create extra Y axis for some series
 CreateYAxis(chart1, ca, chart1.Series["Current"], 5, 9, 8, true);
 CreateYAxis(chart1, ca, chart1.Series["Capacity"], 13, 9, 8, true);
 CreateYAxis(chart1, ca, chart1.Series["testing"], 21, 9, 8, true);
..然后在右侧添加一个系列轴:

// Set custom chart area position
ChartArea ca = chart1.ChartAreas["ChartArea1"];
ca .Position = new ElementPosition(15, 10, 83, 85);
ca .InnerPlotPosition = new ElementPosition(12, 0, 67, 90);

// Create extra Y axis for some series
CreateYAxis(chart1,ca , chart1.Series["Current"], 5, 9, 8, true);
CreateYAxis(chart1, ca , chart1.Series["Capacity"], 13, 9, 8, true);
CreateYAxis(chart1, ca , chart1.Series["testing"], 64, 21, 8, false);
请注意,复选框事件的
else
分支尝试删除额外的图表区域。它有一个硬编码的数字
3
;这和整个反转代码都不太稳定

关于代码本身功能的简短描述:

它为每个额外的“系列轴”添加两个额外的图表区域:

  • 一个将原始序列与关联。这个区域必须始终与原始图表区域具有相同的位置和大小!它的目的是允许图形缩放到最大程度,因为没有其他系列与此新图表区域关联。图形保持可见,但所有其他部分(如轴边框等)不可见

  • 另一个将显示轴。这里的一切都是无形的,但轴心是无形的;要填充轴,将原始序列中的点复制到与此图表区域关联的新序列中

关于用法的最后一点:整个用法仍然取决于你用来布置图表区域的数字!我给自己写了一个小助手工具,如果你感兴趣的话可以使用。这是它的工作原理:


您调用了CreateYAxis两次以创建两个附加轴。相反,您可以将其中一个放置在次Y轴(右侧)。只是一个想法,因为您已经将图表定制到这个范围,所以您可以添加单独的图例/轴标题,甚至注释,并将它们定位用于指示目的。@TaW,是的,代码不是我的,有些是我更改的。我是更新的。所以我不能维护我希望的代码。我想重新安排这个代码,就像我上面给出的第二张图片一样。我想在图表区域的右侧获得容量轴。其他轴可以。如果可以的话,所以请纠正它。这将有助于克服我的问题。谢谢sir@TaW谢谢你的帮助,先生,这花了我一段时间,但我很高兴我完成了你找到的这段有趣的代码。非常感谢你,先生。我会尝试这样做,我会告诉你我使用你的代码得到的结果,先生。非常感谢你的帮助你的帮助。