R

ReflexKR

Documentación de Reflex

El taller de componentes: los 100 componentes de Reflex

·

Resumen del curso

Diseño

·

Box

·

Flex

·

Stack

·

Grid

·

Container

·

Section

·

Center

·

Spacer

·

Separator

·

Card

·

Inset

·

Aspect Ratio

·

Fragment

Tipografía

·

Text

·

Heading

·

Link

·

Code

·

Markdown

·

Blockquote

·

Quote

·

Strong

·

Em

·

Kbd

Formularios

·

Button

·

Input

·

Text Area

·

Checkbox

·

Switch

·

Radio Group

·

Select

·

Slider

·

Form

·

Upload

Visualización de datos

·

Badge

·

Avatar

·

Icon

·

Callout

·

List

·

Data List

·

Code Block

·

Progress

·

Spinner

·

Scroll Area

·

Moment

Mostrar y ocultar

·

Tabs

·

Accordion

·

Segmented Control

Superposiciones

·

Tooltip

·

Popover

·

Hover Card

·

Dialog

·

Alert Dialog

·

Drawer

·

Dropdown Menu

·

Context Menu

·

Toast

Renderizado dinámico

·

Cond

·

Match

·

Foreach

·

Auto Scroll

Multimedia

·

Image

·

Audio

·

Video

Tablas y cuadrículas de datos

·

Table

·

Data Table

·

Data Editor

Gráficos

·

Area Chart

·

Bar Chart

·

Line Chart

·

Composed Chart

·

Pie Chart

·

Radar Chart

·

Radial Bar Chart

·

Scatter Chart

·

Funnel Chart

·

Treemap

·

Sankey Chart

·

Error Bar

Piezas de gráficos

·

Axis

·

Cartesian Grid

·

Chart Tooltip

·

Legend

·

Label

·

Reference

·

Brush

Otras bibliotecas de gráficos

·

Plotly

·

Pyplot

Elementos HTML

·

HTML

·

HTML Text

·

HTML Layout

·

HTML Forms

·

HTML Media

·

HTML Tables

·

SVG

Otras herramientas

·

Theme

·

Skeleton

·

Clipboard

·

Html Embed

·

Script

·

Memo

El taller de componentes: los 100 componentes de Reflex
Gráficos

Sankey Chart

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

Documentación oficial

Pedido del taller

Muestra con el grosor de los flujos de dónde entran los ingresos del mes y cuánto se va al alquiler, a la comida y al ahorro.

rx.recharts.sankey_chart es un diagrama de Sankey: muestra nodos y la cantidad que fluye entre ellos mediante el grosor de unas bandas. Se usa para ver «flujos», como por qué páginas pasan los visitantes hasta llegar a la compra, o de dónde viene el dinero y adónde va.

data no es una lista sino un dict con la forma {"nodes": [...], "links": [...]}. El source y el target de links son posiciones (desde 0) de la lista nodes, y value es la cantidad de ese flujo. El tooltip se añade como hijo.

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

Prueba las propiedades

Si das un dict a node y a link, todos los nodos y bandas reciben el mismo estilo SVG. Las claves del dict son los nombres de los atributos SVG tal cual (en camelCase, como strokeOpacity). link_curvature es cuánto se curvan las bandas (con 0, rectas).

Prueba las propiedades

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,
)
Con sort desactivado, los nodos se colocan en el orden de los datos; activado, se ordenan de arriba abajo para que las bandas se crucen menos.
PropiedadValoresPor defectoUso
data{"nodes": [...], "links": [...]}ningunoNodos y flujos. Los enlaces se unen por la posición del nodo
name_keycadena"name"Clave del nombre del nodo
data_keycadena"value"Clave de la cantidad del flujo
nodedict o función @sankey_chart.nodeEstilo de los nodos o función que los dibuja
linkdict o función @sankey_chart.linkEstilo de las bandas o función que las dibuja
node_widthnúmero10Grosor de la barra del nodo
node_paddingnúmero10Espacio entre nodos de la misma columna
link_curvature0~10.5Cuánto se curvan las bandas
sortTrue / FalseTrueSi se ordenan los nodos de arriba abajo
iterationsnúmero32Veces que se repite el cálculo de la disposición
margin, width, heightdict / número o porcentaje5 por lado / "100%"Margen y tamaño. Si se cortan los nombres de la derecha, amplía margin
Eventoson_click on_mouse_enter on_mouse_leave on_mouse_moveEventos de ratón sobre el área del gráfico

Flujos que cambian con State

Hemos conectado a data un dict de State. Al pulsar el botón se generan nuevos value para los enlaces, y se recalculan el grosor de las bandas y la altura de los nodos. Aquí node y link reciben un dict con color, borde y opacidad.

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

Dibujar nodos y bandas a mano

Si un dict no basta, escribe tú las funciones que dibujan nodos y bandas. Una función decorada con @rx.recharts.sankey_chart.node recibe como Var la información de un nodo (SankeyNodeProps: posición x e y, tamaño width y height, datos originales payload) y devuelve un componente SVG. @rx.recharts.sankey_chart.link recibe la información de una banda (SankeyLinkProps: coordenadas de inicio y fin, grosor linkWidth, payload).

  • rx.recharts.use_chart_width() es el ancho real del gráfico. Sirve para poner a la izquierda el nombre de los nodos del extremo derecho.
  • Las claves propias que metas en los datos ("fill") se leen convirtiendo a dict, como en payload.to(dict)["fill"].
  • rx.vars.use_id() crea para cada banda un id de degradado que no se repite. Cada banda pasa del color del nodo de origen al del nodo de destino.

Las dos funciones se definen una sola vez a nivel de módulo antes de usarlas en la pantalla.

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

Completar el pedido

Dos fuentes de ingresos se juntan en el nodo «Budget» y luego se dividen en tres ramas. Los nodos van en un color intenso y las bandas en un tono claro del mismo color, para que el flujo parezca salir de los nodos, y ampliamos el margin derecho para que no se corten los nombres de la última columna.

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

Notas del taller

  • data es {"nodes": [...], "links": [...]}. El source y el target de cada enlace son posiciones de nodos.

  • Un dict en node o link da el estilo de todos (atributos SVG en camelCase).

  • La disposición se ajusta con node_width, node_padding, link_curvature y sort.

  • Para dibujar con más libertad, devuelve SVG desde funciones @rx.recharts.sankey_chart.node / .link.

  • Con un dict de State en data, se recalcula cuando cambian los flujos.

← Anterior

Gráficos · Treemap

Siguiente →

Gráficos · Error Bar

Recibe avisos de nuevas lecciones

Te avisaremos por correo cuando este curso tenga lecciones nuevas o se abra un curso de continuación.

Datos: tu correo electrónico · Finalidad: avisos de nuevas lecciones o de la publicación de este curso · Conservación: hasta que pidas que lo borremos. No lo usamos para nada más ni lo compartimos. Responde a cualquier aviso y lo borraremos enseguida.

Preguntas y respuestas

Pregunta lo que quieras sobre esta lección. Aquí se reúnen las preguntas de todas las versiones de idioma de esta página.

Se muestra como texto plano, sin enlaces ni formato.

R

ReflexKR

Aprende Python y Reflex haciendo. Todos los ejemplos se ejecutaron y verificaron en Reflex 0.10.0.

ReflexKR es gratis y sin banners publicitarios. Si te ayudó, puedes apoyarlo con un café. ☕ Invítanos un café

Aviso de afiliados
한국어English日本語简体中文EspañolDeutsch

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

Built with Reflex