Die Komponentenwerkstatt: Reflex' 100 Bibliotheksbausteine
·
Kursüberblick
Layout
·
Box
·
Flex
·
Stack
·
Grid
·
Container
·
Section
·
Center
·
Spacer
·
Separator
·
Card
·
Inset
·
Aspect Ratio
·
Fragment
Typografie
·
Text
·
Heading
·
Link
·
Code
·
Markdown
·
Blockquote
·
Quote
·
Strong
·
Em
·
Kbd
Formulare
·
Button
·
Input
·
Text Area
·
Checkbox
·
Switch
·
Radio Group
·
Select
·
Slider
·
Form
·
Upload
Datenanzeige
·
Badge
·
Avatar
·
Icon
·
Callout
·
List
·
Data List
·
Code Block
·
Progress
·
Spinner
·
Scroll Area
·
Moment
Auf- und Zuklappen
·
Tabs
·
Accordion
·
Segmented Control
Overlays
·
Tooltip
·
Popover
·
Hover Card
·
Dialog
·
Alert Dialog
·
Drawer
·
Dropdown Menu
·
Context Menu
·
Toast
Dynamisches Rendern
·
Cond
·
Match
·
Foreach
·
Auto Scroll
Medien
·
Image
·
Audio
·
Video
Tabellen und Datengrids
·
Table
·
Data Table
·
Data Editor
Diagramme
·
Area Chart
·
Bar Chart
·
Line Chart
·
Composed Chart
·
Pie Chart
·
Radar Chart
·
Radial Bar Chart
·
Scatter Chart
·
Funnel Chart
·
Treemap
·
Sankey Chart
·
Error Bar
Diagrammbausteine
·
Axis
·
Cartesian Grid
·
Chart Tooltip
·
Legend
·
Label
·
Reference
·
Brush
Andere Diagrammbibliotheken
·
Plotly
·
Pyplot
HTML-Elemente
·
HTML
·
HTML Text
·
HTML Layout
·
HTML Forms
·
HTML Media
·
HTML Tables
·
SVG
Weitere Werkzeuge
·
Theme
·
Skeleton
·
Clipboard
·
Html Embed
·
Script
·
Memo
Werkstattauftrag
Zeig über die Breite der Ströme, woher das Monatseinkommen kommt und wie viel davon in Miete, Essen und Sparen fließt.
rx.recharts.sankey_chart ist ein Sankey-Diagramm: Es zeigt Knoten und die Menge, die zwischen ihnen fließt, als unterschiedlich breite Bänder. Du nimmst es für „Ströme“, etwa über welche Seiten Besucher zum Kauf gelangen oder woher Geld kommt und wohin es geht.
data ist keine Liste, sondern ein Dict der Form {"nodes": [...], "links": [...]}. source und target in links sind Positionen (ab 0) in der nodes-Liste, und value ist die Menge dieses Stroms. Den Tooltip legst du als Kind hinein.
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,
)Gibst du node und link ein Dict, bekommen alle Knoten und Bänder denselben SVG-Stil. Die Schlüssel des Dicts sind die SVG-Attributnamen, unverändert in camelCase (etwa strokeOpacity). link_curvature ist die Krümmung der Bänder (0 bedeutet gerade).
Props ausprobieren
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,
)| Prop | Werte | Standard | Verwendung |
|---|---|---|---|
data | {"nodes": [...], "links": [...]} | keiner | Knoten und Ströme. Links verbinden über Knotenpositionen |
name_key | String | "name" | Schlüssel des Knotennamens |
data_key | String | "value" | Schlüssel der Strommenge |
node | Dict oder @sankey_chart.node-Funktion | Knotenstil oder eigene Zeichenfunktion | |
link | Dict oder @sankey_chart.link-Funktion | Bandstil oder eigene Zeichenfunktion | |
node_width | Zahl | 10 | Breite der Knotenbalken |
node_padding | Zahl | 10 | Abstand zwischen Knoten derselben Spalte |
link_curvature | 0–1 | 0.5 | Krümmung der Bänder |
sort | True / False | True | Ob die Knoten vertikal sortiert werden |
iterations | Zahl | 32 | Anzahl der Durchläufe bei der Layoutberechnung |
margin, width, height | Dict / Zahl/Prozent | je 5 / "100%" | Außenabstand und Größe. Werden Namen rechts abgeschnitten, margin vergrößern |
| Events | on_click on_mouse_enter on_mouse_leave on_mouse_move | Maus-Events im Diagrammbereich |
data ist an ein Dict im State gebunden. Ein Klick auf den Button würfelt die values der Links neu, und Bandbreiten sowie Knotenhöhen werden neu berechnet. Farbe, Rand und Deckkraft bekommen node und link hier per 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%",
)Reicht ein Dict nicht, schreibst du eigene Funktionen zum Zeichnen von Knoten und Bändern. Eine mit @rx.recharts.sankey_chart.node dekorierte Funktion bekommt die Angaben zu einem Knoten (SankeyNodeProps: Position x und y, Größe width und height, Originaldaten payload) als Var und gibt eine SVG-Komponente zurück. @rx.recharts.sankey_chart.link bekommt die Angaben zu einem Band (SankeyLinkProps: Start- und Endkoordinaten, Breite linkWidth, payload).
rx.recharts.use_chart_width() ist die tatsächliche Breite des Diagramms. Damit setzt du bei Knoten am rechten Rand den Namen nach links."fill") liest du, indem du in ein Dict umwandelst: payload.to(dict)["fill"].rx.vars.use_id() erzeugt für jedes Band eine eindeutige Verlaufs-id. Jedes Band färbt sich von der Farbe des Startknotens zu der des Zielknotens.Beide Funktionen definierst du einmal auf Modulebene, bevor du sie in der Oberfläche verwendest.
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,
)Zwei Einkommensquellen laufen im Knoten „Budget“ zusammen und teilen sich dann in drei Zweige. Die Knoten sind kräftig gefärbt, die Bänder in einer helleren Stufe derselben Farbe, sodass die Ströme aus den Knoten herauszufließen scheinen; ein breiterer rechter margin verhindert, dass die Namen der letzten Spalte abgeschnitten werden.
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,
)Werkstattnotizen
data ist {"nodes": [...], "links": [...]}. source und target eines Links sind Knotenpositionen.
Ein Dict an node und link setzt den Stil für alle (SVG-Attributnamen in camelCase).
node_width, node_padding, link_curvature und sort feilen am Layout.
Für mehr Freiheit geben @rx.recharts.sankey_chart.node- bzw. .link-Funktionen eigenes SVG zurück.
Ist data an ein State-Dict gebunden, wird bei geänderten Strömen neu berechnet.
Über neue Lektionen informiert werden
Wir schicken dir eine E-Mail, wenn dieser Kurs neue Lektionen bekommt oder ein Folgekurs erscheint.
R
ReflexKR
Python und Reflex zum Anfassen. Alle Beispiele wurden mit Reflex 0.10.0 ausgeführt und geprüft.
ReflexKR ist kostenlos und ohne Werbebanner. Wenn es dir geholfen hat, kannst du es mit einem Kaffee unterstützen. ☕ Spendier uns einen Kaffee
Hinweis zu Affiliate-Links© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
Fragen & Antworten
Frag alles zu dieser Lektion. Fragen aus allen Sprachversionen dieser Seite erscheinen hier gemeinsam.