대기과학/프로그래밍

[Matplotlib] 기후 나선 그리기 3: 밑그림 그리기

레까 2024. 9. 24. 09:50

- 개요

저번 포스트에서는 기온 자료의 전처리 작업을 했습니다.

이번 포스트에서는 기온 자료를 시각화하기 전에

NASA Climate change 기후 나선 그림에서 1, 0, -1도를 나타내는 원과 그림 중앙의 연도, 외곽의 1~12월 문자를 밑그림으로 그립니다. 

 

이번 포스트에서 그릴 밑그림

- 밑그림 그리기

원을 그리는 것과 1월부터 12월을 텍스트로 적는 것은 반복 작업이므로 하나하나 적지말고 함수를 만듭니다.

저는 극좌표계로 생각하고 이를 x ,y 좌표로 변환해서 그림을 그렸습니다.

코드에서 r은 반지름을 의미합니다.

 

1. 기본 그림

matplotlib으로 그림을 그리면 기본 하얀 바탕에 축이 그려집니다.

우린 검은 바탕을 써야하고, 축을 지워야 합니다.

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(7,7))
fig.patch.set_facecolor('black') # 기본 바탕색을 검정
ax = fig.add_subplot()

'''
저는 그림을 다 완성했기 때문에 x, y 범위를 정확히 적을 수 있는 것입니다.
실제로는 여러가지값을 테스트하며 그립니다.
'''
ax.set_xlim(-6.5, 6.5) 
ax.set_ylim(-6.5, 6.5)
ax.set_axis_off() # 축 제거

 

2. 원 그리는 함수 정의: draw_circle(ax, r_offset, circle_offset, dtheta, color)

입력 변수 설명

ax matplotlib의 axes class로 그림을 그릴 곳
r_offset 원래 극좌표계에서 r=0이면 화면의 중심을 의미하지만 NASA Climate change 그림을 보면 0도는 중심이 아닙니다. 즉, 0일 때는 반지름에 특정값을 더해서 원을 그려야합니다.
circle_offset 다른 크기의 원을 3개 그려야 하므로 반지름을 조절하는 부분.
r_offset도 같은 기능을 하지만 circle_offset=0이면 0도 원, -1이면 -1도원처럼 알아보기 쉽게하려고 offset을 하나 더 만듭니다.
dtheta 원의 윗부분에는 온도값을 넣어야하기 때문에 윗부분은 그리면 안됩니다.
dtheta를 크게 할수록 원의 윗부분의 빈공간이 커집니다.
color 원의 색 (0도 원은 색이 다름)

 

 

# 상수 정의
PI = np.pi
YELLOW = (202/255.,183/255.,24/255.)
GREEN = (0., 176/255., 0.)
str_month = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 
				'AUG', 'SEP', 'OCT', 'NOV', 'DEC' ] # 1~12월 텍스트 선언

r_offset = 2. # 원래 r에 r_offset을 더해서 그림

def draw_circle(ax, r_offset, circle_offset, dtheta, color):
    theta = np.linspace(90 + dtheta, 360 + 90 - dtheta, 361)
    x = (r_offset + circle_offset) * np.cos(theta / 180. * PI)
    y = (r_offset + circle_offset) * np.sin(theta / 180. * PI)
    ax.plot(x, y, c=color)

 

3. 1~12월을 적는 함수: draw_text_month(ax, str_month, theta):

입력 변수 설명

ax matplotlib의 axes class로 그림을 그릴 곳
str_month 1월부터 12월까지를 Jan ~ Dec인 글자로 넣어야함
theta 텍스트가 써지는 위치의 각도(극좌표계의 각도값)

 

'''
극좌표계의 0도는 12시방향이 아니라 3시 방향입니다.
그리고 각도가 증가하면 반시계방향으로 회전합니다.
하지만 이 그림에서는 1월이 12시에 위치하고 각도가 증가하면 시계방향으로 가야합니다.
'''
theta = np.linspace(0+90, -360+90, 13) # 90도가 12시방향
theta = theta[:-1] # 반시계방향을 시계방향으로 전환

def draw_text_month(ax, str_month, theta):
    for i in range(len(str_month)):
        x = 6.3 * np.cos(theta[i] / 180. * PI)
        y = 6.3 * np.sin(theta[i] / 180. * PI)
        # ha, va는 center로 하면 텍스트의 중심이 좌표가 됩니다.
        ax.text(x, y, str_month[i], ha='center', va='center', c=YELLOW, size= 12)

 

4. 밑그림 그리기

연도를 적는 건 따로 설명하기에는 너무 짧아 그냥 여기에서 추가합니다.

 

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib import cm
from matplotlib.colors import Normalize
PI = np.pi
YELLOW = (202/255.,183/255.,24/255.)
GREEN = (0., 176/255., 0.)
r_offset = 2.

str_month = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC' ]

fig = plt.figure(figsize=(7,7))
fig.patch.set_facecolor('black')

ax = fig.add_subplot()

ax.set_xlim(-6.5, 6.5)
ax.set_ylim(-6.5, 6.5)
ax.set_axis_off()


#원 위에 빈 공간에 온도를 적는 코드, \u00b0C => 섭씨온도 문자
# -1, 0, 3.5도를 기준으로 세 개의 원을 그림
ax.text(0, -1 + r_offset, '-1\u00b0C', c=YELLOW, size=10, va= 'center', ha='center')
ax.text(0, 0 + r_offset, '0\u00b0C', c=GREEN, size=10, va= 'center', ha='center')
ax.text(0, 3.5 + r_offset, '+3.5\u00b0C', c=YELLOW, size=10, va= 'center', ha='center')

theta = np.linspace(0+90, -360+90, 13)
theta = theta[:-1]
draw_text_month(ax, str_month, theta)
draw_circle(ax, r_offset, -1, 25., YELLOW)
draw_circle(ax, r_offset, 0, 15., GREEN)
draw_circle(ax, r_offset, 3.5, 8., YELLOW)

ax.text(0, 0, '2024', c='white', size=14, ha='center', va='center') # 연도 적는 코드

 

밑그림

 

다음 포스트에서는 기온 자료를 밑그림 위에 그려보겠습니다.