- 개요
하나의 axes에 그림을 여러 개 그리면 같은 코드를 여러 번 반복할 수밖에 없습니다.
저는 6개의 변수를 그리기 때문에 6번의 비슷한 코드가 반복되죠.
이런 부분은 for문으로 만들어야 관리 및 함수화하기 쉽습니다.
만약 for문으로 만들지 않는다면?
실수를 1번 했을 때 수정을 6번 해야합니다. (같은 코드가 6번 반복되니까)
또한, 나중에 코드를 재활용할 때도 수정을 6번 해야합니다.
그리고 보통 몇 주, 몇 개월 후에 코드를 재활용하는 경우가 많습니다.
오랜만에 코드를 다시보면 이 코드가 어떤 순서로 동작하는지 기억도 잘 안나는데
코드는 엄청 길기 때문에 어디를 수정해야되는지도 알기 어려워 혼란스러울겁니다.
그리고 기상청 ASOS/AWS 따라그리기에 대한 포스트를 더 연재할 것이라 코드를 for문으로 만들어야 제가 다루기 좋습니다. 그럼 지금까지 만든 코드에 for문을 넣어보겠습니다.
- spines method의 두가지 형태
spine method를 쓰는 코드라인을 되짚어 보면
ax.spines.right.set_position()과 같은 식으로
spines 뒤에 .left, .right가 있어 y축의 왼쪽인지 오른쪽인지 지정을 해줍니다.
이렇게 .을 붙여서 method로 호출해도 되지만
ax.spines['right'].set_position()처럼 사용해도 됩니다.
즉 ax.spines.right.set_position()와 ax.spines['right'].set_position()는 같습니다.
for문에서는 parameter를 담는 변수를 선언하고 이를 전달하는 방식으로 코딩할 것이므로 후자를 쓰는 것이 좋습니다.
- for문으로 만든 코드
import matplotlib.pyplot as plt
# 변수의 이상치를 처리하는 작업을 먼저 해야함
df['WS10'][df['WS10'] == -99.9] = np.NaN
color_TA = 'red'
color_PS = (255./255., 51./255., 204./255.)
color_HM = (0, 102./255., 153/255.)
color_WS = (50./255., 108./255., 17./255.)
color_WD = (255./255., 153./255., 51./255.)
color_RN60 = (102./255., 153./255., 1.)
color_RN15 = (1., 153./255., 1.)
color_RE = (204./255., 255./255., 255./255.)
# 그림을 그릴 때 필요한 변수를 담는 매개인자(parameter) 선언
# 강수 > 온도 > 현지기압 > 습도 > 풍속 > 풍향 순
varnames = ['RN-60m', 'TA', 'PS', 'HM', 'WS10', 'WD10']
colors = [color_RN60, color_TA, color_PS, color_HM, color_WS, color_WD]
ymins = [0, 16, 999, 0, 0, 90] # y최소값
ymaxs = [40, 36, 1019, 100, 20, 90+360] # y최댓값
dys = [4, 2, 2, 10, 2, 90] # y간격
# True는 왼쪽 y축, False는 오른쪽 y축
direction = [True, True, False, False, True, True]
# True면 right, False면 left
direction_str = ['left' if i == True else 'right' for i in direction]
# direction_str과 방향을 반대로
direction_str_reverse = ['right' if i == True else 'left' for i in direction]
# y축 위치 설정
spine_set_positions = [70, 0, 0, 35, 25, 50]
fig = plt.figure(figsize=(13,5))
for i, varname in enumerate(varnames):
if varname == 'RN-60m':
ax_base = fig.add_subplot()
ax = ax_base
x = range(len(df[varname]))
dx = x[1] - x[0]
ax.bar(x, df['RE']*40, color=color_RE, width=dx)
ax.bar(x, df[varname], color=colors[i], width=dx)
ax.bar(x, df['RN-15m'], color=color_RN15, width=dx)
else:
if varname == 'WD10':
df.loc[df[varname] < 90, varname] += 360
ax = ax_base.twinx()
ax.scatter(x, df[varname], color=colors[i], s=4)
else:
ax = ax_base.twinx()
ax.plot(x, df[varname], color=colors[i], lw=1)
ymin, ymax, dy = ymins[i], ymaxs[i], dys[i]
ax.set_ylim(ymin, ymax)
ax.set_yticks(range(ymin, ymax+1, dy))
# set_yticks를 먼저 선언 안하면 set_yticklabels 선언시 오류가 남
if varname == 'WD10':
ax.set_yticklabels(['E', 'S', 'W', 'N', 'E'])
ax.spines[direction_str[i]].set_position(('outward', spine_set_positions[i]))
ax.spines[direction_str_reverse[i]].set_visible(False)
ax.yaxis.set_ticks_position(direction_str[i])
ax.yaxis.set_label_position(direction_str[i])
ax.tick_params(axis='y', which='both', length=0)
ax.tick_params(axis='y', labelcolor=colors[i])
if varname == 'TA' or varname == 'PS':
ax.spines[direction_str[i]].set_color('gray')
ax.spines[direction_str[i]].set_linewidth(2)
else:
ax.spines[direction_str[i]].set_color(colors[i])
ax.spines[direction_str[i]].set_linewidth(2)
솔직히 그냥 이전에 있던 코드를 for문으로 바꾼 것뿐이라 딱히 설명할 것이 더 없네요.
참고로 이번 연재에서는 딱히 자동화를 다룰 생각은 없습니다만
아래의 작업을 하시면 그림 그리는 일을 자동화 할 수 있습니다.
1. 그림 그리는 부분을 함수 혹은 클래스로 변환하되 parameter값을 입력값으로 받음
2. 다양한 parameter값을 저장하는 문서 작성 (보통 configuration 파일이라 부름)
3. configuration 파일을 수정할 수 있는 코드 작성(보통 shell 파일로 작성함)
위의 작업을 하면 3개의 코드가 나올텐데 하나의 코드에서 위의 세 작업을 수행해도 큰 상관은 없습니다.
다만 이러면 코드가 길어져서 유지, 보수가 어렵습니다.
다음 포스트에서는 y축 위에 변수 이름, y축 아래에 변수의 단위를 추가해보겠습니다.
'대기과학 > 프로그래밍' 카테고리의 다른 글
[Matplotlib] 기상청 ASOS/AWS 그래프 따라 그리기 7: x축 라벨 적기 (0) | 2024.07.25 |
---|---|
[Matplotlib] 기상청 ASOS/AWS 그래프 따라 그리기 6: y축 제목, 단위 적기 (2) | 2024.07.23 |
[Matplotlib] 기상청 ASOS/AWS 그래프 따라 그리기 4: y축, 축의 라벨 색 바꾸기 (0) | 2024.07.18 |
[Matplotlib] 기상청 ASOS/AWS 그래프 따라 그리기 3: 선과 음영 그리기 (1) | 2024.07.12 |
[Matplotlib] 기상청 ASOS/AWS 그래프 따라 그리기 2: 왼쪽에 y축 여러 개 그리기 (0) | 2024.07.11 |