I want to generate a heat map in windows form. I have a set of points as the input. How to go about doing this in the simplest way? Thanks.
This is a fix for Sam's code.
public Color HeatMapColor(decimal value, decimal min, decimal max)
{
decimal val = (value - min) / (max - min);
int r = Convert.ToByte(255 * val);
int g = Convert.ToByte(255 * (1 - val));
int b = 0;
return Color.FromArgb(255,r,g,b);
}
If you want red to green via yellow, you could also use HSL to get your heatmap. The numbers in that instance would be 0 - 60, where 0 = red and 60 = green (see figure 11 on this link).
To implement, you need to use System.Runtime.InteropServices and add the following:
[DllImport("shlwapi.dll")]
public static extern int ColorHLSToRGB(int H, int L, int S);
In the method, val is a long value and m_iMax is the largest number in the collection, you could change it as required:
if (val == 0)
return ColorTranslator.ToHtml(Color.FromArgb(255, 255, 255)); // white
else
{
// 0 = red, 60 = green
int col = 60 - (int)(60 * val / m_iMax);
return ColorTranslator.ToHtml(ColorTranslator.FromWin32(ColorHLSToRGB(col, 120, 240)));
}
The following is the result of the code above in a HTML table:
A solution going from red to yellow to green
static Color CreateHeatColor(int value, decimal max)
{
if (max == 0) max = 1M;
decimal pct = value/max;
Color color = new Color();
color.A = 255;
if (pct < 0.34M)
{
color.R = (byte) (128 + (127 * Math.Min(3 * pct, 1M)));
color.G = 0;
color.B = 0;
}
else if (pct < 0.67M)
{
color.R = 255;
color.G = (byte) (255 * Math.Min(3 * (pct - 0.333333M), 1M));
color.B = 0;
}
else
{
color.R = (byte)(255 * Math.Min(3 * (1M - pct), 1M));
color.G = 255;
color.B = 0;
}
return color;
}
Building on the answers already here, this method allows you to specify the Colors
you wish to use as the max and min colours.
private Color HeatMapColor(double value, double min, double max)
{
Color firstColour = Color.RoyalBlue;
Color secondColour = Color.LightSkyBlue;
// Example: Take the RGB
//135-206-250 // Light Sky Blue
// 65-105-225 // Royal Blue
// 70-101-25 // Delta
int rOffset = Math.Max(firstColour.R, secondColour.R);
int gOffset = Math.Max(firstColour.G, secondColour.G);
int bOffset = Math.Max(firstColour.B, secondColour.B);
int deltaR = Math.Abs(firstColour.R - secondColour.R);
int deltaG = Math.Abs(firstColour.G - secondColour.G);
int deltaB = Math.Abs(firstColour.B - secondColour.B);
double val = (value - min) / (max - min);
int r = rOffset - Convert.ToByte(deltaR * (1 - val));
int g = gOffset - Convert.ToByte(deltaG * (1 - val));
int b = bOffset - Convert.ToByte(deltaB * (1 - val));
return Color.FromArgb(255, r, g, b);
}
The results look like this for a test DataGrid
with some sample data.
Here is a simple method that will generate a color based on the relative position of a value between min and max. Values closer to min will be greener, while values closer to max will be redder.
To use this method, generate your list of values and calculate the min and max values. If you are building a grid you can handle the RowDataBound event or something similar and call the HeatMap method from there. Get a reference to the cell and set the background color to the color returned by the HeatMap method.
public Color HeatMap(decimal value, decimal min, decimal max)
{
decimal val = (value - min) / (max-min);
return new Color
{
A = 255,
R = Convert.ToByte(255 * val),
G = Convert.ToByte(255 * (1-val)),
B = 0
};
}
The C# version of "Curtis White"'s answer:
public Color HeatMap(decimal value, decimal min, decimal max)
{
decimal val = (value - min) / (max - min);
int A, B, R, G;
A = 255;
R = Convert.ToByte(255 * val);
B = Convert.ToByte(255 * (1 - val));
G = 0;
return Color.FromArgb(A, R, G, B);
}