NG 체계의 그래픽 함수들 중에서 색상을 채우는 기능을 지원하는 것들이 몇개 있습니다. CONTOUR, FILLPLOT, BARPLOT, POLYGON 등의 함수들이 대표적이고 PLOT 함수의 경우도 나름대로의 방식으로 이런 기능을 지원합니다. 사실 "색상을 채운다"는 것은 내부 공간을 동일한 색상으로 빈 공간 없이 꽉 채운다는 의미로 보면 됩니다. 먼저 이러한 예제로서 다음과 같이 POLYGON 함수를 이용하여 간단한 그림을 하나 표출해보겠습니다.
win = WINDOW(DIMENSIONS=[600, 600], /NO_TOOLBAR)
xp = [0.1, 0.1, 0.9, 0.9, 0.1]
yp = [0.1, 0.9, 0.9, 0.1, 0.1]
plg = POLYGON(xp, yp, FILL_COLOR=' sea green', /NORMAL)
여기서는 FILL_COLOR 속성을 green 색상으로 설정함으로써 사각형의 내부를 초록색으로 채우는 효과를 얻게 됩니다. 위의 과정에 의하여 표출되는 그림은 다음과 같습니다.

그래서 "색상을 채운다"는 것은 통상적으로는 이러한 의미라고 볼 수 있습니다. 그런데 색상을 채우는데 있어서는 또 다른 방식도 있는데요. 바로 패턴(Pattern)을 사용하여 채우는 방식입니다. 이러한 방식을 사용할 경우 디폴트 설정은 비스듬한 빗금들로 구성된 모습의 패턴으로 내부를 채우는 방식이 됩니다. 실제로 POLYGON 함수에서 지원되는 속성들 중에는 'PATTERN_'으로 시작하는 이름의 속성들인 PATTERN_ORIENTATION, PATTERN_SPACING, PATTERN_THICK 속성들이 빗금 형태의 패턴에 대한 세부 특성을 조정하는 기능을 담당합니다. 위의 예제 코드에서 POLYGON 함수가 사용되었던 부분을 다음과 같은 내용으로 변경해봅시다.
plg = POLYGON(xp, yp, FILL_COLOR='green', $
PATTERN_ORIENTATION=45, PATTERN_SPACING=5, $
/NORMAL)
이렇게 패턴과 관련된 속성들 몇가지를 사용하여 표출된 그림은 다음과 같습니다.

여기서 사용된 속성들을 보면 PATTERN_ORIENTATION은 빗금의 경사각도, PATTERN_SPACING은 빗금들 사이의 간격을 조정하는 역할을 합니다. 이번에는 POLYGON 함수의 내용을 다음과 같이 변경해봅시다.
plg = POLYGON(xp, yp, FILL_COLOR='green', $
PATTERN_ORIENTATION=-60, PATTERN_SPACING=10, $
PATTERN_THICK=2, /NORMAL)
여기서는 PATTERN_THICK 속성은 빗금 선 자체의 두께를 조정하는 역할을 합니다. 또한 이번에는 기울기 각도를 변경하고 또한 빗금들 사이의 간격을 조금 더 넓혔보았습니다. 그 결과는 다음 그림과 같습니다.

이와 같이 POLYGON 함수에서 지원되는 PATTERN 관련 속성들을 사용하면 내부를 색상으로 채우는데 있어서 빗금 모양의 패턴을 사용할 수 있습니다. 이와 같이 빗금 모양의 패턴을 채우고 설정하는 역할의 속성들은 사실 POLYGON 함수 뿐 아니라 다른 몇몇 그래픽 함수들에서도 지원되는데요. 해당되는 그래픽 함수들은 다음과 같습니다.
BARPLOT, ELLIPSE, FILLPLOT, POLYGON
그래도 이러한 기능이 꼭 필요한 함수들에서 지원되고 있다고 볼 수는 있지만 그 갯수 자체는 그리 많은 것은 아닙니다. 물론 패턴의 형태가 아니라 그냥 단순히 단일 색상으로 채우는 방식을 지원하는 그래픽 함수들은 더 많습니다. 위의 것들은 당연히 포함이고 그 외에도 BOXPLOT, CONTOUR, PLOT 등의 함수들도 단일 색상을 채우는 방식의 기능을 지원합니다.
BARPLOT, ELLIPSE, FILLPLOT, POLYGON, BOXPLOT, CONTOUR, PLOT
그런데 앞서 언급한 PATTERN 관련 속성들을 사용할 경우 실제로 사용 가능한 패턴의 종류는 빗금 형태 하나로 한정되어 있습니다. 그런데 만약 빗금이 아닌 다른 형태의 커스텀 패턴을 사용하고 싶다면 어떻게 해야 할까요? 사실 'PATTERN_~~' 속성들만으로는 불가능합니다. 물론 그렇다고 해서 아예 불가능한 것은 아닙니다. 그 비법은 바로 PATTERN_BITMAP 속성을 사용하는 것입니다. 다만 이 속성을 제대로 사용하려면 전제조건이 하나 붙는데, 바로 패턴 자체를 유저가 직접 만들어주는 과정이 선행되어야 합니다. 이 부분이 다소 번거로울 수는 있지만 내가 원하는 커스텀 패턴을 넣으려면 필연적으로 거쳐야 하는 과정입니다. 그래서 그 방법을 한번 차근차근 소개해보도록 하겠습니다.
먼저 커스텀 패턴을 정의해야 하는데, 구체적으로는 32x32의 구조를 갖는 2차원 바이트형 배열로 정의되어야 합니다. 예를 들어서 다음과 같은 방식입니다.
arr = BYTARR(32, 32)
arr[15, 15] = 255
이렇게 하면 32x32의 구조를 갖는 바이트형 배열 내에서 모든 값들은 0인데 가운데 쯤에 위치한 하나의 픽셀만 그 값이 255가 됩니다. 실제로 이 패턴의 모습은 다음 그림과 같습니다. 텅 빈 공간의 한가운데에 점 하나만 덩그러니 있는 모습입니다.

이렇게 하면 점 하나로만 구성된 패턴이 만들어집니다. 이제 이렇게 생성된 배열 arr에 대하여 한 단계만 더 거치면 되는데, 여기서 다음과 같이 CVTTOBM이라는 함수를 사용해야 합니다.
arr_pat = CVTTOBM(arr)
여기서 사용된 CVTTOBM 함수의 역할은 IDL 도움말을 보면 다음과 같이 설명되어 있는데요.
The CVTTOBM function converts a byte array in which each byte represents one pixel into a “bitmap byte array” in which each bit represents one pixel.
이 설명을 보면 하나의 바이트가 하나의 픽셀에 대응되는 바이트형 배열을 하나의 비트가 하나의 픽셀에 대응되는 배열로 변환하는 역할을 합니다. 중요한 것은 앞서 생성했던 바이트형 배열을 CVTTOBM 함수에 투입하여 변환하는 과정이 반드시 필요하다는 것입니다. 그리고 이러한 방식으로 얻어진 배열인 arr_pat를 PATTERN_BITMAP 속성에 부여해야 합니다. 따라서 앞서 POLYGON 함수가 사용되었던 내용을 다음과 같이 변경하면 됩니다. 그리고 이번에는 색상을 crimson으로 바꿔보았습니다.
plg = POLYGON(xp, yp, FILL_COLOR='salmon', $
PATTERN_BITMAP=arr_pat, /NORMAL)
이러한 변경사항을 반영하여 전체 과정을 다시 실행해보면 그 결과는 다음 그림과 같습니다.

얼핏 보면 잘 안보일 수도 있으나 자세히 들여다보면 점들로 구성된 패턴이 사각형의 내부를 채우고 있는 것을 확인할 수 있습니다. 물론 점들이 너무 작아서 잘 보이지는 않을 수도 있습니다. 그럴 수 밖에 없는 것이 이 패턴에서는 픽셀 하나가 점 하나이기 때문입니다. 그러면 이번에는 점들의 크기를 더 키워봅시다. 그러려면 패턴 배열 생성 과정을 좀 바꿔주면 됩니다. 즉 배열 arr을 생성하는 부분을 다음과 같은 내용으로 바꿔봅시다.
arr[13:18, 13:18] = 255
이렇게 하면 패턴 자체는 다음 그림과 같이 가운데 부분의 점이 훨씬 더 커진 형태가 됩니다.

그리고 이 상태로 나머지 POLYGON 함수가 사용되는 과정을 그대로 다시 실행해보면 표출되는 그림은 다음과 같습니다.

그러면 아까보다는 점들도 더 커졌고 색상도 식별이 잘 되는 것을 볼 수 있습니다. 결국 32x32의 패턴 배열을 어떻게 만드느냐에 따라서 사용자가 원하는 어떤 패턴으로든 채울 수 있게 됩니다. 즉 패턴 배열 arr을 만드는 부분만 사용자의 목적에 맞게 바꾸면 됩니다. 만약 점들이 더 촘촘하게 찍히는 패턴을 사용하고자 한다면 어떻게 하면 될까요? 이런 경우에는 배열 arr을 다음과 같은 방식으로 만드는 방법도 있습니다.
FOR j = 0, 3 DO BEGIN
FOR i = 0, 3 DO BEGIN
arr[i*8:i*8+3, j*8:j*8+3] = 255
ENDFOR
ENDFOR
이 경우에는 패턴 자체는 다음 그림과 같아집니다.

그리고 이 패턴을 사용하여 다시 실행해보면 그 결과는 다음 그림과 같습니다.

아마 이 정도면 패턴을 직접 만들어서 그림에 반영하는 방식에 대해서는 설명이 되었을 것 같습니다. 그러면 이와 같이 커스텀 패턴을 사용할 수 있도록 해주는 PATTERN_BITMAP 속성은 어떤 그래픽 함수들에서 사용이 가능할까요? 당연히 앞서 소개했던대로 'PATTERN_~' 속성을 지원하는 4종의 그래픽 함수들(BARPLOT, ELLIPSE, FILLPLOT, POLYGON)이 여기에 해당됩니다. 그런데 실제로는 하나 더 있는데, 바로 CONTOUR 함수입니다. 다만 CONTOUR 함수에서는 해당 속성의 이름이나 적용 방식이 약간 다릅니다(PATTERN_BITMAP이 아님). 즉 CONTOUR 함수에서 지원되는 C_FILL_PATTERN이란 속성이 그 역할을 합니다. 어쨌든 이러한 속성을 사용하면, 색상을 채운 등위선(Filled Contour)을 표출하는데 있어서 패턴이 채워지도록 하는 것이 가능합니다. 예제 코드를 한꺼번에 적으면 다음과 같습니다. 바로 앞서 생성했던 촘촘한 점들로 구성된 패턴이 적용되도록 하였습니다.
data = HANNING(400, 400)*100
add = FLTARR(400, 400)
add[240, 40] = HANNING(150, 150)*50
data = data + add
win = WINDOW(DIMENSIONS=[600, 600], /NO_TOOLBAR)
arr = BYTARR(32, 32)
FOR j = 0, 3 DO BEGIN
FOR i = 0, 3 DO BEGIN
arr[i*8:i*8+2, j*8:j*8+2] = 255
ENDFOR
ENDFOR
arr_pat = CVTTOBM(arr)
oPat = OBJ_NEW('IDLgrPattern', PATTERN=arr_pat, STYLE=2)
cn = CONTOUR(data, /FILL, RGB_TABLE=74, C_FILL_PATTERN=oPat, $
XTICKLEN=0.01, YTICKLEN=0.01, AXIS_STYLE=2, $
MARGIN=0.1, /CURRENT)
cno = CONTOUR(data, COLOR='black', C_THICK=2, /OVERPLOT)
전반적인 과정은 앞서 설명한 내용과 전반적으로 거의 유사합니다. 다만 여기서는 단 한가지 차이점이 있는데요. 바로 IDLgrPattern 클래스의 객체가 사용된 것입니다. 바로 볼드체로 표시한 라인에서 생성한 oPat입니다. 굳이 이렇게 하는 이유는 CONTOUR 함수의 C_FILL_PATTERN 속성은 IDLgrPattern 클래스의 객체만 받을 수 있다는 특성 때문입니다. 문법 자체가 그렇기 때문에 어쩔 수 없습니다. 어쨌든 이와 같이 처리하여 얻게 되는 최종 결과물은 다음 그림과 같습니다.

색상을 꽉 채운 등위선 그림은 아마 많이들 보셨겠지만 이러한 형태는 약간 생소할 수도 있을 것 같습니다. 어쨌든 패턴을 나름대로 구성하여 그 패턴으로 '색상을 채워서' 표출하는 것이 이와 같은 방식으로 가능하다는 점을 참고해두시면 좋을 것 같습니다. 물론 이를 위해서는 패턴 자체를 유저가 직접 설계하고 구성하는 것이 필요한데, 약간 귀찮을 수도 있지만 그 대신 수많은 다양한 종류의 패턴들을 사용할 수 있게 된다는 장점도 분명 있을 것입니다.
그리고 위의 그림을 파일로 저장할 때 유의해야 할 점이 있습니다. 즉 커스텀 패턴으로 채워진 그래픽 결과물을 JPG, PNG 등과 같은 비트맵 형식의 그림 파일로 저장하기 위하여 Save 메서드를 사용할 때에는 ANTIALIAS 속성의 값을 0으로 설정하는 것이 반드시 필요하다는 것을 유의해야 합니다. 즉 예를 들어 PNG 형식의 파일로 저장할 경우 다음과 같이 처리하는 것이 바람직합니다.
win.Save, 'result.png', WIDTH=600, ANTIALIAS=0
사실 통상적으로는 Save 메서드를 사용할 때 ANTIALIAS 속성을 사용할 일이 흔하지는 않은데, 이와 같이 커스텀 패턴이 포함된 그래픽 결과물을 저장할 경우에 한하여 이러한 방식이 필요합니다. 만약 ANTIALIAS 속성을 사용하지 않고 저장할 경우에는 그림 파일 내에서 패턴이 깨지는 현상이 발생할 수도 있기 때문입니다. 이 점만 유의하시기 바랍니다.
* 이 내용은 지난 2020년에 올렸던 게시물의 내용을 수정 및 보강하여 다시 새롭게 올리는 것입니다. 따라서 기존의 게시물은 삭제하고 이번에 작성한 게시물로 대체합니다.
* 이 글이 도움이 되었다면 게시물에 대하여 공감 버튼(하트 모양) 클릭 및 블로그 구독도 해주시면 더 큰 힘이 됩니다. 감사합니다.
'IDL > New Graphics' 카테고리의 다른 글
| 이미지(Image)를 격자(Grid)와 함께 표시하기 (0) | 2025.10.28 |
|---|---|
| 줄기형 플롯 표출하기 (0) | 2025.10.21 |
| 계단형 플롯 표출하기 (0) | 2025.10.13 |
| 축(Axis)의 범위 뒤집기 (0) | 2025.10.01 |
| 막대 그래프(BarPlot)를 수평 방향으로 표출하기 (0) | 2025.09.29 |