2016-03-31 136 views
4

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

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

我想要的是类似下面的图片:

enter image description here

我真正想要的是图表中的矩形区域,该区域被不同颜色的基础上,我从列表中得到点绘制点和形成图表中的彩色部分。

+1

问题是,您不知道自己的问题是什么。你有代码吗?为什么它不工作?请阅读[常见问题]和[问]。 – Marco

回答

7

您可以选择至少三种方式来创建包含组成热图的彩色矩形的图表。

这里是一个example 使用/滥用DataGridView。虽然我不会提出这个建议,但是这篇文章包含了一个有用的函数,可以创建漂亮的颜色列表以用于任务。

然后可以选择使用GDI +方法绘制图表,即Graphics.FillRectangle。这并不难,但一旦你想得到一个Chart控件提供的那些很好的附加功能,比如缩放,坐标轴,工具提示等,这些工作就会加起来。

所以让我们来看看选项三:使用DataVisualization命名空间中的Chart控件。

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

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

而且你已成功地投射你的数据在INT索引的二维数组到这点颜色列表:

int[,] coloredData = null; 

接下来,您必须选择适合您的一个ChartTypeSeries S1真的是我唯一能想到的,这将有助于:

S1.ChartType = SeriesChartType.Point; 

积分用Markers显示。我们希望DataPoints不是真正显示为标准MarkerTypes之一。

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

因此我们使用定制 marker将每个点的MarkerImage设置为合适大小和颜色的位图

这是一个循环,增加了DataPoints我们Series,并设置每个有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不是在路径的磁盘上,但必须驻留在Chart's Images集合中。这意味着需要是NamedImage类型。任何图像都可以使用,但必须添加一个唯一的名称字符串才能在NamedImagesCollection中识别它。我选择的名称是'NI1','NI2'..

显然,我们需要创建所有这些图像;这里有一个功能:

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大小的更改,我们再次设置:

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

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

enter image description hereenter image description here

由于你可以看到调整大小工程确定..

这是完整的代码建立我的例子:

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

的几个注意事项的限制:

  • 点总是坐在上面的任何网格线。如果您真的需要这些,您需要在Paint事件中的其中一个上绘制它们。

  • 所示的标签是指数据数组的整数索引。如果要显示原始数据,一种方法是将CustomLabels添加到轴上。请参阅here for an example

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

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

生成位图看起来很熟悉:

enter image description here

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

+0

感谢您的答案我抓住了它的一些逻辑。 – LittleThunder