C# 绘制二维热图

C# 绘制二维热图,c#,charts,heatmap,C#,Charts,Heatmap,我有一张图表,我想在上面画一张热图;我仅有的数据是湿度和温度,它们代表了图表中的一个点 如何在c#中获得图表上的矩形热图 我想要的与下图类似: 我真正想要的是图表中的一个矩形区域,该区域根据我从点列表中获得的点以不同的颜色绘制,并形成图表中的彩色部分。您可以选择至少三种方法来创建具有彩色矩形的图表,这些矩形构成热图 这里有一个 使用/滥用DataGridView。虽然我不建议这样做,但这篇文章包含了一个有用的函数,可以创建漂亮的颜色列表,以便在任务中使用 然后可以选择使用GDI+方法绘制图表,

我有一张图表,我想在上面画一张热图;我仅有的数据是湿度和温度,它们代表了图表中的一个点

如何在c#中获得图表上的矩形热图

我想要的与下图类似:


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

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

这里有一个 使用/滥用
DataGridView
。虽然我不建议这样做,但这篇文章包含了一个有用的函数,可以创建漂亮的颜色列表,以便在任务中使用

然后可以选择使用GDI+方法绘制图表,即
Graphics.FillRectangle
。这一点都不难,但一旦你想得到图表控件提供的那些额外的功能,比如缩放、轴、工具提示等,你的工作就会累加起来。。看下面

让我们看一下选项三:使用
DataVisualization
命名空间中的
Chart
控件

首先假设您已经创建了一个颜色列表:

List<Color> colorList = new List<Color>();
接下来,您必须为您的
系列S1选择一个
图表类型
,我能想到的只有一个:

S1.ChartType = SeriesChartType.Point;
点通过
标记显示。我们希望
数据点
不会真正显示为标准之一

如果我们想显示正方形,
Square
就可以了;但对于矩形来说,它不会很好地工作:即使我们让它们重叠,边界上仍然会有大小不同的点,因为它们没有完全重叠

因此,我们通过将每个点的
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];

    }
我们希望所有的标记至少有大致正确的大小;因此,每当大小发生变化时,我们都会再次设置:

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
等细节无关,即要绘制的实际区域;所以这里有一些改进的空间

我们在设置图表时,也在调整大小时称之为:

private void chart1_Resize(object sender, EventArgs e)
{
    setMarkerSize(chart1);
    createMarkers(chart1, 100);
}
让我们使用一些廉价的测试数据来看看结果:

正如您所见,调整大小工作正常

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

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];
        }
}
生成的位图看起来很熟悉:


这很简单;但是,将所有额外的内容添加到填充所保留的空间并不容易。

问题是,您不知道自己的问题是什么。你有密码吗?为什么不起作用?请阅读答案,谢谢你的回答,我从中找到了一些逻辑。
private void chart1_Resize(object sender, EventArgs e)
{
    setMarkerSize(chart1);
    createMarkers(chart1, 100);
}
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];
        }
}
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;
}