【问题标题】:Scatter Graph In C# With PictureBoxC# 中的散点图与 PictureBox
【发布时间】:2017-05-17 21:24:17
【问题描述】:

有一个大小为 n 的点的输入,如下所示:

S = {x1,y1,x2,y2,...,xn,yn}

我想在图片框中显示 S 序列的散点图。因此,为了将它们转换为图片框尺寸,我对它们进行了归一化,并将它们乘以图片框的宽度和高度,同时考虑图片框的左侧和顶部:

waveData= wave.GetWaveData();
normalizedData = GetSignedNormalized();
n = normalizedData.Count;
picW = pictureBox1.Width;
picH = pictureBox1.Height;
picL = pictureBox1.Left;
picT = pictureBox1.Top;
normalizedInPictureBox = new List<float>();

for (int i=0;i< n; i +=2)
{
    float px = normalizedData[i];
    float py = normalizedData[i+1];
    px = px * (picW - picL);
    py = py * (picH - picT) ;                
    normalizedInPictureBox.Add(px);
    normalizedInPictureBox.Add(py);
}

Normalize 方法也是:

public List<float> GetSignedNormalized()
{
    List<float> data = new List<float>();
    short max = waveData.Max();
    int m = waveData.Count;
    for(int i=0;i< m; i++)
    {
        data.Add((float)waveData[i] / (float)max);
    }
    return data;
}

现在我在想 normalizedInPictureBox List 包含图片框范围内的顶点,这是在图片框上绘制它们的代码:

在图片框的绘制方法中:

Graphics gr = e.Graphics;
gr.Clear(Color.Black);
for(int i=0;i< n; i +=2)
{
    float x = normalizedInPictureBox[i] ;
    float y = normalizedInPictureBox[i+1];

    gr.FillEllipse(Brushes.Green, new RectangleF(x, y, 2.25f, 2.25f));
}

但是结果如下图:

我不知道这里出了什么问题,但我认为图形应该是水平的而不是对角的,期望的结果是这样的:

我知道我可以在此之后将其转换为图片框的中心。但是如何将我自己的结果更改为渴望的结果?

提前致谢。

【问题讨论】:

  • 您确定normalizedData中的数据正确吗?
  • 您是否仔细检查了原始数据?我建议将它们(或多或少)未缩放为位图,然后您可以在 PBox 中使用 size mode = zoom .. 显示。你有多少个数据点?这两个图像的波范围是否相同?
  • @Jens 是的,我更新了标准化数据的方法,我在 Excel 中测试过,结果和原来的一样
  • @TaW ,我用 Excel 图表工具绘制了它们,一切正常。数据长度也不重要。
  • short max = waveData.Max(); 为什么 short 只能转换为 float? - 波形数据短吗?您没有向我们展示.. - 不告诉我们尺寸会使评估图像变得更加困难。

标签: c# winforms picturebox


【解决方案1】:

我真的不知道为什么您的代码在没有查看实际数据并使用它的情况下无法正常工作,但是之前已经完成了图表绘制,我建议您完全了解并明确定义您的轴范围并进行适当的插值。从那里开始变得更加清晰。

这是我想出来的

static Bitmap DrawChart(float[] Values, int Width, int Height)
{
    var n = Values.Count();
    if (n % 2 == 1) throw new Exception("Invalid data");

    //Split the data into lists for easy access
    var x = new List<float>();
    var y = new List<float>();
    for (int i = 0; i < n - 1; i += 2)
    {
        x.Add(Values[i]);
        y.Add(Values[i + 1]);
    }

    //Chart axis limits, change here to get custom ranges like -1,+1
    var minx = x.Min();
    var miny = y.Min();
    var maxx = x.Max();
    var maxy = y.Max();

    var dxOld = maxx - minx;
    var dyOld = maxy - miny;

    //Rescale the y-Range to add a border at the top and bottom
    miny -= dyOld * 0.2f;
    maxy += dyOld * 0.2f;

    var dxNew = (float)Width;
    var dyNew = (float)Height;

    //Draw the data
    Bitmap res = new Bitmap(Width, Height);
    using (var g = Graphics.FromImage(res))
    {
        g.Clear(Color.Black);
        for (int i = 0; i < x.Count; i++)
        {
            //Calculate the coordinates
            var px = Interpolate(x[i], minx, maxx, 0, dxNew);
            var py = Interpolate(y[i], miny, maxy, 0, dyNew);
            //Draw, put the ellipse center around the point
            g.FillEllipse(Brushes.ForestGreen, px - 1.0f, py - 1.0f, 2.0f, 2.0f);
        }
    }
    return res;
}

static float Interpolate(float Value, float OldMin, float OldMax, float NewMin, float NewMax)
{
    //Linear interpolation
    return ((NewMax - NewMin) / (OldMax - OldMin)) * (Value - OldMin) + NewMin;
}

它应该是相对不言自明的。您可以考虑绘制线条而不是单点,这取决于您想要达到的外观和感觉。根据自己的喜好绘制其他图表元素。

重要提示: y 轴在上面的代码中实际上是反转的,所以正值向下,负值向上,它像屏幕坐标一样缩放。你会想办法解决这个问题的:-)

带有 5000 个随机 y 点的示例(x 已编入索引):

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-17
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    相关资源
    最近更新 更多