R

ReflexKR

Reflex-Dokumentation

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

Die Komponentenwerkstatt: Reflex' 100 Bibliotheksbausteine
Diagramme

Sankey Chart

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

Offizielle Doku

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,
)

Props ausprobieren

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,
)
Ohne sort stehen die Knoten in der Reihenfolge der Daten; mit sort wird die vertikale Reihenfolge so gewählt, dass sich die Bänder weniger verheddern.
PropWerteStandardVerwendung
data{"nodes": [...], "links": [...]}keinerKnoten und Ströme. Links verbinden über Knotenpositionen
name_keyString"name"Schlüssel des Knotennamens
data_keyString"value"Schlüssel der Strommenge
nodeDict oder @sankey_chart.node-FunktionKnotenstil oder eigene Zeichenfunktion
linkDict oder @sankey_chart.link-FunktionBandstil oder eigene Zeichenfunktion
node_widthZahl10Breite der Knotenbalken
node_paddingZahl10Abstand zwischen Knoten derselben Spalte
link_curvature0–10.5Krümmung der Bänder
sortTrue / FalseTrueOb die Knoten vertikal sortiert werden
iterationsZahl32Anzahl der Durchläufe bei der Layoutberechnung
margin, width, heightDict / Zahl/Prozentje 5 / "100%"Außenabstand und Größe. Werden Namen rechts abgeschnitten, margin vergrößern
Eventson_click on_mouse_enter on_mouse_leave on_mouse_moveMaus-Events im Diagrammbereich

Ströme aus dem State

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%",
)

Knoten und Bänder selbst zeichnen

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.
  • Eigene Schlüssel in den Daten ("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,
)

Auftrag erledigt

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.

← Zurück

Diagramme · Treemap

Weiter →

Diagramme · Error Bar

Über neue Lektionen informiert werden

Wir schicken dir eine E-Mail, wenn dieser Kurs neue Lektionen bekommt oder ein Folgekurs erscheint.

Erhoben: deine E-Mail-Adresse · Zweck: Hinweise auf neue Lektionen oder den Start dieses Kurses · Speicherdauer: bis du die Löschung verlangst. Keine andere Nutzung, keine Weitergabe. Antworte einfach auf eine Benachrichtigung, dann löschen wir sie sofort.

Fragen & Antworten

Frag alles zu dieser Lektion. Fragen aus allen Sprachversionen dieser Seite erscheinen hier gemeinsam.

Wird als reiner Text angezeigt, ohne Links oder Formatierung.

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
한국어English日本語简体中文EspañolDeutsch

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

Built with Reflex