绘制2D热图 [英] Plotting 2D heat map

查看:214
本文介绍了绘制2D热图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有我想要绘制热图的图表;我的唯一数据是湿度和温度,这表示在图表中的一个点。

I have a chart on which I want to plot a heat map; the only data I have is humidity and temperature, which represent a point in the chart.

我如何得到矩形式热图的C#中的图表?

How do I get the rectangular type of heat map on the chart in c#?

我要的是类似下面图片:

What I want is similar to picture below :

我真正想要的是这是基于我从点列表中获取,形成图中的多彩段的点不同的颜色绘制图表中的矩形区域。

What I really want is a rectangular region in the chart which is plotted in different color based on the point that i get from the list of points and form the colorful section in the chart.

推荐答案

您有至少三种方式来创建具有彩色矩形组成一个热图图表的选择。

You have a choice of at least three ways to create a chart with colored rectangles that make up a heat map.

下面一个例如使用
/虐待一个 DataGridView的。虽然我不建议这,岗位包含创建漂亮的颜色列表中你的任务是用一个有用的功能。

Here is one example that uses/abuses a DataGridView. While I would not suggest this, the post contains a useful function that creates nice color lists to use in your task.

再有就是绘制使用GDI图表的选项+方法,即 Graphics.FillRectangle 。这不难的,但一旦你要取得这些不错的演员图表控件提供,如缩放,斧头,提示等工作增加了..见下文!

Then there is the option to draw the chart using GDI+ methods, namely Graphics.FillRectangle. This not hard at all but once you want to get those nice extras a Chart control offers, like scaling, axes, tooltips etc the work adds up.. See below!

因此,让我们一起来看看方案三:使用从数据可视化命名空间中的控制

So let's have a look at option three: Using the Chart control from the DataVisualization namespace.

让我们先假设你已经创建了一个颜色列表:

Let's first assume that you have created a list of colors:

List<Color> colorList = new List<Color>();

和您所管理的项目数据到INT指数的二维数组指向到颜色清单:

And that you have managed to project your data onto a 2D array of int indices that point into the color list:

int[,] coloredData = null;



接下来,您必须选择一个图表类型的你的系列S1 真的是我唯一能想到的,这将有助于:

Next you have to pick a ChartType for your Series S1 There really is only one I can think of that will help:

S1.ChartType = SeriesChartType.Point;



点由显示标记。我们希望数据点没有真正显示为一个标准的 MarkerTypes

Points are displayed by Markers. We want the DataPoints not really displayed as one of the standard MarkerTypes.

广场将是确定的,如果我们想展示广场;但对于矩形将无法正常工作:即使我们让他们重叠,仍然会有在具有不同的大小,因为他们并不完全重叠。

Square would be ok, if we wanted to display squares; but for rectangles it will not work well: Even if we let them overlap there will still be points at the borders that have a different size because they don't fully overlap..

所以我们使用自定义通过设置 MarkerImage 到合适大小的位图标记,颜色。

So we use a custom marker by setting the MarkerImage of each point to a bitmap of a suitable size and color.

下面是一个循环,增加了数据点我们的系列,并设置每个有一个 MarkerImage

Here is a loop that adds the DataPoints to our Series and sets each to have a MarkerImage:

for (int x = 1; x < coloredData.GetLength(0); x++)
    for (int y = 1; y < coloredData.GetLength(1); y++)
    {
        int pt = S1.Points.AddXY(x, y);
        S1.Points[pt].MarkerImage = "NI" +  coloredData[x,y];

    }

这需要一些解释:要设置 MarkerImage 不是在磁盘上的路径,它必须驻留在图表的图片集合。这就意味着必须键入 NamedImage 的。所有图像都可以,但是它必须有增加的唯一名称字符串来标识它在 NamedImagesCollection 。我选择的名字是'NI1','NI2'..

This takes some explaining: To set a MarkerImage that is not at a path on the disk, it has to reside in the Chart's Images collection. This means is needs to be of type NamedImage. Any image will do, but it has to have a unique name string added to identify it in the NamedImagesCollection . I chose the names to be 'NI1', 'NI2'..

显然,我们需要创建所有这些图像;这里是一个函数来做到这一点:

Obviously we need to create all those images; here is a function to do that:

void createMarkers(Chart chart, int count)
{
    // rough calculation:
    int sw = chart.ClientSize.Width / coloredData.GetLength(0);
    int sh = chart.ClientSize.Height / coloredData.GetLength(1);

    // clean up previous images:
    foreach(NamedImage ni in chart1.Images) ni.Dispose();
    chart.Images.Clear();

    // now create count images:
    for (int i = 0; i < count; i++)
    {
        Bitmap bmp = new Bitmap(sw, sh);
        using (Graphics G = Graphics.FromImage(bmp))
            G.Clear(colorList[i]);
        chart.Images.Add(new NamedImage("NI" + i, bmp));
    }
}

我们希望所有的标志至少有大致正确的尺寸;所以whenevet大小的更改,我们再次设定:

We want all markers to have at least roughly the right size; so whenevet that size changes we set it again:

void setMarkerSize(Chart chart)
{
    int sx = chart1.ClientSize.Width / coloredData.GetLength(0);
    int sy = chart1.ClientSize.Height / coloredData.GetLength(1);
    chart1.Series["S1"].MarkerSize = (int)Math.Max(sx, sy);
}

这并不那么在意细节一样的 InnerPlotPosition ,即实际面积提请;所以这里是一些空间进行细化。

This doesn't care much about details like the InnerPlotPosition, i.e. the actual area to draw to; so here is some room for refinement..!

我们把这个当我们建立图表,还取决于调整

We call this when we set up the chart but also upon resizing:

private void chart1_Resize(object sender, EventArgs e)
{
    setMarkerSize(chart1);
    createMarkers(chart1, 100);
}



让我们用一些廉价的TESTDATA看看结果:

Let's have a look at the result using some cheap testdata:

href=\"http://i.stack.imgur.com/bHklF.png\" rel=\"nofollow\"> < IMG SRC =htt​​p://i.stack.imgur.com/bHklF.pngALT =在这里输入的形象描述>

正如你可以看到调整好的作品。

As you can see resizing works ok..

下面是完整的代码,建立了我的例子:

Here is the full code that set up my example:

private void button6_Click(object sender, EventArgs e)
{
    List<Color> stopColors = new List<Color>()
    { Color.Blue, Color.Cyan, Color.YellowGreen, Color.Orange, Color.Red };
    colorList = interpolateColors(stopColors, 100);

    coloredData = getCData(32, 24);
    // basic setup..
    chart1.ChartAreas.Clear();
    ChartArea CA = chart1.ChartAreas.Add("CA");
    chart1.Series.Clear();
    Series S1 = chart1.Series.Add("S1");
    chart1.Legends.Clear();
    // we choose a charttype that lets us add points freely:
    S1.ChartType = SeriesChartType.Point;

    Size sz = chart1.ClientSize;

    // we need to make the markers large enough to fill the area completely:
    setMarkerSize(chart1);
    createMarkers(chart1, 100);

    // now we fill in the datapoints
    for (int x = 1; x < coloredData.GetLength(0); x++)
        for (int y = 1; y < coloredData.GetLength(1); y++)
        {
            int pt = S1.Points.AddXY(x, y);
            //  S1.Points[pt].Color = coloredData[x, y];

            S1.Points[pt].MarkerImage = "NI" +  coloredData[x,y];
        }
}

这是限制的几个注意事项:

A few notes on limitations:


  • 该点将总在最上面坐的网格线。如果你真的需要那些你必须吸引他们之上在该油漆的事件之一。

所示的标签是指数据阵列的整数指数。如果你想显示的原始数据,一种方法是到 CustomLabels 添加到轴..见的这里的一个例子

The labels as shown are referring to the integers indices of the data array. If you want to show the original data, one way would be to add CustomLabels to the axes.. See here for an example!

这应该给你的,你可以用控制做什么的想法;在这里完成你的困惑是如何+使用相同的颜色和数据绘制的矩形在GDI:

This should give you an idea of what you can do with a Chart control; to complete your confusion here is how to draw those rectangles in GDI+ using the same colors and data:

Bitmap getChartImg(float[,] data, Size sz, Padding pad) 
{
    Bitmap bmp = new Bitmap(sz.Width , sz.Height);
    using (Graphics G = Graphics.FromImage(bmp))
    {
        float w = 1f * (sz.Width - pad.Left - pad.Right) / coloredData.GetLength(0);
        float h = 1f * (sz.Height - pad.Top - pad.Bottom) / coloredData.GetLength(1);
        for (int x = 0; x < coloredData.GetLength(0); x++)
            for (int y = 0; y < coloredData.GetLength(1); y++)
            {
                using (SolidBrush brush = new SolidBrush(colorList[coloredData[x,y]]))
                    G.FillRectangle(brush, pad.Left + x * w, y * h - pad.Bottom, w, h);
            }

    }
    return bmp;
}



生成位图看起来很熟悉:

The resulting Bitmap looks familiar:

这很简单;但所有的演员加入到由填充预留的空间将不会那么容易。

That was simple; but to add all the extras into the space reserved by the padding will not be so easy..

这篇关于绘制2D热图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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