본문 바로가기
프로그래밍/C#

C# 히트맵(HeatMap) 그리기

by bantomak 2023. 5. 8.

 

 

Heatmap style gradients in .NET

I am trying to create a heat map with gradients that look similar to this: This image shows three points and the gradients blend nicely together. Here is what I am currently doing in my drawing

stackoverflow.com

 

라이브러리를 사용하지 않고 C#을 통해서 히트맵을 그려봤습니다. 해당 내용은 스택오버플로우에 질문과 답변을 참고하여 작성하였습니다.

 

원하는 목표

  • 히트맵(Heatmap)을 만들기 위해서 원을 그린다.
  • 원은 중첩 가능하며 중첩된 부분은 진한 색으로 표현되어야 한다.
  • 빨강에서 시작해서 파랑으로 끝나는 컬러맵(ColorMap)으로 표현되어야 한다.

 

히트맵
우리가 도달하고 싶은 목표

구현 방법

  • 중심이 검은색(Black), 바깥쪽은 투명(Transparent)으로 그라데이션 색상이 들어간 원을 그린다.
  • Remap에 사용할 가로 256 * 세로 1의 컬러맵을 2개 생성해서 준비한다.
  • Grayscale맵은 검정(Black)에서 투명(Transparent)으로 구성된 컬러맵이다.
  • HeatmapColor맵은 빨강(Red)에서 시작해서 투명(Transparent)으로 진행되는 컬러맵이다.
    (자연스러운 히트맵 생성을 위해서 중간값을 넣어주자)
  • SetRemapTable함수를 이용해서 색을 재맵핑(Remap)된다.

grayscale을 heatmap컬러로 재배치한 결과

 

예제코드

원 그리기 함수

CenterColor 검정에서 시작해서 SurroundColor가 투명으로 채워진다.

public static void DrawCircle(Graphics grf, int x, int y, int circleSize, int alphaValue)
{
    var myEllipse = new Rectangle(x, y, circleSize, circleSize);

    using (var gp = new GraphicsPath())
    {
        gp.AddEllipse(myEllipse);

        var pgb = new PathGradientBrush(gp);
        pgb.CenterPoint = new PointF(myEllipse.X + myEllipse.Width / 2,
                                     myEllipse.Y + myEllipse.Height / 2);
        pgb.CenterColor = Color.FromArgb(alphaValue, Color.Black);
        pgb.SurroundColors = new Color[] { Color.FromArgb(0, Color.Transparent) };

        grf.FillPath(pgb, gp);
    };
}

 

Grayscale 컬러맵 생성 함수

SetRemapTable함수에 사용할 컬러맵 정보를 생성합니다.

width와 height는 256 * 1 사이즈로 작성합니다.

public static Bitmap CreateGrayscaleMap(int width, int height)
{
    Bitmap grayscaleMap = new Bitmap(width, height);
    using (Graphics grf = Graphics.FromImage(grayscaleMap))
    {
        LinearGradientBrush lgb = new LinearGradientBrush(new Rectangle(0, 0, width, height), Color.Black, Color.Transparent, LinearGradientMode.Horizontal);
        ColorBlend colorblend = new ColorBlend();
        colorblend.Colors = new Color[] { Color.Black, Color.Transparent };
        colorblend.Positions = new Single[] { 0.0F, 1.0F };
        lgb.InterpolationColors = colorblend;

        grf.FillRectangle(lgb, new Rectangle(0, 0, width, height));
    }

    return grayscaleMap;
}

 

Heatmap 컬러맵 생성 함수

동일하게 width와 height는 256 * 1 사이즈로 작성합니다.

public static Bitmap CreateHeatColorMap(int width, int height)
{
    Bitmap colorListHeatmap = new Bitmap(width, height);
    using (Graphics grf = Graphics.FromImage(colorListHeatmap))
    {
        LinearGradientBrush lgb = new LinearGradientBrush(new Rectangle(0, 0, width, height), Color.Black, Color.Transparent, LinearGradientMode.Horizontal);
        ColorBlend colorblend = new ColorBlend();
        colorblend.Colors = new Color[] { Color.Red, Color.Yellow, Color.Lime, Color.Cyan, Color.Blue, Color.Transparent };
        colorblend.Positions = new Single[] { 0.0F, 0.2F, 0.4F, 0.6F, 0.75F, 1.0F };
        lgb.InterpolationColors = colorblend;

        grf.FillRectangle(lgb, new Rectangle(0, 0, width, height));
    }

    return colorListHeatmap;
}

 

SetRemapTable 함수

var cm = DrawUtil.CreateGrayscaleMap(_colorMapWidth, _colorMapHeight);
var hcm = DrawUtil.CreateHeatColorMap(_colorMapWidth, _colorMapHeight);

ColorMap[] colorMap = new ColorMap[256];

for (int i = 0; i < colorMap.Length; i++)
{
    colorMap[i] = new ColorMap();
    colorMap[i].OldColor = cm.GetPixel(i, 0);
    colorMap[i].NewColor = hcm.GetPixel(i, 0);
}

ImageAttributes imageAttr = new ImageAttributes();
imageAttr.SetRemapTable(colorMap);

해당 함수를 호출하면 grayscale 스타일로 적용되었던 색들이 히트맵에 맞는 지정된 색들로 재맵핑된다.

 

이제 세부조정을 통해서 원하는 크기와 느낌의 히트맵을 작성하면 된다.

댓글