限制 Windows 窗体数据可视化图表中的纵横比

2024-03-23

使用图表控件System.Windows.Forms.DataVisualization.Charting.Chart,我正在制作散点图。

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

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

我可以选择一个特定的尺寸并将其调整为方形,但它需要既是方形的又可以调整大小。

我在文档和属性浏览器中进行了多次搜索,但我找不到任何东西,也找不到任何方法可以在调整大小事件中执行此操作。


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

我们先来看看相关的玩家:

  • The Chart控制有一个内在的Size called ClientSize, 哪一个是Chart.Size减去边框。两种尺寸均以像素为单位进行测量。

  • 里面可能有一个或多个ChartAreas https://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.chartarea%28v=vs.110%29.aspx。每个都有一个Position这是类型ElementPosition https://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.elementposition%28v=vs.110%29.aspx.

  • 每个里面ChartArea是用于实际绘制点的区域;它被称为InnerPlotPosition https://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.chartarea.innerplotposition(v=vs.110).aspx.

InnerPlotPosition 属性定义图表内的矩形 用于绘制数据的区域元素;它不包括刻度线, 轴标签等。

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

InnerPlotPosition 属性可用于对齐多个图表 地区。但是,如果一个图表区域有刻度线和轴标签,并且 另一个则不然,它们的轴线无法对齐。

  • Both ChartArea.Position and ChartArea.InnerPlotPosition不仅仅包含location but also the size地区;所有值都在percent外部区域,即ChartArea.InnerPlotPosition是相对于ChartArea.Position and ChartArea.Position是相对于Chart.ClientSize。所有百分比均来自0-100.

So the ChartArea包括Labels and LegendsAxes and TickMarks..

我们想要的是找到一种方法来使InnerPlotArea正方形,即具有相同的宽度和高度以像素为单位。百分比不行!

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

    // 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 is

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

接下来是什么?自从Chart.Size刚刚确定,我们不想搞乱它。我们也不应该搞乱ChartArea: 还需要空间来容纳Legend etc..

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

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

   ElementPosition ipp0 = null;

我们需要它保留原始百分比,即边距,以便在计算新百分比时使用它们。当我们调整图表时,当前的图表将已经被更改/扭曲。

然后我们创建一个函数来使InnerPlotArea正方形,将其全部包裹起来:

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

}

您可以在调整大小之后或期间调用该函数。

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

这里函数正在工作:

The original size: original

Squeezed a little: scaled

And made square again: square

注意绿色如何ChartArea预留足够的空间LabelsLegend以及轴的自动缩放如何仍然有效。但是 X 轴标签现在不适合放在一行中。还要注意如何ChartArea.BackColor actually是的颜色InnerPlotArea only!

请注意,您可能需要刷新变量ipp0修改后反映变化的百分比ChartArea布局,如放大、移动或删除Legends或改变尺寸或角度Labels etc..

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

限制 Windows 窗体数据可视化图表中的纵横比 的相关文章

  • 金特 + XNA (C#)

    是否可以使用jint http jint codeplex com操作使用 XNA C 创建的 3D 环境 并向该环境添加功能 再次使用 jint 作为 Jint 的贡献者 我会推荐你Jint http jint codeplex com
  • 我应该把 try/catch 和“using”语句放在哪里? [复制]

    这个问题在这里已经有答案了 可能的重复 try catch using 正确的语法 https stackoverflow com questions 4590490 try catch using right syntax 我想try c
  • 我如何知道 C 程序的可执行文件是在前台还是后台运行?

    在我的 C 程序中 我想知道我的可执行文件是否像这样在前台运行 a out 或者像这样 a out 如果你是前台工作 getpgrp tcgetpgrp STDOUT FILENO or STDIN FILENO or STDERR FIL
  • 进程退出后 POSIX 名称信号量不会释放

    我正在尝试使用 POSIX 命名信号量进行跨进程同步 我注意到进程死亡或退出后 信号量仍然被系统打开 在进程 打开它 死亡或退出后是否有办法使其关闭 释放 早期的讨论在这里 当将信号量递减至零的进程崩溃时 如何恢复信号量 https sta
  • MFC CList 支持复制分配吗?

    我在 MSVC 中查找了 CList 定义afxtempl h http www cppdoc com example mfc classdoc MFC AFXTEMPL H html并记录在MSDN http msdn microsoft
  • 如果 JSON.NET 中的值为 null 或空格,则防止序列化

    我有一个对象需要以这样的方式序列化 即 null 和 空白 空或只是空格 值都不会序列化 我不控制对象本身 因此无法设置属性 但我知道所有属性都是字符串 环境NullValueHandling显然 忽略 只能让我找到解决方案的一部分 它 似
  • 如何以编程方式播放 16 位 pcm 数组 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有一个包含 16 位 pcm 值的短 数组 我希望能够在不添加任何标题 也不将任何文件保存到内存的情况下播放它 我知道我可能需要一个提供
  • while循环中的变量初始化

    我有一个可以分块读取文件的函数 public static DataObject ReadNextFile 数据对象看起来像这样 public DataObject public string Category get set And ot
  • C# 编译器数字文字

    有谁知道 C 编译器数字文字修饰符的完整列表 默认情况下 声明 0 使其成为 Int32 声明 0 0 使其成为 Double 我可以在末尾使用文字修饰符 f 来确保某些内容被视为 Single 例如像这样 var x 0 x is Int
  • 如何在win32中使用GetSaveFileName保存文件?

    我编写此代码是为了获取 fileName 来保存我的文件 include stdafx h include
  • 通过 C# Mailkit / Mimekit 发送电子邮件,但出现服务器证书错误

    Visual Studio 2015 中的 0 代码 1 我正在使用 Mailkit 最新版本 1 18 1 1 从我自己的电子邮件服务器发送电子邮件 2 电子邮件服务器具有不受信任的自签名证书 3 我在代码中添加了以下两行 以忽略服务器证
  • 用于连接 DataTable 上的动态列的动态 LINQ

    我目前遇到的情况不确定如何继续 我有两个从数据库填充的数据表 我还有一个可用的列名称列表 可用于将这两个数据表连接在一起 我希望编写一组 LINQ 查询 这些查询将 显示两个数据表中的行 内部联接 用于从一个数据表更新另一个数据表 显示一个
  • Resharper:IEnumerable 的可能多重枚举

    我正在使用新的 Resharper 版本 6 在我的代码中的几个地方 它给一些文本加了下划线 并警告我可能存在IEnumerable 可能的多重枚举 我理解这意味着什么 并在适当的情况下采纳了建议 但在某些情况下 我不确定这实际上是一个大问
  • 如何使用 CSI.exe 脚本参数

    当你运行csi exe 安装了 Visual Studio 2015 update 2 您将得到以下语法 Microsoft R Visual C Interactive Compiler version 1 2 0 51106 Copyr
  • doxygen c++:记录由“using”声明公开的私有继承成员

    作为一个例子 我有以下课程 class A public void methodOne class B private A public Brief description using A methodOne 我还没有找到强制 doxyge
  • EnumDisplayDevices 与 WMI Win32_DesktopMonitor,如何检测活动监视器?

    对于我当前的 C 项目 我需要为在大量计算机上连接并处于活动状态的每个监视器检测一个唯一的字符串 研究指出了两种选择 使用 WMI 并查询 Win32 DesktopMonitor 以获取所有活动监视器 使用 PNPDeviceID 来唯一
  • 为什么 f(i = -1, i = -1) 是未定义的行为?

    我正在读关于违反评估顺序 http en cppreference com w cpp language eval order 他们举了一个令我困惑的例子 1 如果标量对象上的副作用相对于同一标量对象上的另一个副作用是无序的 则行为未定义
  • 从 NumPy 数组到 Mat 的 C++ 转换 (OpenCV)

    我正在围绕 ArUco 增强现实库 基于 OpenCV 编写一个薄包装器 我试图构建的界面非常简单 Python 将图像传递给 C 代码 C 代码检测标记并将其位置和其他信息作为字典元组返回给 Python 但是 我不知道如何在 Pytho
  • C 语言中的 Alpha 混合 2 RGBA 颜色[重复]

    这个问题在这里已经有答案了 可能的重复 如何快速进行阿尔法混合 https stackoverflow com questions 1102692 how to do alpha blend fast 对 2 个 RGBA 整数 颜色进行
  • “必须声明标量变量”错误[重复]

    这个问题在这里已经有答案了 必须声明标量变量 Id SqlConnection con new SqlConnection connectionstring con Open SqlCommand cmd new SqlCommand cm

随机推荐