IDL/New Graphics

색상을 채운 플롯(Filled Plot)의 표출 [2]

이상우_idl 2020. 10. 7. 14:39
728x90
반응형

NG 체계에서 색상을 채운 플롯(Filled Plot)을 표출하는 방법에 관해서는 제가 예전에 관련 게시물을 통하여 한번 소개한 바 있습니다.

 

blog.daum.net/swrush/309

 

색상을 채운 플롯(Filled Plot)의 표출 [1]

NG 체계의 그래픽 함수들 중 아무래도 가장 많이 사용되는 것이 바로 PLOT 함수일 것 같습니다. 오늘은 이 PLOT 함수의 여러 기능들 중, 색상을 채워서 그리는 기능에 관한 소개 및 팁을 올려볼까 합

blog.daum.net

 

오늘은 이것을 약간 응용한 주제라고 할 수 있을 것 같은데, 색상을 채운 플롯을 표출하는데 있어서 조건에 따라 구간을 구분하여 차별적으로 색상을 채워서 표출하는 예제를 하나 다뤄보고자 합니다. 말이 좀 애매한데, 먼저 결과 그림부터 보여드리면 다음과 같습니다.

 

 

이 그림은 Sine 곡선과 Cosine 곡선을 플롯의 형태로 중첩 표출하되, Sine의 값이 더 큰 구간과 Cosine의 값이 더 큰 구간을 구분하여 서로 다른 색상으로 채운 것입니다. 이와 같이 두 곡선 사이의 관계에 따라서 색상을 구분하여 채워주는 방식의 표출인데, 미리 좀 말씀드리자면 PLOT 함수의 색상 채우기 기능만으로 바로 편하게 구현되지는 않고 약간의 추가적인 코딩이 필요합니다. 왜냐하면 PLOT 함수에서 색상을 채우는 기능이 FILL_BACKGROUND, FILL_COLOR, FILL_LEVEL 속성들을 통하여 지원되는 것은 맞지만, 이 기능들은 대상 데이터 전체 구간에 대하여 일괄적으로 적용될 뿐 내부적으로 구간을 세분화하여 차등적으로 색상을 채우는 기능까지는 포함되어 있지 않기 때문입니다. 따라서 위의 그림과 같은 표출을 하기 위해서는 조건에 따라 구간을 구분하여 각 구간에 대한 개별적인 표출이 필요하며, 이 때문에 약간의 코딩이 필요합니다. 그렇다고 아주 무지막지하게 난해한 코딩이 필요한 것은 아닙니다. 그러면 일단 시작해봅시다.

 

먼저 예제 데이터 x, y1, y2를 생성하고 이를 플롯의 형태로 표출하는 과정부터 시작해보겠습니다. 그 과정은 다음과 같습니다.

 

x = [0:360:1.0]

y1 = SIN(x*!dtor)+2

y2 = COS(x*!dtor)+2

win = WINDOW(DIMENSIONS=[600, 500], /NO_TOOLBAR)

p1 = PLOT(x, y1, THICK=2, XRANGE=[0, 360], XTICKINTERVAL=90, $

  YRANGE=[0, 3], /CURRENT)

p2 = PLOT(x, y2, THICK=2, /OVERPLOT)

 

일단 이렇게 표출된 그림의 모습은 다음과 같습니다.

 

 

이제 여기서 Cosine 데이터인 y2에 대한 플롯인 p2의 표출에 있어서 색상을 채우는 기능들을 사용해봅시다. 이미 표출된 p2에 대하여 색상을 채우는 기능과 관련된 속성들을 다음과 같이 추가적으로 이어서 실행하면 됩니다.

 

p2.FILL_BACKGROUND = 1

p2.FILL_LEVEL = 0

p2.FILL_COLOR = 'lime'

 

이렇게 하여 표출된 그림은 다음과 같습니다.

 

 

만약에 이 상태에서 Sine 데이터 y1에 대한 플롯인 p1에 대하여 색상을 채우는 속성들에 대한 설정을 다음과 같이 추가적으로 이어서 적용하면 어떻게 될까요?

 

p1.FILL_BACKGROUND = 1

p1.FILL_LEVEL = 0

p1.FILL_COLOR = 'magenta'

 

그러면 그 결과는 다음 그림과 같습니다.

 

 

이와 같이 겉으로 보기엔 그럴싸해보이긴 하지만 우리의 의도와는 전혀 맞지 않는 그림들이 표출되고 있는 상황입니다. 이러한 작업을 해본 이유는 PLOT 함수의 색상 채우기 기능만 있는 그대로 사용해서는 우리가 원하는 표출이 불가능하다는 점을 보여드리기 위한 것입니다. 그러면 이제부터 우리가 당초 의도했던 방향으로 작업을 해보겠습니다. 이를 위하여 우리가 나중에 추가했던 여섯 줄의 내용은 모두 지우고 처음에 적었던 내용만 남겨둡시다.

 

x = [0:360:1.0]

y1 = SIN(x*!dtor)+2

y2 = COS(x*!dtor)+2

win = WINDOW(DIMENSIONS=[600, 500], /NO_TOOLBAR)

p1 = PLOT(x, y1, THICK=2, XRANGE=[0, 360], XTICKINTERVAL=90, $

  YRANGE=[0, 3], /CURRENT)

p2 = PLOT(x, y2, THICK=2, /OVERPLOT)

p2.FILL_BACKGROUND = 1

p2.FILL_LEVEL = 0

p2.FILL_COLOR = 'lime'

p1.FILL_BACKGROUND = 1

p1.FILL_LEVEL = 0

p1.FILL_COLOR = 'magenta'

 

(붉은 색으로 표시된 여섯 줄 모두 제거!)

 

이제 먼저 Sine값이 Cosine값보다 큰 구간부터 다음과 같이 WHERE 함수를 사용하여 탐색해봅시다.

 

ww = WHERE(y1 GE y2, count, COMPLEMENT=wn)

 

여기서는 조건에 해당되는 논리식을 y1 GE y2로 명시하였습니다. 이렇게 하면 y1 값이 y2 값보다 크거나 같은 구간에 해당되는 인덱스들이 ww로 추출되고, 반면 그 조건에 부합하지 않는 나머지 인덱스들이 wn으로 추출됩니다. 이제 이 상태에서 다음과 같은 작업을 추가적으로 진행합시다.

 

y1_tmp = y1

y1_tmp[wn] = !values.f_nan

 

이 내용은 약간의 요령이라고 볼 수 있는데요. 원본 데이터 y1을 복제한 y1_tmp에서 위 조건에 부합하지 않는 부분의 값들을 모두 NaN으로 대체한 것입니다. 이렇게 처리된 y1_tmp를 다음과 같이 기존의 플롯 공간에 중첩하여 표출하되, 색상을 채우는 기능들도 함께 사용합니다.

 

IF count NE 0 THEN BEGIN

  p_12a = PLOT(x, y1_tmp, /FILL_BACKGROUND, FILL_LEVEL=0, $

    FILL_COLOR='lime', /OVERPLOT)

ENDIF

 

이렇게 하여 표출된 모습은 다음 그림과 같습니다.

 

 

이렇게 하면 일단 Sine이 Cosine보다 큰 구간에 대해서만 선별적으로 색상을 채우는 것까지는 구현이 된 셈입니다. 다만 Y축 방향으로 0에 해당되는 바닥까지 색상이 채워진 것이 다소 거슬립니다. 우리가 원하는 것은 Sine 곡선과 바로 아래의 Cosine 곡선 사이 부분만 색상이 채워지도록 하는 것이며, 이러한 방식의 구현을 위해서는 몇가지 내용이 더 추가되어야 합니다. 어차피 추가될 내용은 앞서 기술한 예제 코드의 내용의 사이사이에 들어가야 하기 때문에, WHERE 함수가 사용되었던 라인부터 다시 적어보면 다음과 같습니다.

 

ww = WHERE(y1 GE y2, count, COMPLEMENT=wn)

y1_tmp = y1

y1_tmp[wn] = !values.f_nan

y2_tmp = y2

y2_tmp[wn] = !values.f_nan

IF count NE 0 THEN BEGIN

  p_12a = PLOT(x, y1_tmp, /FILL_BACKGROUND, FILL_LEVEL=0, $

    FILL_COLOR='lime', /OVERPLOT)

  p_12b = PLOT(x, y2_tmp, /FILL_BACKGROUND, FILL_LEVEL=0, $

    FILL_COLOR='white', /OVERPLOT)

ENDIF

 

여기서 볼드체로 된 라인들이 새로 추가된 내용입니다. 추가된 내용에서는 y2를 복제한 y2_tmp를 만들고 wn 인덱스 부분에 대하여 NaN 값으로 대체한 다음, 이렇게 처리된 y2_tmp를 색상을 채워서 표출하는데 이 때 색상을 흰색으로 처리한 것입니다. 이렇게 아래쪽 곡선에 대하여 흰색이 채워지도록 하여 우리가 원하는 효과를 얻을 수 있습니다. 그 결과는 다음 그림과 같습니다.

 

 

이제 뭔가 좀 그럴싸한 그림이 나오고 있다는 느낌이 듭니다. 그러면 남은 작업은 뭘까요? 이번에는 Cosine이 Sine보다 큰 구간을 WHERE 함수로 선별하고 이 구간에 대하여 또 유사한 요령으로 처리를 하면 됩니다. 단지 채우는 색상만 다른 색으로 바꿔줄 필요는 있겠지요. 이 내용은 그냥 한꺼번에 적습니다. 다음과 같은 내용을 추가하여 실행하면 됩니다. WHERE 함수 내의 논리식이 앞선 경우와 반대가 되었음에 주목하세요. 그리고 색상은 이번에는 magenta를 골랐습니다.

 

ww = WHERE(y2 GE y1, count, COMPLEMENT=wn)

y1_tmp = y1

y1_tmp[wn] = !values.f_nan

y2_tmp = y2

y2_tmp[wn] = !values.f_nan

IF count NE 0 THEN BEGIN

  p_21a = PLOT(x, y2_tmp, /FILL_BACKGROUND, FILL_LEVEL=0, $

    FILL_COLOR='magenta', /OVERPLOT)

  p_21b = PLOT(x, y1_tmp, /FILL_BACKGROUND, FILL_LEVEL=0, $

    FILL_COLOR='white', /OVERPLOT)

ENDIF

 

이 내용까지 처리된 결과는 다음 그림과 같습니다.

 

 

이 정도면 우리가 당초에 의도했던 방향과 거의 완벽하게 일치하는 것 같습니다. 실제로 제가 처음에 보여드렸던 그림이 바로 이 그림입니다. 어쨌든 앞서 언급했듯이 이러한 결과물을 얻기 위해서는 PLOT 함수에서 지원되는 기본적인 색상 채우기 기능과 함께 약간의 추가적인 코딩이 필요하다는 점을 참고하시면 됩니다. 어쩌면 동일한 결과를 얻기 위한 다른 코딩 방법이 또 있을 수도 있습니다만, 일단 제가 생각하는 방법은 이런 방식이다 정도로 참고해주시면 될 것 같습니다.

반응형