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
차트

Sankey Chart

rx.recharts.sankey_chartrx.recharts.sankey_chart.noderx.recharts.sankey_chart.link

공식 문서

공방 주문서

한 달 수입이 어디서 들어와 월세·식비·저축으로 얼마씩 흘러가는지, 흐름의 굵기로 보여 주세요.

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,
)
sort를 끄면 노드가 데이터에 적힌 순서대로 놓이고, 켜면 띠가 덜 엉키도록 위아래 순서를 정합니다.
속성값기본값쓰임
data{"nodes": [...], "links": [...]}없음노드와 흐름. 링크는 노드 순번으로 잇는다
name_key문자열"name"노드 이름의 열쇠
data_key문자열"value"흐름 양의 열쇠
nodedict 또는 @sankey_chart.node 함수노드 스타일이나 직접 그리는 함수
linkdict 또는 @sankey_chart.link 함수띠 스타일이나 직접 그리는 함수
node_width숫자10노드 막대의 굵기
node_padding숫자10같은 열의 노드 사이 간격
link_curvature0~10.5띠가 휘는 정도
sortTrue / FalseTrue노드를 위아래로 정렬할지
iterations숫자32배치 계산을 되풀이하는 횟수
margin, width, heightdict / 숫자·퍼센트5씩 / "100%"여백과 크기. 오른쪽 이름이 잘리면 margin을 넓힌다
이벤트on_click on_mouse_enter on_mouse_leave on_mouse_move차트 영역의 마우스 이벤트

State로 바뀌는 흐름

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를 연결하면 흐름이 바뀔 때 다시 계산된다.

← 이전

차트 · Treemap

다음 →

차트 · Error Bar

새 교시·새 강의 소식 받기

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

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

질문과 답변

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

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

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