Excelでヒートマップ
どうもヒートマップとかのキーワードでやってくる人が一定数いるようで、バッドエクスペリエンスしかないというのも良心がとがめるので、自作のヒートマップ作成マクロおいてみます。あくまでアレイの発現比を可視化するために組んだものなので、0を中心にした三色スケールのみです。
最小・最大値で指定したmについて、-m ~ 0 ~ mで、値に対応した色の正方形シェイプが出力されます。選択範囲内の全てで評価が行われて、シェイプはグループ化されます。
セルの背景色でなく、シェイプを出力するようにしたのはExcel2003以前でセルに指定できる色が少なかったためですが、パワーポイントなどに転用することを考えるとExcel2007でも有用です。
heatBlockは線形に色が変化しますが、heatBlockSqrtは(value/m)^2を評価して色を決定します。0付近の値が小さく見積もられるので、発現変動が小さいものなどの色が弱くなり、大きな発現変動が強調されます。
見よう見まねで組んでいるので、ベストなアルゴリズムではないかも。その辺について気づいたことがあったら、気軽にコメください。
Sub heatmapBlock() Dim i As Integer Dim j As Integer Dim colN As Integer Dim rowN As Integer Dim aC As Integer Dim aR As Integer Dim m As Long Dim colR As Integer Dim colG As Integer Dim colB As Integer Dim color1() As Variant Dim color2() As Variant Dim color3() As Variant Dim colind As Integer Dim myShapes() As Variant rowN = Selection.Rows.Count colN = Selection.Columns.Count ReDim myShapes(1 To rowN * colN) m = Application.InputBox( _ "最大・最小値を指定してください。", _ "最大最小値の指定", _ 2) color1 = Application.InputBox( _ Prompt:="最小時の色を指定してください", _ Title:="色の指定1", _ Default:="{0,255,0}", _ Type:=64) color2 = Application.InputBox( _ Prompt:="中央値の色を指定してください", _ Title:="色の指定2", _ Default:="{0,0,0}", _ Type:=64) color3 = Application.InputBox( _ Prompt:="最大時の色を指定してください", _ Title:="色の指定3", _ Default:="{255,0,102}", _ Type:=64) aR = Selection.Rows(1).Row aC = Selection.Columns(1).Column For i = 1 To rowN For j = 1 To colN Cells(aR + i - 1, aC + j - 1).Activate myVal = ActiveCell ActiveSheet.Shapes.AddShape(msoShapeRectangle, j * 20, i * 20, 20, 20).Select If myVal <= -m Then colR = color1(1) colG = color1(2) colB = color1(3) ElseIf -m < myVal And myVal < 0 Then colind = -myVal / m * 128 colR = color2(1) + WorksheetFunction.Round((color1(1) - color2(1)) * colind / 128, 0) colG = color2(2) + WorksheetFunction.Round((color1(2) - color2(2)) * colind / 128, 0) colB = color2(3) + WorksheetFunction.Round((color1(3) - color2(3)) * colind / 128, 0) ElseIf myVal = 0 Then colR = color2(1) colG = color2(2) colB = color2(3) ElseIf 0 < myVal And myVal < m Then colind = myVal / m * 128 colR = color2(1) + WorksheetFunction.Round((color3(1) - color2(1)) * colind / 128, 0) colG = color2(2) + WorksheetFunction.Round((color3(2) - color2(2)) * colind / 128, 0) colB = color2(3) + WorksheetFunction.Round((color3(3) - color2(3)) * colind / 128, 0) ElseIf myVal >= m Then colR = color3(1) colG = color3(2) colB = color3(3) End If With Selection.ShapeRange .Line.Visible = msoTrue .Fill.Visible = msoTrue .Fill.ForeColor.RGB = RGB(colR, colG, colB) .Fill.Solid End With myShapes(colN * (i - 1) + j) = Selection.Name Next j Next i ActiveSheet.Shapes.Range(myShapes).Group Erase myShapes End Sub
Sub heatmapBlockSqrt() Dim i As Integer Dim j As Integer Dim colN As Integer Dim rowN As Integer Dim aC As Integer Dim aR As Integer Dim m As Long Dim colR As Integer Dim colG As Integer Dim colB As Integer Dim color1() As Variant Dim color2() As Variant Dim color3() As Variant Dim colind As Integer Dim myShapes() As Variant rowN = Selection.Rows.Count colN = Selection.Columns.Count ReDim myShapes(1 To rowN * colN) m = Application.InputBox( _ "最大・最小値を指定してください。", _ "最大最小値の指定", _ 2) color1 = Application.InputBox( _ Prompt:="最小時の色を指定してください", _ Title:="色の指定1", _ Default:="{0,255,0}", _ Type:=64) color2 = Application.InputBox( _ Prompt:="中央値の色を指定してください", _ Title:="色の指定2", _ Default:="{0,0,0}", _ Type:=64) color3 = Application.InputBox( _ Prompt:="最大時の色を指定してください", _ Title:="色の指定3", _ Default:="{255,0,102}", _ Type:=64) aR = Selection.Rows(1).Row aC = Selection.Columns(1).Column For i = 1 To rowN For j = 1 To colN Cells(aR + i - 1, aC + j - 1).Activate myVal = ActiveCell ActiveSheet.Shapes.AddShape(msoShapeRectangle, j * 20, i * 20, 20, 20).Select If myVal <= -m Then colR = color1(1) colG = color1(2) colB = color1(3) ElseIf -m < myVal And myVal < 0 Then colind = (myVal / m)^2 * 128 colR = color2(1) + WorksheetFunction.Round((color1(1) - color2(1)) * colind / 128, 0) colG = color2(2) + WorksheetFunction.Round((color1(2) - color2(2)) * colind / 128, 0) colB = color2(3) + WorksheetFunction.Round((color1(3) - color2(3)) * colind / 128, 0) ElseIf myVal = 0 Then colR = color2(1) colG = color2(2) colB = color2(3) ElseIf 0 < myVal And myVal < m Then colind = (myVal / m)^2 * 128 colR = color2(1) + WorksheetFunction.Round((color3(1) - color2(1)) * colind / 128, 0) colG = color2(2) + WorksheetFunction.Round((color3(2) - color2(2)) * colind / 128, 0) colB = color2(3) + WorksheetFunction.Round((color3(3) - color2(3)) * colind / 128, 0) ElseIf myVal >= m Then colR = color3(1) colG = color3(2) colB = color3(3) End If With Selection.ShapeRange .Line.Visible = msoTrue .Fill.Visible = msoTrue .Fill.ForeColor.RGB = RGB(colR, colG, colB) .Fill.Solid End With myShapes(colN * (i - 1) + j) = Selection.Name Next j Next i ActiveSheet.Shapes.Range(myShapes).Group Erase myShapes End Sub