Autores: Manuel Jesús Gómez Moratilla, José Antonio Ruipérez Valiente y Mariano Albaladejo González
En esta sesión guiada vamos a construir, paso a paso, un dashboard interactivo con datos educacionales:
un dataset de rendimiento de estudiantes en exámenes (notas de matemáticas, lectura y escritura, junto con variables de contexto).
Un dashboard (cuadro de mando) es una pantalla que reúne indicadores clave (KPIs) y visualizaciones interactivas para ayudarte a:
Características típicas de un buen dashboard:
¿Qué estudiantes están en riesgo?
¿Qué actividad del curso tiene mayor impacto en el rendimiento?).
Usaremos el dataset “Students Performance in Exams” (1000 estudiantes),
que incluye variables como:
gender: género del estudiante race/ethnicity: grupo étnico parental level of education: máximo nivel educativo de los padres lunch: tipo de almuerzo (estándar vs subvencionado) test preparation course: si ha realizado un curso de preparación math score, reading score, writing score: notas de 0 a 100El primer paso es preparar nuestro entorno con la importación de paquetes necesarios:
import plotly
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
# Renderizador recomendado para Colab
import plotly.io as pio
pio.renderers.default = "colab"
print("Entorno listo. Versión de Plotly:", plotly.__version__)
Entorno listo. Versión de Plotly: 5.24.1
Ahora, cargamos nuestro conjunto de datos desde el archivo CSV que tenemos.
df = pd.read_csv("StudentsPerformance.csv")
df
| gender | race/ethnicity | parental level of education | lunch | test preparation course | math score | reading score | writing score | |
|---|---|---|---|---|---|---|---|---|
| 0 | female | group B | bachelor's degree | standard | none | 72 | 72 | 74 |
| 1 | female | group C | some college | standard | completed | 69 | 90 | 88 |
| 2 | female | group B | master's degree | standard | none | 90 | 95 | 93 |
| 3 | male | group A | associate's degree | free/reduced | none | 47 | 57 | 44 |
| 4 | male | group C | some college | standard | none | 76 | 78 | 75 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 995 | female | group E | master's degree | standard | completed | 88 | 99 | 95 |
| 996 | male | group C | high school | free/reduced | none | 62 | 55 | 55 |
| 997 | female | group C | high school | free/reduced | completed | 59 | 71 | 65 |
| 998 | female | group D | some college | standard | completed | 68 | 78 | 77 |
| 999 | female | group D | some college | free/reduced | none | 77 | 86 | 86 |
1000 rows × 8 columns
Vamos a realizar una exploración básica del dataset, fijándonos en la estructura y en el tipo de variables que contiene.
print("Dimensiones del dataset:", df.shape)
print("\nColumnas:\n", list(df.columns))
Dimensiones del dataset: (1000, 8) Columnas: ['gender', 'race/ethnicity', 'parental level of education', 'lunch', 'test preparation course', 'math score', 'reading score', 'writing score']
print("\nDescripción de las columnas numéricas:")
df.describe()
Descripción de las columnas numéricas:
| math score | reading score | writing score | |
|---|---|---|---|
| count | 1000.00000 | 1000.000000 | 1000.000000 |
| mean | 66.08900 | 69.169000 | 68.054000 |
| std | 15.16308 | 14.600192 | 15.195657 |
| min | 0.00000 | 17.000000 | 10.000000 |
| 25% | 57.00000 | 59.000000 | 57.750000 |
| 50% | 66.00000 | 70.000000 | 69.000000 |
| 75% | 77.00000 | 79.000000 | 79.000000 |
| max | 100.00000 | 100.000000 | 100.000000 |
Este dataset incluye:
Variables categóricas:
genderrace/ethnicityparental level of educationlunchtest preparation courseVariables numéricas (nuestro foco para el dashboard):
math scorereading scorewriting scoreAlgunas preguntas típicas que podemos hacernos:
Iremos construyendo visualizaciones para ir respondiendo a estas preguntas.
Vamos a construir algunos gráficos básicos para entender el rendimiento de los estudiantes:
Usaremos plotly.express (px), que permite crear gráficos interactivos con muy poco código.
# crear un DataFrame con nombres de columnas más manejables
df_edu = df.rename(columns={
"race/ethnicity": "race_ethnicity",
"parental level of education": "parent_education",
"test preparation course": "test_prep",
"math score": "math_score",
"reading score": "reading_score",
"writing score": "writing_score"
})
df_edu.head()
| gender | race_ethnicity | parent_education | lunch | test_prep | math_score | reading_score | writing_score | |
|---|---|---|---|---|---|---|---|---|
| 0 | female | group B | bachelor's degree | standard | none | 72 | 72 | 74 |
| 1 | female | group C | some college | standard | completed | 69 | 90 | 88 |
| 2 | female | group B | master's degree | standard | none | 90 | 95 | 93 |
| 3 | male | group A | associate's degree | free/reduced | none | 47 | 57 | 44 |
| 4 | male | group C | some college | standard | none | 76 | 78 | 75 |
Creamos un histograma de la columna math_score:
nbins=20 controlamos cuántos “trozos” se usan para dividir el eje X.labels nos permite mostrar un nombre más amigable en el eje.# Histograma con las notas de matemáticas
fig_math_hist = px.histogram(
df_edu,
x="math_score",
nbins=20,
title="Distribución de notas de Matemáticas",
labels={"math_score": "Nota de Matemáticas"}
)
fig_math_hist
Podemos exportar cualquier figura de Plotly a un archivo HTML interactivo:
fig.write_html("nombre_figura.html")
fig_math_hist.write_html("figura_ejemplo.html")
Este gráfico es una extensión del histograma anterior, pero ahora:
color="gender" para dibujar una distribución por cada género.barmode="overlay" superponemos las distribuciones.opacity=0.6 hace que las barras sean semitransparentes y podamos ver ambas.# Histograma comparando géneros
fig_math_gender = px.histogram(
df_edu,
x="math_score",
color="gender",
barmode="overlay",
nbins=20,
title="Distribución de notas de Matemáticas por género",
labels={"math_score": "Nota de Matemáticas", "gender": "Género"},
opacity=0.6
)
fig_math_gender
Aquí damos un paso hacia el análisis agregado:
parent_education con groupby.math_scorereading_scorewriting_scoredf_parent_avg donde cada fila es un nivel educativo de los padres y las columnas son las notas medias correspondientes.Este tipo de tabla es muy típico para construir visualizaciones: no miramos cada estudiante individual, sino patrones por grupo.
# Calculamos medias por nivel educativo de los padres
df_parent_avg = (
df_edu
.groupby("parent_education", as_index=False)[["math_score", "reading_score", "writing_score"]]
.mean()
)
df_parent_avg
| parent_education | math_score | reading_score | writing_score | |
|---|---|---|---|---|
| 0 | associate's degree | 67.882883 | 70.927928 | 69.896396 |
| 1 | bachelor's degree | 69.389831 | 73.000000 | 73.381356 |
| 2 | high school | 62.137755 | 64.704082 | 62.448980 |
| 3 | master's degree | 69.745763 | 75.372881 | 75.677966 |
| 4 | some college | 67.128319 | 69.460177 | 68.840708 |
| 5 | some high school | 63.497207 | 66.938547 | 64.888268 |
Este gráfico de barras muestra, para cada nivel educativo de los padres:
y=[...] indicamos que queremos varias series a la vez.barmode="group" las barras de cada asignatura aparecen una al lado de la otra.Objetivo:
fig_parent_avg = px.bar(
df_parent_avg,
x="parent_education",
y=["math_score", "reading_score", "writing_score"],
title="Notas medias por nivel educativo de los padres",
labels={"value": "Nota media", "parent_education": "Nivel educativo de los padres"},
barmode="group"
)
fig_parent_avg.update_layout(
xaxis_tickangle=45,
template="plotly_white"
)
fig_parent_avg
Vamos a crear un scatter para ver la relación entre matemáticas y lectura, usando el color para distinguir el tipo de almuerzo (indicador socioeconómico aproximado), y el símbolo para marcar si ha realizado el curso de preparación.
Ahora usamos un gráfico de dispersión (scatter plot):
math_score).reading_score).lunch (tipo de almuerzo).test_prep (si ha hecho un curso de preparación o no).hover_data añade información extra al pasar el ratón por encima (género, educación de los padres).Este tipo de gráfico es muy útil para ver correlaciones o patrones:
fig_math_read = px.scatter(
df_edu,
x="math_score",
y="reading_score",
color="lunch",
symbol="test_prep",
hover_data=["gender", "parent_education"],
title="Relación entre Matemáticas y Lectura",
labels={
"math_score": "Nota de Matemáticas",
"reading_score": "Nota de Lectura",
"lunch": "Tipo de almuerzo",
"test_prep": "Curso de preparación"
}
)
fig_math_read.update_layout(template="plotly_white")
fig_math_read
Un dashboard suele mostrar varios gráficos o visualizaciones a la vez.
Vamos a combinar en una misma figura:
Pasos clave:
gender y por test_prep para obtener las medias.make_subplots(rows=1, cols=2) para crear una figura con dos columnas.go.Bar(...) a cada subplot indicando en qué fila/columna debe ir (row=1, col=1 y row=1, col=2).Este tipo de figura es habitual en dashboards cuando queremos que el usuario:
from plotly.subplots import make_subplots
# Medias por género
df_math_gender = df_edu.groupby("gender", as_index=False)["math_score"].mean()
# Medias por curso de preparación
df_math_prep = df_edu.groupby("test_prep", as_index=False)["math_score"].mean()
fig_sub = make_subplots(
rows=1, cols=2,
subplot_titles=("Media de Matemáticas por género", "Media de Matemáticas por curso de preparación")
)
fig_sub.add_trace(
go.Bar(
x=df_math_gender["gender"],
y=df_math_gender["math_score"],
name="Por género"
),
row=1, col=1
)
fig_sub.add_trace(
go.Bar(
x=df_math_prep["test_prep"],
y=df_math_prep["math_score"],
name="Por curso preparación"
),
row=1, col=2
)
fig_sub.update_layout(
title_text="Comparación de rendimiento en Matemáticas",
template="plotly_white",
showlegend=False
)
fig_sub
Ahora vamos a construir una figura con un menú desplegable (dropdown)
para que el usuario pueda elegir qué asignatura visualizar:
La idea: un histograma cuyo eje X cambia según la asignatura seleccionada.
Este gráfico introduce una idea muy importante en dashboards: usar controles (menús, botones) que cambian lo que se muestra.
¿Qué hace esta celda?
fig_dd.math_score, reading_score, writing_score).visible=(i == 0)).updatemenus) con botones:Ventajas:
subjects = ["math_score", "reading_score", "writing_score"]
subject_labels = {
"math_score": "Matemáticas",
"reading_score": "Lectura",
"writing_score": "Escritura"
}
fig_dd = go.Figure()
# Creamos un histograma por cada asignatura, inicialmente visible solo el primero
for i, subj in enumerate(subjects):
fig_dd.add_trace(
go.Histogram(
x=df_edu[subj],
name=subject_labels[subj],
visible=(i == 0),
opacity=0.75
)
)
# Botones del dropdown
buttons = []
for i, subj in enumerate(subjects):
visibility = [False] * len(subjects)
visibility[i] = True
buttons.append(
dict(
label=subject_labels[subj],
method="update",
args=[
{"visible": visibility},
{"title": f"Distribución de notas de {subject_labels[subj]}",
"xaxis": {"title": "Nota"},
"yaxis": {"title": "Frecuencia"}}
]
)
)
fig_dd.update_layout(
updatemenus=[
dict(
buttons=buttons,
direction="down",
showactive=True,
x=0.5,
xanchor="center",
y=1.15,
yanchor="top"
)
],
title="Distribución de notas de Matemáticas",
xaxis_title="Nota",
yaxis_title="Frecuencia",
template="plotly_white"
)
fig_dd
En un dashboard para docentes o gestores es útil mostrar indicadores globales como:
Vamos a definir una función que calcule estos KPIs a partir del DataFrame.
def compute_kpis_edu(df):
math_mean = df["math_score"].mean()
read_mean = df["reading_score"].mean()
write_mean = df["writing_score"].mean()
# Diferencia media de Matemáticas entre estudiantes con y sin curso de preparación
df_prep = df.groupby("test_prep")["math_score"].mean()
diff_prep = df_prep.max() - df_prep.min()
return {
"math_mean": math_mean,
"read_mean": read_mean,
"write_mean": write_mean,
"prep_diff_math": diff_prep,
"prep_means": df_prep.to_dict()
}
kpis_edu = compute_kpis_edu(df_edu)
kpis_edu
{'math_mean': np.float64(66.089),
'read_mean': np.float64(69.169),
'write_mean': np.float64(68.054),
'prep_diff_math': 5.617649106319291,
'prep_means': {'completed': 69.69553072625699, 'none': 64.0778816199377}}
Representaremos los KPIs como texto formateado (tipo “tarjeta”).
En una implementación más avanzada (Dash/Streamlit) serían cajas con colores, iconos, etc.
Un dashboard no son solo gráficos:
a veces, un buen bloque de texto bien formateado comunica mejor los resultados clave.
En esta celda:
Markdown y display para mostrar los KPIs en un bloque de texto con formato.kpis dentro de una plantilla de texto usando f"""...""".test_prep.Esto se parece al panel de indicadores que suele aparecer en la parte superior de un dashboard.
from IPython.display import Markdown, display
def show_kpis_edu(kpis):
text = f"""
### 🎓 Indicadores globales de rendimiento
- **Nota media en Matemáticas:** {kpis['math_mean']:.2f}
- **Nota media en Lectura:** {kpis['read_mean']:.2f}
- **Nota media en Escritura:** {kpis['write_mean']:.2f}
**Efecto del curso de preparación (en Matemáticas):**
- Media por grupo: `{kpis['prep_means']}`
- Diferencia entre el grupo con mejor y peor media: **{kpis['prep_diff_math']:.2f} puntos**
"""
display(Markdown(text))
show_kpis_edu(kpis_edu)
Efecto del curso de preparación (en Matemáticas):
{'completed': 69.69553072625699, 'none': 64.0778816199377} Vamos a juntar todo en una especie de dashboard vertical dentro del notebook:
La idea es que un docente pueda usarlo para:
display(Markdown("# 📊 Dashboard de rendimiento estudiantil"))
# 1) KPIs
show_kpis_edu(kpis_edu)
# 2) Medias por nivel educativo de los padres
fig_parent_avg.show()
# 3) Relación Matemáticas vs Lectura con contexto
fig_math_read.show()
# 4) Histograma interactivo por asignatura
fig_dd.show()
Efecto del curso de preparación (en Matemáticas):
{'completed': 69.69553072625699, 'none': 64.0778816199377} En este cuaderno vamos a dar el salto desde las visualizaciones con Plotly en un notebook (como en la sesión anterior) a la creación de un dashboard interactivo con Dash.
La idea es que puedas ver, paso a paso, siguiendo el código en python del fichero app_dash_edu.py:
dcc.Dropdown, dcc.RadioItems, dcc.Graph, etc.). Primero importamos las librerías necesarias:
pandas: para trabajar con el dataset educacional. plotly.express (px): para crear las figuras, igual que en el cuaderno anterior. dash: para construir la app que contiene el dashboard.dcc (componentes interactivos) y html (contenedores y etiquetas HTML). Input y Output: se usan para definir los callbacks.Después cargaremos el mismo dataset de rendimiento de estudiantes que usamos en el cuaderno anterior y renombraremos algunas columnas para que sea más cómodo trabajar.
from dash import Dash, dcc, html, Input, Output
import plotly.express as px
import pandas as pd
# ---------------------------------------------------------
# 1. Carga y preparación de datos
# ---------------------------------------------------------
# Asumimos el mismo dataset que en el notebook
# Si lo tienes en otro sitio, ajusta la ruta:
# - local: "StudentsPerformance.csv"
# - o una URL si lo descargas de internet
df = pd.read_csv("datasets/StudentsPerformance.csv")
# Renombramos columnas para que el código sea más legible
df_edu = df.rename(columns={
"race/ethnicity": "race_ethnicity",
"parental level of education": "parent_education",
"test preparation course": "test_prep",
"math score": "math_score",
"reading score": "reading_score",
"writing score": "writing_score"
})
En el cuaderno anterior:
px.histogram(...), px.scatter(...), px.bar(...). Con Dash:
app.layout) hecha de componentes Dash. Es decir: Dash envuelve nuestros gráficos de Plotly para convertirlos en un dashboard completo.
En este cuaderno vamos a explicar cómo construir un dashboard parecido al que ya has visto como script, pero explicando cada pieza para que puedas entender qué hace.
La estructura mínima de una app Dash en un notebook es:
from jupyter_dash import JupyterDash
from dash import html, dcc
app = JupyterDash(__name__)
app.layout = html.Div([
html.H1("Título"),
dcc.Graph(figure=figura_plotly)
])
app.run()
app = JupyterDash(__name__): creamos la aplicación (en Colab usamos JupyterDash para que se vea dentro del notebook).app.layout = ...: definimos qué componentes aparecen en la página.app.run_server(): arrancamos el servidor.En nuestro dashboard queremos que el usuario pueda elegir qué asignatura explorar (Matemáticas, Lectura, Escritura).
Para eso usaremos dcc.Dropdown.
Primero definimos un diccionario para mapear nombres de columna a etiquetas legibles:
SUBJECT_OPTIONS = {
"math_score": "Mathematics",
"reading_score": "Reading",
"writing_score": "Writing",
}
Ahora, un ejemplo de dcc.Dropdown:
```python dcc.Dropdown( id="subject-dropdown", options=[ {"label": label, "value": col} for col, label in SUBJECT_OPTIONS.items() ], value="math_score", clearable=False )
id="subject-dropdown": identificador único del componente. Lo usaremos en los callbacks.options=[...]: lista de opciones; cada opción tiene una etiqueta visible (label) y un valor interno (value).value="math_score": valor por defecto cuando se carga el dashboard.clearable=False: evita que el usuario deje el selector en blanco.En el layout final colocaremos este Dropdown dentro de un html.Div.
Para filtrar por género y por curso de preparación usaremos dcc.RadioItems.
Son parecidos a un conjunto de botones donde solo puedes seleccionar una opción.
Ejemplo para el filtro de género:
gender_selector = dcc.RadioItems(
id="gender-radio",
options=[
{"label": "All", "value": "all"},
{"label": "Female", "value": "female"},
{"label": "Male", "value": "male"},
],
value="all",
inline=True,
)
Y algo similar para el curso de preparación (test_prep):
dcc.RadioItems(
id="prep-radio",
options=[
{"label": "All", "value": "all"},
{"label": "Completed", "value": "completed"},
{"label": "None", "value": "none"},
],
value="all",
inline=True,
)
RadioItems tiene un id que luego usaremos en el callback.value es la opción seleccionada actualmente.inline=True
hacemos que las opciones se vean en la misma línea.
En el dashboard final, estos componentes estarán en la parte superior como filtros.html.Div con estilo¶Queremos mostrar algunos indicadores clave (KPIs), como:
Cada KPI será un html.Div con:
html.H4). html.H2). html.P). Ejemplo de plantilla para una tarjeta:
kpi_example = html.Div(
[
html.H4("Nombre del KPI"),
html.H2("123"),
html.P("Descripción breve del indicador."),
],
style={
"border": "1px solid #ddd",
"borderRadius": "8px",
"padding": "15px",
"boxShadow": "0 1px 3px rgba(0,0,0,0.08)",
"minWidth": "220px",
},
)
En el dashboard final tendremos tres tarjetas, una para cada KPI principal, que iremos rellenando dentro del callback.
dcc.Graph¶Los gráficos que ya conoces de Plotly (histogramas, barras, dispersión...) se integran en Dash usando dcc.Graph.
En el cuaderno anterior teníamos, por ejemplo:
px.histogram(df_edu, x="math_score", ...). En Dash, la idea es:
fig_hist = px.histogram(df_edu, x="math_score", nbins=20)
dcc.Graph(id="graph-hist", figure=fig_hist)
En nuestro dashboard, sin embargo, la figura no será fija, sino que se construirá dinámicamente dentro del callback según los filtros.
Por eso en el layout solo definimos el contenedor dcc.Graph(id="graph-hist"), y la figura (atributo figure) se actualizará desde el callback.
Ahora sí, creamos la aplicación Dash y definimos el layout completo, combinando:
html.Div vacíos que rellenaremos con el callback). Tres gráficos (dcc.Graph) vacíos que se actualizarán desde el callback:
Relación con el cuaderno anterior:
Los gráficos que vemos aquí son “versiones Dash” de los que ya creamos con Plotly en la clase anterior:
parent_education. Ahora necesitamos decirle a Dash qué debe pasar cuando el usuario cambia un filtro.
Un callback de Dash:
Input(...): valores que escuchamos (por ejemplo, el valor seleccionado en el dropdown). Output(...): propiedades que vamos a actualizar (por ejemplo, la figura de un gráfico o el contenido de una tarjeta). Los cambios con respecto a la sesión anterior son:
px.histogram(df_edu, x="math_score", ...). df_filtered) y con la asignatura seleccionada (subject_col). @app.callback(
[
Output("kpi-num-students", "children"),
Output("kpi-mean-subject", "children"),
Output("kpi-diff-prep", "children"),
Output("graph-hist", "figure"),
Output("graph-parent", "figure"),
Output("graph-scatter", "figure"),
],
[
Input("subject-dropdown", "value"),
Input("gender-radio", "value"),
Input("prep-radio", "value"),
],
)
def update_dashboard(subject_col, gender_filter, prep_filter):
# 1. Filtrar datos según los controles
df_filtered = df_edu.copy()
if gender_filter != "all":
df_filtered = df_filtered[df_filtered["gender"] == gender_filter]
if prep_filter != "all":
df_filtered = df_filtered[df_filtered["test_prep"] == prep_filter]
# 2. Calcular KPIs con la función auxiliar
num_students, subject_mean, diff_prep = compute_kpis(df_filtered, subject_col)
subject_label = SUBJECT_OPTIONS.get(subject_col, subject_col)
# 3. Contenido de las tarjetas KPI
kpi_num = html.Div(
[
html.H4("Number of students"),
html.H2(f"{num_students}"),
html.P("After applying current filters."),
]
)
kpi_mean = html.Div(
[
html.H4(f"Average score in {subject_label}"),
html.H2(f"{subject_mean:.2f}"),
html.P("Mean value for the filtered group."),
]
)
kpi_prep = html.Div(
[
html.H4(f"Gap by test preparation course ({subject_label})"),
html.H2(f"{diff_prep:.2f}"),
html.P(
"Difference between the best and worst group "
"according to the test preparation course."
),
]
)
# 4. Gráfico 1: histograma (versión Dash del histograma del cuaderno anterior)
if len(df_filtered) > 0:
fig_hist = px.histogram(
df_filtered,
x=subject_col,
nbins=20,
title=f"Distribution of {subject_label} scores",
labels={subject_col: subject_label, "count": "Number of students"},
)
fig_hist.update_layout(template="plotly_white")
else:
fig_hist = px.histogram(title="No data for current filters")
fig_hist.update_layout(template="plotly_white")
# 5. Gráfico 2: barras de medias por nivel educativo de los padres
if len(df_filtered) > 0:
df_parent = (
df_filtered.groupby("parent_education", as_index=False)[subject_col].mean()
)
fig_parent = px.bar(
df_parent,
x="parent_education",
y=subject_col,
labels={
"parent_education": "Parents' education level",
subject_col: f"Average {subject_label} score",
},
)
fig_parent.update_layout(
template="plotly_white",
xaxis_tickangle=45,
margin={"b": 100},
)
else:
fig_parent = px.bar(title="No data for current filters")
fig_parent.update_layout(template="plotly_white")
# 6. Gráfico 3: dispersión Matemáticas vs Lectura (versión Dash del scatter anterior)
if len(df_filtered) > 0:
fig_scatter = px.scatter(
df_filtered,
x="math_score",
y="reading_score",
color="lunch",
symbol="test_prep",
hover_data=["gender", "parent_education"],
labels={
"math_score": "Math score",
"reading_score": "Reading score",
"lunch": "Lunch type",
"test_prep": "Test preparation",
},
)
fig_scatter.update_layout(template="plotly_white")
else:
fig_scatter = px.scatter(title="No data for current filters")
fig_scatter.update_layout(template="plotly_white")
return kpi_num, kpi_mean, kpi_prep, fig_hist, fig_parent, fig_scatter
El decorador @app.callback(...) registra la función update_dashboard dentro de la app Dash:
Le dice a Dash: “Oye, cuando cambie el valor de subject-dropdown.value, gender-radio.value o prep-radio.value, llama a esta función y usa lo que devuelva para actualizar estos Output”.
Los Inputs:
Input("subject-dropdown", "value")Input("gender-radio", "value")Input("prep-radio", "value")se corresponden con componentes definidos en el layout:
dcc.Dropdown(id="subject-dropdown", ...)dcc.RadioItems(id="gender-radio", ...)dcc.RadioItems(id="prep-radio", ...)Los Outputs:
Output("kpi-num-students", "children")Output("graph-hist", "figure"), etc.se corresponden con otros componentes del layout:
html.Div(id="kpi-num-students", ...)dcc.Graph(id="graph-hist"), etc.Ejercicio para entregar
Añadir un nuevo filtro
lunch) usando otro RadioItems o Dropdown.Añadir un nuevo gráfico
dcc.Graph en el layout y devuelve su figura desde el callback para mostrarlo en el dashboard.Para el dashboard final, indica: