在约束WindowsForms数据可视化图表宽高比 [英] Constrain aspect ratio in WindowsForms DataVisualization Chart

查看:155
本文介绍了在约束WindowsForms数据可视化图表宽高比的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从使用 System.Windows.Forms.DataVisualization.Charting.Chart 的图表控件,我想提出一个散点图。



我怎么能限制它使X轴的比例是相同的Y轴的规模有多大?



简单的设置控制本身是方是不够的,因为它具有绘制和标签这是不相等的轴的内部空间。



我可以选择一个特定的大小,并调整它是正方形的,但它需要两个广场和调整大小。



我已经搜查高和低的文档中,并在属性浏览器,但我无法找到任何东西,或想到的什么方法可以做到这一点的resize事件。


解决方案

这是一个很好的问题,但遗憾的是像锁定没有简单的解决方案两个或设定一个值。



让我们通过查看相关的玩家开始:




  • 控制的内尺寸名为 ClientSize ,这是 Chart.Size 减去边界。这两种尺寸以像素为单位。


  • 里面可能有一个或一个以上的 ChartAreas 。每个人都有一个位置这是一个类型的 ElementPosition


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





InnerPlotPosition属性定义图表
区元素中的矩形用于绘制数据;它排除刻度标记,
轴标签,等等。



用于此属性(0,0至100,100)的坐标有关
将ChartArea对象,而不是对整个图表



的InnerPlotPosition属性可用于对齐多个图表
区。但是,如果一个图表地区的刻度线和轴标签和
另一个没有,他们的轴线不能对齐。





  • 双方 ChartArea.Position ChartArea.InnerPlotPosition 不仅包含在位置,但同时尺寸的领域;所有值都在%的外区,即 ChartArea.InnerPlotPosition 是相对于 ChartArea.Position C $ C>和 ChartArea.Position 是相对于 Chart.ClientSize 。所有百分比从根本 0-100



所以 ChartArea 包括标签传说以及刻度线 ..



我们需要的是找到一种方法,使 InnerPlotArea 平方,即具有相同的宽度和高度的像素即可。 !百分比不会做



让我们先从一些简单的计算;如果这些是我们拥有的数据..:

  //我们只有一个ChartArea工作..:
ChartArea CA = chart1.ChartAreas [0];
ElementPosition上限= ca.Position;
ElementPosition IPP = ca.InnerPlotPosition;



..然后这是两个区域的像素大小:

  // chartarea像素尺寸:
规格= CASIZE新的大小((INT)(cap.Width * chart1.ClientSize.Width / 100F),
(INT)(cap.Height * chart1.ClientSize.Height / 100F));

// InnerPlotArea像素尺寸:
规格= IppSize新的大小((INT)(ipp.Width * CaSize.Width / 100F),
(INT)(ipp.Height * CaSize.Height / 100F));



在理想情况下,我们希望 InnerPlotArea 是广场;因为不能很好地让小边长(或者图表会透支,)我们需要收缩较大的一个。因此, InnerPlotArea



  INT ippNewSide =数学的新的像素大小.Min(IppSize.Width,IppSize.Height); 

下一步是什么?因为 Chart.Size 刚刚成立,我们不想惹它。也不应我们乱用 ChartArea :它仍然需要空间来容纳联想



所以我们修改 InnerPlotArea ..大小:



第一创建一个类级别变量存储 InnerPlotPosition 的原始值:

  ElementPosition ipp0 = NULL; 

我们将需要它保持原有的百分比,即利润率为了计算何时使用它们新的。当我们适应了当时最新的将已经被改变了图/扭曲。



然后,我们创建一个函数,使 InnerPlotArea 平方,这都结束了:

 无效makeSquare(图图)
{
ChartArea CA = chart.ChartAreas [0];

//存储原始价值:
如果(ipp0 == NULL)ipp0 = ca.InnerPlotPosition;

//获得当前图表区:
ElementPosition上限= ca.Position;

//以像素为单位同时获得区域大小:
规格= CASIZE新的大小((INT)(cap.Width * chart1.ClientSize.Width / 100F),
(INT )(cap.Height * chart1.ClientSize.Height / 100F));

规格= IppSize新的大小((INT)(ipp0.Width * CaSize.Width / 100F),
(INT)(ipp0.Height * CaSize.Height / 100F));

//我们需要用更小的一面:
INT ippNewSide = Math.Min(IppSize.Width,IppSize.Height);

//计算比例因子
浮动PX = ipp0.Width / IppSize.Width * ippNewSide;
浮动PY = ipp0.Height / IppSize.Height * ippNewSide;

//使用一个或另一个:
如果(IppSize.Width< IppSize.Height)
ca.InnerPlotPosition =新ElementPosition(ipp0.X,ipp0.Y, ipp0.Width,PY);
,否则
ca.InnerPlotPosition =新ElementPosition(ipp0.X,ipp0.Y,PX,ipp0.Height);

}



后或调整过程中你会调用该函数。

 私人无效chart1_Resize(对象发件人,EventArgs五)
{
makeSquare(chart1);
}

下面的功能在起作用:



原来大小:



挤了一点:$ b​​ $ b的



和广场再次进行:



注意绿色 ChartArea 如何保留对标签足够的空间和联想,以及如何为坐标轴自动调整功能仍然有效。但X轴的标签,现在不适合一行。还要注意如何使用 ChartArea.BackColor 实际是唯一的 InnerPlotArea 颜色<! / p>

请注意,您可能需要刷新变量 ipp0 来反映变化的百分比,使得修改的<$之后C $ C> ChartArea 布局就像放大或移动或删除传说或改变标签的大小和角度



当然,你可以修改函数中的任何其他比例通过维持,而不是保持绘图区的方..


Using the charting control from System.Windows.Forms.DataVisualization.Charting.Chart, I am making a scatter plot.

How can I constrain it so that the scale of the X axis is the same as the scale of the Y axis?

Simply setting the control itself to be square is insufficient, because it has internal margins for drawing and labeling the axes which are not equal.

I could pick a specific size and tweak it to be square, but it needs to be both square and resizable.

I've searched high and low in the documentation and in the property browser, but I can't find anything or think of any ways to do it in the resize event.

解决方案

This is a good question but unfortunately there is no simple solution like locking the two Axes or setting one value..

Let's start by looking at the relevant players:

  • The Chart control has an inner Size called ClientSize, which is the Chart.Size minus the borders. Both sizes are measured in pixels.

  • Inside there may be one or more ChartAreas. Each has a Position which is of type ElementPosition.

  • Inside each ChartArea the is an area which is used for the actual drawing of the points; it is called InnerPlotPosition.

The InnerPlotPosition property defines the rectangle within a chart area element that is used for plotting data; it excludes tick marks, axis labels, and so forth.

The coordinates used for this property (0,0 to 100,100) are related to the ChartArea object, and not to the entire Chart.

The InnerPlotPosition property can be used to align multiple chart areas. However, if one chart area has tick marks and axis labels and another one does not, their axis lines cannot be aligned.

  • Both ChartArea.Position and ChartArea.InnerPlotPosition contain not just the location but also the size of the areas; all values are in percent of the outer area, ie ChartArea.InnerPlotPosition is relative to the ChartArea.Position and ChartArea.Position is relative to the Chart.ClientSize. All percentages go from 0-100.

So the ChartArea includes Labels and Legends as well as Axes and TickMarks..

What we want is to find a way to make the InnerPlotArea square, i.e. have the same width and height in pixels. The percentages won't do!

Let's start with a few simple calculations; if these are the data we have..:

    // we'll work with one ChartArea only..:
    ChartArea ca = chart1.ChartAreas[0];
    ElementPosition cap = ca.Position;
    ElementPosition ipp = ca.InnerPlotPosition;

.. then these are the pixel sizes of the two areas:

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

Ideally we would like the InnerPlotArea to be square; since can't very well let the smaller side grow (or else the chart would overdraw,) we need to shrink the larger one. So the new pixel size of the InnerPlotArea is

int ippNewSide = Math.Min(IppSize.Width, IppSize.Height);

What next? Since the Chart.Size has just been set, we don't want to mess with it. Nor should we mess with the ChartArea: It still needs space to hold the Legend etc..

So we change the size of the InnerPlotArea..:

First create a class level variable to store the original values of the InnerPlotPosition :

   ElementPosition ipp0 = null;

We will need it to keep the original percentages, i.e. the margins in order to use them when calculating the new ones. When we adapt the chart the then current ones will already have been changed/distorted..

Then we create a function to make the InnerPlotArea square, which wraps it all up:

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

}

You would call the function after or during resizing.

private void chart1_Resize(object sender, EventArgs e)
{
    makeSquare(chart1);
}

Here the function is at work:

The original size:

Squeezed a little:

And made square again:

Note how the green ChartArea reserves enough space for the Labels and the Legend and how the automatic scaling for the axes still works.. But the X-Axis labels now don't fit in one row. Also note how the ChartArea.BackColor actually is the color of the InnerPlotArea only!

Note that you may have to refresh the variable ipp0 to reflect the changed percentages, after making modification to the ChartArea layout like enlarging or moving or removing Legends or changing the size or angle of Labels etc..

Of course you can modify the function to pass in any other ratio to keep instead of keeping the plot area a square..

这篇关于在约束WindowsForms数据可视化图表宽高比的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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