C# WindowsForms数据可视化图表中的约束纵横比

C# WindowsForms数据可视化图表中的约束纵横比,c#,winforms,charts,data-visualization,C#,Winforms,Charts,Data Visualization,使用System.Windows.Forms.DataVisualization.charting.Chart中的图表控件,我正在绘制散点图 如何约束它,使X轴的比例与Y轴的比例相同 简单地将控件本身设置为正方形是不够的,因为它具有用于绘制和标记不相等轴的内部边距 我可以选择一个特定的尺寸,并将其调整为正方形,但它必须是正方形,并且可以调整大小 我在文档和属性浏览器中搜索了上下,但在调整大小事件中找不到任何东西或想不出任何方法。这是一个好问题,但不幸的是,没有像锁定两个轴或设置一个值这样简单的解

使用
System.Windows.Forms.DataVisualization.charting.Chart
中的图表控件,我正在绘制散点图

如何约束它,使X轴的比例与Y轴的比例相同

简单地将控件本身设置为正方形是不够的,因为它具有用于绘制和标记不相等轴的内部边距

我可以选择一个特定的尺寸,并将其调整为正方形,但它必须是正方形,并且可以调整大小


我在文档和属性浏览器中搜索了上下,但在调整大小事件中找不到任何东西或想不出任何方法。

这是一个好问题,但不幸的是,没有像锁定两个
或设置一个值这样简单的解决方案

让我们从相关参与者开始:

  • Chart
    控件有一个名为
    ClientSize
    的内部
    Size
    ,它是
    Chart.Size
    减去边框的值。这两种尺寸都以像素为单位

  • 里面可能有一个或多个。每个都有一个
    位置
    ,该位置属于类型

  • 在每个
    图表区域内
    是用于实际绘制点的区域;它被称为

InnerPlotPosition属性定义图表中的矩形 用于绘制数据的面积元素;它不包括勾号, 轴标签等

用于此属性的坐标(0,0到100100)与 ChartArea对象,而不是整个图表

InnerPlotPosition属性可用于对齐多个图表 地区。但是,如果一个图表区域有记号标记和轴标签 另一个没有,它们的轴线无法对齐

  • ChartArea.Position
    ChartArea.InnerPlotPosition
    不仅包含位置,还包含区域的大小;所有值均以外部区域的百分比表示,即
    图表区域。内部绘图位置
    相对于
    图表区域。位置
    图表区域。位置
    相对于
    图表。客户端大小
    。所有百分比都从
    0-100
    开始
因此
图表区
包括
标签
图例
以及
记号

我们想要的是找到一种使
内部绘图区域
为正方形的方法,即在像素中具有相同的宽度和高度。百分比不行

让我们从几个简单的计算开始;如果这些是我们掌握的数据

    // we'll work with one ChartArea only..:
    ChartArea ca = chart1.ChartAreas[0];
    ElementPosition cap = ca.Position;
    ElementPosition ipp = ca.InnerPlotPosition;
。。然后是两个区域的像素大小:

    // chartarea pixel size:
    Size CaSize = new Size( (int)( cap.Width * chart1.ClientSize.Width / 100f), 
                            (int)( cap.Height * chart1.ClientSize.Height / 100f));

    // InnerPlotArea pixel size:
   Size IppSize = new Size((int)(ipp.Width * CaSize.Width / 100f),
                            (int)(ipp.Height * CaSize.Height / 100f));
理想情况下,我们希望
InnerPlotArea
为正方形;由于我们不能很好地让较小的一方增长(否则图表会透支),我们需要缩小较大的一方。因此,
InnerPlotArea
的新像素大小为

int ippNewSide = Math.Min(IppSize.Width, IppSize.Height);
接下来呢?由于刚刚设置了
Chart.Size
,我们不想弄乱它。我们也不应该弄乱
图表区
:它仍然需要空间来容纳
图例

因此,我们更改
内部绘图区域的大小

首先创建一个类级变量来存储
InnerPlotPosition
的原始值:

   ElementPosition ipp0 = null;

我们需要它保持原始百分比,即利润率,以便在计算新百分比时使用它们。当我们调整图表时,当前的图表将已经改变/扭曲

然后,我们创建一个函数,使
内部绘图区域
为方形,将其全部封装起来:

void makeSquare(Chart chart)
{
    ChartArea ca = chart.ChartAreas[0];

    // store the original value:
    if (ipp0 == null) ipp0 = ca.InnerPlotPosition;

    // get the current chart area :
    ElementPosition cap = ca.Position;

    // get both area sizes in pixels:
    Size CaSize = new Size( (int)( cap.Width * chart1.ClientSize.Width / 100f), 
                            (int)( cap.Height * chart1.ClientSize.Height / 100f));

    Size IppSize = new Size((int)(ipp0.Width * CaSize.Width / 100f),
                            (int)(ipp0.Height * CaSize.Height / 100f));

    // we need to use the smaller side:
    int ippNewSide = Math.Min(IppSize.Width, IppSize.Height);

    // calculate the scaling factors
    float px = ipp0.Width / IppSize.Width * ippNewSide;
    float py = ipp0.Height / IppSize.Height * ippNewSide;

    // use one or the other:
    if (IppSize.Width  < IppSize.Height)
        ca.InnerPlotPosition = new ElementPosition(ipp0.X, ipp0.Y, ipp0.Width, py);
    else 
        ca.InnerPlotPosition = new ElementPosition(ipp0.X, ipp0.Y, px, ipp0.Height);

}
这里的功能正在发挥作用:

原始尺寸:

挤一点:

然后又变方了:

请注意绿色的
图表区如何为
标签和
图例保留足够的空间,以及轴的自动缩放如何仍然工作。。但是X轴标签现在不能放在一行中。还要注意,
图表区.BackColor实际上是
内部绘图区的颜色

请注意,在对
图表区
布局进行修改(如放大、移动或删除
图例
或更改
标签
的大小或角度等)后,您可能必须刷新变量
ipp0
,以反映更改的百分比


当然,您可以修改函数以传递任何其他比率以保持,而不是将绘图区域保持为正方形。

太棒了,非常感谢!您能解释一下cip0的用途吗?我们需要它来保持原始的百分比,即保证金,以便在计算新的百分比时使用它们。当我们调整图表时,当前的图表将已经改变/扭曲。我想澄清我的问题是它代表什么/应该如何初始化。我看到了
ipp0
所代表的内容以及它的初始化位置,但没有看到
cip0
。哎呀,一个打字错误。我改了名字,这只是剩下的。更正。谢谢你的回答。这使我更接近于限制特定的纵横比。
private void chart1_Resize(object sender, EventArgs e)
{
    makeSquare(chart1);
}