컴포넌트 공방: 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
공방 주문서
한 달 수입이 어디서 들어와 월세·식비·저축으로 얼마씩 흘러가는지, 흐름의 굵기로 보여 주세요.
rx.recharts.sankey_chart는 노드(마디)와 그 사이를 흐르는 양을 띠의 굵기로 보여 주는 생키 다이어그램입니다. 방문자가 어느 페이지를 거쳐 구매까지 가는지, 돈이 어디서 와서 어디로 가는지처럼 "흐름"을 볼 때 씁니다.
data는 리스트가 아니라 {"nodes": [...], "links": [...]} 모양의 dict입니다. links의 source와 target은 nodes 리스트의 순번(0부터)이고, value가 그 흐름의 양입니다. 툴팁은 자식으로 넣습니다.
sankeychart_data = {
"nodes": [
{"name": "Website"},
{"name": "Landing"},
{"name": "Product"},
{"name": "Checkout"},
{"name": "Purchase"},
],
"links": [
{"source": 0, "target": 1, "value": 1200},
{"source": 1, "target": 2, "value": 900},
{"source": 2, "target": 3, "value": 420},
{"source": 3, "target": 4, "value": 260},
],
}
rx.recharts.sankey_chart(
rx.recharts.graphing_tooltip(),
data=sankeychart_data,
node_padding=24,
node_width=12,
link_curvature=0.55,
width="100%",
height=300,
)node와 link에 dict를 주면 모든 노드와 띠에 같은 SVG 스타일이 들어갑니다. dict의 키는 SVG 속성 이름 그대로(strokeOpacity처럼 카멜 표기) 씁니다. link_curvature는 띠가 휘는 정도(0이면 직선)입니다.
속성 바꿔 보기
node_color
link_opacity
0.35
link_curvature
0.5
sort
rx.recharts.sankey_chart(
rx.recharts.graphing_tooltip(),
data={
"nodes": [{"name": "Ads"}, {"name": "Search"}, {"name": "Signup"}, {"name": "Leave"}, {"name": "Paid"}],
"links": [
{"source": 0, "target": 2, "value": 300},
{"source": 0, "target": 3, "value": 500},
{"source": 1, "target": 2, "value": 600},
{"source": 1, "target": 3, "value": 200},
{"source": 2, "target": 4, "value": 350},
],
},
node={"fill": rx.color("indigo", 9), "stroke": "none"},
link={"stroke": rx.color("gray", 9), "strokeOpacity": 0.35},
link_curvature=0.5,
sort=True,
node_padding=20,
node_width=12,
width="100%",
height=300,
)| 속성 | 값 | 기본값 | 쓰임 |
|---|---|---|---|
data | {"nodes": [...], "links": [...]} | 없음 | 노드와 흐름. 링크는 노드 순번으로 잇는다 |
name_key | 문자열 | "name" | 노드 이름의 열쇠 |
data_key | 문자열 | "value" | 흐름 양의 열쇠 |
node | dict 또는 @sankey_chart.node 함수 | 노드 스타일이나 직접 그리는 함수 | |
link | dict 또는 @sankey_chart.link 함수 | 띠 스타일이나 직접 그리는 함수 | |
node_width | 숫자 | 10 | 노드 막대의 굵기 |
node_padding | 숫자 | 10 | 같은 열의 노드 사이 간격 |
link_curvature | 0~1 | 0.5 | 띠가 휘는 정도 |
sort | True / False | True | 노드를 위아래로 정렬할지 |
iterations | 숫자 | 32 | 배치 계산을 되풀이하는 횟수 |
margin, width, height | dict / 숫자·퍼센트 | 5씩 / "100%" | 여백과 크기. 오른쪽 이름이 잘리면 margin을 넓힌다 |
| 이벤트 | on_click on_mouse_enter on_mouse_leave on_mouse_move | 차트 영역의 마우스 이벤트 |
data에 State의 dict를 연결했습니다. 버튼을 누르면 링크의 value가 새로 정해지고, 띠의 굵기와 노드 높이가 다시 계산됩니다. 여기서는 node와 link에 dict로 색·테두리·투명도를 줍니다.
import random
from typing import Any
class SankeyChartLiveState(rx.State):
data: dict[str, Any] = {
"nodes": [
{"name": "Marketing"},
{"name": "Trial"},
{"name": "Sales"},
{"name": "Support"},
{"name": "Retained"},
],
"links": [
{"source": 0, "target": 1, "value": 600},
{"source": 1, "target": 2, "value": 320},
{"source": 2, "target": 4, "value": 210},
{"source": 1, "target": 3, "value": 180},
{"source": 3, "target": 4, "value": 130},
],
}
@rx.event
def shuffle(self):
self.data = {
"nodes": self.data["nodes"],
"links": [{**link, "value": random.randint(80, 700)} for link in self.data["links"]],
}
rx.vstack(
rx.recharts.sankey_chart(
rx.recharts.graphing_tooltip(),
data=SankeyChartLiveState.data,
node={
"fill": rx.color("accent", 7),
"stroke": rx.color("accent", 10),
"strokeWidth": 2,
},
link={
"stroke": rx.color("gray", 7),
"strokeOpacity": 0.35,
},
node_padding=18,
node_width=14,
width="100%",
height=300,
),
rx.button("Randomize flows", on_click=SankeyChartLiveState.shuffle),
width="100%",
)dict로 부족하면 노드와 띠를 그리는 함수를 직접 씁니다. @rx.recharts.sankey_chart.node를 붙인 함수는 노드 하나의 정보(SankeyNodeProps: 위치 x·y, 크기 width·height, 원래 데이터 payload)를 Var로 받아 SVG 컴포넌트를 돌려줍니다. @rx.recharts.sankey_chart.link는 띠 하나의 정보(SankeyLinkProps: 시작·끝 좌표, 굵기 linkWidth, payload)를 받습니다.
rx.recharts.use_chart_width()는 차트의 실제 폭입니다. 오른쪽 끝 노드는 이름을 왼쪽에 두는 데 씁니다."fill")는 payload.to(dict)["fill"]처럼 dict로 바꿔 읽습니다.rx.vars.use_id()는 띠마다 겹치지 않는 그라디언트 id를 만듭니다. 띠는 출발 노드 색에서 도착 노드 색으로 물듭니다.함수 두 개는 화면에 쓰기 전에 모듈 수준에서 한 번 정의합니다.
sankeychart_styled = {
"nodes": [
{"name": "Sources", "fill": rx.color("blue", 8)},
{"name": "Direct", "fill": rx.color("green", 8)},
{"name": "Search", "fill": rx.color("grass", 8)},
{"name": "Paid", "fill": rx.color("amber", 8)},
{"name": "Revenue", "fill": rx.color("purple", 8)},
],
"links": [
{"source": 0, "target": 1, "value": 350},
{"source": 0, "target": 2, "value": 500},
{"source": 0, "target": 3, "value": 220},
{"source": 1, "target": 4, "value": 190},
{"source": 2, "target": 4, "value": 260},
{"source": 3, "target": 4, "value": 150},
],
}
@rx.recharts.sankey_chart.node
def sankeychart_node(node: rx.Var[rx.recharts.SankeyNodeProps]) -> rx.Component:
# put the name on the left for the rightmost nodes
is_out = node.x + node.width + 6 > rx.recharts.use_chart_width()
return rx.fragment(
rx.el.svg.text(
node.payload.name,
x=rx.cond(is_out, node.x - 6, node.x + node.width + 6).to(int),
y=(node.y + node.height / 2).to(int),
text_anchor=rx.cond(is_out, "end", "start"),
fill=rx.color("gray", 12),
font_size=10,
),
rx.el.svg.rect(
x=node.x.to(int),
y=node.y.to(int),
width=node.width.to(int),
height=node.height.to(int),
# read the payload's custom key (fill) after converting it to a dict
fill=node.payload.to(dict)["fill"],
stroke=rx.color("gray", 12),
stroke_width=1,
),
)
@rx.recharts.sankey_chart.link
def sankeychart_link(link: rx.Var[rx.recharts.SankeyLinkProps]) -> rx.Component:
link_id = rx.vars.use_id()
source = link.payload.source.to(dict)
target = link.payload.target.to(dict)
return rx.fragment(
rx.el.svg.linear_gradient(
rx.el.svg.stop(offset="0%", stop_color=source["fill"]),
rx.el.svg.stop(offset="100%", stop_color=target["fill"]),
id=link_id,
),
rx.el.svg.path(
d=(
f"M{link.sourceX},{link.sourceY} "
f"C{link.sourceControlX},{link.sourceY} "
f"{link.targetControlX},{link.targetY} "
f"{link.targetX},{link.targetY}"
),
fill="none",
stroke=f"url(#{link_id})",
stroke_opacity=0.35,
stroke_width=link.linkWidth,
),
rx.el.svg.text(
link.payload.value,
x=((link.sourceX + link.targetX) / 2).to(int),
y=((link.sourceY + link.targetY) / 2).to(int),
text_anchor="middle",
fill=rx.color("gray", 12),
font_size=10,
),
)
rx.recharts.sankey_chart(
data=sankeychart_styled,
node=sankeychart_node,
link=sankeychart_link,
width="100%",
height=320,
)수입 두 곳이 "Budget" 노드로 모였다가 세 갈래로 나뉩니다. 노드는 진한 색, 띠는 같은 색의 옅은 단계로 칠해 흐름이 노드에서 이어져 나오는 것처럼 보이게 하고, 오른쪽 margin을 넓혀 마지막 열의 이름이 잘리지 않게 했습니다.
rx.recharts.sankey_chart(
rx.recharts.graphing_tooltip(),
data={
"nodes": [
{"name": "Salary"},
{"name": "Side job"},
{"name": "Budget"},
{"name": "Rent"},
{"name": "Food"},
{"name": "Savings"},
],
"links": [
{"source": 0, "target": 2, "value": 3000},
{"source": 1, "target": 2, "value": 600},
{"source": 2, "target": 3, "value": 1400},
{"source": 2, "target": 4, "value": 900},
{"source": 2, "target": 5, "value": 1300},
],
},
node={"fill": rx.color("accent", 9), "stroke": "none"},
link={"stroke": rx.color("accent", 6), "strokeOpacity": 0.5},
node_padding=28,
node_width=10,
margin={"top": 10, "right": 80, "bottom": 10, "left": 10},
width="100%",
height=300,
)공방 노트
data는 {"nodes": [...], "links": [...]}. 링크의 source·target은 노드 순번.
node·link에 dict를 주면 전체 스타일(SVG 속성 이름은 카멜 표기).
node_width·node_padding·link_curvature·sort로 배치를 다듬는다.
더 자유롭게 그리려면 @rx.recharts.sankey_chart.node / .link 함수로 SVG를 돌려준다.
data에 State의 dict를 연결하면 흐름이 바뀔 때 다시 계산된다.
새 교시·새 강의 소식 받기
이 강의에 새 교시가 더해지거나 이어지는 강의가 열리면 이메일로 알려 드려요.
R
ReflexKR
눌러 보며 배우는 파이썬과 Reflex. 모든 예제는 Reflex 0.10.0에서 직접 실행해 확인했습니다.
ReflexKR은 배너 광고 없이 무료로 운영돼요. 도움이 되셨다면 커피 한 잔으로 응원해 주세요.
© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
질문과 답변
이 교시에서 궁금한 점을 남겨 주세요. 모든 언어 페이지의 질문이 함께 모입니다.