我有一张图表,我想要绘制热图;我所拥有的唯一数据是湿度和温度,它代表图表中的一个点。
如何在c#中获取图表上的矩形热图?
我想要的是类似于下图:
我真正想要的是图表中的一个矩形区域,它根据我从点列表中得到的点以不同的颜色绘制,并在图表中形成彩色部分。
答案 0 :(得分:9)
您可以选择至少三种方法来创建带有构成热图的彩色矩形的图表。
这是一个example
使用/滥用DataGridView
的人。虽然我不建议这样做,但帖子包含一个有用的功能,可以在您的任务中创建漂亮的颜色列表。
然后可以选择使用GDI +方法绘制图表,即Graphics.FillRectangle
。这一点并不难,但是一旦你想获得Chart控件提供的那些漂亮的附加功能,比如缩放,轴,工具提示等,工作就会增加..见下文!
让我们看一下选项三:使用Chart
命名空间中的DataVisualization
控件。
我们首先假设您已经创建了一个颜色列表:
List<Color> colorList = new List<Color>();
并且您已设法将数据投影到指向颜色列表的2D索引数组中:
int[,] coloredData = null;
接下来,您必须为ChartType
选择一个Series S1
。我真的只能想到一个会有所帮助:
S1.ChartType = SeriesChartType.Point;
点数由Markers
显示。我们希望DataPoints
不会真正显示为标准MarkerTypes之一。
Square
就可以了;但是对于矩形,它将无法正常工作:即使我们让它们重叠,在边界处仍然会有不同大小的点,因为它们没有完全重叠。
因此,我们使用自定义标记,方法是将每个点的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
类型。任何图像都可以,但必须添加唯一的名称字符串才能在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));
}
}
中标识它。我选择的名字是'NI1','NI2'..
显然我们需要创建所有这些图像;这是一个功能:
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];
}
}
让我们看一下使用一些便宜的testdata的结果:
你可以看到调整大小正常..
以下是设置我的示例的完整代码:
Paint
关于限制的一些注释:
该点始终位于任何网格线的顶部。如果您确实需要那些,则必须在其中一个CustomLabels
事件中将它们绘制在顶部。
如图所示的标签是指数据数组的整数索引。如果您想显示原始数据,一种方法是将Chart
添加到轴上。请参阅here for an example!
这可以让您了解使用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;
}
控件可以做些什么。在这里完成您的混淆是如何使用相同的颜色和数据在GDI +中绘制这些矩形:
<head>
{{ $page_content['head'] }}
</head>
生成的Bitmap看起来很熟悉:
这很简单;但要将所有额外内容添加到填充所保留的空间中将不会那么容易..