如何在左侧或右侧以不同比例向MSChart添加更多Y轴 [英] How to add more Y-axes to MSChart with different scale at left or right side

查看:141
本文介绍了如何在左侧或右侧以不同比例向MSChart添加更多Y轴的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to add 3 Y-axes for the chart with different scales.

我想要一个x轴和另一个y轴.我像下面的代码那样做,但是我想显示一个y轴,就像我附加的第二张图片中一样.

I want to get one x axis and different y axis. I did it like below code but I want to show one y axis like in the 2nd image that I attached..

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

My C# code so far:

   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;

    }
    };

推荐答案

这是一个有趣的问题,其中包含一段相当复杂的代码,可以解决我从未注意到的问题.

This is an interesting question with a piece of quite involved code which solves a problem that I never noticed..

让我们首先谈谈基础知识.

Let's first talk about the basics.

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

In a chart you can add several series of data to the same area. As long as the ranges of y-values are more or less the same there is usually no problem. But if they aren't, the y-axis will scale so that all values will fit in the chart area. This means that those series with small ranges will get squashed. Here is an example:

除了橙色系列以外,除了所有不可读的y值外,我们还看到只有一个轴标题.如果适用于所有系列,可以;但是,如果没有:最好将其保留..

In addition to the unreadable y-values for all but the orange series we also see that there is only one axis title; if it applies to all series, ok; but if it doesn't: best leave it out..

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

(Sometimes setting the y-axis to be logarithmic can help, but usually this would just confuse things and not help at all.)

这需要更多的轴.实际上,有一个附加轴内置,就在这里:仅用于询问:每个图表区域可以具有一个主要 y轴,用于左边是另一个,右边是'中学'AxisY2.

This calls for more axes. In fact there is one extra axis built-in, right there just for the asking: Each chart area can have a primary y-axis to the left and another one, called 'secondary' AxisY2 to the right.

您可以启用它,并将一个系列与其关联:

You can enable it and associate one series to it:

chart1.ChartAreas[0].AxisY2.Enabled = AxisEnabled.True;
chart1.Series[1].YAxisType = AxisType.Secondary;

这很好,效果很好.但是我们的示例要求使用2个以上的y轴.这正是您找到的代码所提供的.

This is fine and works well. But our example calls for more than 2 y-axes.. which is just what the code you found provides.

让我们先看看结果:

这很好.现在我们可以看到范围从0 - 300 - 120-20 - 30以及最后是0 - 1200.

This is nice; now we can see how the ranges differ from 0 - 30 to 0 - 120 , -20 - 30 and finally 0 - 1200.

但是当所有轴都添加到左侧时,它们离绘图区域越来越远.因此,您的问题.

But as all axes are added to the left they get further and further away from the plot area. Hence your question..

我发现,最简单的方法是扩展找到的代码,而不是从头开始编写更好的版本.这意味着大多数代码问题仍然存在:

I found it easiest to expand on the code you found instead of writing a better version from scratch. This implies that most issues with the code are still there:

  • 未模块化
  • 常规程序取决于魔术"值
  • 通过反复试验来发现这些价值是乏味的

我在CreateYAxis方法中添加了两个参数;一个设置添加轴区域的宽度,另一个设置将其添加到左侧或右侧.

I have added two params to the CreateYAxis method; one sets the width of the added axis-areas and the other toggles adding them to the left or right.

让我们先看一下结果:

Let's look at the result first:

现在输入更改后的代码:

Now for the changed code:

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;
}

我添加了一些代码,使轴具有系列颜色. (*) alignLeft为false时,将选择 secondary 轴,而不是 primary 轴. (**)

I have added a little code to make the axes have the series colors. (*) The alignLeft will, when false, pick the secondary axis instead of the primary one. (**)

在复选框事件中调用方法时,将使用必要的数字.

The necessary numbers are used when calling the method in the checkbox event.

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

Here are the lines and numbers that were used for my screenshots:

首先是普通的..

// 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);

..然后将一个带有一个系列轴的轴添加到右侧:

..then the one with one series axis added to the right:

// 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;这样和整个反向代码都不太稳定!

Note that the else branch of the checkbox event tries to remove the extra chart areas. It has a hard-coded numer 3; this and the whole reversal code is not quite stable!

对代码本身的作用的简短描述:

A short desciption about what the code itself does:

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

It adds two extra chart areas for each extra 'series axis':

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

  • One to associate the original series to. This one must always have the same position&size as the orginal chart area! Its purpose is to allow the graphics to scale to the maximum extent, which it will do, as no other series is associated with this new chart area. The graphics stays visible but all other parts like axes borders etc are invisible.

另一个将显示轴.在这里,所有轴都不可见;并填充轴以将原始系列中的点复制到与此图表区域相关联的新系列中.

The other one will show the axis. Here everything but the axis is invisible; and to fill the axis the points from the original series are copied to a new series, which is associated with this chart area.

关于用法的最后说明:整个用法仍取决于您用于布置图表区域的数字!我为自己编写了一个小帮手工具,如果您有兴趣,可以下载.这是在工作:

Final note about usage: The whole usage still depends on the numbers you use to lay out the chart areas! I wrote myself a little helper tool, which you can download if you are interested. Here is it at work:

这篇关于如何在左侧或右侧以不同比例向MSChart添加更多Y轴的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆