콘텐츠 대표 이미지 - 데이터 시각화의 끝판왕: Plotly & Seaborn으로 만드는 인터랙티브 차트 완전 정복
🐍 Python · 데이터 시각화

데이터 시각화의 끝판왕: Plotly & Seaborn으로 만드는 인터랙티브 차트 완전 정복

정적인 그래프는 이제 그만 🚀 | 데이터를 살아 숨쉬게 만드는 파이썬 시각화 가이드

야 솔직히 말해서... 데이터 분석하고 나서 그냥 숫자만 쭉 나열하면 아무도 안 봄 ㅋㅋㅋ 진짜로. 아무리 인사이트가 쩔어도 "그래서 이게 뭔데?" 소리 듣기 딱 좋음. 그래서 데이터 시각화가 존재하는 거고, 그 중에서도 Plotly랑 Seaborn은 파이썬 생태계에서 진짜 투탑이라고 할 수 있음.

이 글에서는 두 라이브러리의 특성부터 실전 코드까지 싹 다 정리해줄 거니까 끝까지 집중해줘! 데이터 시각화 처음 접하는 사람도, 이미 좀 써봤는데 더 깊이 파고 싶은 사람도 다 커버할 수 있게 구성했음 😎


파이썬 데이터 시각화 라이브러리 비교 📊 Plotly 인터랙티브 차트의 제왕 ✅ 마우스 호버·줌·클릭 인터랙션 ✅ 웹 대시보드 연동 (Dash) ✅ 3D 차트 지원 ✅ HTML 파일로 저장·공유 가능 🎨 Seaborn 통계 시각화의 정석 ✅ 통계 기반 차트 자동 생성 ✅ Matplotlib 기반 고품질 출력 ✅ 데이터프레임 직접 연동 ✅ 논문·보고서용 정적 이미지 VS 상황에 맞게 골라 쓰는 게 진짜 고수의 길 💡

🔧 환경 세팅부터 시작하자

일단 설치부터 해야지 뭘 하든 ㅋㅋ 파이썬 환경에서 pip 명령어로 간단하게 설치 가능함.

# Plotly 설치
pip install plotly

# Seaborn 설치 (Matplotlib도 같이 설치됨)
pip install seaborn

# 주피터 노트북에서 Plotly 인터랙션 활성화
pip install notebook ipywidgets

# 데이터 분석 기본 패키지
pip install pandas numpy
💡 Tip! Jupyter Notebook이나 JupyterLab 환경에서 작업하면 Plotly 인터랙티브 차트가 바로 셀 안에서 렌더링됨. VS Code에서도 Jupyter 확장 설치하면 OK!

설치 완료했으면 이제 기본 임포트 구조를 알아두자. 매번 쓰는 거니까 외워두면 편함.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots

plotly.express는 빠르고 간단한 차트용, plotly.graph_objects는 세밀한 커스터마이징용이라고 생각하면 됨. 이 두 개의 차이를 이해하는 게 Plotly 마스터의 첫걸음임 😤


📊 Plotly Express로 5분 만에 인터랙티브 차트 만들기

Plotly Express(px)는 진짜 말도 안 되게 간단함. 코드 몇 줄로 인터랙티브 차트가 뚝딱 나옴. 처음 보면 "이게 맞아?" 싶을 정도 ㅋㅋㅋ

📈 기본 라인 차트
import plotly.express as px
import pandas as pd
import numpy as np

# 샘플 데이터 생성
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=100)
df = pd.DataFrame({
    '날짜': dates,
    '매출': np.cumsum(np.random.randn(100) * 100 + 50),
    '비용': np.cumsum(np.random.randn(100) * 80 + 30)
})

# 라인 차트 생성
fig = px.line(
    df,
    x='날짜',
    y=['매출', '비용'],
    title='월별 매출 vs 비용 추이',
    labels={'value': '금액(만원)', 'variable': '항목'},
    color_discrete_map={'매출': '#5b9bd5', '비용': '#e8a96a'}
)

fig.update_layout(
    plot_bgcolor='#f8f9fa',
    paper_bgcolor='white',
    font=dict(family='Malgun Gothic', size=13),
    hovermode='x unified'  # 호버 시 같은 x축 값 한번에 표시
)

fig.show()
🖱️ 인터랙션 포인트: 마우스를 차트 위에 올리면 정확한 값이 툴팁으로 표시되고, 드래그로 특정 구간을 줌인할 수 있음. 우상단 버튼으로 PNG 저장도 가능!
🔵 산점도 (Scatter Plot)

산점도는 두 변수 간의 관계를 볼 때 쓰는 건데, Plotly로 만들면 각 점에 마우스 올렸을 때 해당 데이터 정보가 다 뜸. 진짜 개꿀 기능임.

# 내장 데이터셋 활용 (gapminder)
df_gap = px.data.gapminder().query("year == 2007")

fig = px.scatter(
    df_gap,
    x='gdpPercap',
    y='lifeExp',
    size='pop',           # 버블 크기 = 인구수
    color='continent',    # 색상 = 대륙
    hover_name='country', # 호버 시 국가명 표시
    log_x=True,           # x축 로그 스케일
    size_max=60,
    title='2007년 국가별 GDP vs 기대수명 (버블 크기 = 인구)',
    labels={
        'gdpPercap': '1인당 GDP (달러)',
        'lifeExp': '기대수명 (세)',
        'continent': '대륙'
    }
)

fig.update_layout(
    plot_bgcolor='#f8f9fa',
    paper_bgcolor='white'
)

fig.show()

이 코드 한 번 실행해봐. 각 나라 버블에 마우스 올리면 국가명, GDP, 기대수명, 인구 다 뜨고 대륙별로 색이 구분됨. 이걸 정적 이미지로 만들면 절대 이 정보량을 담을 수 없음 ㅋㅋ

📊 막대 차트 + 애니메이션

Plotly의 진짜 킬러 기능 중 하나가 애니메이션임. 시간에 따른 변화를 슬라이더로 조작하면서 볼 수 있음.

# 연도별 대륙 GDP 변화 애니메이션
df_anim = px.data.gapminder()

fig = px.bar(
    df_anim,
    x='continent',
    y='gdpPercap',
    color='continent',
    animation_frame='year',    # 연도별 애니메이션
    animation_group='country',
    range_y=[0, 50000],
    title='연도별 대륙별 평균 GDP 변화',
    labels={
        'gdpPercap': '1인당 GDP',
        'continent': '대륙'
    }
)

fig.update_layout(
    showlegend=False,
    plot_bgcolor='#f8f9fa'
)

fig.show()
💡 animation_frame 파라미터 하나로 슬라이더가 자동 생성됨. 재생 버튼 누르면 연도별로 자동 전환되는 애니메이션이 실행됨. 발표 자료로 쓰면 진짜 임팩트 쩔음 🔥

🎯 Plotly Graph Objects로 세밀하게 커스터마이징

px가 빠른 프로토타이핑용이라면, go(graph_objects)는 세밀한 제어가 필요할 때 씀. 좀 더 코드가 길어지지만 그만큼 자유도가 높음.

🍩 도넛 차트 만들기
import plotly.graph_objects as go

labels = ['파이썬', '자바스크립트', '자바', 'C++', '기타']
values = [35, 28, 18, 12, 7]
colors = ['#5b9bd5', '#7bbf6a', '#e8a96a', '#d57b7b', '#a89bd5']

fig = go.Figure(data=[go.Pie(
    labels=labels,
    values=values,
    hole=0.45,          # 도넛 구멍 크기 (0~1)
    marker=dict(
        colors=colors,
        line=dict(color='white', width=2)
    ),
    textinfo='label+percent',
    hovertemplate='<b>%{label}</b><br>비율: %{percent}<br>응답수: %{value}명<extra></extra>'
)])

fig.update_layout(
    title=dict(
        text='2024 개발자 선호 언어 조사',
        font=dict(size=18, color='#1e3a5f')
    ),
    showlegend=True,
    legend=dict(orientation='h', yanchor='bottom', y=-0.2),
    paper_bgcolor='white'
)

fig.show()
📉 서브플롯 (여러 차트 한 화면에)

대시보드처럼 여러 차트를 한 화면에 배치하고 싶을 때 make_subplots를 씀.

from plotly.subplots import make_subplots
import plotly.graph_objects as go
import numpy as np

# 2행 2열 서브플롯 생성
fig = make_subplots(
    rows=2, cols=2,
    subplot_titles=('라인 차트', '막대 차트', '산점도', '히스토그램'),
    vertical_spacing=0.12,
    horizontal_spacing=0.08
)

x = np.linspace(0, 10, 50)

# 1행 1열: 라인 차트
fig.add_trace(
    go.Scatter(x=x, y=np.sin(x), name='sin(x)',
               line=dict(color='#5b9bd5', width=2)),
    row=1, col=1
)

# 1행 2열: 막대 차트
categories = ['A', 'B', 'C', 'D', 'E']
values = [23, 45, 12, 67, 34]
fig.add_trace(
    go.Bar(x=categories, y=values, name='카테고리별',
           marker_color='#7bbf6a'),
    row=1, col=2
)

# 2행 1열: 산점도
fig.add_trace(
    go.Scatter(
        x=np.random.randn(100),
        y=np.random.randn(100),
        mode='markers',
        name='랜덤 데이터',
        marker=dict(color='#e8a96a', size=6, opacity=0.7)
    ),
    row=2, col=1
)

# 2행 2열: 히스토그램
fig.add_trace(
    go.Histogram(
        x=np.random.normal(0, 1, 500),
        name='정규분포',
        marker_color='#d57b7b',
        opacity=0.75
    ),
    row=2, col=2
)

fig.update_layout(
    height=600,
    title_text='대시보드 스타일 서브플롯',
    showlegend=False,
    plot_bgcolor='#f8f9fa',
    paper_bgcolor='white'
)

fig.show()
📌 핵심 포인트: make_subplots로 생성한 레이아웃에 add_trace()로 차트를 하나씩 추가하는 방식. row와 col로 위치 지정함.

Seaborn 차트 유형 한눈에 보기 📊 분포 시각화 histplot kdeplot ecdfplot rugplot 🔗 관계 시각화 scatterplot lineplot relplot pairplot 📦 범주형 시각화 boxplot violinplot barplot stripplot 🗺️ 행렬 시각화 heatmap clustermap pairplot jointplot 🎯 Seaborn의 핵심 철학 "최소한의 코드로 최대한의 통계적 인사이트를 시각화한다" 💡 언제 뭘 써야 할까? 탐색적 데이터 분석(EDA) → Seaborn | 웹 대시보드·발표 자료 → Plotly 논문·보고서 정적 이미지 → Seaborn | 실시간 인터랙션 필요 → Plotly

🎨 Seaborn으로 통계 시각화 제대로 하기

Seaborn은 Matplotlib 위에 올라탄 고수준 라이브러리인데, 통계적 시각화에 특화되어 있음. 특히 EDA(탐색적 데이터 분석) 단계에서 진짜 빛을 발함 ✨

🌡️ 히트맵 (상관관계 분석)

변수들 간의 상관관계를 한눈에 보여주는 히트맵은 데이터 분석에서 거의 필수로 씀.

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# 한글 폰트 설정 (Windows)
plt.rcParams['font.family'] = 'Malgun Gothic'
plt.rcParams['axes.unicode_minus'] = False

# 샘플 데이터 생성
np.random.seed(42)
df = pd.DataFrame({
    '매출': np.random.randn(100) * 100 + 500,
    '광고비': np.random.randn(100) * 50 + 200,
    '방문자수': np.random.randn(100) * 1000 + 5000,
    '전환율': np.random.randn(100) * 0.05 + 0.15,
    '고객만족도': np.random.randn(100) * 0.5 + 4.0
})

# 상관관계 행렬 계산
corr_matrix = df.corr()

# 히트맵 그리기
fig, ax = plt.subplots(figsize=(8, 6))

sns.heatmap(
    corr_matrix,
    annot=True,          # 셀 안에 수치 표시
    fmt='.2f',           # 소수점 2자리
    cmap='RdYlBu_r',     # 색상 팔레트
    center=0,            # 0을 중심으로 색상 분기
    square=True,         # 정사각형 셀
    linewidths=0.5,      # 셀 경계선
    cbar_kws={'shrink': 0.8},
    ax=ax
)

ax.set_title('변수 간 상관관계 히트맵', fontsize=15, fontweight='bold', pad=15)
plt.tight_layout()
plt.savefig('heatmap.png', dpi=150, bbox_inches='tight')
plt.show()
🎻 바이올린 플롯

박스플롯보다 훨씬 더 많은 정보를 담을 수 있는 바이올린 플롯. 분포의 형태까지 보여줌.

# 내장 데이터셋 활용
tips = sns.load_dataset('tips')

fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# 왼쪽: 바이올린 플롯
sns.violinplot(
    data=tips,
    x='day',
    y='total_bill',
    hue='sex',
    split=True,          # 성별로 반반 나눠서 표시
    palette={'Male': '#5b9bd5', 'Female': '#d57b7b'},
    inner='quart',       # 내부에 사분위수 표시
    ax=axes[0]
)
axes[0].set_title('요일별 계산서 금액 분포 (성별)', fontsize=13, fontweight='bold')
axes[0].set_xlabel('요일')
axes[0].set_ylabel('계산서 금액 ($)')

# 오른쪽: 박스플롯 + 스트립플롯 조합
sns.boxplot(
    data=tips,
    x='day',
    y='tip',
    palette='pastel',
    ax=axes[1]
)
sns.stripplot(
    data=tips,
    x='day',
    y='tip',
    color='#2d2d2d',
    alpha=0.4,
    size=3,
    ax=axes[1]
)
axes[1].set_title('요일별 팁 분포', fontsize=13, fontweight='bold')
axes[1].set_xlabel('요일')
axes[1].set_ylabel('팁 ($)')

plt.tight_layout()
plt.show()
🔍 페어플롯 (pairplot)

데이터셋의 모든 수치형 변수 쌍의 관계를 한 번에 보여주는 페어플롯. EDA할 때 진짜 자주 씀.

iris = sns.load_dataset('iris')

# 페어플롯 생성
g = sns.pairplot(
    iris,
    hue='species',           # 종별 색상 구분
    palette={'setosa': '#5b9bd5', 
             'versicolor': '#7bbf6a', 
             'virginica': '#e8a96a'},
    diag_kind='kde',         # 대각선: KDE 분포
    plot_kws={'alpha': 0.6, 's': 40},
    diag_kws={'alpha': 0.7}
)

g.fig.suptitle('붓꽃 데이터셋 페어플롯', y=1.02, fontsize=15, fontweight='bold')
plt.show()
⚠️ 주의! 변수가 많을수록 페어플롯 생성 시간이 기하급수적으로 늘어남. 변수가 10개 이상이면 상관관계 히트맵으로 먼저 필터링하고 중요한 변수만 페어플롯 그리는 게 효율적임.

🚀 Plotly + Seaborn 실전 조합 레시피

실제 데이터 분석 프로젝트에서는 두 라이브러리를 상황에 맞게 섞어 쓰는 게 베스트임. 탐색은 Seaborn으로 빠르게, 최종 결과물은 Plotly로 인터랙티브하게 만드는 패턴이 많이 쓰임.

🌊 Seaborn 스타일을 Plotly에 적용하기
import plotly.express as px
import plotly.graph_objects as go

# Seaborn 팔레트를 Plotly에서 활용
import seaborn as sns
palette = sns.color_palette("husl", 8)
# RGB 튜플을 hex 코드로 변환
hex_colors = ['#{:02x}{:02x}{:02x}'.format(
    int(r*255), int(g*255), int(b*255)
) for r, g, b in palette]

# Plotly에 Seaborn 색상 적용
df = px.data.gapminder().query("year == 2007")
fig = px.scatter(
    df,
    x='gdpPercap',
    y='lifeExp',
    color='continent',
    size='pop',
    hover_name='country',
    log_x=True,
    color_discrete_sequence=hex_colors,
    title='Seaborn 팔레트 + Plotly 인터랙션의 조합'
)
fig.show()
📊 FacetGrid 스타일 인터랙티브 차트

Seaborn의 FacetGrid처럼 조건별로 나눠서 보는 걸 Plotly에서도 구현할 수 있음.

import plotly.express as px

tips = px.data.tips()

# facet_col로 요일별 분리, facet_row로 성별 분리
fig = px.histogram(
    tips,
    x='total_bill',
    color='smoker',
    facet_col='day',
    facet_row='sex',
    nbins=20,
    title='요일 × 성별 × 흡연여부별 계산서 금액 분포',
    color_discrete_map={'Yes': '#e8a96a', 'No': '#5b9bd5'},
    labels={
        'total_bill': '계산서 금액',
        'smoker': '흡연 여부',
        'day': '요일',
        'sex': '성별'
    }
)

fig.update_layout(
    plot_bgcolor='#f8f9fa',
    paper_bgcolor='white',
    height=500
)

fig.show()
🎯 실전 팁: facet_col과 facet_row를 조합하면 Seaborn의 FacetGrid와 동일한 효과를 인터랙티브하게 구현 가능. 각 서브플롯이 독립적으로 줌/호버 기능을 지원함!

🗺️ 지도 시각화 (Plotly Geo Charts)

Plotly의 숨겨진 강점 중 하나가 바로 지도 시각화임. 지리 데이터를 다룰 때 진짜 강력함 ㅋㅋ

import plotly.express as px

# 국가별 데이터 시각화 (Choropleth Map)
df = px.data.gapminder().query("year == 2007")

fig = px.choropleth(
    df,
    locations='iso_alpha',        # ISO 국가 코드
    color='lifeExp',              # 색상으로 표현할 값
    hover_name='country',
    color_continuous_scale='RdYlGn',  # 빨강→노랑→초록
    range_color=[40, 85],
    title='2007년 국가별 기대수명 세계 지도',
    labels={'lifeExp': '기대수명(세)'}
)

fig.update_layout(
    geo=dict(
        showframe=False,
        showcoastlines=True,
        projection_type='natural earth'
    ),
    coloraxis_colorbar=dict(
        title='기대수명',
        ticksuffix='세'
    )
)

fig.show()
# 버블 맵 (특정 위치에 버블 표시)
import plotly.express as px
import pandas as pd

# 한국 주요 도시 데이터
cities = pd.DataFrame({
    '도시': ['서울', '부산', '인천', '대구', '대전', '광주'],
    '위도': [37.5665, 35.1796, 37.4563, 35.8714, 36.3504, 35.1595],
    '경도': [126.9780, 129.0756, 126.7052, 128.6014, 127.3845, 126.8526],
    '인구': [9720846, 3404423, 2947217, 2427954, 1471040, 1441970],
    '지역': ['수도권', '영남', '수도권', '영남', '충청', '호남']
})

fig = px.scatter_mapbox(
    cities,
    lat='위도',
    lon='경도',
    size='인구',
    color='지역',
    hover_name='도시',
    hover_data={'인구': ':,', '위도': False, '경도': False},
    size_max=50,
    zoom=6,
    center={'lat': 36.5, 'lon': 127.8},
    mapbox_style='carto-positron',
    title='한국 주요 도시 인구 분포'
)

fig.update_layout(margin={'r': 0, 't': 40, 'l': 0, 'b': 0})
fig.show()
💡 scatter_mapbox를 쓰려면 Mapbox 토큰이 필요하거나 mapbox_style='open-street-map'처럼 오픈소스 스타일을 쓰면 됨. carto-positron은 토큰 없이도 사용 가능한 깔끔한 스타일!

⚡ 고급 기법: 커스텀 호버 & 업데이트 메뉴

Plotly의 진짜 고급 기능들을 알아보자. 이걸 쓸 줄 알면 진짜 프로처럼 보임 ㅋㅋㅋ

🖱️ 커스텀 호버 템플릿
import plotly.graph_objects as go
import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    '제품명': [f'제품{i}' for i in range(1, 21)],
    '매출': np.random.randint(100, 1000, 20),
    '이익률': np.random.uniform(0.05, 0.35, 20),
    '카테고리': np.random.choice(['전자', '의류', '식품', '가구'], 20)
})

# 카테고리별 색상 매핑
color_map = {'전자': '#5b9bd5', '의류': '#d57b7b', 
             '식품': '#7bbf6a', '가구': '#e8a96a'}

fig = go.Figure()

for category in df['카테고리'].unique():
    mask = df['카테고리'] == category
    subset = df[mask]
    
    fig.add_trace(go.Scatter(
        x=subset['매출'],
        y=subset['이익률'],
        mode='markers',
        name=category,
        marker=dict(
            size=12,
            color=color_map[category],
            opacity=0.8,
            line=dict(width=1, color='white')
        ),
        # 커스텀 호버 템플릿
        hovertemplate=(
            '<b>%{customdata[0]}</b><br>'
            '카테고리: ' + category + '<br>'
            '매출: %{x:,}만원<br>'
            '이익률: %{y:.1%}<br>'
            '<extra></extra>'  # 트레이스 이름 숨기기
        ),
        customdata=subset[['제품명']].values
    ))

fig.update_layout(
    title='제품별 매출 vs 이익률',
    xaxis_title='매출 (만원)',
    yaxis_title='이익률',
    yaxis_tickformat='.0%',
    plot_bgcolor='#f8f9fa',
    paper_bgcolor='white',
    hovermode='closest'
)

fig.show()
🎛️ 드롭다운 메뉴로 차트 전환
import plotly.graph_objects as go
import numpy as np

x = np.linspace(0, 4*np.pi, 200)

fig = go.Figure()

# 여러 함수 데이터 추가 (처음엔 sin만 보이게)
fig.add_trace(go.Scatter(
    x=x, y=np.sin(x), name='sin(x)',
    line=dict(color='#5b9bd5', width=2), visible=True
))
fig.add_trace(go.Scatter(
    x=x, y=np.cos(x), name='cos(x)',
    line=dict(color='#7bbf6a', width=2), visible=False
))
fig.add_trace(go.Scatter(
    x=x, y=np.tan(x), name='tan(x)',
    line=dict(color='#e8a96a', width=2), visible=False
))

# 드롭다운 메뉴 설정
fig.update_layout(
    title='삼각함수 선택 차트',
    updatemenus=[dict(
        type='dropdown',
        direction='down',
        x=0.1, y=1.15,
        showactive=True,
        buttons=[
            dict(label='sin(x)',
                 method='update',
                 args=[{'visible': [True, False, False]},
                       {'title': 'y = sin(x)'}]),
            dict(label='cos(x)',
                 method='update',
                 args=[{'visible': [False, True, False]},
                       {'title': 'y = cos(x)'}]),
            dict(label='tan(x)',
                 method='update',
                 args=[{'visible': [False, False, True]},
                       {'title': 'y = tan(x)'}]),
            dict(label='전체 보기',
                 method='update',
                 args=[{'visible': [True, True, True]},
                       {'title': '삼각함수 비교'}])
        ]
    )],
    plot_bgcolor='#f8f9fa',
    paper_bgcolor='white'
)

fig.show()
🎯 활용 포인트: 드롭다운 메뉴를 활용하면 하나의 차트에서 여러 시나리오를 전환해서 볼 수 있음. 발표 자료나 대시보드에서 진짜 유용한 기능!

💾 차트 저장 및 공유 방법

만든 차트를 어떻게 저장하고 공유하느냐도 중요함. 각 라이브러리별로 방법이 다름.

방법 라이브러리 코드 특징
HTML 저장 Plotly fig.write_html('chart.html') 인터랙션 유지, 공유 쉬움
PNG/SVG 저장 Plotly fig.write_image('chart.png') kaleido 패키지 필요
PNG 저장 Seaborn plt.savefig('chart.png', dpi=150) 고해상도 정적 이미지
JSON 저장 Plotly fig.write_json('chart.json') 나중에 재로드 가능
임베드 코드 Plotly fig.to_html(include_plotlyjs='cdn') 웹페이지에 삽입 가능
# Plotly HTML 저장 (인터랙션 완전 유지)
fig.write_html(
    'interactive_chart.html',
    include_plotlyjs='cdn',    # CDN에서 plotly.js 로드 (파일 크기 절약)
    full_html=True
)

# Plotly 이미지 저장 (kaleido 필요: pip install kaleido)
fig.write_image('chart.png', width=1200, height=800, scale=2)
fig.write_image('chart.svg')  # 벡터 이미지

# Seaborn/Matplotlib 저장
plt.savefig(
    'seaborn_chart.png',
    dpi=300,              # 해상도 (논문용은 300 이상)
    bbox_inches='tight',  # 여백 자동 조정
    facecolor='white'     # 배경색
)

🏆 실전 프로젝트: 판매 데이터 대시보드

지금까지 배운 걸 종합해서 실제로 쓸 수 있는 대시보드 스타일 시각화를 만들어보자. 이 정도 수준이면 포트폴리오에 올려도 손색없음 😎

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np

# 샘플 판매 데이터 생성
np.random.seed(42)
months = ['1월', '2월', '3월', '4월', '5월', '6월',
          '7월', '8월', '9월', '10월', '11월', '12월']
categories = ['전자제품', '의류', '식품', '가구']

# 월별 카테고리 매출 데이터
sales_data = {cat: np.random.randint(200, 800, 12) for cat in categories}
df_sales = pd.DataFrame(sales_data, index=months)

# 전체 월별 매출
total_sales = df_sales.sum(axis=1)

# 대시보드 레이아웃 생성
fig = make_subplots(
    rows=2, cols=2,
    subplot_titles=(
        '월별 총 매출 추이',
        '카테고리별 매출 비중',
        '카테고리별 월별 매출',
        '월별 성장률'
    ),
    specs=[
        [{'type': 'scatter'}, {'type': 'pie'}],
        [{'type': 'bar'}, {'type': 'bar'}]
    ],
    vertical_spacing=0.14,
    horizontal_spacing=0.1
)

# 1. 월별 총 매출 라인 차트
fig.add_trace(
    go.Scatter(
        x=months,
        y=total_sales,
        mode='lines+markers',
        name='총 매출',
        line=dict(color='#5b9bd5', width=3),
        marker=dict(size=8, color='#5b9bd5'),
        fill='tozeroy',
        fillcolor='rgba(91, 155, 213, 0.15)',
        hovertemplate='%{x}: %{y:,}만원<extra></extra>'
    ),
    row=1, col=1
)

# 2. 카테고리별 파이 차트
category_totals = df_sales.sum()
fig.add_trace(
    go.Pie(
        labels=category_totals.index,
        values=category_totals.values,
        hole=0.4,
        marker=dict(colors=['#5b9bd5', '#d57b7b', '#7bbf6a', '#e8a96a']),
        hovertemplate='%{label}: %{value:,}만원 (%{percent})<extra></extra>'
    ),
    row=1, col=2
)

# 3. 카테고리별 누적 막대 차트
colors = ['#5b9bd5', '#d57b7b', '#7bbf6a', '#e8a96a']
for i, cat in enumerate(categories):
    fig.add_trace(
        go.Bar(
            x=months,
            y=df_sales[cat],
            name=cat,
            marker_color=colors[i],
            hovertemplate=f'{cat}: %{{y:,}}만원<extra></extra>'
        ),
        row=2, col=1
    )

# 4. 월별 성장률
growth_rate = total_sales.pct_change() * 100
growth_colors = ['#7bbf6a' if v >= 0 else '#d57b7b' 
                 for v in growth_rate.fillna(0)]

fig.add_trace(
    go.Bar(
        x=months[1:],
        y=growth_rate.dropna(),
        name='성장률',
        marker_color=growth_colors[1:],
        hovertemplate='%{x}: %{y:.1f}%<extra></extra>'
    ),
    row=2, col=2
)

# 레이아웃 설정
fig.update_layout(
    title=dict(
        text='📊 2024년 연간 판매 대시보드',
        font=dict(size=20, color='#1e3a5f'),
        x=0.5
    ),
    height=700,
    plot_bgcolor='#f8f9fa',
    paper_bgcolor='white',
    barmode='stack',
    showlegend=True,
    legend=dict(
        orientation='h',
        yanchor='bottom',
        y=-0.15,
        xanchor='center',
        x=0.5
    ),
    font=dict(size=12)
)

# y축 포맷 설정
fig.update_yaxes(ticksuffix='만', row=1, col=1)
fig.update_yaxes(ticksuffix='%', row=2, col=2)

fig.show()

# HTML로 저장
fig.write_html('sales_dashboard.html', include_plotlyjs='cdn')
💡 이 코드 실행하면 4개 차트가 한 화면에 배치된 인터랙티브 대시보드가 생성됨. 각 차트에서 호버, 줌, 범례 클릭으로 특정 카테고리 숨기기/보이기 등 다양한 인터랙션이 가능함!

🎨 테마와 스타일 커스터마이징

기본 스타일에서 벗어나 나만의 스타일을 만드는 방법도 알아두면 좋음.

Plotly 테마 설정
import plotly.io as pio
import plotly.express as px

# 내장 테마 목록
# 'plotly', 'plotly_white', 'plotly_dark', 
# 'ggplot2', 'seaborn', 'simple_white', 'none'

# 전역 테마 설정
pio.templates.default = 'plotly_white'

# 커스텀 테마 생성
import plotly.graph_objects as go

custom_template = go.layout.Template()
custom_template.layout = go.Layout(
    font=dict(family='Malgun Gothic', size=13, color='#2d2d2d'),
    plot_bgcolor='#f8f9fa',
    paper_bgcolor='white',
    colorway=['#5b9bd5', '#7bbf6a', '#e8a96a', '#d57b7b', '#a89bd5'],
    title=dict(font=dict(size=18, color='#1e3a5f')),
    xaxis=dict(gridcolor='#e0e8f0', linecolor='#c0d0e0'),
    yaxis=dict(gridcolor='#e0e8f0', linecolor='#c0d0e0')
)

# 커스텀 테마 등록 및 적용
pio.templates['my_theme'] = custom_template
pio.templates.default = 'my_theme'

# 이제 모든 차트에 자동 적용됨
fig = px.line(px.data.gapminder().query("country=='Korea, Rep.'"),
              x='year', y='gdpPercap', title='한국 GDP 추이')
fig.show()
Seaborn 테마 설정
import seaborn as sns
import matplotlib.pyplot as plt

# Seaborn 스타일 설정
# 스타일: 'darkgrid', 'whitegrid', 'dark', 'white', 'ticks'
# 컨텍스트: 'paper', 'notebook', 'talk', 'poster'
# 팔레트: 'deep', 'muted', 'bright', 'pastel', 'dark', 'colorblind'

sns.set_theme(
    style='whitegrid',
    context='notebook',
    palette='muted',
    font='Malgun Gothic',
    font_scale=1.1,
    rc={
        'axes.spines.top': False,
        'axes.spines.right': False,
        'figure.facecolor': 'white',
        'axes.facecolor': '#f8f9fa'
    }
)

# 커스텀 팔레트 생성
custom_palette = ['#5b9bd5', '#7bbf6a', '#e8a96a', '#d57b7b', '#a89bd5']
sns.set_palette(custom_palette)

# 이제 모든 Seaborn 차트에 자동 적용
tips = sns.load_dataset('tips')
fig, ax = plt.subplots(figsize=(8, 5))
sns.boxplot(data=tips, x='day', y='total_bill', ax=ax)
ax.set_title('요일별 계산서 금액')
plt.show()

🔥 성능 최적화 팁

데이터가 많아지면 차트 렌더링이 느려질 수 있음. 이럴 때 쓸 수 있는 최적화 기법들을 알아두자.

📌 Plotly 성능 최적화 1. WebGL 렌더러 사용
대용량 데이터(10만 개 이상 포인트)에서는 go.Scattergl을 사용하면 WebGL 기반으로 렌더링되어 훨씬 빠름.

go.Scatter → go.Scattergl 로 교체만 하면 됨!

2. 데이터 샘플링
시각화 목적에 따라 전체 데이터가 필요 없을 수 있음. 트렌드 파악이 목적이라면 적절히 샘플링해서 사용.

3. 범주형 데이터 최적화
범주형 컬럼은 pd.Categorical로 변환하면 메모리와 처리 속도 모두 개선됨.
# WebGL 렌더러로 대용량 산점도
import plotly.graph_objects as go
import numpy as np

# 100만 개 데이터 포인트
n = 1_000_000
x = np.random.randn(n)
y = np.random.randn(n)

# go.Scatter 대신 go.Scattergl 사용
fig = go.Figure(go.Scattergl(
    x=x,
    y=y,
    mode='markers',
    marker=dict(
        size=2,
        color=np.random.randn(n),
        colorscale='Viridis',
        opacity=0.3
    )
))

fig.update_layout(title=f'{n:,}개 데이터 포인트 WebGL 렌더링')
fig.show()
⚠️ 주의! go.Scattergl은 일부 기능(예: 특정 마커 심볼)이 지원되지 않을 수 있음. 기능 제한 확인 후 사용할 것!

🌐 재능넷에서 데이터 시각화 활용하기

데이터 시각화 스킬은 요즘 진짜 핫한 역량임. 재능넷에서도 데이터 분석, 파이썬 개발, 대시보드 제작 관련 의뢰가 꾸준히 올라오는 걸 볼 수 있음. Plotly로 인터랙티브 대시보드 만들어주는 서비스나, Seaborn으로 데이터 분석 보고서 시각화해주는 서비스 등 다양한 형태로 재능을 공유할 수 있음 💪

특히 비즈니스 데이터 분석 결과를 시각화해서 보여주는 능력은 클라이언트 입장에서 진짜 가치 있는 스킬임. 숫자만 나열한 엑셀 파일보다 인터랙티브 대시보드 하나가 훨씬 더 임팩트 있으니까!


🚀 데이터 시각화 마스터 로드맵 Plotly & Seaborn 완전 정복 여정 1️⃣ 기초 단계 pip 설치 → 기본 임포트 → px로 첫 차트 Seaborn 내장 데이터셋으로 EDA 연습 2️⃣ 중급 단계 go로 커스터마이징 → 서브플롯 구성 Seaborn 통계 차트 마스터 → 테마 설정 3️⃣ 고급 단계 애니메이션 → 드롭다운 메뉴 → 지도 시각화 커스텀 호버 → 대시보드 구성 4️⃣ 실전 단계 실제 데이터로 대시보드 제작 Dash 연동 → 웹 배포 → 포트폴리오 완성 📦 핵심 패키지 스택 plotly · seaborn · matplotlib · pandas · numpy · kaleido · dash 💡 최종 조언 탐색(EDA) → Seaborn으로 빠르게 패턴 파악 발표·공유 → Plotly로 인터랙티브하게 완성

📝 마무리 정리

자 이제 Plotly랑 Seaborn에 대해 꽤 깊이 파봤음 ㅋㅋ 핵심만 다시 정리하면:

🎯 Plotly를 써야 할 때 - 웹 기반 인터랙티브 차트가 필요할 때
- 발표 자료나 대시보드를 만들 때
- 사용자가 직접 데이터를 탐색해야 할 때
- 애니메이션이나 지도 시각화가 필요할 때
- HTML 파일로 공유해야 할 때
🎨 Seaborn을 써야 할 때 - EDA(탐색적 데이터 분석) 단계에서 빠르게 패턴을 파악할 때
- 논문이나 보고서용 고품질 정적 이미지가 필요할 때
- 통계적 분포나 관계를 시각화할 때
- Matplotlib과 연동해서 세밀한 제어가 필요할 때

두 라이브러리 모두 파이썬 데이터 사이언스 생태계에서 없어서는 안 될 존재임. 어느 하나만 고집하지 말고 상황에 맞게 유연하게 활용하는 게 진짜 데이터 시각화 고수의 자세임 💪

그리고 재능넷에서 파이썬 데이터 시각화 관련 프로젝트를 찾거나 본인의 스킬을 공유하고 싶다면 적극적으로 활용해봐. 이 분야 수요가 진짜 많거든 😎

오늘 배운 코드들 직접 실행해보면서 손에 익히는 게 제일 중요함. 백 번 읽는 것보다 한 번 직접 돌려보는 게 훨씬 효과적이니까! 화이팅 🔥

댓글 작성

이 글에 대한 여러분의 생각을 들려주세요

댓글 0
댓글을 불러오는 중입니다.

아직 댓글이 없습니다.