"차트가 내부적으로 어떻게 생겼는지 궁금하지 않아?"
강주원 선배의 메시지였다.
"그냥 fig.show() 하면 되는 거 아닌가요?"
"써보면 왜 알아야 하는지 느끼게 될 거야. update_layout이나 update_traces 쓸 때 어떤 이름으로 속성을 불러야 하는지 알아야 하거든. 그때 Figure 구조를 알면 훨씬 빠르게 찾을 수 있어."
Figure 딕셔너리 확인하기
Plotly Figure는 내부적으로 딕셔너리 구조를 가집니다. fig.to_dict()로 전체 구조를 확인할 수 있습니다.
# 파일: figure_structure.pyimport plotly.express as pximport pprintdf = px.data.iris()fig = px.scatter( df, x="sepal_width", y="sepal_length", color="species")pprint.pprint(fig.to_dict())
출력 결과는 길지만, 크게 두 부분으로 나뉩니다.
{
'data': [...], ← 트레이스(데이터 시리즈) 목록
'layout': {...} ← 전체 레이아웃 설정
}
data: 트레이스 목록
data는 리스트입니다. 각 항목이 하나의 트레이스(trace)입니다. 트레이스는 "차트에 그려지는 하나의 데이터 시리즈"를 뜻합니다.
iris 데이터를 세 종으로 색구분한 산점도라면 트레이스가 3개 생깁니다. 각 종이 하나의 트레이스입니다.
# 파일: figure_data.pyimport plotly.express as pxdf = px.data.iris()fig = px.scatter( df, x="sepal_width", y="sepal_length", color="species")print(f"트레이스 개수: {len(fig.data)}")print(f"첫 번째 트레이스 타입: {type(fig.data[0])}")print(f"첫 번째 트레이스 이름: {fig.data[0].name}")
출력 결과입니다.
트레이스 개수: 3
첫 번째 트레이스 타입: <class 'plotly.graph_objs._scatter.Scatter'>
첫 번째 트레이스 이름: setosa
각 트레이스에는 x, y 데이터와 마커 스타일, 이름 등이 담겨 있습니다.
layout: 전체 레이아웃
layout은 차트 전체에 적용되는 설정입니다. 제목, 축 레이블, 범례 위치, 배경색, 크기 등이 여기에 있습니다.
# 파일: figure_layout.pyimport plotly.express as pxdf = px.data.iris()fig = px.scatter( df, x="sepal_width", y="sepal_length", color="species", title="붓꽃 산점도")print(fig.layout.title.text) # "붓꽃 산점도"print(fig.layout.xaxis.title) # 축 제목 객체
fig.layout은 딕셔너리가 아닌 객체입니다. 점 표기법으로 속성에 접근할 수 있습니다.
Figure 구조 요약
go.Figure
├── data: [Trace, Trace, ...]
│ ├── Trace 0: {type, x, y, name, marker, ...}
│ ├── Trace 1: {type, x, y, name, marker, ...}
│ └── ...
└── layout: Layout
├── title: {text, ...}
├── xaxis: {title, range, ...}
├── yaxis: {title, range, ...}
├── legend: {x, y, ...}
└── ...
이 구조를 이해하면 update_layout()과 update_traces()에서 어떤 이름의 속성을 수정해야 하는지 바로 알 수 있습니다.
"이제 update 메서드 쓸 때 느낌이 오지?" 선배가 물었다.
"네, layout은 전체 설정이고, data 안에 각 트레이스가 있는 거군요."
"맞아. update_layout은 layout 딕셔너리를 수정하는 거고, update_traces는 data 안의 트레이스들을 수정하는 거야."
자주 묻는 질문
Q: fig.to_dict()와 fig.to_json()의 차이는 뭔가요?
to_dict()는 Python 딕셔너리를 반환하고, to_json()은 JSON 문자열을 반환합니다. 둘 다 같은 내용이지만, API나 파일로 저장할 때는 to_json()이 편하고, Python 코드에서 처리할 때는 to_dict()가 편합니다.
Q: 트레이스가 몇 개인지 확인하는 방법은 뭔가요?
len(fig.data)로 확인합니다. 또는 print(fig.data)로 전체 트레이스 목록을 볼 수 있습니다.
Q: 특정 트레이스만 꺼내서 수정할 수 있나요?
fig.data[0]처럼 인덱스로 접근할 수 있습니다. 단, 반환된 객체의 속성을 직접 수정하면 예상치 못한 동작이 생길 수 있습니다. update_traces(selector=dict(name="setosa"), ...)처럼 선택자를 사용하는 것이 더 안전합니다.