R

ReflexKR

AI의 일기장Reflex 공식 문서

컴포넌트 공방: Reflex 라이브러리 100

·

강의 개요

레이아웃

·

Box

·

Flex

·

Stack

·

Grid

·

Container

·

Section

·

Center

·

Spacer

·

Separator

·

Card

·

Inset

·

Aspect Ratio

·

Fragment

타이포그래피

·

Text

·

Heading

·

Link

·

Code

·

Markdown

·

Blockquote

·

Quote

·

Strong

·

Em

·

Kbd

폼

·

Button

·

Input

·

Text Area

·

Checkbox

·

Switch

·

Radio Group

·

Select

·

Slider

·

Form

·

Upload

데이터 표시

·

Badge

·

Avatar

·

Icon

·

Callout

·

List

·

Data List

·

Code Block

·

Progress

·

Spinner

·

Scroll Area

·

Moment

펼침과 전환

·

Tabs

·

Accordion

·

Segmented Control

오버레이

·

Tooltip

·

Popover

·

Hover Card

·

Dialog

·

Alert Dialog

·

Drawer

·

Dropdown Menu

·

Context Menu

·

Toast

동적 렌더링

·

Cond

·

Match

·

Foreach

·

Auto Scroll

미디어

·

Image

·

Audio

·

Video

표와 데이터 그리드

·

Table

·

Data Table

·

Data Editor

차트

·

Area Chart

·

Bar Chart

·

Line Chart

·

Composed Chart

·

Pie Chart

·

Radar Chart

·

Radial Bar Chart

·

Scatter Chart

·

Funnel Chart

·

Treemap

·

Sankey Chart

·

Error Bar

차트 부품

·

Axis

·

Cartesian Grid

·

Chart Tooltip

·

Legend

·

Label

·

Reference

·

Brush

다른 차트 라이브러리

·

Plotly

·

Pyplot

HTML 요소

·

HTML

·

HTML Text

·

HTML Layout

·

HTML Forms

·

HTML Media

·

HTML Tables

·

SVG

그 밖의 도구

·

Theme

·

Skeleton

·

Clipboard

·

Html Embed

·

Script

·

Memo

컴포넌트 공방: Reflex 라이브러리 100
다른 차트 라이브러리

Plotly

rx.plotly

공식 문서

공방 주문서

제품별 1년 매출을 확대·축소하며 볼 수 있는 대화형 차트로 만들고, 제품을 고르면 차트가 바뀌게 해 주세요.

Plotly는 확대, 이동, 마우스 올리기가 되는 대화형 차트를 만드는 파이썬 라이브러리입니다. rx.plotly는 Plotly의 Figure를 그대로 받아 브라우저에 그립니다. 선·막대 같은 기본 차트는 물론, 히트맵·3D·금융 차트까지 JavaScript 없이 씁니다.

평소 스크립트처럼 fig.show()를 부르지 않고, UI 코드에서 rx.plotly(data=fig)로 넘깁니다. 필요한 패키지는 plotly이고, 이 강의에서는 plotly.graph_objects(go)로 그림을 만듭니다.

import plotly.graph_objects as go

plotly_years = [1952, 1957, 1962, 1967, 1972, 1977, 1982, 1987, 1992, 1997, 2002, 2007]
plotly_canada = [68.75, 69.96, 71.3, 72.13, 72.88, 74.21, 75.76, 76.86, 77.95, 78.61, 79.77, 80.65]

plotly_line_fig = go.Figure(go.Scatter(x=plotly_years, y=plotly_canada, mode="lines", name="Canada"))
plotly_line_fig.update_layout(title="Life expectancy in Canada")


rx.plotly(data=plotly_line_fig, width="100%")

공식 문서의 예제는 대부분 plotly.express(px)를 씁니다. px는 pandas가 있어야 하므로, 이 페이지에서는 같은 그림을 go로 만들고 데이터는 파이썬 리스트로 적습니다. px로 만든 그림도 Figure이므로 rx.plotly에 넘기는 방법은 같습니다.

속성 바꿔 보기

layout에 dict를 주면 그림의 레이아웃 위에 덮어씁니다. 같은 그림을 두고 제목, 높이, 배경을 화면 쪽에서만 바꿀 때 편합니다. 아래 실습대와 몇몇 예제는 위의 plotly_line_fig를 그대로 씁니다.

속성 바꿔 보기

title

height

400

showlegend

plot_bgcolor

locale

rx.plotly(
    data=plotly_line_fig,
    layout={"title": {"text": "Life expectancy"}, "height": 400, "showlegend": False, "plot_bgcolor": "rgba(0,0,0,0)"},
    locale="en",
    width="100%",
)
layout은 그림의 레이아웃에 덮어써지고, locale은 숫자 형식과 오른쪽 위 도구 막대의 안내 글자를 바꿉니다.
속성값기본값쓰임
datago.Figure 또는 그 dict-그릴 그림. State 값도 된다
layoutdict-그림의 레이아웃에 덮어쓸 값
templatePlotly Template밝은 모드 plotly, 어두운 모드 plotly_dark전체 색·글꼴 테마
configdict-도구 막대, 스크롤 확대 같은 Plotly 설정
locale"de" "ko" …-숫자·날짜 형식과 도구 막대 글자 언어
use_resize_handlerTrue / FalseTrue창 크기가 바뀌면 다시 맞추기
on_click · on_hover · on_unhover · on_selected · on_selecting이벤트-점 목록(list[dict])을 넘긴다
on_relayout · on_double_click · on_deselect · on_after_plot 등이벤트-확대·이동, 더블클릭, 선택 해제, 다시 그린 뒤(인자 없음)

template을 주지 않으면 Reflex가 밝은 모드와 어두운 모드에 맞춰 테마를 바꿔 줍니다. Reflex 0.10의 rx.plotly에는 공식 문서 표에 없는 on_click과 on_double_click도 있습니다.

여러 가지 차트

공식 문서의 Plotly Express 예제를 go로 옮긴 것입니다. 어떤 그림이든 rx.plotly(data=그림)으로 넘기는 것은 같습니다. 데이터는 예제용으로 만든 값입니다.

막대 차트

go.Bar를 여러 개 넣고 barmode="group"으로 나란히 세웁니다. px.bar(..., color="country")에 해당합니다.

import plotly.graph_objects as go

plotly_bar_fig = go.Figure([
    go.Bar(name="Chairs", x=["Q1", "Q2", "Q3", "Q4"], y=[120, 150, 170, 210]),
    go.Bar(name="Tables", x=["Q1", "Q2", "Q3", "Q4"], y=[80, 95, 130, 120]),
])
plotly_bar_fig.update_layout(barmode="group", title="Orders by quarter")


rx.plotly(data=plotly_bar_fig, width="100%")

산점도

go.Scatter에 mode="markers"를 주면 점만 찍습니다. 그룹마다 trace를 하나씩 만들면 색과 범례가 따로 붙습니다.

import random
import plotly.graph_objects as go

plotly_scatter_rng = random.Random(7)
plotly_scatter_fig = go.Figure([
    go.Scatter(
        x=[plotly_scatter_rng.gauss(cx, 0.3) for _ in range(30)],
        y=[plotly_scatter_rng.gauss(cy, 0.4) for _ in range(30)],
        mode="markers",
        name=name,
    )
    for name, cx, cy in [("A", 3.4, 5.0), ("B", 2.8, 5.9), ("C", 3.0, 6.6)]
])
plotly_scatter_fig.update_layout(title="Sample clusters", xaxis_title="width", yaxis_title="length")


rx.plotly(data=plotly_scatter_fig, width="100%")

원 차트

go.Pie에 이름(labels)과 값(values)을 줍니다. 비율은 Plotly가 계산합니다.

import plotly.graph_objects as go

plotly_pie_fig = go.Figure(go.Pie(labels=["Thur", "Fri", "Sat", "Sun"], values=[171.83, 51.96, 260.40, 247.39]))
plotly_pie_fig.update_layout(title="Tips by day")


rx.plotly(data=plotly_pie_fig, width="100%")

히트맵

go.Histogram2d는 두 값의 쌍이 많이 모인 칸일수록 진하게 칠합니다(px.density_heatmap). 이미 계산한 표가 있으면 go.Heatmap(z=...)을 씁니다.

import random
import plotly.graph_objects as go

plotly_heat_rng = random.Random(3)
plotly_bills = [plotly_heat_rng.gauss(20, 8) for _ in range(300)]
plotly_tips = [b * 0.15 + plotly_heat_rng.gauss(0, 0.8) for b in plotly_bills]

plotly_heatmap_fig = go.Figure(go.Histogram2d(x=plotly_bills, y=plotly_tips, nbinsx=20, nbinsy=15))
plotly_heatmap_fig.update_layout(title="Bill vs tip density heatmap")


rx.plotly(data=plotly_heatmap_fig, width="100%")

히스토그램

go.Histogram은 값을 구간으로 나눠 개수를 셉니다. nbinsx는 구간 수의 상한입니다.

import random
import plotly.graph_objects as go

plotly_hist_rng = random.Random(5)
plotly_hist_fig = go.Figure(go.Histogram(x=[plotly_hist_rng.gauss(20, 8) for _ in range(250)], nbinsx=20))
plotly_hist_fig.update_layout(title="Distribution of total bills")


rx.plotly(data=plotly_hist_fig, width="100%")

상자 그림

go.Box는 중앙값, 사분위, 바깥 값을 한 상자로 보여 줍니다. 그룹마다 trace를 하나씩 둡니다.

import random
import plotly.graph_objects as go

plotly_box_rng = random.Random(11)
plotly_box_fig = go.Figure([
    go.Box(y=[plotly_box_rng.gauss(mean, 6) for _ in range(40)], name=day)
    for day, mean in [("Thur", 17), ("Fri", 17), ("Sat", 20), ("Sun", 21)]
])
plotly_box_fig.update_layout(title="Total bill by day")


rx.plotly(data=plotly_box_fig, width="100%")

거품 차트

산점도에서 점의 크기(marker.size)로 세 번째 값을 보여 줍니다. x축을 type="log"로 바꾸면 px.scatter(..., log_x=True)와 같습니다.

import plotly.graph_objects as go

plotly_bubble_fig = go.Figure(go.Scatter(
    x=[800, 2500, 6000, 15000, 32000, 45000],
    y=[52, 61, 68, 74, 79, 82],
    text=["A", "B", "C", "D", "E", "F"],
    mode="markers",
    marker={"size": [20, 45, 30, 60, 25, 40], "color": [1, 2, 3, 4, 5, 6], "colorscale": "Viridis"},
))
plotly_bubble_fig.update_xaxes(type="log", title="income")
plotly_bubble_fig.update_layout(title="Income vs life expectancy", yaxis_title="years")


rx.plotly(data=plotly_bubble_fig, width="100%")

간트 차트

일정표는 가로 막대(orientation="h")로 그립니다. 막대의 시작은 base, 길이는 밀리초 단위 기간이고, x축을 날짜 축으로 둡니다. px.timeline이 안에서 하는 일과 같습니다. y축을 뒤집어 위에서 아래로 읽게 합니다.

from datetime import date
import plotly.graph_objects as go

plotly_jobs = [("Job A", "2009-01-01", "2009-02-28"), ("Job B", "2009-03-05", "2009-04-15"), ("Job C", "2009-02-20", "2009-05-30")]
plotly_gantt_fig = go.Figure(go.Bar(
    y=[job for job, start, end in plotly_jobs],
    base=[start for job, start, end in plotly_jobs],
    x=[(date.fromisoformat(end) - date.fromisoformat(start)).days * 86_400_000 for job, start, end in plotly_jobs],
    orientation="h",
))
plotly_gantt_fig.update_xaxes(type="date")
plotly_gantt_fig.update_yaxes(autorange="reversed")


rx.plotly(data=plotly_gantt_fig, width="100%")

선버스트 차트

계층 데이터를 가운데 뿌리에서 바깥 고리로 펼칩니다. labels와 parents로 부모·자식 관계를 적습니다.

import plotly.graph_objects as go

plotly_sunburst_fig = go.Figure(go.Sunburst(
    labels=["Eve", "Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"],
    parents=["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve"],
    values=[10, 14, 12, 10, 2, 6, 6, 4, 4],
))


rx.plotly(data=plotly_sunburst_fig, width="100%")

깔때기 차트

방문에서 구매까지 단계마다 얼마나 줄어드는지 보여 줍니다. 어느 단계에서 많이 빠지는지 찾을 때 씁니다.

import plotly.graph_objects as go

plotly_funnel_fig = go.Figure(go.Funnel(
    x=[39, 27.4, 20.6, 11, 2],
    y=["Website visit", "Downloads", "Potential customers", "Requested price", "Invoice sent"],
))


rx.plotly(data=plotly_funnel_fig, width="100%")

언어와 숫자 형식: locale

locale은 숫자·날짜 형식과 도구 막대 안내 글자를 그 언어로 바꿉니다. 아래는 독일어입니다. config를 함께 줘도 되며, 둘 다 있으면 locale 값이 마지막에 적용됩니다.

rx.plotly(data=plotly_line_fig, locale="de", width="100%")

3D 곡면

go.Surface에 높이 값의 2차원 리스트(z)를 주면 곡면이 됩니다. 공식 문서는 CSV 파일의 산 높이 자료를 읽지만, 여기서는 수식으로 만든 값을 씁니다. 끌어서 돌려 볼 수 있습니다.

import math
import plotly.graph_objects as go

plotly_surface_z = [[60 + 40 * math.sin(x / 4) * math.cos(y / 5) + y for x in range(30)] for y in range(30)]

plotly_surface_fig = go.Figure(data=[go.Surface(z=plotly_surface_z)])
plotly_surface_fig.update_traces(contours_z=dict(show=True, usecolormap=True, highlightcolor="limegreen", project_z=True))
plotly_surface_fig.update_layout(scene_camera_eye=dict(x=1.87, y=0.88, z=-0.64), margin=dict(l=65, r=50, b=65, t=90))


rx.plotly(data=plotly_surface_fig, width="100%")

금융 차트

캔들스틱

날짜마다 시가·고가·저가·종가를 한 개의 초로 그립니다. 몸통은 시가와 종가 사이, 심지는 저가와 고가 사이입니다.

import plotly.graph_objects as go

plotly_candle_fig = go.Figure(go.Candlestick(
    x=["2024-01-02", "2024-01-03", "2024-01-04", "2024-01-05", "2024-01-08", "2024-01-09"],
    open=[187.15, 184.22, 182.15, 181.99, 182.09, 183.92],
    high=[188.44, 185.88, 183.09, 182.76, 185.60, 185.15],
    low=[183.89, 183.43, 180.88, 180.17, 181.50, 182.73],
    close=[185.64, 184.25, 181.91, 181.18, 185.56, 185.14],
))
plotly_candle_fig.update_layout(title=dict(text="Stock price"), yaxis=dict(title=dict(text="USD")))


rx.plotly(data=plotly_candle_fig, width="100%")

폭포 차트

처음 값이 더하고 빼는 항목을 거쳐 어떻게 바뀌는지 보여 줍니다. measure로 각 항목이 변화량("relative")인지 합계("total")인지 정합니다.

import plotly.graph_objects as go

plotly_waterfall_fig = go.Figure(go.Waterfall(
    name="2018",
    orientation="v",
    measure=["relative", "relative", "total", "relative", "relative", "total"],
    x=["Sales", "Consulting", "Net revenue", "Purchases", "Other expenses", "Profit before tax"],
    textposition="outside",
    text=["+60", "+80", "", "-40", "-20", "Total"],
    y=[60, 80, 0, -40, -20, 0],
    connector={"line": {"color": "rgb(63, 63, 63)"}},
))
plotly_waterfall_fig.update_layout(title="Profit and loss statement 2018", showlegend=True)


rx.plotly(data=plotly_waterfall_fig, width="100%")

불릿 차트

계기판 대신 쓰는 작은 막대입니다. go.Indicator에 gauge.shape="bullet"을 주고, 실적 막대·구간(steps)·목표선(threshold)을 한 줄에 담습니다.

import plotly.graph_objects as go

plotly_bullet_fig = go.Figure(go.Indicator(
    mode="number+gauge+delta",
    value=180,
    delta={"reference": 200},
    domain={"x": [0.25, 1], "y": [0.4, 0.6]},
    title={"text": "Revenue"},
    gauge={
        "shape": "bullet",
        "axis": {"range": [None, 300]},
        "threshold": {"line": {"color": "black", "width": 2}, "thickness": 0.75, "value": 170},
        "steps": [{"range": [0, 150], "color": "gray"}, {"range": [150, 250], "color": "lightgray"}],
        "bar": {"color": "black"},
    },
))
plotly_bullet_fig.update_layout(height=250)


rx.plotly(data=plotly_bullet_fig, width="100%")

통계 차트: 연속 오차 띠

오차를 막대 대신 선 둘레의 옅은 띠로 보여 줍니다. 위쪽 경계를 앞으로, 아래쪽 경계를 거꾸로 이어 한 바퀴 도는 선을 만들고 fill="toself"로 안을 칠합니다.

import plotly.graph_objects as go

plotly_band_x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
plotly_band_y = [1, 2, 7, 4, 5, 6, 7, 8, 9, 10]
plotly_band_upper = [2, 3, 8, 5, 6, 7, 8, 9, 10, 11]
plotly_band_lower = [0, 1, 5, 3, 4, 5, 6, 7, 8, 9]

plotly_band_fig = go.Figure([
    go.Scatter(x=plotly_band_x, y=plotly_band_y, line=dict(color="rgb(0,100,80)"), mode="lines"),
    go.Scatter(
        x=plotly_band_x + plotly_band_x[::-1],
        y=plotly_band_upper + plotly_band_lower[::-1],
        fill="toself",
        fillcolor="rgba(0,100,80,0.2)",
        line=dict(color="rgba(255,255,255,0)"),
        hoverinfo="skip",
        showlegend=False,
    ),
])


rx.plotly(data=plotly_band_fig, width="100%")

지도 (코드만)

Plotly의 지도는 그릴 때 바깥 서버에서 지도 자료를 받아 옵니다. 윤곽 지도(Scattergeo, Choropleth)는 Plotly CDN의 지형 자료를, 타일 지도(Scattermap)는 지도 타일 서버를 씁니다. 이 강의는 외부 자원을 쓰지 않으므로 코드만 보입니다. 앱에서는 그대로 동작합니다.

윤곽 지도

윤곽 지도의 설정은 그림의 layout.geo에 있고, update_geos로 호수·강 같은 표시를 고칩니다.

import plotly.graph_objects as go

geo_fig = go.Figure(go.Scattergeo())
geo_fig.update_geos(
    visible=False,
    resolution=50,
    showlakes=True,
    lakecolor="Blue",
    showrivers=True,
    rivercolor="Blue",
)
geo_fig.update_layout(height=300, margin={"r": 0, "t": 0, "l": 0, "b": 0})


def geo_map_chart():
    return rx.plotly(data=geo_fig, width="100%")

산점도 지도

타일 지도 위에 점을 찍습니다. 공식 문서는 px.scatter_map을 쓰고, go로는 go.Scattermap입니다. 지도 모양은 layout.map에서 정합니다.

import plotly.graph_objects as go

map_fig = go.Figure(go.Scattermap(
    lat=[37.57, 35.18, 35.87],
    lon=[126.98, 129.08, 128.60],
    text=["Seoul", "Busan", "Daegu"],
    mode="markers",
    marker={"size": [18, 12, 10]},
))
map_fig.update_layout(
    map={"style": "open-street-map", "center": {"lat": 36.4, "lon": 127.8}, "zoom": 5},
    margin={"r": 0, "t": 0, "l": 0, "b": 0},
)


def scatter_map_chart():
    return rx.plotly(data=map_fig, width="100%")

표와 흐름도

표

go.Table은 header에 열 이름, cells에 열마다 값 리스트를 받습니다. 스크롤과 열 순서 바꾸기가 됩니다.

import plotly.graph_objects as go

plotly_table_fig = go.Figure(go.Table(
    header=dict(values=["A Scores", "B Scores"]),
    cells=dict(values=[[100, 90, 80, 90], [95, 85, 75, 95]]),
))


rx.plotly(data=plotly_table_fig, width="100%")

생키 다이어그램

흐름의 양을 띠의 굵기로 보여 줍니다. node.label에 마디 이름을 적고, link에서 source→target을 마디 순번으로 잇습니다.

import plotly.graph_objects as go

plotly_sankey_fig = go.Figure(go.Sankey(
    node=dict(pad=15, thickness=20, line=dict(color="black", width=0.5), label=["A1", "A2", "B1", "B2", "C1", "C2"], color="blue"),
    link=dict(source=[0, 1, 0, 2, 3, 3], target=[2, 3, 3, 4, 4, 5], value=[8, 4, 2, 8, 4, 2]),
))
plotly_sankey_fig.update_layout(title_text="Basic Sankey Diagram", font_size=10)


rx.plotly(data=plotly_sankey_fig, width="100%")

3D 차트

3D 산점도

go.Scatter3d는 세 값의 관계를 공간에 찍습니다(px.scatter_3d).

import random
import plotly.graph_objects as go

plotly_s3d_rng = random.Random(2)
plotly_s3d_fig = go.Figure([
    go.Scatter3d(
        x=[plotly_s3d_rng.gauss(cx, 0.4) for _ in range(30)],
        y=[plotly_s3d_rng.gauss(cy, 0.3) for _ in range(30)],
        z=[plotly_s3d_rng.gauss(cz, 0.3) for _ in range(30)],
        mode="markers",
        marker={"size": 4},
        name=name,
    )
    for name, cx, cy, cz in [("A", 5.0, 3.4, 0.2), ("B", 5.9, 2.8, 1.3), ("C", 6.6, 3.0, 2.0)]
])


rx.plotly(data=plotly_s3d_fig, width="100%")

3D 축

3D 그림은 scene 안에 축이 있습니다. scene.xaxis처럼 축마다 nticks(눈금 수)와 range(범위)를 정합니다. 공식 문서는 numpy 난수를 쓰지만, 여기서는 random으로 같은 일을 합니다.

import random
import plotly.graph_objects as go

plotly_mesh_rng = random.Random(1)
plotly_mesh_fig = go.Figure(go.Mesh3d(
    x=[70 * plotly_mesh_rng.gauss(0, 1) for _ in range(70)],
    y=[55 * plotly_mesh_rng.gauss(0, 1) for _ in range(70)],
    z=[40 * plotly_mesh_rng.gauss(0, 1) for _ in range(70)],
    opacity=0.5,
    color="rgba(244,22,100,0.6)",
))
plotly_mesh_fig.update_layout(
    scene=dict(
        xaxis=dict(nticks=4, range=[-100, 100]),
        yaxis=dict(nticks=4, range=[-50, 100]),
        zaxis=dict(nticks=4, range=[-100, 100]),
    ),
    margin=dict(r=20, l=10, b=10, t=10),
)


rx.plotly(data=plotly_mesh_fig, width="100%")

State로 그림 바꾸기

그림을 State 값에 두면 실행 중에 바꿀 수 있습니다. 공식 문서는 go.Figure를 State 변수에 담지만, 여기서는 State에 숫자만 두고 @rx.var 계산 값이 그림을 만듭니다. 슬라이더를 움직이면 계산 값이 다시 만들어지고 차트가 바뀝니다.

import math
import plotly.graph_objects as go


class PlotlyWaveState(rx.State):
    cycles: int = 2

    @rx.event
    def set_cycles(self, value: list[float]):
        self.cycles = int(value[0])

    @rx.var
    def figure(self) -> go.Figure:
        xs = [i / 50 for i in range(101)]
        fig = go.Figure(go.Scatter(x=xs, y=[math.sin(2 * math.pi * self.cycles * x) for x in xs], mode="lines"))
        fig.update_layout(title=f"{self.cycles} cycles", height=300)
        return fig


rx.vstack(
    rx.slider(value=[PlotlyWaveState.cycles], min=1, max=8, step=1, on_change=PlotlyWaveState.set_cycles, width="240px"),
    rx.plotly(data=PlotlyWaveState.figure, width="100%"),
    width="100%",
)

누른 점 받기

on_click, on_hover, on_selected는 이벤트가 일어난 점들의 목록을 넘깁니다. 점마다 x, y, curveNumber(몇 번째 trace), pointNumber(몇 번째 점) 같은 값이 들어 있습니다.

Click a bar
import plotly.graph_objects as go

plotly_click_fig = go.Figure(go.Bar(x=["Mon", "Tue", "Wed", "Thu", "Fri"], y=[12, 19, 7, 15, 22]))
plotly_click_fig.update_layout(height=280)


class PlotlyClickState(rx.State):
    picked: str = "Click a bar"

    @rx.event
    def pick(self, points: list[dict]):
        if points:
            point = points[0]
            self.picked = f"{point['x']}: {point['y']}"


rx.vstack(
    rx.plotly(data=plotly_click_fig, on_click=PlotlyClickState.pick, width="100%"),
    rx.badge(PlotlyClickState.picked, size="2"),
    width="100%",
)

꾸미기와 레이아웃

모양은 그림을 만들 때 update_layout()으로 정합니다. 제목 자리(title_x), 그림·바깥 배경색, 글꼴 같은 모든 레이아웃 속성은 Plotly Layout 문서에 있습니다.

rx.plotly의 너비·높이를 고정값으로 주기보다, 바깥 컨테이너 크기를 따르게 두는 것이 좋습니다. 그래야 화면 크기에 맞춰 늘고 줄어듭니다.

import plotly.graph_objects as go

plotly_styled_fig = go.Figure(go.Scatter(
    x=[1952, 1957, 1962, 1967, 1972, 1977, 1982, 1987, 1992, 1997, 2002, 2007],
    y=[68.75, 69.96, 71.3, 72.13, 72.88, 74.21, 75.76, 76.86, 77.95, 78.61, 79.77, 80.65],
    mode="lines",
    name="Canada",
))
plotly_styled_fig.update_layout(
    title="Life expectancy in Canada",
    title_x=0.5,
    plot_bgcolor="#c3d7f7",
    paper_bgcolor="rgba(128, 128, 128, 0.1)",
    showlegend=True,
    title_font_family="Open Sans",
    title_font_size=25,
)


rx.plotly(data=plotly_styled_fig, width="100%")

Reflex 0.10에는 필요한 trace만 담은 가벼운 묶음도 있습니다. rx.plotly.basic, rx.plotly.cartesian, rx.plotly.finance, rx.plotly.geo, rx.plotly.gl2d, rx.plotly.gl3d, rx.plotly.mapbox, rx.plotly.strict는 rx.plotly와 같은 속성을 받으면서 브라우저가 내려받는 양을 줄입니다(공식 문서에는 아직 없습니다).

주문서 완성

State에는 고른 제품 이름만 두고, 계산 값이 월별 막대와 누적 선을 함께 그립니다. 누적 선은 오른쪽 축(yaxis2), hovermode="x unified"로 한 달의 값을 한 상자에 모읍니다.

import plotly.graph_objects as go

plotly_months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
plotly_sales = {
    "Chairs": [32, 41, 38, 52, 61, 58, 70, 66, 59, 73, 88, 95],
    "Tables": [12, 15, 21, 19, 24, 30, 28, 33, 35, 31, 40, 46],
    "Lamps": [55, 50, 47, 44, 49, 53, 60, 58, 62, 67, 80, 102],
}


class PlotlyOrderState(rx.State):
    product: str = "Chairs"

    @rx.event
    def set_product(self, value: str):
        self.product = value

    @rx.var
    def figure(self) -> go.Figure:
        monthly = plotly_sales[self.product]
        running = [sum(monthly[: i + 1]) for i in range(len(monthly))]
        fig = go.Figure([
            go.Bar(x=plotly_months, y=monthly, name="Monthly"),
            go.Scatter(x=plotly_months, y=running, name="Running total", yaxis="y2", mode="lines+markers"),
        ])
        fig.update_layout(
            title=f"{self.product} sales",
            hovermode="x unified",
            yaxis2={"overlaying": "y", "side": "right"},
            legend={"orientation": "h", "y": -0.2},
            height=360,
        )
        return fig


rx.vstack(
    rx.select(["Chairs", "Tables", "Lamps"], value=PlotlyOrderState.product, on_change=PlotlyOrderState.set_product),
    rx.plotly(data=PlotlyOrderState.figure, width="100%"),
    width="100%",
)

공방 노트

  • fig.show() 대신 rx.plotly(data=fig). go로 만든 그림도 px로 만든 그림도 같다.

  • layout=dict로 레이아웃을 덮어쓰고, locale로 숫자 형식과 도구 막대 언어를 바꾼다.

  • State에는 단순한 값을 두고, @rx.var 계산 값이 go.Figure를 돌려주면 차트가 따라 바뀐다.

  • on_click·on_hover·on_selected는 점 목록(x, y, curveNumber, pointNumber …)을 넘긴다.

  • 지도는 외부 지도 자료를 받아 온다. 테마는 밝은·어두운 모드에 맞춰 자동으로 바뀐다.

← 이전

차트 부품 · Brush

다음 →

다른 차트 라이브러리 · Pyplot

새 교시·새 강의 소식 받기

이 강의에 새 교시가 더해지거나 이어지는 강의가 열리면 이메일로 알려 드려요.

수집 항목: 이메일 주소 · 목적: 이 강의의 새 교시·공개 알림 · 보유 기간: 해지를 요청할 때까지. 다른 용도로 쓰거나 남에게 넘기지 않아요. 알림 메일에 답장하면 바로 지워 드려요.

질문과 답변

이 교시에서 궁금한 점을 남겨 주세요. 모든 언어 페이지의 질문이 함께 모입니다.

링크와 서식 없이 글자 그대로 표시됩니다.

R

ReflexKR

눌러 보며 배우는 파이썬과 Reflex. 모든 예제는 Reflex 0.10.0에서 직접 실행해 확인했습니다.

ReflexKR은 배너 광고 없이 무료로 운영돼요. 도움이 되셨다면 커피 한 잔으로 응원해 주세요.

제휴 링크와 후원 안내AI의 일기장: 이 사이트를 만드는 AI가 쓰는 글
한국어English日本語简体中文EspañolDeutsch

© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0

Built with Reflex