본문 바로가기
자료처리

바람장미 파이썬 코드

by Prof. Sung-Deuk Choi 2026. 9. 8.

대기오염 수업시간에 예시로 보여줄 바람장미 파이썬 코드입니다. 

기본 코드는 Claude로 작성했고, Spyder로 표출할 때 생기는 오류 수정 등은 Gemini를 사용했습니다. 이후 세부적인 수정은 Spyder에서 직접했습니다.

 

기상청에서 입수한 2024년 울산 기상자료입니다.

OBS_ASOS_TIM_20250917112548.csv
0.90MB
2024년 울산 연간/계절별 바람장미

 

기상청 바람장비와 잘 맞습니다.  기상자료개방포털[기후통계분석:계급별일수:바람 계급별일수(바람장미)]

 

 

import pandas as pd
import matplotlib.pyplot as plt
from windrose import WindroseAxes


plt.rcParams['font.family'] = 'Arial'

# 1. 자료 불러오기 및 데이터 전처리
file_path = r'C:\Users\ 본인 파일 경로 \OBS_ASOS_TIM_20250917112548.csv' # 기상청 1년 자료
df = pd.read_csv(file_path, encoding='cp949')

data = df[['일시', '풍속(m/s)', '풍향(16방위)']].dropna().copy()
data['풍속(m/s)'] = data['풍속(m/s)'].astype(float)
data['풍향(16방위)'] = data['풍향(16방위)'].astype(float)

# 날짜 변환 및 계절 구분
data['일시'] = pd.to_datetime(data['일시'])
month = data['일시'].dt.month

def get_season(m):
    if m in [3, 4, 5]:
        return 'Spring (3-5)'
    elif m in [6, 7, 8]:
        return 'Summer (6-8)'
    elif m in [9, 10, 11]:
        return 'Fall (9-11)'
    else:
        return 'Winter (12-2)'

data['계절'] = month.apply(get_season)
# bins_range = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
bins_range = [0, 1, 2, 3, 4, 5]


# -------------------------------------------------------------
# ★ 범례 텍스트 커스텀 변환 함수 (대괄호 제거 및 en-dash 변경)
# -------------------------------------------------------------
def fix_legend_labels(legend):
    for text in legend.get_texts():
        t = text.get_text()
        t = t.replace('[', '').replace(')', '').replace(']', '')
        t = t.replace(':', '–')
        # '>' 기호 바로 뒤에 공백 추가 (예: '>9.0' -> '> 9.0')
        t = t.replace('>', '> ')
        text.set_text(t)


# ==========================================
# [그림 1] 1년 전체 바람장미 (단독 창)
# ==========================================
fig1 = plt.figure(figsize=(8, 7))
ax1 = fig1.add_subplot(1, 1, 1, projection='windrose')

ax1.bar(
    data['풍향(16방위)'], data['풍속(m/s)'],
    normed=True,
    opening=0.8,
    edgecolor='white',
    bins=bins_range,
    cmap=plt.cm.jet
)
ax1.set_title('Wind Rose - Ulsan Station (152), Yearly Overall', fontsize=14, pad=20, fontweight='bold')

# 범례 생성 후 텍스트 수정 적용
leg1 = ax1.set_legend(
    title='Wind speed (m/s)', 
    loc='lower right', 
    bbox_to_anchor=(1.25, -0.05)
)
fix_legend_labels(leg1)


# ==========================================
# [그림 2] 계절별 바람장미 (2x2 배열)
# ==========================================
fig2 = plt.figure(figsize=(12, 10))

seasons_list = [
    ('Spring (3-5)', data[data['계절'] == 'Spring (3-5)']),
    ('Summer (6-8)', data[data['계절'] == 'Summer (6-8)']),
    ('Fall (9-11)', data[data['계절'] == 'Fall (9-11)']),
    ('Winter (12-2)', data[data['계절'] == 'Winter (12-2)'])
]

for idx, (season_name, s_data) in enumerate(seasons_list, 1):
    ax2 = fig2.add_subplot(2, 2, idx, projection='windrose')
    
    ax2.bar(
        s_data['풍향(16방위)'], s_data['풍속(m/s)'],
        normed=True,
        opening=0.8,
        edgecolor='white',
        bins=bins_range,
        cmap=plt.cm.jet
    )
    ax2.set_title(f'Ulsan (152) - {season_name}', fontsize=12, pad=15, fontweight='bold')
    
    # 범례 생성 후 텍스트 수정 적용
    leg2 = ax2.set_legend(
        title='WS (m/s)', 
        loc='lower right', 
        bbox_to_anchor=(1.28, -0.05), 
        fontsize=8
    )
    fix_legend_labels(leg2)

fig2.tight_layout()

# 5. 그림 출력
plt.show()

 

댓글