IDL/New Graphics

NG체계에서 다중 플롯 그리기 (Multi-Plot in NG) [2] - 업데이트!

이상우_IDL 2016. 2. 22. 12:00
728x90

지난 회에서는 NG 체계에서 다중 플롯 그리는데 있어서 PLOT 함수의 LAYOUT, MARGIN 속성을 사용하는 방법 위주로 소개를 했었습니다. 오늘은 POSITION이라는 속성을 사용하는 방법을 소개해볼까 합니다. 사실 POSITION이라는 개념은 IDL에서 오래전부터 존재해왔었습니다. DG 체계에서 PLOT 프로시저에서도 지원되는 키워드입니다. 그리고 개념적으로는 NG에서나 DG에서나 다 같습니다.


이 POSITION의 개념은 근본적으로는 지난 회에 소개했던 MARGIN과 거의 유사합니다. 다만 사용하는데 있어서 문법적인 방식이약간 다릅니다. MARGIN이 좌하우상의 "여백"에 해당되는 개념이라면, POSITON은 꼭지점의 "위치"에 해당되는 개념이라고 볼 수있습니다. POSITION의 개념에 대한 도식적인 이해를 위하여 다음과 같은 그림을 준비해보았습니다.



이 그림을 통하여 아마 좀 더 명확한 이해가 가능할 것으로 생각됩니다. 정리해보면 POSITION에 대해서는 네 개의 숫자들로 구성된 배열이 부여되는데, 이 네 개의 숫자들은 순서대로 각각 X1, Y1, X2, Y2가 됩니다. 좌측하단 구석의 좌표 및 우측상단 구석의 좌표가 순서대로 합쳐진 셈입니다. 숫자의 값들은 normal 좌표계를 기준으로 하므로 0~1의 범위를 가져야 합니다. 비교를 위하여 MARGIN의 개념으로 대응시켜본다면 마치 MARGIN의 값이 좌하우상 모두 0.1인 경우와 마찬가지입니다. 그리고 MARGIN과 마찬가지로 POSITION 역시 XY축으로 이루어진 사각형 자체에 해당되며, 축 라벨문자 등의 요소들은 해당되지 않습니다.


개념의 이해 및 간단한 테스트를 위하여 다음과 같은 명령을 그냥 IDL의 커맨드 입력창에 입력하고 실행해봅시다. 그러면, 그래픽창에 꽉 차는 플롯이 그려지는 것을 볼 수 있을 것입니다. 여기서 POSITION 키워드에 주어진 값이 [0, 0, 1, 1]이므로 그래픽창에서 좌측하단 및 우측상단 부분이 완전히 끝까지 채워진 상태로 그림이 그려지게 됩니다.


IDL> PLOT, INDGEN(11), POSITION=[0, 0, 1, 1]


이제 다중 플롯을 구현하는 문제에 있어서 이 POSITION이란 개념의 사용도 충분히 가능해 보입니다. 다만 지난번처럼 구획의 형태를미리 나눠놓는 방식이 아니라, 개별 플롯의 위치를 POSITION으로 일일이 지정하는 방식이 될텐데요. 사실 이것은 좀 귀찮은 작업입니다. 만약 2X2의 구획으로 총 4개의 플롯들을 그리는데 있어서 각 플롯의 위치를 POSITION으로 지정해야 할 경우, 각 플롯의 적정한 위치를 계산하는 것은 약간은 귀찮지만 아주 어렵기만 하지는 않습니다. 각 플롯의 XY축 사각형들이 여백없이 서로 맞닿도록 그린다고 가정할 경우 각 플롯의 POSITION 값은 다음과 같아야 할 것입니다.


상단좌측 Plot : [0.0, 0.5, 0.5, 1.0]

상단우측 Plot : [0.5, 0.5, 1.0, 1.0]

하단좌측 Plot : [0.5, 0.0, 1.0, 0.5]

하단우측 Plot : [0.0, 0.0, 0.5, 0.5]


그런데, 지금은 2X2로 비교적 간단한 편이지만 더 나아가서 4X3, 5X5 등과 같이 구획들이 더 많아져야 한다면, 이러한 방식으로 각 플롯의 위치좌표를 일일이 계산하는 것은 상당히 귀찮고 비효율적일 수도 있는 일입니다. 따라서 이러한 귀찮은 작업을 대신 해줄 수 있는 프로그램을 제가 하나 만들어 보았습니다. 프로그램의 이름은 GET_POSITIONS이며, 해당 파일을 이 게시물에 첨부하였습니다. 이 프로그램은 함수형으로서 내가 원하는 구획의 구조에 맞는 적절한 위치좌표 값들을 계산하여 전달해주는 역할을 합니다. 예를 들어, 앞서 언급했던 2X2의 구획 형태 생각할 경우 각 플롯별 위치좌표를 직접 계산을 하지 않고도 다음과 같이 간단하게 얻을 수 있습니다.


IDL> positions = GET_POSITIONS(2, 2)


여기서 GET_POSITIONS 함수로 얻은 결과는 4X4의 구조를 갖는 배열로 전달됩니다. 이 배열의 첫번째 차원은 구획의 인덱스로서 총 4개의 구획들이 0, 1, 2, 3 인덱스에 각각 해당됩니다. 그리고 두번째 차원은 POSITION에 부여할 수 있는 위치좌표값들에 해당되며, 당연히 X1, Y1, X2, Y2의 순서로 들어가 있습니다. 따라서 2X2 구획 형태에서 첫번째 구획에 위치할 플롯의 위치좌표들을 출력해보면 그 값들은 0.1, 0.5, 0.5, 0.9가 됩니다. 두번째 구획은 바로 우측이므로 0.5, 0.5, 0.9, 0.9가 되고, 세번째는 아래쪽 좌측로 내려가서 0.1, 0.1, 0.5, 0.5, 네번째는 그 우측이므로 0.5, 0.1, 0.9, 0.5가 되는 식입니다.


IDL> HELP, positions

POSITIONS       FLOAT     = Array[4, 4]

IDL> PRINT, positions[0, *]

     0.100000

     0.500000

     0.500000

     0.900000

IDL> PRINT, positions[1, *]

     0.500000

     0.500000

     0.900000

     0.900000

IDL> PRINT, positions[2, *]

     0.100000

     0.100000

     0.500000

     0.500000

IDL> PRINT, positions[3, *]

     0.500000

     0.100000

     0.900000

     0.500000


숫자들이 자꾸 나와서 좀 장황해졌는데, 이 숫자 자체에 연연하지 말고 실제 그림을 그리는데 사용을 해봅시다. 지난 회에서 사용했던예제 데이터를 그대로 사용하여 2X2 구획에 그림을 그려보겠습니다. 사용 데이터를 정의하고 PLOT 함수를 사용하여 개별 플롯을 표출하는 방식은 이전과 같습니다. 다만 여기서는 GET_POSITIONS 함수로 얻은 위치좌표를 POSITION 속성에 부여하는 방식을 사용합니다.


x = FINDGEN(101)
y1 = SQRT(x)/10
y2 = x^2/1E4
y3 = x^4/1E8
y4 = x/100
positions =
GET_POSITIONS(2, 2)

win = WINDOW(DIMENSIONS=[600, 600], BACKGROUND_COLOR=[240, 240, 240])

p1 = PLOT(x, y1, XRANGE=[0, 100], /CURRENT, POSITION=positions[0, *], $

  THICK=2, COLOR='red')

p2 = PLOT(x, y2, XRANGE=[0, 100], /CURRENT, POSITION=positions[1, *], $

  THICK=2, COLOR='green')

p3 = PLOT(x, y3, XRANGE=[0, 100], /CURRENT, POSITION=positions[2, *], $

  THICK=2, COLOR='blue')

p4 = PLOT(x, y4, XRANGE=[0, 100], /CURRENT, POSITION=positions[3, *], $

  THICK=2, COLOR='magenta')


여기서는 GET_POSITIONS 함수를 사용하여 얻은 위치좌표 값들로 구성된 positions라는 배열을 PLOT 함수의 POSITION 속성에 부여하는 방식을 사용하고 있습니다. 이렇게 하면 다음 그림과 같은 결과를 얻을 수 있습니다.



이 그림은 마치 지난 회 게시물에 있었던 세번째 그림과 유사합니다. 네 개의 플롯들이 서로 밀착되어 있는 상태라는 점에서는 그렇습니다. 그런데 차이점이 있습니다. 지난 회의 그림에서는 네 개의 플롯들 전체가 화면을 꽉 채웠던 반면, 오늘 그린 그림에서는 플롯들끼리는 서로 밀착이 되어 있으면서도 전체적으로는 그래픽창에 꽉 차진 않습니다. 약간의 여백을 두고 있는 상황입니다. 그 이유는 오늘 우리가 사용하고 있는 GET_POSITIONS 함수가 개별 그림들간의 여백 뿐 아니라 전체 집단의 그래픽창에 대한 여백도 설정할 수 있도록 만들어져 있기 때문입니다. 즉, "그림간 여백"과 "그림들 외곽의 여백"을 따로 설정할 수 있습니다. GET_POSITIONS함수에는 이러한 설정을 위하여 GAP, XMARGIN, YMARGIN 키워드들을 지원합니다. 이 중 XMARGIN, YMARGIN은 "그림들 외곽의 여백"에 해당되며, GAP은 "그림간 여백"에 해당됩니다. XMARGIN, YMARGIN 키워드의 값은 각각 [0.1, 0.1]과 같은 형태의 값들이 됩니다. XMARGIN의 경우에는 좌측 및 우측 여백이 되며, YMARGIN의 경우에는 하단 및 상단 여백이 됩니다. 디폴트값은 0.1이며, [0.1, 0.1]과 같이 두 값이 동일한 경우에는 그냥 0.1 단일값으로 적어도 됩니다. GAP의 경우에는 그림들 사이사이 여백에 대한 X, Y 방향의 값들로 구성된 배열 또는 단일값을 부여하면 됩니다. 디폴트값은 0입니다.


위의 예제코드에서 GET_POSITIONS 함수가 사용되는 방법만 살짝 바꿔봅시다. 먼저 XMARGIN, YMARGIN 키워드의 값을 다음과 같이 각각 0.2로 설정해서 플롯들을 그려보면 그 결과는 다음 그림과 같습니다.


positions = GET_POSITIONS(2, 2, XMARGIN=0.2, YMARGIN=0.2)



그리고 이번에는 다음과 같이 GAP의 값을 0.05로 설정하고 XMARGIN, YMARGIN은 디폴트 값을 그대로 사용하도록 해보면 그 결과는 다음 그림과 같습니다.


positions = GET_POSITIONS(2, 2, GAP=0.05)



물론 플롯들 사이의 간격에 따라 축 라벨문자들을 그냥 두거나 아니면 제거하는 것은 지난 회 게시물에서 언급했던 XSHOWTEXT, YSHOWTEXT와 같은 속성을 사용하여 필요에 맞게 조정하면 됩니다. 다음 두 그림은 이러한 예제들입니다. 특히 두번째 것은 구획을 1X3의 형태로 즉, 세 개의 플롯을 세로 방향으로 배치한 것으로, 동일한 X축 데이터를 공유하는 서로 다른 데이터들을 표출할 때 유용한 방법입니다. 구현 방법은 위의 예제 코드들의 내용과 유사하므로 생략합니다.



이와 같이 GET_POSITIONS 함수를 키워드들과 함께 사용하면 다중 플롯을 표출하는데 있어서 다양한 방식의 적용이 가능합니다.따라서 지난 회에서 언급했던 방법과 병행해서 알아두고 목적에 맞는 방법을 사용하면 좋을 것 같습니다. 당연한 얘기겠지만, 오늘 소개한 방법의 경우도 유사한 성격인 BARPLOT, SCATTERPLOT 등과 같은 NG 체계의 그래픽 함수들에서도 동일한 방식으로 적용이 가능하다는 점을 참조하시기 바랍니다. GET_POSITIONS 함수의 파일은 아래에 첨부합니다.


get_positions.pro



get_positions.pro
0.0MB
get_positions.pro
0.0MB
get_positions.pro
0.0MB
LIST