Presentación 6:
Visualización Interactiva de Datos con Dash
Alberto García Robledo
Visualización de Datos Aplicada
Junio 2024
Contenido
- ¿Qué es Dash?
- Layouts de Dash
- Callbacks de Dash
- Componentes Dash de terceros
- Actividad
¿Qué es Dash?
¿Qué es Dash?
¿Qué es Dash?
-
Dash es código abierto, publicado bajo la licencia MIT.
-
Está disponible para múltiples lenguajes:
-
Python
-
R
-
Julia
-
.NET
-
Instalación
-
En una terminal, instala Dash a través de pip:
pip install dash
-
Si prefieres desarrollar en Jupyter Notebook o Jupyter Lab, instala jupyter-dash:
pip install jupyter-dash
-
En este taller utilizaremos Google Colab
Layouts de Dash
Layouts de Dash
-
Una aplicación Dash está integrada de dos partes:
-
La descripción del UI (layout)
-
La descripción de la interactividad (callbacks)
-
-
Un layout de Dash está integrado de uno o más componentes Dash anidados. Los hay de dos tipos:
Ejemplo 1: Hello Dash
Ejemplo 1: Hello Dash
import dash_html_components as html
from jupyter_dash import JupyterDash
app = JupyterDash(__name__)
app.layout = html.Div([
html.H1('H1 header!'),
html.H2('H2 header!'),
html.H3('H3 header!'),
html.H4('H4 header!'),
html.H5('H5 header!'),
html.H6('H6 header!'),
])
app.run_server()
Ejemplo 1: Para recordar
-
dash_html_components provee un componente Dash por cada etiqueta HTML.
-
Un layout está compuesto por Dash components anidados:
-
Un layout de Dash es parecido a un árbol DOM.
-
-
El componente raíz de un layout es asignado a app.layout.
Ejemplo 2: Markdown
Ejemplo 2: Markdown
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
app = JupyterDash(__name__)
markdown = '''
# Lorem Ipsum
**Lorem ipsum dolor sit amet**, consectetur adipiscing elit.
1. Duis ullamcorper nisl eget diam laoreet, ac rutrum enim aliquet.
2. Curabitur aliquam libero et leo consectetur, at pretium urna mollis.
3. Cras et vestibulum nisi, sit amet sollicitudin turpis.
***Nam imperdiet porttitor venenatis***. Aenean vitae maximus enim, ac consectetur augue.
## Vestibulum nec felis ac erat auctor pharetra.
> Vestibulum vitae velit at nisl pretium ultricies.
>> Suspendisse mi urna, lobortis sed ante sit amet, porta venenatis ligula.
Text generated by the [Lorem Ipsum generator](https://www.lipsum.com/).
'''
app.layout = html.Div([
dcc.Markdown(children=markdown)
])
app.run_server()
Ejemplo 2: Para recordar
-
Puede ser tedioso construir un layout utilizando únicamente los dash_html_components.
-
Para desplegar bloques de texto con formato de manera rápida, puedes usar el componente Markdown del dash_core_components.
Ejemplo 3: Hello Graph
Ejemplo 3: Hello Graph
Ejemplo 3: Hello Graph
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
df = px.data.iris() # iris is a pandas DataFrame
app = JupyterDash(__name__)
fig = px.scatter(df, x='petal_length', y='sepal_length')
app.layout = html.Div([
dcc.Graph(
figure=fig,
style={'height': 300},
)
])
app.run_server()
Ejemplo 3: Para recordar
-
Puedes utilizar DataFrames de Pandas como la fuente de datos de tus tableros Dash.
-
Dash provee Plotly Express, el cual contiene funciones para crear gráficas ricas y complejas de manera fácil.
-
El componente dcc.Graph puede visualizar figuras generadas por Plotly y Plotly Express:
- Sólo hay que pasar la figura Plotly al componente dcc.Graph a través del argumento "figure"
Callbacks de Dash
Callbacks de Dash
-
Un callback es una función de Python que permite definir la interacción de un tablero Dash.
-
Cada componente Dash puede tener un id único
-
Un callback contiene uno o más Input y Output:
-
Cada entrada/salida está asociada al id de un componente y a un atributo del componente.
-
Ejemplo 4: Callback simple
Ejemplo 4: Callback simple
import dash_html_components as html
import dash_core_components as dcc
from jupyter_dash import JupyterDash
from dash.dependencies import Input, Output
app = JupyterDash(__name__)
app.layout = html.Div([
html.Div(['Text:',
dcc.Input(id='text-input',
value='',
type='text')]),
html.Div(id='echo-div')
])
@app.callback(
Output('echo-div', 'children'),
Input('text-input', 'value')
)
def update_echo_div_callback(text_value):
if text_value:
return f'Echo: {text_value}'
app.run_server()
Ejemplo 4: Para recordar
-
Es necesario asignar un id único a un componente si deseamos hacer referencia a éste en un callback.
-
Un Output dado sólo puede aparecer en un callback.
-
Pero un Input dado puede aparecer en más de un callback.
-
Los callbacks son disparados de manera automática al iniciar la aplicación.
Ejemplo 5: Múltiples Inputs y Outputs
Ejemplo 5: Múltiples Inputs y Outputs
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
app = JupyterDash(__name__)
app.layout = html.Div([
dcc.Input(
id='x',
type='number',
value=1
),
dcc.Input(
id='c',
type='number',
value=0
),
html.Table([
html.Tr(html.Td(id='y-1-td')),
html.Tr(html.Td(id='y-2-td')),
html.Tr(html.Td(id='y-3-td')),
html.Tr(html.Td(id='y-4-td')),
html.Tr(html.Td(id='y-5-td'))
])
])
@app.callback(
Output('y-1-td', 'children'),
Output('y-2-td', 'children'),
Output('y-3-td', 'children'),
Output('y-4-td', 'children'),
Output('y-5-td', 'children'),
Input('x', 'value'),
Input('c', 'value'))
def compute_callback(x, c):
if (not x is None) and (not c is None):
return x*1+c, x*2+c, x*3+c, x*4+c, x*5+c
app.run_server(debug=True)
Ejemplo 5: Para recordar
-
Un callback puede tener múltiples Inputs y Outputs
-
Tienes que asegurarte que todos los Inputs tengan valores válidos:
-
Puedes pasar prevent_initial_call = True al decorador de un callback para evitar que el callback se dispare automáticamente
-
Diseñar callbacks puede ser complicado en un principio ¡No te desanimes!
-
Ejemplo 6: States
Ejemplo 6: States
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
app = JupyterDash(__name__)
app.layout = html.Div([
dcc.Input(
id='name-input',
type='text',
value=''
),
dcc.Input(
id='lastname-input',
type='text',
value=''
),
dcc.Input(
id='age-input',
type='number',
value=18
),
html.Button(id='submit-button', children='Submit'),
html.Table([
html.Tr(html.Td(id='name-td')),
html.Tr(html.Td(id='lastname-td')),
html.Tr(html.Td(id='age-td'))
])
])
@app.callback(
Output('name-td', 'children'),
Output('lastname-td', 'children'),
Output('age-td', 'children'),
Input('submit-button', 'n_clicks'),
State('name-input', 'value'),
State('lastname-input', 'value'),
State('age-input', 'value'))
def compute_callback(n_clicks, name_input, lastname_input, age_input):
if n_clicks and name_input and lastname_input and age_input:
return name_input, lastname_input, age_input
else:
return '', '', ''
app.run_server()
Ejemplo 6: Para recordar
-
Los "States" nos permiten recolectar valores de componentes sin tener que disparar un callback
-
Nos permiten pasar valores a un callback adicionales al valor disparador
-
No olvides proveer valores por defecto a todas las salidas de un callback para el disparo de inicialización
Componentes Dash de terceros
Componentes Dash de terceros
-
Dash provee herramientas para que puedas desarrollar tus propios componentes
-
Básicamente, un componente Dash no es más que un envoltorio de un componente React.js
-
Dash goza de una nutrida comunidad de desarrolladores que han creado sus propios componentes Dash
dash-extensions
-
Provee varias extensiones útiles al framework Dash:
-
Aplicaciones Dash de múltiples páginas
-
Grupos de Outputs para permitir que un Output pueda ser utilizado en múltiples callbacks
-
Outputs del lado del servidor
-
Dash Bootstrap Components
-
Provee componentes de UI basados en el framework Bootstrap 4:
-
Modal
-
Cards
-
Form
-
Jumbotron
-
Navbar
-
Ejemplo 7: Google Play Top
Ejemplo 7: Google Play Top
Ejemplo 7: Google Play Top
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
df = pd.read_csv(
'https://raw.githubusercontent.com/jasonchang0/kaggle-google-apps/master/google-play-store-apps/googleplaystore.csv', delimiter=',')
app = JupyterDash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
navbar = dbc.NavbarSimple(
brand="Google Play Top",
brand_href="#",
color="primary",
dark=True,
)
controls = dbc.Card(
[
dbc.FormGroup(
[
dbc.Label('Category'),
dcc.Dropdown(
id='category-dropdown',
options=[
{'label': col, 'value': col} for col in df['Category'].unique()
],
value='ART_AND_DESIGN',
),
]
),
dbc.FormGroup(
[
dbc.Label('Top'),
dcc.Dropdown(
id='top-dropdown',
options=[
{'label': 5, 'value': 5},
{'label': 10, 'value': 10},
{'label': 20, 'value': 20},
{'label': 30, 'value': 30},
{'label': 40, 'value': 40},
{'label': 50, 'value': 50},
],
value=5,
),
]
)
],
body=True
)
app.layout = dbc.Container(
[
navbar,
dbc.Row(
[
dbc.Col(controls, md=4),
dbc.Col(dcc.Graph(id='top-graph'), md=8),
],
align='center'
),
]
)
@app.callback(
Output('top-graph', 'figure'),
Input('category-dropdown', 'value'),
Input('top-dropdown', 'value')
)
def update_callback(category, top):
df2 = df[df['Category'] == category]
df2 = df2.sort_values(by='Rating', ascending=False).head(top)
fig = px.bar(df2, x='App', y='Rating')
return fig
app.run_server()
Ejemplo 7: Para recordar
-
Puedes utilizar archivos CSV como fuente de datos de tus tableros Dash utilizando Pandas.
-
Puedes utilizar Pandas para manipular el dataset dentro de un callback (e.g. filtrarlo u ordenarlo).
-
La biblioteca Dash Bootstrap Components permite la utilización de componentes de Bootstrap 4 en nuestras aplicaciones Dash.
-
Elige un dataset de kaggle.com
-
Desarrolla una aplicación de Dash que utilize un Plotly Express scatter plot para visualizar las potenciales correlaciones entre cualesquiera dos variables numéricas
-
La aplicación de Dash debe utilizar la biblioteca Dash Bootstrap Components para la UI: dos columnas y un navbar
Actividad: Correlaciones
Actividad: Correlaciones
Actividad: Correlaciones
Paso 0. Haz una copia del siguiente notebook:
Actividad: Correlaciones
Paso 1. Asigna a la variable df el dataset Iris provisto por Plotly Express:
Actividad: Correlaciones
df = px.data.iris() # iris is a pandas DataFrame
Actividad: Correlaciones
Paso 2. Define un Dropdown que tenga como options diferentes columnas del dataset. Asígnale el id xaxis-dropdown:
dcc.Dropdown(
id='xaxis-dropdown',
options=[
{'label': 'sepal_width', 'value': 'sepal_width'},
{'label': 'sepal_length', 'value': 'sepal_length'},
{'label': 'petal_length', 'value': 'petal_length'}
],
value='sepal_width',
)
Actividad: Correlaciones
Paso 3. Define otro Dropdown que tenga como options diferentes columnas del dataset. Asígnale el id yaxis-dropdown:
dcc.Dropdown(
id='yaxis-dropdown',
options=[
{'label': 'sepal_width', 'value': 'sepal_width'},
{'label': 'sepal_length', 'value': 'sepal_length'},
{'label': 'petal_length', 'value': 'petal_length'}
],
value='sepal_width',
)
Actividad: Correlaciones
Paso 4. un objeto dcc.Graph en el layout en donde se ubicará el scatterplot. Asígnale el id top-graph:
dbc.Col(dcc.Graph(id='top-graph'), md=8),
Actividad: Correlaciones
Paso 5. Define un callback que tenga como inputs el valor de xaxis-dropdown y yaxis-dropdown y como output la figura de top-graph:
@app.callback(
Output('top-graph', 'figure'),
Input('xaxis-dropdown', 'value'),
Input('yaxis-dropdown', 'value'),
)
def update_callback(xaxis_col, yaxis_col):
fig = px.scatter(df, x=xaxis_col, y=yaxis_col)
return fig
Para saber más
- Dabbas, E. (2021) Interactive Dashboards and Data Apps with Plotly and Dash, Packt.
VDA 2022 - Visualización Interactiva de Datos con Dash
By Alberto Garcia-Robledo
VDA 2022 - Visualización Interactiva de Datos con Dash
- 199