Al terminar esta lección, en la parte inferior de la tarjeta aparecerá un gráfico de barras horizontales con el número de clientes por género, y las barras crecerán cada vez que añadas un cliente. Es el patrón básico de cualquier panel de datos: transformar los datos con Python y mostrarlos en pantalla.
Recharts (la librería de gráficos de React que Reflex envuelve y ofrece) recibe una lista de diccionarios. Cada diccionario es una barra.
# los datos que tenemos # los datos que espera el gráfico
[User(..., gender="Male"), [{"name": "Male", "value": 1},
User(..., gender="Female")] → {"name": "Female", "value": 1}]Por eso, antes de dibujar el gráfico, hace falta un paso de transformación (agregación).
from collections import Counter
class State(rx.State):
users: list[User] = [...]
users_for_graph: list[dict] = [] # datos para el gráfico
add_user_dialog_open: bool = False
@rx.event
def transform_data(self):
gender_counts = Counter(user.gender for user in self.users)
self.users_for_graph = [
{"name": gender_group, "value": count}
for gender_group, count in gender_counts.items()
]Counter forma parte de la librería estándar de Python. Counter(["Male", "Female", "Male"]) → {"Male": 2, "Female": 1}.El valor inicial de users_for_graph es una lista vacía. Hay que rellenarla en dos momentos.
Al abrir la página: registra el manejador en el on_load de add_page.
app.add_page(
index,
title="Customer Data App",
description="A simple app to manage customer data.",
on_load=State.transform_data, # se ejecuta cada vez que se entra o se recarga la página
)Al añadir un cliente: llámalo directamente dentro de add_user.
@rx.event
def add_user(self, form_data: dict):
self.users.append(User(**form_data))
self.transform_data() # vuelve a calcular los datos del gráfico
self.add_user_dialog_open = Falsedescription es la descripción de la página (una etiqueta meta) que aparece en los buscadores y en las vistas previas de enlaces.transform_data() en cada sitio donde cambies users. Si añades una función para borrar y se te olvida la llamada, el gráfico y la tabla dejarán de coincidir.Con @rx.var puedes declarar "un valor que se calcula a partir de otro estado". Cada vez que cambia users, Reflex lo vuelve a calcular por su cuenta.
class State(rx.State):
users: list[User] = [...]
@rx.var
def users_for_graph(self) -> list[dict]: # la anotación del tipo de retorno es obligatoria
counts = Counter(user.gender for user in self.users)
return [{"name": g, "value": c} for g, c in counts.items()]transform_data, on_load y la llamada dentro de add_user. El código de pantalla (data=State.users_for_graph) no cambia.Nota para el instructor — "Guardar el valor y actualizarlo cada vez" frente a "declarar cómo se calcula". Se entiende muy bien con la analogía de Excel: escribir un valor a mano en una celda frente a poner una fórmula (=COUNTIF(...)).
def graph():
return rx.recharts.bar_chart(
rx.recharts.cartesian_grid(
horizontal=False, stroke_dasharray="3 3", stroke=rx.color("slate", 4)
),
rx.recharts.x_axis(
type_="number",
allow_decimals=False,
axis_line=False,
tick_line=False,
domain=[0, "dataMax + 1"],
),
rx.recharts.y_axis(
type_="category",
data_key="name",
axis_line=False,
tick_line=False,
width=64,
),
rx.recharts.bar(
data_key="value",
fill=rx.color("accent", 9),
radius=[0, 6, 6, 0],
bar_size=28,
),
data=State.users_for_graph,
layout="vertical",
width="100%",
height=160,
margin={"top": 0, "right": 16, "bottom": 0, "left": 0},
)Un gráfico también es un componente: las piezas se pasan como hijos, y los datos y el tamaño, como argumentos de palabra clave.
| Pieza | Función | Argumentos clave |
|---|---|---|
bar_chart | Marco de todo el gráfico | data (lista de diccionarios), layout="vertical" (barras horizontales) |
cartesian_grid | Cuadrícula de fondo | horizontal=False (solo líneas verticales), stroke_dasharray="3 3" (línea discontinua) |
x_axis | Eje horizontal = número de clientes | type_="number", allow_decimals=False (evita marcas como 1,5 clientes), domain=[0, "dataMax + 1"] (deja 1 de margen por encima del máximo) |
y_axis | Eje vertical = género | type_="category", data_key="name" (qué clave del diccionario se usa como nombre) |
bar | Barras | data_key="value" (la clave que se usa como longitud), radius=[0, 6, 6, 0] (esquinas superior izquierda, superior derecha, inferior derecha e inferior izquierda: solo se redondea el extremo) |
layout="vertical", el eje x es numérico y el eje y es de categorías. Es justo lo contrario que en las barras verticales (el valor por defecto), y es lo que más suele confundir.rx.color("accent", 9) es el color de acento del tema. Si lo cambias en rxconfig.py, por ejemplo con RadixThemesPlugin(theme=rx.theme(accent_color="indigo")), cambiarán a la vez el color de los botones y de las barras.graph() se añade como tercer hijo de la tarjeta, junto con su título.rx.box(
rx.text("Audience breakdown", size="3", weight="bold"),
rx.text(
"Customers by gender",
size="2",
color=rx.color("slate", 11),
margin_top="4px",
margin_bottom="20px",
),
graph(),
padding="24px",
),Compruébalo en el navegador — Debajo de la tabla aparece la zona "Audience breakdown", con las barras Male y Female llegando cada una hasta 1. Que el eje x llegue hasta 2 se debe a domain=[0, "dataMax + 1"]. Las barras aparecen con una animación que las va llenando desde la izquierda, así que espera 1 o 2 segundos.
localhost:3000
PruébaloYour customer directory and audience breakdown.
Audience breakdown
Customers by gender
Si añades una clienta Female en la vista previa de arriba, la barra Female sube a 2 y el eje x se amplía hasta 3. Si el gráfico no cambia, revisa la llamada a self.transform_data() dentro de add_user.
Una vez que hayas comprobado que todo funciona hasta 5-5, cambia el enfoque basado en eventos por una computed var sin tocar la pantalla. Hay que modificar tres sitios:
State, borra el campo users_for_graph: list[dict] = [] y el método transform_data, y añade el método @rx.var de 5-4. Como el nombre es el mismo, es imprescindible borrar el campo.self.transform_data() de dentro de add_user.on_load=State.transform_data de app.add_page.class State(rx.State):
users: list[User] = [...]
add_user_dialog_open: bool = False
@rx.event
def set_add_user_dialog_open(self, open_: bool):
self.add_user_dialog_open = open_
@rx.event
def add_user(self, form_data: dict):
self.users.append(User(**form_data))
self.add_user_dialog_open = False # sin llamada a transform_data()
@rx.var
def users_for_graph(self) -> list[dict]:
counts = Counter(user.gender for user in self.users)
return [{"name": g, "value": c} for g, c in counts.items()]
app = rx.App()
app.add_page(
index,
title="Customer Data App",
description="A simple app to manage customer data.",
) # sin on_loaddata=State.users_for_graph en graph(). Desde la pantalla, una variable de estado normal y una computed var se ven exactamente igual.from collections import Counter tal como está.Compruébalo en el navegador — Al guardar, tras el hot reload, el gráfico se ve exactamente igual que en 5-5. Si añades una clienta Female y la barra sube a 2, la refactorización ha funcionado. Que se actualice sin que hayas hecho ninguna llamada es la esencia de una computed var.
rx.recharts.graphing_tooltip() como hijo del gráfico para que se vea el valor al pasar el ratón por encima.@rx.var def female_count(self) -> int y muéstrala junto al título del gráfico como "Female: N".@).on_load y el de computed var.← Anterior
Lección 4 · Eventos y formularios: añadir clientes
Siguiente →
Lección 6 · Resumen, depuración y próximos pasos
Recibe avisos de nuevas lecciones
Te avisaremos por correo cuando este curso tenga lecciones nuevas o se abra un curso de continuación.
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© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
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.