iBetter Books
수정

DataFrame에서 바로 그리기

지윤은 팀원들에게 Plotly Express의 가장 편리한 기능부터 보여주기로 했습니다. 바로 DataFrame을 함수에 그대로 넣는 것입니다.

import plotly.express as pximport pandas as pddf = px.data.iris()fig = px.scatter(df, x="sepal_width", y="sepal_length")fig.show()

실행 결과

딱 세 줄입니다. DataFrame을 만들고, 어느 열을 x축과 y축으로 쓸지 이름만 적으면 됩니다. 열 이름을 문자열로 전달하기 때문에 오타만 조심하면 됩니다.

px 함수에 DataFrame 전달하기

plotly.express의 모든 차트 함수는 첫 번째 인자로 DataFrame을 받습니다. 그 뒤에 어느 열을 어느 축에 매핑할지 지정합니다.

# 새 파일: chapter04_01_dataframe.pyimport plotly.express as pximport pandas as pd# 내장 데이터셋 활용df = px.data.iris()print(df.head())print(df.columns.tolist())

실행하면 열 이름 목록이 출력됩니다.

   sepal_length  sepal_width  petal_length  petal_width species  species_id
0           5.1          3.5           1.4          0.2  setosa           1
...
['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'species', 'species_id']

이제 열 이름을 그대로 x, y에 넣습니다.

# 수정: chapter04_01_dataframe.pyimport plotly.express as pximport pandas as pddf = px.data.iris()# 기본 산점도: x축=sepal_width, y축=sepal_length, 색상=speciesfig = px.scatter(    df,    x="sepal_width",    y="sepal_length",    color="species",    size="petal_length",    hover_data=["petal_width"],    title="붓꽃 품종별 꽃받침 크기 분포")fig.show()

실행 결과

세 품종이 색으로 구분되고, 점의 크기가 꽃잎 길이에 비례하는 버블 산점도가 나타납니다. 마우스를 올리면 꽃잎 너비까지 확인할 수 있습니다.

color="species"를 추가하면 품종별로 색을 자동으로 구분해줍니다. size="petal_length"를 추가하면 꽃잎 길이에 따라 점의 크기가 달라집니다. 열 이름 하나만 더 적었을 뿐인데 차트가 훨씬 풍부해집니다.

와이드폼과 롱폼 데이터

데이터를 받다 보면 같은 정보를 두 가지 형태로 저장한 파일을 만나게 됩니다. 어떤 형태냐에 따라 px 함수를 쓰는 방법이 달라집니다.

와이드폼(Wide-form)은 각 카테고리가 별도의 열로 들어있습니다.

월   서울   부산   대구
1월  2.5   5.2   4.8
2월  3.1   5.8   5.3
3월  7.2   9.1   8.7

롱폼(Long-form)은 카테고리를 하나의 열로 묶고 값을 다른 열에 넣습니다.

월   도시   기온
1월  서울   2.5
1월  부산   5.2
1월  대구   4.8
2월  서울   3.1
...

Plotly Express는 롱폼을 선호합니다. color, facet_col 같은 파라미터가 하나의 열에서 카테고리를 읽어오기 때문입니다.

# 수정: chapter04_01_dataframe.pyimport plotly.express as pximport pandas as pddf = px.data.iris()fig = px.scatter(    df,    x="sepal_width",    y="sepal_length",    color="species",    size="petal_length",    hover_data=["petal_width"],    title="붓꽃 품종별 꽃받침 크기 분포")fig.show()# 와이드폼 예시wide_df = pd.DataFrame({    "월": ["1월", "2월", "3월", "4월", "5월"],    "서울": [2.5, 3.1, 7.2, 13.5, 18.9],    "부산": [5.2, 5.8, 9.1, 14.3, 19.2],    "대구": [4.8, 5.3, 8.7, 14.8, 20.1],})# 와이드폼을 px.line에 바로 넣으면: y에 여러 열을 리스트로 전달fig_wide = px.line(    wide_df,    x="월",    y=["서울", "부산", "대구"],    title="월별 평균 기온 (와이드폼)")fig_wide.show()

실행 결과

월별 세 도시의 기온 변화를 세 개의 선으로 표시한 선 그래프가 나타납니다.

와이드폼에서 y에 열 이름 리스트를 넘기면 각 열이 하나의 선으로 그려집니다. 간단하지만, 색상 구분이나 추가 정보를 넣기가 어렵습니다.

pd.melt()로 롱폼 변환하기

와이드폼을 롱폼으로 바꾸는 도구가 pd.melt()입니다.

# 수정: chapter04_01_dataframe.pyimport plotly.express as pximport pandas as pddf = px.data.iris()fig = px.scatter(    df,    x="sepal_width",    y="sepal_length",    color="species",    size="petal_length",    hover_data=["petal_width"],    title="붓꽃 품종별 꽃받침 크기 분포")fig.show()wide_df = pd.DataFrame({    "월": ["1월", "2월", "3월", "4월", "5월"],    "서울": [2.5, 3.1, 7.2, 13.5, 18.9],    "부산": [5.2, 5.8, 9.1, 14.3, 19.2],    "대구": [4.8, 5.3, 8.7, 14.8, 20.1],})fig_wide = px.line(    wide_df,    x="월",    y=["서울", "부산", "대구"],    title="월별 평균 기온 (와이드폼)")fig_wide.show()# pd.melt()로 롱폼 변환long_df = pd.melt(    wide_df,    id_vars=["월"],        # 유지할 열    var_name="도시",       # 카테고리 열 이름    value_name="기온"      # 값 열 이름)print(long_df)# 롱폼으로 더 풍부한 차트 만들기fig_long = px.line(    long_df,    x="월",    y="기온",    color="도시",          # 도시별로 색 구분    markers=True,    title="월별 평균 기온 (롱폼)")fig_long.show()

실행 결과

롱폼으로 변환한 뒤 그린 선 그래프입니다. 서울, 부산, 대구가 색으로 구분되고, 데이터 포인트마다 마커가 표시됩니다. 마우스를 올리면 해당 도시의 기온을 확인할 수 있습니다.

롱폼으로 바꾸고 나면 color="도시"처럼 열 이름 하나로 색을 구분할 수 있습니다. 데이터가 늘어나도 코드는 바뀌지 않습니다.

DataFrame.plot() vs px 함수 비교

Matplotlib을 쓰던 시절에는 df.plot()으로 차트를 그렸습니다. 이제 Plotly도 df.plot(backend='plotly')를 지원합니다. 하지만 두 방식은 목적이 다릅니다.

# 수정: chapter04_01_dataframe.pyimport plotly.express as pximport pandas as pddf = px.data.iris()fig = px.scatter(    df,    x="sepal_width",    y="sepal_length",    color="species",    size="petal_length",    hover_data=["petal_width"],    title="붓꽃 품종별 꽃받침 크기 분포")fig.show()wide_df = pd.DataFrame({    "월": ["1월", "2월", "3월", "4월", "5월"],    "서울": [2.5, 3.1, 7.2, 13.5, 18.9],    "부산": [5.2, 5.8, 9.1, 14.3, 19.2],    "대구": [4.8, 5.3, 8.7, 14.8, 20.1],})fig_wide = px.line(    wide_df,    x="월",    y=["서울", "부산", "대구"],    title="월별 평균 기온 (와이드폼)")fig_wide.show()long_df = pd.melt(    wide_df,    id_vars=["월"],    var_name="도시",    value_name="기온")fig_long = px.line(    long_df,    x="월",    y="기온",    color="도시",    markers=True,    title="월별 평균 기온 (롱폼)")fig_long.show()# DataFrame.plot()으로 Plotly 차트 그리기# pandas >= 1.0 + plotly 설치 필요pd.options.plotting.backend = "plotly"fig_plot = wide_df.set_index("월")[["서울", "부산", "대구"]].plot(    title="월별 평균 기온 (df.plot 방식)")fig_plot.show()print("두 방식의 차이점:")print("df.plot(backend='plotly') : 빠른 탐색, 코드 최소화")print("px.line(df, ...) : 세밀한 제어, color/facet 등 추가 파라미터")

실행 결과

df.plot(backend='plotly')로 생성한 인터랙티브 선 그래프가 나타납니다. Matplotlib 스타일의 코드로 Plotly 차트를 빠르게 확인할 수 있습니다.

df.plot()은 기존 Matplotlib 코드를 빠르게 Plotly로 전환할 때 유용합니다. px 함수는 더 많은 옵션을 제공하고 Plotly의 기능을 완전히 활용할 수 있습니다.

실전: CSV 파일 읽어서 바로 시각화하기

이제 실제 CSV 파일을 읽어서 시각화해봅니다. Plotly에 내장된 tips 데이터를 CSV로 저장한 뒤 다시 읽어 사용합니다.

# 새 파일: chapter04_01_csv_practice.pyimport plotly.express as pximport pandas as pd# tips 데이터를 CSV로 저장 (실습용)df_tips = px.data.tips()df_tips.to_csv("tips.csv", index=False)# CSV 파일 읽기df = pd.read_csv("tips.csv")print(df.dtypes)print(df.shape)# 성별·흡연 여부별 팁 분포fig = px.scatter(    df,    x="total_bill",    y="tip",    color="sex",    symbol="smoker",    size="size",    hover_data=["day", "time"],    title="식사 금액과 팁의 관계")fig.show()# 요일별 평균 팁 막대 그래프fig2 = px.bar(    df,    x="day",    y="tip",    color="sex",    barmode="group",    category_orders={"day": ["Thur", "Fri", "Sat", "Sun"]},    title="요일별 팁 (성별 비교)")fig2.show()

실행 결과

실행 결과

첫번째 차트는 식사 금액과 팁의 관계를 보여주는 산점도로, 성별은 색으로, 흡연 여부는 마커 모양으로 구분됩니다. 두번째 차트는 요일별 팁을 성별로 비교한 막대 그래프입니다. 마우스를 올리면 요일, 시간대 정보까지 확인할 수 있습니다.

CSV를 읽자마자 dtypes로 열 타입을 확인하는 습관을 갖는 것이 좋습니다. 숫자 열이 문자열로 읽힌다면 pd.to_numeric()으로 변환해야 합니다.