R

ReflexKR

Documentación de Reflex

Desarrollo web full stack con Python y Reflex

·

Resumen del curso

1

Conoce Reflex y prepara tu entorno

2

Dibujar la pantalla con componentes

3

State y Vars: que los datos dibujen la pantalla

4

Eventos y formularios: añadir clientes

5

Transformar datos y gráficos

6

Resumen, depuración y próximos pasos

·

Apéndice

Desarrollo web full stack con Python y Reflex
Lección 5

Tiempo 3:05–3:45

Transformar datos y gráficos

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.

5-1. La forma de los datos que espera el gráfico (5 min)

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

5-2. Agregar con Counter (10 min)

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}.
  • Los manejadores son Python de verdad ejecutándose en el servidor, así que puedes usar tanto la librería estándar como pandas sin cambiar nada. Dentro de una función de pantalla esto es imposible (la tabla de la lección 3).

5-3. ¿Cuándo transformar? on_load y la llamada dentro del manejador (5 min)

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 = False
  • description es la descripción de la página (una etiqueta meta) que aparece en los buscadores y en las vistas previas de enlaces.
  • El punto débil de este enfoque es que no puedes olvidarte de llamar a 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.

5-4. Una forma mejor: computed var (5 min)

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()]
  • Con este cambio puedes eliminar transform_data, on_load y la llamada dentro de add_user. El código de pantalla (data=State.users_for_graph) no cambia.
  • El código original usa el enfoque basado en eventos. En el curso, primero mostramos el gráfico con el enfoque original hasta 5-5 y luego, en 5-6, lo refactorizamos todos juntos a computed var.

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(...)).

5-5. Dibujar el gráfico de barras (10 min)

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.

PiezaFunciónArgumentos clave
bar_chartMarco de todo el gráficodata (lista de diccionarios), layout="vertical" (barras horizontales)
cartesian_gridCuadrícula de fondohorizontal=False (solo líneas verticales), stroke_dasharray="3 3" (línea discontinua)
x_axisEje horizontal = número de clientestype_="number", allow_decimals=False (evita marcas como 1,5 clientes), domain=[0, "dataMax + 1"] (deja 1 de margen por encima del máximo)
y_axisEje vertical = génerotype_="category", data_key="name" (qué clave del diccionario se usa como nombre)
barBarrasdata_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)
  • Con 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.
  • La función 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ébalo

Customers

2

Your customer directory and audience breakdown.

NameEmailGender
Danilo Sousadanilo@example.comMale
Zahra Ambessazahra@example.comFemale

Audience breakdown

Customers by gender

Lección 5 completada: al añadir clientes, el gráfico de barras por género crece con ellos.

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.

5-6. Hazlo tú: refactorizar a computed var (5 min)

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:

  1. En 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.
  2. Borra la línea self.transform_data() de dentro de add_user.
  3. Quita 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_load
  • No cambies ni una letra de data=State.users_for_graph en graph(). Desde la pantalla, una variable de estado normal y una computed var se ven exactamente igual.
  • Deja 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.

Práctica

  1. Añade rx.recharts.graphing_tooltip() como hijo del gráfico para que se vea el valor al pasar el ratón por encima.
  2. Siguiendo el mismo método que en 5-6, crea otra computed var @rx.var def female_count(self) -> int y muéstrala junto al título del gráfico como "Female: N".
  3. Crea otro gráfico con el número de clientes por dominio de email (lo que va después de @).

Punto de control

  • Al abrir la página, el gráfico muestra las barras Male 1 y Female 1.
  • Al añadir un cliente, la barra correspondiente se alarga.
  • Puedes explicar la diferencia entre el enfoque con on_load y el de computed var.
  • Después de pasar a computed var, el gráfico se sigue actualizando al añadir clientes.

← 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.

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