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.
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
};
}
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.
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);
}
Divide the surface up into a grid of cells, and count the points inside each cell.
Given the count of points, calculate a color for each cell
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;
}
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);
}
This worked well for me.
public Color HeatMap(float value, float max)
{
int r, g, b;
float val = value / max; // Assuming that range starts from 0
if (val > 1)
val = 1;
if (val > 0.5f)
{
val = (val - 0.5f) * 2;
r = Convert.ToByte(255 * val);
g = Convert.ToByte(255 * (1 - val));
b = 0;
}
else
{
val = val * 2;
r = 0;
g = Convert.ToByte(255 * val);
b = Convert.ToByte(255 * (1 - val));
}
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:
Related
Can you help me with my color matching
I tried to search some codes it didn't work well
My logic is like below, with adjustable tolerance like 5% or 10% closest to color:
Red and Light Red = True
Red and Dark Red = True
Red and black = False
here's my code but it didn't work very well
public static bool MatchArgb(int Argb1, int Argb2, int tolerance)
{
Color c1 = Color.FromArgb(Argb1);
Color c2 = Color.FromArgb(Argb2);
return Math.Abs(c1.R - c2.R) <= tolerance ^
Math.Abs(c1.G - c2.G) <= tolerance ^
Math.Abs(c1.B - c2.B) <= tolerance;
}
public static bool MatchColor(Color c1, Color c2, int tolerance)
{
return Math.Abs(c1.R - c2.R) <= tolerance ^
Math.Abs(c1.G - c2.G) <= tolerance ^
Math.Abs(c1.B - c2.B) <= tolerance;
}
Maybe it is a good idea to check how this is done in Paint.NET. I found a clone of it and the corresponding source code here: Pinta/Flood Tool
private static bool CheckColor (ColorBgra a, ColorBgra b, int tolerance)
{
int sum = 0;
int diff;
diff = a.R - b.R;
sum += (1 + diff * diff) * a.A / 256;
diff = a.G - b.G;
sum += (1 + diff * diff) * a.A / 256;
diff = a.B - b.B;
sum += (1 + diff * diff) * a.A / 256;
diff = a.A - b.A;
sum += diff * diff;
return (sum <= tolerance * tolerance * 4);
}
Hello guys i am trying plotting the mandlebrot fractal but the result is very far from it, can you help me to find the why?
Here is the code:
void Button1Click(object sender, EventArgs e)
{
Graphics g = pbx.CreateGraphics();
Pen p = new Pen(Color.Black);
double xmin = -2.0;
double ymin = -1.2;
double xmax = 0;
double ymax = 0;
double x = xmin, y = ymin;
int MAX = 1000;
double stepY = Math.Abs(ymin - ymax)/(pbx.Height);
double stepX = Math.Abs(xmin - xmax)/(pbx.Width);
for(int i = 0; i < pbx.Width; i++)
{
y = ymin;
for(int j = 0; j < pbx.Height; j++)
{
double rez = x;
double imz = y;
int iter = 0;
while(rez * rez + imz * imz <= 4 && iter < MAX)
{
rez = rez * rez - imz * imz + x;
imz = 2 * rez * imz + y;
iter++;
}
if(iter == MAX)
{
p.Color = Color.Black;
g.DrawRectangle(p, i, j, 1, 1);
}
else
{
p.Color = Color.White;
g.DrawRectangle(p, i, j, 1, 1);
}
y += stepY;
}
x += stepX;
}
}
please help me my mind is getting crushed thinking how to get the beautiful mandlebrot set...
and sorry if i committed some mistakes but English is not my speaked language!
You have some irregularities elsewhere. The range you're plotting isn't the entire set, and I would calculate x and y directly for each pixel, rather than using increments (so as to avoid rounding error accumulating).
But it looks to me as though your main error is in the iterative computation. You are modifying the rez variable before you use it in the computation of the new imz value. Your loop should look more like this:
while(rez * rez + imz * imz <= 4 && iter < MAX)
{
double rT = rez * rez - imz * imz + x;
imz = 2 * rez * imz + y;
rez = rT;
iter++;
}
Additionally to Peters answer, you should use a color palette instead of drawing just black and white pixels.
Create a array of colors, like this: (very simple example)
Color[] colors = new Colors[768];
for (int i=0; i<256; i++) {
colors[i ]=Color.FromArgb( i, 0, 0);
colors[i+256]=Color.FromArgb(255-i, i, 0);
colors[i+512]=Color.FromArgb(0 , 255-i, i);
}
Then use the iter value to pull a color and draw it:
int index=(int)((double)iter/MAX*767);
p.Color c = colors[index];
g.DrawRectangle(p, i, j, 1, 1);
Replace the entire if (iter == MAX) ... else ... statement with this last step.
I want to implement a function in java that calculate brightness of a color exactly as same as C# getbrightness() function. So I need to know the exact algorithm that used in C#. There is some algorithms here but all of them have about 5% error.
Use official source:
http://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Color.cs#23adaaa39209cc1f
public float GetBrightness()
{
float r = (float)R / 255.0f;
float g = (float)G / 255.0f;
float b = (float)B / 255.0f;
float max, min;
max = r; min = r;
if (g > max) max = g;
if (b > max) max = b;
if (g < min) min = g;
if (b < min) min = b;
return (max + min) / 2;
}
currently working on a application and trying to find colors(complementary, split-Complementary, analogous, triad, tetratic, square, etc...) from a provided base colors.
What i am doing right now:
Convert RGB Color to HSV
Adjust the H value to get a color around the 360 degrees wheel(S and V values are untouched)
Convert HSV back to RGB
Here is an example for Triad(hsv object represent the base color):
colors.Add(new HSVData() { h = hsv.h + 120, s = hsv.s, v = hsv.v });
colors.Add(new HSVData() { h = hsv.h - 120, s = hsv.s, v = hsv.v });
And for Square:
colors.Add(new HSVData() { h = hsv.h + 90, s = hsv.s, v = hsv.v });
colors.Add(new HSVData() { h = hsv.h + 180, s = hsv.s, v = hsv.v });
colors.Add(new HSVData() { h = hsv.h + 270, s = hsv.s, v = hsv.v });
RGB to HSV:
public static HSVData RGBtoHSV(RGBResult RGB)
{
double min;
double max;
double delta;
double r = (double)RGB.r / 255;
double g = (double)RGB.g / 255;
double b = (double)RGB.b / 255;
double h;
double s;
double v;
min = Math.Min(Math.Min(r, g), b);
max = Math.Max(Math.Max(r, g), b);
v = max;
delta = max - min;
if (max == 0 || delta == 0)
{
s = 0;
h = 0;
}
else
{
s = delta / max;
if (r == max)
{
// Between Yellow and Magenta
h = (g - b) / delta;
}
else if (g == max)
{
// Between Cyan and Yellow
h = 2 + (b - r) / delta;
}
else
{
// Between Magenta and Cyan
h = 4 + (r - g) / delta;
}
}
h *= 60;
if (h < 0)
{
h += 360;
}
return new HSVData()
{
h = (int)(h / 360 * 255),
s = (int)(s * 255),
v = (int)(v * 255)
};
}
HSV to RGB:
public static Color ConvertHsvToRgb(float h, float s, float v)
{
byte MAX = 255;
h = h / 360;
if (s > 0)
{
if (h >= 1)
h = 0;
h = 6 * h;
int hueFloor = (int)Math.Floor(h);
byte a = (byte)Math.Round(MAX * v * (1.0 - s));
byte b = (byte)Math.Round(MAX * v * (1.0 - (s * (h - hueFloor))));
byte c = (byte)Math.Round(MAX * v * (1.0 - (s * (1.0 - (h - hueFloor)))));
byte d = (byte)Math.Round(MAX * v);
switch (hueFloor)
{
case 0: return Color.FromArgb(MAX, d, c, a);
case 1: return Color.FromArgb(MAX, b, d, a);
case 2: return Color.FromArgb(MAX, a, d, c);
case 3: return Color.FromArgb(MAX, a, b, d);
case 4: return Color.FromArgb(MAX, c, a, d);
case 5: return Color.FromArgb(MAX, d, a, b);
default: return Color.FromArgb(0, 0, 0, 0);
}
}
else
{
byte d = (byte)(v * MAX);
return Color.FromArgb(255, d, d, d);
}
}
The colors I am getting are wrong according to many online colors tools! Should I be using HSL intead of HSV? What am I doing wrong?
Online Tools compared with:
http://colorschemedesigner.com/
http://www.colorsontheweb.com/colorwizard.asp
Thanks in advance!
What range of values are you expecting to get in the ConvertHsvToRgb method? It looks to me like it is:
0 <= h <= 360
0 <= s <= 1.0
0 <= v <= 1.0
You don't show how you are calling this method, but if you aren't passing values in these ranges, you won't get the correct conversion. You probably want to include a way to normalize the hue to 0 - 360 if you plan to subtract hues, like you do in the triad.
I think your conversions are correct except you should not be converting your h,s,v values to integers; keep them as doubles, in the ranges shown above.
public static HSVData RGBtoHSV(Color RGB)
{
double r = (double)RGB.R / 255;
double g = (double)RGB.G / 255;
double b = (double)RGB.B / 255;
double h;
double s;
double v;
double min = Math.Min(Math.Min(r, g), b);
double max = Math.Max(Math.Max(r, g), b);
v = max;
double delta = max - min;
if (max == 0 || delta == 0)
{
s = 0;
h = 0;
}
else
{
s = delta / max;
if (r == max)
{
// Between Yellow and Magenta
h = (g - b) / delta;
}
else if (g == max)
{
// Between Cyan and Yellow
h = 2 + (b - r) / delta;
}
else
{
// Between Magenta and Cyan
h = 4 + (r - g) / delta;
}
}
h *= 60;
if (h < 0)
{
h += 360;
}
return new HSVData()
{
h = h,
s = s,
v = v
};
}
Now you can pass these h,s,v valuew directly into the ConvertHsvToRgb method. I have changed the arguments to double, validating the saturation and value inputs, and normalized the hue.
public static Color ConvertHsvToRgb(double h, double s, double v)
{
Debug.Assert(0.0 <= s && s <= 1.0);
Debug.Assert(0.0 <= v && v <= 1.0);
// normalize the hue:
while (h < 0)
h += 360;
while (h > 360)
h -= 360;
h = h / 360;
byte MAX = 255;
if (s > 0)
{
if (h >= 1)
h = 0;
h = 6 * h;
int hueFloor = (int)Math.Floor(h);
byte a = (byte)Math.Round(MAX * v * (1.0 - s));
byte b = (byte)Math.Round(MAX * v * (1.0 - (s * (h - hueFloor))));
byte c = (byte)Math.Round(MAX * v * (1.0 - (s * (1.0 - (h - hueFloor)))));
byte d = (byte)Math.Round(MAX * v);
switch (hueFloor)
{
case 0: return Color.FromArgb(MAX, d, c, a);
case 1: return Color.FromArgb(MAX, b, d, a);
case 2: return Color.FromArgb(MAX, a, d, c);
case 3: return Color.FromArgb(MAX, a, b, d);
case 4: return Color.FromArgb(MAX, c, a, d);
case 5: return Color.FromArgb(MAX, d, a, b);
default: return Color.FromArgb(0, 0, 0, 0);
}
}
else
{
byte d = (byte)(v * MAX);
return Color.FromArgb(255, d, d, d);
}
}
Based on my tests, these two methods will now give "round-trip" conversions for any color from RGB to HSV and back.
For the "triad" you are are adjusting +/- 120 degrees from the original color. So for example, if you start with Red as your base color, the +/- 120 degree colors are Green and Blue. These conversions appear to work correctly:
HSVData hsv = HSVData.RGBtoHSV(Color.FromArgb(255, 0, 0));
HSVData hsv2 = new HSVData() { h = hsv.h + 120, s = hsv.s, v = hsv.v };
HSVData hsv3 = new HSVData() { h = hsv.h - 120 , s = hsv.s, v = hsv.v };
Color red = HSVData.ConvertHsvToRgb(hsv.h, hsv.s, hsv.v);
Color green = HSVData.ConvertHsvToRgb(hsv2.h, hsv2.s, hsv2.v);
Color blue = HSVData.ConvertHsvToRgb(hsv3.h, hsv3.s, hsv3.v);
HSVData hsv4 = HSVData.RGBtoHSV(Color.YellowGreen);
Color yellowGreen = HSVData.ConvertHsvToRgb(hsv4.h, hsv4.s, hsv4.v);
My question here is similar to the question here, except that I am working with C#.
I have two colors, and I have a predefine steps. How to retrieve a list of Colors that are the gradients between the two?
This is an approach that I tried, which didn't work:
int argbMax = Color.Chocolate.ToArgb();
int argbMin = Color.Blue.ToArgb();
var colorList = new List<Color>();
for(int i=0; i<size; i++)
{
var colorAverage= argbMin + (int)((argbMax - argbMin) *i/size);
colorList.Add(Color.FromArgb(colorAverage));
}
If you try the above code, you will find that a gradual increase in argb doesn't correspond to a visual gradual increase in the color.
Any idea on this?
You will have to extract the R, G, B components and perform the same linear interpolation on each of them individually, then recombine.
int rMax = Color.Chocolate.R;
int rMin = Color.Blue.R;
// ... and for B, G
var colorList = new List<Color>();
for(int i=0; i<size; i++)
{
var rAverage = rMin + (int)((rMax - rMin) * i / size);
var gAverage = gMin + (int)((gMax - gMin) * i / size);
var bAverage = bMin + (int)((bMax - bMin) * i / size);
colorList.Add(Color.FromArgb(rAverage, gAverage, bAverage));
}
Oliver's answer was very close... but in my case some of my stepper numbers needed to be negative. When converting the stepper values into a Color struct my values were going from negative to the higher values e.g. -1 becomes something like 254. I setup my step values individually to fix this.
public static IEnumerable<Color> GetGradients(Color start, Color end, int steps)
{
int stepA = ((end.A - start.A) / (steps - 1));
int stepR = ((end.R - start.R) / (steps - 1));
int stepG = ((end.G - start.G) / (steps - 1));
int stepB = ((end.B - start.B) / (steps - 1));
for (int i = 0; i < steps; i++)
{
yield return Color.FromArgb(start.A + (stepA * i),
start.R + (stepR * i),
start.G + (stepG * i),
start.B + (stepB * i));
}
}
Maybe this function can help:
public IEnumerable<Color> GetGradients(Color start, Color end, int steps)
{
Color stepper = Color.FromArgb((byte)((end.A - start.A) / (steps - 1)),
(byte)((end.R - start.R) / (steps - 1)),
(byte)((end.G - start.G) / (steps - 1)),
(byte)((end.B - start.B) / (steps - 1)));
for (int i = 0; i < steps; i++)
{
yield return Color.FromArgb(start.A + (stepper.A * i),
start.R + (stepper.R * i),
start.G + (stepper.G * i),
start.B + (stepper.B * i));
}
}
public static List<Color> GetGradientColors(Color start, Color end, int steps)
{
return GetGradientColors(start, end, steps, 0, steps - 1);
}
public static List<Color> GetGradientColors(Color start, Color end, int steps, int firstStep, int lastStep)
{
var colorList = new List<Color>();
if (steps <= 0 || firstStep < 0 || lastStep > steps - 1)
return colorList;
double aStep = (end.A - start.A) / steps;
double rStep = (end.R - start.R) / steps;
double gStep = (end.G - start.G) / steps;
double bStep = (end.B - start.B) / steps;
for (int i = firstStep; i < lastStep; i++)
{
var a = start.A + (int)(aStep * i);
var r = start.R + (int)(rStep * i);
var g = start.G + (int)(gStep * i);
var b = start.B + (int)(bStep * i);
colorList.Add(Color.FromArgb(a, r, g, b));
}
return colorList;
}
Use double instead of int:
double stepA = ((end.A - start.A) / (double)(steps - 1));
double stepR = ((end.R - start.R) / (double)(steps - 1));
double stepG = ((end.G - start.G) / (double)(steps - 1));
double stepB = ((end.B - start.B) / (double)(steps - 1));
and:
yield return Color.FromArgb((int)start.A + (int)(stepA * step),
(int)start.R + (int)(stepR * step),
(int)start.G + (int)(stepG * step),
(int)start.B + (int)(stepB * step));
Combining this answer with the idea from several other answers to use floating-point steps, here's a complete method snippet for stepping with floating point. (With integer stepping, I had been getting asymmetrical gradient colors in a 16-color gradient from blue to red.)
Important difference in this version: you pass the total number of colors you want in the returned gradient sequence, not the number of steps to take within the method implementation.
public static IEnumerable<Color> GetColorGradient(Color from, Color to, int totalNumberOfColors)
{
if (totalNumberOfColors < 2)
{
throw new ArgumentException("Gradient cannot have less than two colors.", nameof(totalNumberOfColors));
}
double diffA = to.A - from.A;
double diffR = to.R - from.R;
double diffG = to.G - from.G;
double diffB = to.B - from.B;
var steps = totalNumberOfColors - 1;
var stepA = diffA / steps;
var stepR = diffR / steps;
var stepG = diffG / steps;
var stepB = diffB / steps;
yield return from;
for (var i = 1; i < steps; ++i)
{
yield return Color.FromArgb(
c(from.A, stepA),
c(from.R, stepR),
c(from.G, stepG),
c(from.B, stepB));
int c(int fromC, double stepC)
{
return (int)Math.Round(fromC + stepC * i);
}
}
yield return to;
}