表示したいヒートマップがあります。表示される値を構成する数値は不明です(正の整数になることを除いて)。数の範囲も不明です(これも、正のインターガーになることを除いて)。範囲は、0〜200、578〜1Mなどです。それは不明なデータに依存します。
未知の範囲の正の整数を取得し、それをスケーリングされた(圧縮された)範囲に変換して、ヒートマップにRGB値で表示したいと考えています。これが理にかなっていることを願っています。ありがとう!
最小/最大値をフォーラムに「プラグイン」する必要があることを明確にしたい。
最小値と最大値を取得するには、最初にこれらの値の範囲を見つける必要があります。次に、この画像の下にあるバーのようなカラースケールを作成する必要があります。さまざまな関数を試して、整数をRGBにマッピングできます。 3つの関数R(X)、G(X)、B(X)が必要です。下の画像を見ると、B(X)中央にピークがあり、R(X)最後にピークがあり、緑はどこかにあります。 Xの値に対して2つ(RGB)を取得しないことを確認する限り、変換を取得できます。
(出典: globalwarmingart.com )
編集:考えてみると、YUVスペースの周りの単位円をサンプリングできます。 代替テキストhttp://www.biocrawler.com/w/images/e/ec/Yuv.png
または、高解像度のカラーバーをダウンロードしてサンプルすることもできます。
編集2:カラーバーの生成に直面し、MATLAB/Octaveカラーバーコードを思い出しました。私は彼らのデータをプロットし、次の画像を取得しました。
データ値を光の周波数に変換したい:
可視光の周波数は約350nm(紫)から650nm(赤)になります。
(出典: gamonline.com )
次の関数は、指定された範囲の数値を可視光の範囲に変換してから、rgbを取得します。
function DataPointToColor(Value, MinValue, MaxValue: Real): TColor;
var
r, g, b: Byte;
WaveLength: Real;
begin
WaveLength := GetWaveLengthFromDataPoint(Value, MinValue, MaxValue);
WavelengthToRGB(Wavelength, r, g, b);
Result := RGB(r, g, b);
end;
関数を使用して、頭のてっぺんから書き留めました。
function GetWaveLengthFromDataPoint(Value: Real; MinValues, MaxValues: Real): Real;
const
MinVisibleWaveLength = 350.0;
MaxVisibleWaveLength = 650.0;
begin
//Convert data value in the range of MinValues..MaxValues to the
//range 350..650
Result := (Value - MinValue) / (MaxValues-MinValues) *
(MaxVisibleWavelength - MinVisibleWavelength) +
MinVisibleWaveLength;
end;
そして 私がインターネットで見つけた関数 、それは波長をRGBに変換します:
PROCEDURE WavelengthToRGB(CONST Wavelength: Nanometers;
VAR R,G,B: BYTE);
CONST
Gamma = 0.80;
IntensityMax = 255;
VAR
Blue : DOUBLE;
factor : DOUBLE;
Green : DOUBLE;
Red : DOUBLE;
FUNCTION Adjust(CONST Color, Factor: DOUBLE): INTEGER;
BEGIN
IF Color = 0.0
THEN RESULT := 0 // Don't want 0^x = 1 for x <> 0
ELSE RESULT := ROUND(IntensityMax * Power(Color * Factor, Gamma))
END {Adjust};
BEGIN
CASE TRUNC(Wavelength) OF
380..439:
BEGIN
Red := -(Wavelength - 440) / (440 - 380);
Green := 0.0;
Blue := 1.0
END;
440..489:
BEGIN
Red := 0.0;
Green := (Wavelength - 440) / (490 - 440);
Blue := 1.0
END;
490..509:
BEGIN
Red := 0.0;
Green := 1.0;
Blue := -(Wavelength - 510) / (510 - 490)
END;
510..579:
BEGIN
Red := (Wavelength - 510) / (580 - 510);
Green := 1.0;
Blue := 0.0
END;
580..644:
BEGIN
Red := 1.0;
Green := -(Wavelength - 645) / (645 - 580);
Blue := 0.0
END;
645..780:
BEGIN
Red := 1.0;
Green := 0.0;
Blue := 0.0
END;
ELSE
Red := 0.0;
Green := 0.0;
Blue := 0.0
END;
// Let the intensity fall off near the vision limits
CASE TRUNC(Wavelength) OF
380..419: factor := 0.3 + 0.7*(Wavelength - 380) / (420 - 380);
420..700: factor := 1.0;
701..780: factor := 0.3 + 0.7*(780 - Wavelength) / (780 - 700)
ELSE factor := 0.0
END;
R := Adjust(Red, Factor);
G := Adjust(Green, Factor);
B := Adjust(Blue, Factor)
END {WavelengthToRGB};
使用例:
10..65,000,000の範囲のデータセット。そして、この特定のデータポイントの値は638,328です。
color = DataPointToColor(638328, 10, 65000000);
カラーバーの機能
// value between 0 and 1 (percent)
function color(value) {
var RGB = {R:0,G:0,B:0};
// y = mx + b
// m = 4
// x = value
// y = RGB._
if (0 <= value && value <= 1/8) {
RGB.R = 0;
RGB.G = 0;
RGB.B = 4*value + .5; // .5 - 1 // b = 1/2
} else if (1/8 < value && value <= 3/8) {
RGB.R = 0;
RGB.G = 4*value - .5; // 0 - 1 // b = - 1/2
RGB.B = 1; // small fix
} else if (3/8 < value && value <= 5/8) {
RGB.R = 4*value - 1.5; // 0 - 1 // b = - 3/2
RGB.G = 1;
RGB.B = -4*value + 2.5; // 1 - 0 // b = 5/2
} else if (5/8 < value && value <= 7/8) {
RGB.R = 1;
RGB.G = -4*value + 3.5; // 1 - 0 // b = 7/2
RGB.B = 0;
} else if (7/8 < value && value <= 1) {
RGB.R = -4*value + 4.5; // 1 - .5 // b = 9/2
RGB.G = 0;
RGB.B = 0;
} else { // should never happen - value > 1
RGB.R = .5;
RGB.G = 0;
RGB.B = 0;
}
// scale for hex conversion
RGB.R *= 15;
RGB.G *= 15;
RGB.B *= 15;
return Math.round(RGB.R).toString(16)+''+Math.round(RGB.G).toString(16)+''+Math.round(RGB.B).toString(16);
}
Chris Hによって提供された図から離れて、rgb値を次のようにモデル化できます。
r = min(max(0, 1.5-abs(1-4*(val-0.5))),1);
g = min(max(0, 1.5-abs(1-4*(val-0.25))),1);
b = min(max(0, 1.5-abs(1-4*val)),1);
Ian Boydの優れた回答から続けて、ヒートマップを作成するために識別可能な色のセットが必要でした。秘訣は近い色を区別する方法を見つけることでした。HSVに変換し、値に応じてVを変化させ、色の範囲の中央を少し強調して黄色とオレンジを引き出すことで解決策を見つけました。
コードは次のとおりです。
Imports System.Drawing
Imports RGBHSV
Module HeatToColour_
' Thanks to Ian Boyd's excellent post here:
' http://stackoverflow.com/questions/2374959/algorithm-to-convert-any-positive-integer-to-an-rgb-value
Private Const MinVisibleWaveLength As Double = 450.0
Private Const MaxVisibleWaveLength As Double = 700.0
Private Const Gamma As Double = 0.8
Private Const IntensityMax As Integer = 255
Function HeatToColour(ByVal value As Double, ByVal MinValue As Double, ByVal MaxValues As Double) As System.Drawing.Color
Dim wavelength As Double
Dim Red As Double
Dim Green As Double
Dim Blue As Double
Dim Factor As Double
Dim scaled As Double
scaled = (value - MinValue) / (MaxValues - MinValue)
wavelength = scaled * (MaxVisibleWaveLength - MinVisibleWaveLength) + MinVisibleWaveLength
Select Case Math.Floor(wavelength)
Case 380 To 439
Red = -(wavelength - 440) / (440 - 380)
Green = 0.0
Blue = 1.0
Case 440 To 489
Red = 0.0
Green = (wavelength - 440) / (490 - 440)
Blue = 1.0
Case 490 To 509
Red = 0.0
Green = 1.0
Blue = -(wavelength - 510) / (510 - 490)
Case 510 To 579
Red = (wavelength - 510) / (580 - 510)
Green = 1.0
Blue = 0.0
Case 580 To 644
Red = 1.0
Green = -(wavelength - 645) / (645 - 580)
Blue = 0.0
Case 645 To 780
Red = 1.0
Green = 0.0
Blue = 0.0
Case Else
Red = 0.0
Green = 0.0
Blue = 0.0
End Select
' Let the intensity fall off near the vision limits
Select Case Math.Floor(wavelength)
Case 380 To 419
Factor = 0.3 + 0.7 * (wavelength - 380) / (420 - 380)
Case 420 To 700
Factor = 1.0
Case 701 To 780
Factor = 0.3 + 0.7 * (780 - wavelength) / (780 - 700)
Case Else
Factor = 0.0
End Select
Dim R As Integer = Adjust(Red, Factor)
Dim G As Integer = Adjust(Green, Factor)
Dim B As Integer = Adjust(Blue, Factor)
Dim result As Color = System.Drawing.Color.FromArgb(255, R, G, B)
Dim resulthsv As New HSV
resulthsv = ColorToHSV(result)
resulthsv.Value = 0.7 + 0.1 * scaled + 0.2 * Math.Sin(scaled * Math.PI)
result = HSVToColour(resulthsv)
Return result
End Function
Private Function Adjust(ByVal Colour As Double, ByVal Factor As Double) As Integer
If Colour = 0 Then
Return 0
Else
Return Math.Round(IntensityMax * Math.Pow(Colour * Factor, Gamma))
End If
End Function
End Module
Imports System.Drawing
Public Module RGBHSV
Public Class HSV
Sub New()
Hue = 0
Saturation = 0
Value = 0
End Sub
Public Sub New(ByVal H As Double, ByVal S As Double, ByVal V As Double)
Hue = H
Saturation = S
Value = V
End Sub
Public Hue As Double
Public Saturation As Double
Public Value As Double
End Class
Public Function ColorToHSV(ByVal color As Color) As HSV
Dim max As Integer = Math.Max(color.R, Math.Max(color.G, color.B))
Dim min As Integer = Math.Min(color.R, Math.Min(color.G, color.B))
Dim result As New HSV
With result
.Hue = color.GetHue()
.Saturation = If((max = 0), 0, 1.0 - (1.0 * min / max))
.Value = max / 255.0
End With
Return result
End Function
Public Function HSVToColour(ByVal hsv As HSV) As Color
Dim hi As Integer
Dim f As Double
With hsv
hi = Convert.ToInt32(Math.Floor(.Hue / 60)) Mod 6
f = .Hue / 60 - Math.Floor(.Hue / 60)
.Value = .Value * 255
Dim v As Integer = Convert.ToInt32(.Value)
Dim p As Integer = Convert.ToInt32(.Value * (1 - .Saturation))
Dim q As Integer = Convert.ToInt32(.Value * (1 - f * .Saturation))
Dim t As Integer = Convert.ToInt32(.Value * (1 - (1 - f) * .Saturation))
If hi = 0 Then
Return Color.FromArgb(255, v, t, p)
ElseIf hi = 1 Then
Return Color.FromArgb(255, q, v, p)
ElseIf hi = 2 Then
Return Color.FromArgb(255, p, v, t)
ElseIf hi = 3 Then
Return Color.FromArgb(255, p, q, v)
ElseIf hi = 4 Then
Return Color.FromArgb(255, t, p, v)
Else
Return Color.FromArgb(255, v, p, q)
End If
End With
End Function
End Module
結果として得られるヒートマップは、EEC諸国の1人当たりGDPを示しています。
値の範囲がわからなければ、任意の範囲の正の整数をヒートにマッピングする意味のある関数を思い付くためにできることはあまりありません。 -マップタイプの色の範囲。
最小/最大を取得するか、事前にデータを知るには、少なくとも1回はデータを実行する必要があると思います。それができたら、適切に正規化し、任意の数の配色を使用できます。最も簡単な解決策は、「hue」のようなものを指定し、 [〜#〜] hsv [〜#〜] からRGBに変換することです。
この答えはおそらくパーティーに少し遅れています。いくつかの環境データを表示しているので、データセットの最大値と最小値(または関数に最大値と最小値として渡される値)を基準にして、結果のバーを緑から赤に色付けする必要があります。とにかく、以下はそれを実現します。青から赤にかなり簡単に変更できると思います。
// scale colour temp relatively
function getColourTemp(maxVal, minVal, actual) {
var midVal = (maxVal - minVal)/2;
var intR;
var intG;
var intB = Math.round(0);
if (actual >= midVal){
intR = 255;
intG = Math.round(255 * ((maxVal - actual) / (maxVal - midVal)));
}
else{
intG = 255;
intR = Math.round(255 * ((actual - minVal) / (midVal - minVal)));
}
return to_rgb(intR, intG, intB);
}
男、あなたはおそらくYUV色空間を使用することができ、デモンストレーション目的でのみそれをRGBに変換します。
少し遅れましたが、同じことをしようとしていたところ、HSVをRGBに変更して同様の結果を得ることができることがわかりました。これは波長アプローチに似ていますが、最初に波長に変換する必要があります。 Hを値に置き換えて(0から1の間の値を想定)、SとVを1に固定します。ここでのHSVtoRGBの例は非常に役立ちます。
http://www.cs.rit.edu/~ncs/color/t_convert.html
しかし、私は行を変更しなければなりませんでした
h /= 60;
i = floor ( h );
に
h *= 5;
i = (int) h;
スペクトル全体を通過する出力を取得します。