如何在左侧或右侧以不同比例向 MSChart 添加更多 Y 轴
How to add more Y-axes to MSChart with different scale at left or right side
我想为图表添加 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-values 的范围大致相同,通常就没有问题。但如果不是,y-axis 将缩放,以便所有值都适合图表区域。这意味着那些具有小范围的系列将被压扁。这是一个例子:
除了橙色系列以外的所有系列都无法阅读y-values,我们还看到只有一个轴标题;如果适用于所有系列,可以;但如果没有:最好将其排除在外..
(有时将 y-axis 设置为对数可能会有所帮助,但通常这只会混淆事情而根本没有帮助。)
这需要更多轴。事实上还有 one extra axis built-in,就在那里只是为了问:每个图表区域可以有一个 primary y-axis 在左边,另一个叫做'secondary' AxisY2
在右边。
您可以启用它并将一个系列关联到它:
chart1.ChartAreas[0].AxisY2.Enabled = AxisEnabled.True;
chart1.Series[1].YAxisType = AxisType.Secondary;
这很好,效果很好。但是我们的示例需要超过 2 个 y-axes.. 这正是您找到的代码所提供的。
先来看看结果:
这很好;现在我们可以看到范围从 0 - 30
到 0 - 120
, -20 - 30
和最后 0 - 1200
.
有何不同
但是随着所有轴都添加到左侧,它们离绘图区域越来越远。因此你的问题..
我发现最简单的方法是扩展您找到的代码,而不是从头开始编写更好的版本。这意味着大多数代码问题仍然存在:
- 未模块化
- 例程取决于 'magic' 值
- 通过反复试验找到这些值是乏味的
我在 CreateYAxis
方法中添加了两个参数;一个设置添加的宽度 axis-areas,另一个切换将它们添加到左侧或右侧。
现在更改代码:
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 轴。 (**)
在复选框事件中调用方法时使用必要的数字。
以下是用于我的屏幕截图的行和数字:
首先是正常的..
// 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
分支试图删除额外的图表区域。它有一个 hard-coded 数字 3
;这个和整个反转代码都不太稳定!
关于代码本身功能的简短描述:
它为每个额外 'series axis' 添加 两个 个额外图表区域:
一个 将原始系列关联到。这个必须始终与原始图表区域具有相同的位置和大小!它的目的是允许图形最大程度地缩放,它会这样做,因为没有其他系列与这个新图表区域相关联。图形保持可见,但所有其他部分(如轴边界等)都不可见。
另一个会显示坐标轴。这里的一切但轴是不可见的;并填充轴,将原始系列中的点复制到与此图表区域关联的新系列。
关于用法的最后说明:整个用法仍然取决于您用来布置图表区域的数字!我自己写了一个小辅助工具,有兴趣的可以download。这是在工作:
我想为图表添加 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-values 的范围大致相同,通常就没有问题。但如果不是,y-axis 将缩放,以便所有值都适合图表区域。这意味着那些具有小范围的系列将被压扁。这是一个例子:
除了橙色系列以外的所有系列都无法阅读y-values,我们还看到只有一个轴标题;如果适用于所有系列,可以;但如果没有:最好将其排除在外..
(有时将 y-axis 设置为对数可能会有所帮助,但通常这只会混淆事情而根本没有帮助。)
这需要更多轴。事实上还有 one extra axis built-in,就在那里只是为了问:每个图表区域可以有一个 primary y-axis 在左边,另一个叫做'secondary' AxisY2
在右边。
您可以启用它并将一个系列关联到它:
chart1.ChartAreas[0].AxisY2.Enabled = AxisEnabled.True;
chart1.Series[1].YAxisType = AxisType.Secondary;
这很好,效果很好。但是我们的示例需要超过 2 个 y-axes.. 这正是您找到的代码所提供的。
先来看看结果:
这很好;现在我们可以看到范围从 0 - 30
到 0 - 120
, -20 - 30
和最后 0 - 1200
.
但是随着所有轴都添加到左侧,它们离绘图区域越来越远。因此你的问题..
我发现最简单的方法是扩展您找到的代码,而不是从头开始编写更好的版本。这意味着大多数代码问题仍然存在:
- 未模块化
- 例程取决于 'magic' 值
- 通过反复试验找到这些值是乏味的
我在 CreateYAxis
方法中添加了两个参数;一个设置添加的宽度 axis-areas,另一个切换将它们添加到左侧或右侧。
现在更改代码:
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 轴。 (**)
在复选框事件中调用方法时使用必要的数字。
以下是用于我的屏幕截图的行和数字:
首先是正常的..
// 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
分支试图删除额外的图表区域。它有一个 hard-coded 数字 3
;这个和整个反转代码都不太稳定!
关于代码本身功能的简短描述:
它为每个额外 'series axis' 添加 两个 个额外图表区域:
一个 将原始系列关联到。这个必须始终与原始图表区域具有相同的位置和大小!它的目的是允许图形最大程度地缩放,它会这样做,因为没有其他系列与这个新图表区域相关联。图形保持可见,但所有其他部分(如轴边界等)都不可见。
另一个会显示坐标轴。这里的一切但轴是不可见的;并填充轴,将原始系列中的点复制到与此图表区域关联的新系列。
关于用法的最后说明:整个用法仍然取决于您用来布置图表区域的数字!我自己写了一个小辅助工具,有兴趣的可以download。这是在工作: