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

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

问题描述

我有一个图表,我想绘制热图;我唯一的数据是湿度和温度,它们代表图表中的一个点。



如何在c#中的图表上获取矩形类型的热图?



我想要的是类似于下图:





我真的want是图表中的一个矩形区域,根据我从点列表中获得的点,以不同的颜色绘制,并在图表中形成彩色部分。

解决方案

您可以选择至少三种方法来创建带有彩色矩形的图表,构成热图。



一个





下面是设置示例的完整代码:

  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);
//基本设置..
chart1.ChartAreas.Clear();
ChartArea CA = chart1.ChartAreas.Add(CA);
chart1.Series.Clear();
系列S1 = chart1.Series.Add(S1);
chart1Legends.Clear();
//我们选择一个图表类型,让我们自由添加点:$ b​​ $ b S1.ChartType = SeriesChartType.Point;

大小sz = chart1.ClientSize;

//我们需要使标记足够大以完全填充该区域:
setMarkerSize(chart1);
createMarkers(chart1,100);

//现在我们填充数据点
for(int x = 1; x< coloredData.GetLength(0); x ++)
for(int y = 1; y< colorData.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];
}
}

有关限制的几个注意事项:




  • 点将始终位于任何网格线的顶部。如果你真的需要那些,你将不得不把它们在 Paint 事件之一。


  • p>所示的标签是指数据数组的整数索引。如果要显示原始数据,一种方法是向轴添加 CustomLabels 。请参阅



    这很简单;但是添加所有的额外到由填充保留的空间不会那么容易..


    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.

    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.

    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.

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

    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;
    

    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;
    

    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..

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

    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];
    
        }
    

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

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

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

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

    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:

    • The point will always sit on top on any gridlines. If you really needs those you will have to draw them on top in one of the the Paint events.

    • 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!

    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天全站免登陆