コンポーネント工房: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
工房の注文書
1か月の収入がどこから入り、家賃・食費・貯金にいくらずつ流れていくのかを、流れの太さで見せてください。
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を付けた関数は、ノード1つの情報(SankeyNodeProps:位置x・y、大きさwidth・height、元のデータpayload)をVarとして受け取り、SVGコンポーネントを返します。@rx.recharts.sankey_chart.linkは帯1本の情報(SankeyLinkProps:始点・終点の座標、太さlinkWidth、payload)を受け取ります。
rx.recharts.use_chart_width()はチャートの実際の幅です。右端のノードで名前を左側に置くのに使います。"fill")は、payload.to(dict)["fill"]のようにdictに変換して読みます。rx.vars.use_id()は帯ごとに重ならないグラデーションのidを作ります。帯は出発ノードの色から到着ノードの色へと染まります。2つの関数は、画面で使う前にモジュールレベルで一度だけ定義します。
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,
)2つの収入源が「Budget」ノードに集まり、3つに分かれます。ノードは濃い色、帯は同じ色の淡い段階で塗って、流れがノードから続いて出ていくように見せ、右の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
触って学ぶPythonとReflex。すべての例はReflex 0.10.0で実際に動かして確認しています。
ReflexKRはバナー広告なし・無料で運営しています。役に立ったら、コーヒー一杯で応援してください。 ☕ コーヒーで応援する
アフィリエイトと支援について© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
質問と回答
この回について気になることを書き込んでください。すべての言語のページの質問がここに集まります。