Introducción a Dash
#
Introducción#
Descargado 600.000 veces al mes, Dash es el marco original de bajo código para construir rápidamente aplicaciones de datos en
Python, R, Julia y F#.
Escrito sobre
Plotly.js
yReact.js
,Dash
es ideal para construir y desplegar aplicaciones de datos con interfaces de usuario personalizadas enPython, R, Julia
oF#
. Es particularmente adecuado para cualquiera que trabaje con datos.A través de un par de patrones simples,
Dash
abstrae todas las tecnologías y protocolos que se requieren para construir una aplicación web full-stack con visualización de datos interactivos.Dash
es lo suficientemente sencillo como para que puedas vincular una interfaz de usuario a tu códigoPython, R, Julia
oF#
en menos de 10 minutos.Las aplicaciones de
Dash
se muestran en el navegador web. Puedes desplegar tus aplicaciones en máquinas virtuales o clusters Kubernetes y luego compartirlas a través de URLs. Dado que las aplicaciones deDash
se ven en el navegador web,Dash
es intrínsecamente multiplataforma y está preparado para los dispositivos móviles.Hay mucho detrás del framework. Para saber más sobre cómo está construido y qué motivó a
Dash
, lea el post Dash es React para Python. Puede encontrar distintos templates deDash
en el siguiente link, los cuales puedes utlizar para tus proyectos: Dash Enterprise App GalleryDash
es una librería de código abierto liberada bajo la permisiva licencia MIT.Plotly
desarrollaDash
y también ofrece una plataforma para escribir y desplegar aplicacionesDash
en un entorno empresarial.

Configuración de su entorno#
Para la instalación de
Dash
crearemos un entorno especial, en el cual instalaremos cada una de las librerías que necesitaremos en el transcurso de esta sección, en especial la instalación deDash
mediante la orden
pip install dash
En su esencia, el propósito principal de los entornos virtuales (virtual enviroment) de
Python
es crear un espacio aislado para cada proyecto particular dePython
. Esto significa que, cada proyecto puede tener sus propias dependencias, independientemente de las dependencias que tengan los demás proyectos.Lo bueno de esto es que no hay límites en el número de entornos que puedes tener, ya que sólo son directorios que contienen unos pocos scripts. Además, son fácilmente creados usando las herramientas de línea de comandos
virtualenv
opyenv
, en el caso deanaconda
por medio deconda create
En el presente curso, para facilitar la creación de un entorno de desarrollo para
TensorFlow
, se recomienda utilizarMiniconda/Anaconda
. El sitio web oficial deTensorFlow
directamente realiza la recomendación que se hace en el presente curso. Además de utilizar laversión 3.9 de Python
.

Para crear el entorno virtual usando
Miniconda
, puede utilizar la siguiente orden
conda create --name dash_project python=3.9

Para activar y/o desactivar el entorno virtual de
Miniconda
creado, basta con utilizar las siguientes ordenes. Nótese que no es necesario usar el nombre del entorno virtual para desactivarlo
conda activate dash_project
conda deactivate
Usando Python. No Miniconda#
Solo en el caso que no desee utilizar Miniconda
. Para crear un entorno virtual usando soloPython
, debe crear una carpeta llamada por ejemplo,python_enviroments
(o con cualquier otro nombre) en sudisco local C
para evitar problemas de sincronización, la cual va a contener todos sus entornos virtuales.Escriba la siguiente orden un su terminal, en el caso de
Windows
, en el Command Prompt o en el Windows PowerShell que tiene un aspecto muy parecido al deUbuntu
. Puede elegir la carpeta donde van a reposar todos susenviroments
, en este casopython_enviroments
, y el entorno virtual creado recibe el nombredash_project
a manera de ejemplo

Luego debe ubicarse dentro de la carpeta que se creó con el enviroment: dash_project usando el comando
cd
, y dentro de esta ubicación debe ejecutar la siguiente orden para activar el enviroment:
.\Scripts\activate
Tal como se muestra en la figura. Nótese que en la parte izquierda de la línea de comandos, aparece el
nombre del enviroment en color verde, indicando que ha sido creado correctamente y está activado
. Luego de activado el enviroment se puede mover al directorio donde desea realizar el desarrollo de esta sección. Procedemos ahora a instalar algunas librerías, el procedimiento es el mismo cuando usaMiniconda
oPython
puro.

Instalación de Librerías#
Independientemente de si decidió usar solo
Python
directamente, oMiniconda
como recomiendaTensorFlow
, el procedimiento de instalación de librerías es el mismo. En su terminal, instale dash.
pip install dash
Esto también trae consigo la
biblioteca de gráficos plotly
. Esta biblioteca está en desarrollo activo, así que instala y actualiza con frecuencia. Si prefieresJupyter Notebook
oJupyterLab
como entorno de desarrollo, te recomendamos instalar jupyter-dash:
pip install jupyter-dash
También recomendamos instalar
Pandas
, que es requerido porPlotly Express
y utilizado en muchos de nuestros ejemplos.
pip install pandas
Estamos listos para crear nuestra primera
aplicación Dash
. Cada una de estas librerías pueden ser instaladas también a traves de un archivo con requerimientos, el cual podemos crear con el nombre:requirements.txt
y copiar en éste sin espacio a la izquierda el nombre de cada librería, así:
dash
jupyter-dash
pandas
Luego desde la línea de comando ejecutar
pip install -r requirements.txt
Estaremos usando en esta sección
JupyterLab
debido a que es un editor gratuito, que proporciona unainterfaz basada en navegador
que le permite utilizar varios cuadernos juntos de forma eficaz, así como también usarMarkdown
. También estaremos usando el editoVS Code
, el cual ofrece soporte para unaamplia variedad de lenguajes de programación
y marcos de trabajo, lo que lo hace ideal para proyectos multiplataforma, esto es, puedesusarlo en Windows, Mac y Linux
. Seleccione aquel editor con el que se sienta más cómodo. Para instalarjupyter lab
escriba dentro del mismo enviroment
pip install jupyterlab

Iniciamos
jupyter lab
para crear el archivorequirements.txt
con las librerías a instalar. Este archivo podemos ir actualizándolo en el transcurso de la sección a medida que una nueva librería va siendo necesaria.


Crea el archivo
requirements.txt
con librerías a instalar. Nótese quejupyter lab
cuenta también con una terminal integrada, por lo tanto, luego de crear el archivo, puede abrir una terminal dentro dejupyter lab
, activar el enviroment y luego instalar las librerías usandopip install -r requirements.txt

Diseño de Dash#
Estudiaremos el diseño a través de seis aplicaciones autónomas. El diseño de las aplicaciones
Dash
de producción puede ser estilizado con Dash Enterprise Design Kit. Las aplicacionesDash
se componen de dos partes. La primera parte es eldiseño de la aplicación
y describe el aspecto de la misma. La segunda parte describe lainteractividad de la aplicación
y será cubierta más adelante.Mantenemos un conjunto de componentes en la biblioteca
dash_core_components
ydash_html_components
(dash.html
a partir deDash v2.0
) pero también puedes construir los suyos conJavaScript
yReact.js
. A lo largo de esta sección, los ejemplos de códigoPython
están pensados para ser guardados como archivos y ejecutados usandopython app.py
. También puedes usarJupyter
con la bibliotecaJupyterDash
.Para empezar, crea un archivo llamado
app.py
usando su editor favorito, copie el código de abajo en él y ejecútalo con
python app.py
Luego visite http://127.0.0.1:8050/ en su navegador web para ver la aplicación
import dash
from dash import dcc
from dash import html
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = pd.DataFrame({
"Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
"Amount": [4, 1, 2, 2, 4, 5],
"City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
})
fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")
app.layout = html.Div(children=[
html.H1(children='Hello Dash'),
html.Div(children='''
Dash: A web application framework for your data.
'''),
dcc.Graph(
id='example-graph',
figure=fig
)
])
if __name__ == '__main__':
app.run_server(debug=True)




Para tener otro estilo de visualización puede diseñar su propio archivo
style.css
por ejemplo, o utilizar algunos libres que puede solo importar, como por ejemplo BootstrapCDN y Plotly themes. Para importar los estilos de temas en tu app debe importar la librería en el archivo.py
principal de tu app:import dash_bootstrap_components as dbc
, además de usar la siguiente línea para seleccionar el tema de interés
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
Antes debe instalarlo en el enviroment usando:
pip install dash-bootstrap-components


Observaciones
El diseño está compuesto por un árbol de “componentes” como
html.Div
ydcc.Graph
.La biblioteca
dash_html_components
(dash.html
a partir deDash v2.0
) tiene un componente para cada etiquetaHTML
. El componentehtml.H1(children = 'Hola Dash')
genera un elementoHTML <h1>Hola Dash</h1>
en tu aplicación.h1
enHTML
es el primer nivel de encabezado en una página web.No todos los componentes son
HTML
puro. Losdash_core_components
describen componentes de nivel superior que son interactivos y se generan conJavaScript, HTML
yCSS
a través de la bibliotecaReact.js
.Cada componente se describe completamente a través de atributos de palabras clave.
Dash
es declarativo: usted describirá principalmente su aplicación a través de estos atributos.La propiedad
children
es especial. Por convención, siempre es el primer atributo, lo que significa que puedes omitirlo:html.H1(children = 'Hello Dash')
es lo mismo quehtml.H1('Hello Dash')
. Puede contener una cadena, un número, un solo componente o una lista de componentes.Las fuentes en su aplicación se verán un poco diferentes de lo que se muestra en la imágen de arriba a menos que cambie el estilo de la hoja y de
Plotly
. Esta aplicación está utilizando una hoja de estilosBootstrapCDN
y temasPlotly
Realizar tu primer cambio
Dash
incluye “hot-reloading”, esta característica se activa por defecto cuando ejecutas tu aplicación conapp.run_server(debug=True)
. Esto significa queDash
refrescará automáticamente tu navegador cuando hagas un cambio en tu código. Pruébalo: cambia el título “Hello Dash” en tu aplicación o cambia los datos \(x\) o \(y\). Tu aplicación debería refrescarse automáticamente con tu cambio.
Más información sobre los componentes HTML#
dash_html_components
(dash.html
a partir deDash v2.0
) contiene una clase de componente para cada etiquetaHTML
, así como argumentos de palabras clave para todos los argumentosHTML
. Vamos a personalizar el texto de nuestra aplicación modificando los estilos en línea de los componentes. Crea un archivo llamadoapp.py
con el siguiente código
import dash
from dash import dcc
from dash import html
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
colors = {
'background': '#111111',
'text': '#7FDBFF'
}
df = pd.DataFrame({
"Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
"Amount": [4, 1, 2, 2, 4, 5],
"City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
})
fig = px.bar(df, x = "Fruit", y = "Amount", color = "City", barmode = "group")
fig.update_layout(
plot_bgcolor = colors['background'],
paper_bgcolor = colors['background'],
font_color = colors['text']
)
app.layout = html.Div(style={'backgroundColor': colors['background']}, children=[
html.H1(
children = 'Hello Dash',
style = {
'textAlign': 'center',
'color': colors['text']
}
),
html.Div(children = 'Dash: A web application framework for your data.', style = {
'textAlign': 'center',
'color': colors['text']
}),
dcc.Graph(
id='example-graph-2',
figure=fig
)
])
if __name__ == '__main__':
app.run_server(debug=True)

En este ejemplo, hemos modificado los estilos inline de los componentes
html.Div
yhtml.H1
con la propiedad style.
html.H1('Hello Dash', style={'textAlign': 'center', 'color': '#7FDBFF'})
El código anterior se muestra en la aplicación
Dash
como
<h1 style="text-align: center; color: #7FDBFF">Hola Dash</h1>.
Hay algunas diferencias importantes entre los componentes
dash_html_
(dash.html
a partir deDash v2.0
) y los atributosHTML
:La propiedad de estilo en
HTML
es una cadena separada por punto y coma. EnDash
, sólo se puede proporcionar un diccionario.Las claves (keys) en el diccionario de estilo son camelCased. Así, en lugar de
text-align
, estextAlign
. El atributo de claseHTML
esclassName
enDash
.Los hijos (children) de la etiqueta
HTML
se especifican a través del argumento de la palabra clave children. Por convención, éste es siempre el primer argumento, por lo que a menudo se omite.Además de esto, todos los atributos y etiquetas
HTML
disponibles están a tu disposición dentro del contexto dePython
.
Componentes reutilizables#
Escribiendo nuestro markup en
Python
, podemos crear componentes complejos reutilizables como tablas sin cambiar de contexto o de lenguaje. Aquí hay un ejemplo rápido que genera una tablaTable
a partir de un dataframe dePandas
(ver html.Tr, html.Td, html.Thead ). Crea un archivo llamadoapp.py
con el siguiente código
import dash
from dash import html
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/usa-agricultural-exports-2011.csv')
def generate_table(dataframe, max_rows=10):
return html.Table([
html.Thead(
html.Tr([html.Th(col) for col in dataframe.columns])
),
html.Tbody([
html.Tr([
html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
]) for i in range(min(len(dataframe), max_rows))
])
])
app = dash.Dash(__name__)
app.layout = html.Div([
html.H4(children='US Agriculture Exports (2011)'),
generate_table(df)
])
if __name__ == '__main__':
app.run_server(debug=True)

Más información sobre la visualización#
La librería
dash_core_components
incluye un componente llamadoGraph
.Graph
muestra visualizaciones de datos interactivas utilizando la librería de gráficos de código abiertoplotly.js
.Plotly.js
admite más de35 tipos de gráficos
y los representa tanto enSVG
de calidad vectorial como enWebGL
de alto rendimiento.El argumento de figura en el
componenteGraph
es el mismo argumento de figura que utilizaplotly.py
, la biblioteca de gráficosPython
de código abierto dePlotly
. Consulte la documentación y la galería de plotly.py para obtener más información. Aquí presentamos un ejemplo que crea un gráfico de dispersión a partir de un marco de datos dePandas
. Crear un archivo llamadoapp.py
con el siguiente código
import dash
from dash import dcc
from dash import html
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = pd.read_csv('https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/gdp-life-exp-2007.csv')
fig = px.scatter(df, x="gdp per capita", y="life expectancy",
size="population", color="continent", hover_name="country",
log_x=True, size_max=60)
app.layout = html.Div([
dcc.Graph(
id='life-exp-vs-gdp',
figure=fig
)
])
if __name__ == '__main__':
app.run_server(debug=True)

Markdown#
Aunque
Dash
exponeHTML
a través dedash_html_components
(dash.html
a partir deDash v2.0
) , puede ser tedioso escribir tu copia enHTML
. Para escribir bloques de texto, puedes utilizar el componenteMarkdown
endash_core_components
. Crear un archivo llamado app.py con el siguiente código:
import dash
from dash import dcc
from dash import html
app = dash.Dash(__name__)
markdown_text = '''
##Dash and Markdown
- Dash apps can be written in Markdown.
- Dash uses the [CommonMark](http://commonmark.org/) specification of Markdown.
- Check out their [60 Second Markdown Tutorial](http://commonmark.org/help/) if this is your first introduction to Markdown!
'''
app.layout = html.Div([
dcc.Markdown(children=markdown_text)
])
if __name__ == '__main__':
app.run_server(debug=True)

Componentes principales#
dash_core_components
incluye un conjunto de componentes de alto nivel como los desplegables, los gráficos, los bloques markdown, etc.Como todos los componentes de
Dash
, se describen de forma totalmente declarativa. Cada opción configurable está disponible como un argumento de palabra clave del componente.Veremos muchos de estos componentes a lo largo de la sección. Puedes ver todos los componentes disponibles en la Galería de componentes del núcleo de Dash.
Aquí están algunos de los componentes disponibles. Crea un archivo llamado
app.py
con el siguiente código:
import dash
from dash import dcc
from dash import html
app = dash.Dash(__name__)
app.layout = html.Div([
html.Label('Dropdown'),
dcc.Dropdown(
options=[
{'label': 'New York City', 'value': 'NYC'},
{'label': u'Montréal', 'value': 'MTL'},
{'label': 'San Francisco', 'value': 'SF'}
],
value='MTL'
),
html.Label('Multi-Select Dropdown'),
dcc.Dropdown(
options=[
{'label': 'New York City', 'value': 'NYC'},
{'label': u'Montréal', 'value': 'MTL'},
{'label': 'San Francisco', 'value': 'SF'}
],
value=['MTL', 'SF'],
multi=True
),
html.Label('Radio Items'),
dcc.RadioItems(
options=[
{'label': 'New York City', 'value': 'NYC'},
{'label': u'Montréal', 'value': 'MTL'},
{'label': 'San Francisco', 'value': 'SF'}
],
value='MTL'
),
html.Label('Checkboxes'),
dcc.Checklist(
options=[
{'label': 'New York City', 'value': 'NYC'},
{'label': u'Montréal', 'value': 'MTL'},
{'label': 'San Francisco', 'value': 'SF'}
],
value=['MTL', 'SF']
),
html.Label('Text Input'),
dcc.Input(value='MTL', type='text'),
html.Label('Slider'),
dcc.Slider(
min=0,
max=9,
marks={i: 'Label {}'.format(i) if i == 1 else str(i) for i in range(1, 6)},
value=5,
),
], style={'columnCount': 2})
if __name__ == '__main__':
app.run_server(debug=True)

Resumen
El diseño de una aplicación
Dash
describe el aspecto de la aplicación. El diseño es un árbol jerárquico de componentes. La libreríadash_html_components
(dash.html
a partir deDash v2.0
) proporciona clases para todas las etiquetasHTML
y los argumentos de las palabras clave describen los atributosHTML
comostyle, class
eid
. La bibliotecadash_core_components
genera componentes de nivel superior como controles y gráficos.Para consultar la referencia, ver:
La siguiente parte de esta seccíon cubre cómo hacer estas aplicaciones interactivas. Luego estudiaremos con más profundidad algunos Callbacks
básicos
Callbacks básicos Dash#
Como se ha visto,
app.layout
describe el aspecto de la aplicación y es un árbol jerárquico de componentes. La bibliotecadash_html_components
proporciona clases para todas las etiquetasHTML
, y los argumentos de las palabras clave describen los atributosHTML
como style,className
eid
. La bibliotecadash_core_components
genera componentes de nivel superior como controles y gráficos.Ahora se describirá cómo hacer que tus aplicaciones
Dash
utilicen funciones de devolución de llamada (callbacks
): funciones que son llamadas automáticamente porDash
cada vez que la propiedad de un componente de entrada cambia. Comencemos con un ejemplo sencillo de una aplicación Dash interactiva.
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
app = dash.Dash(__name__)
app.layout = html.Div([
html.H6("Change the value in the text box to see callbacks in action!"),
html.Div([
"Input: ",
dcc.Input(id='my-input', value='initial value', type='text')
]),
html.Br(),
html.Div(id='my-output'),
])
@app.callback(
Output(component_id='my-output', component_property='children'),
Input(component_id='my-input', component_property='value')
)
def update_output_div(input_value):
return 'Output: {}'.format(input_value)
if __name__ == '__main__':
app.run_server(debug=True)

Observaciones
Las “
inputs
” y “outputs
” de la interfaz de nuestra aplicación se describen declarativamente como argumentos del decorador@app.callback
.a. Al escribir este decorador, le estamos diciendo a
Dash
que llame a esta función por nosotros cada vez que el valor del componente “input
” (la caja de texto
) cambie para actualizar loschildren
del componente “output
” en la página (eldiv HTML
).b. Puedes usar cualquier nombre para la función que está envuelta por el decorador
@app.callback
. La convención es que el nombre describa la(s) salida(s) delcallback
.c. Puede utilizar cualquier nombre para los argumentos de la función, pero debe utilizar los mismos nombres dentro de la función de devolución de llamada que en su definición, al igual que en una función normal de
Python
. Los argumentos son posicionales por defecto: primero los elementos de entrada y luego los elementos de estado se dan en el mismo orden que en el decorador. También tiene la opción de utilizar argumentos de palabra clave con nombre, en lugar de posicionales.d. Debes utilizar el mismo
id
que le diste a un componenteDash
en elapp.layout
cuando te refieras a él como entrada o salida del decorador@app.callback
.e. El decorador
@app.callback
debe estar directamente encima de la declaración de la funcióncallback
. Si hay una línea en blanco entre el decorador y la definición de la función, el registro de la devolución de llamada no tendrá éxito.En
Dash
, losinputs
youtputs
de nuestra aplicación son simplemente las propiedades de un componente en particular. En este ejemplo, nuestroinput
es la propiedad “value
” del componente que tiene elID
“my-input
”. Nuestra salida es la propiedad “children
” del componente con elID
“my-input
”.Cada vez que una propiedad de entrada cambia, la función que el decorador
callback
envuelve será llamada automáticamente.Dash
proporciona a la función el nuevo valor de la propiedad de entrada como argumento de entrada yDash
actualiza la propiedad del componente de salida con lo que haya devuelto la función.Las palabras clave
component_id
ycomponent_property
son opcionales (sólo hay dos argumentos para cada uno de esos objetos). Se incluyen en este ejemplo para mayor claridad, pero se omitirán en el resto de la sección en aras de la brevedad y la legibilidad.No confunda el objeto
dash.dependencies.Input
con el objetodcc.Input
. El primero sólo se utiliza en estas definiciones decallback
y el segundo es un componente real.Nótese que no establecemos un valor para la propiedad
children
del componentemy-output
en ellayout
. Cuando la aplicaciónDash
se inicia, llama automáticamente a todos loscallbacks
con los valores iniciales de los componentes de entrada para rellenar el estado inicial de los componentes de salida. En este ejemplo, si se especifica algo comohtml.Div(id='my-output', children='Hola mundo')
, se sobrescribiría cuando la aplicación se inicia.Con la interactividad de
Dash
, podemos actualizar dinámicamente cualquier propiedad a través de una funcióncallback
. ¡Frecuentemente actualizaremos loschildren
de un componente para mostrar nuevo texto o la figura de un componentedcc.Graph
para mostrar nuevos datos, pero también podríamos actualizar el estilo de un componente o incluso las opciones disponibles de un componentedcc.Dropdown
. Veamos otro ejemplo en el que undcc.Slider
actualiza undcc.Graph
.
Dash App Layout con Figura y Sliderm#
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/gapminderDataFiveYear.csv')
df.head()
country | year | pop | continent | lifeExp | gdpPercap | |
---|---|---|---|---|---|---|
0 | Afghanistan | 1952 | 8425333.0 | Asia | 28.801 | 779.445314 |
1 | Afghanistan | 1957 | 9240934.0 | Asia | 30.332 | 820.853030 |
2 | Afghanistan | 1962 | 10267083.0 | Asia | 31.997 | 853.100710 |
3 | Afghanistan | 1967 | 11537966.0 | Asia | 34.020 | 836.197138 |
4 | Afghanistan | 1972 | 13079460.0 | Asia | 36.088 | 739.981106 |
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/gapminderDataFiveYear.csv')
app = dash.Dash(__name__)
app.layout = html.Div([
dcc.Graph(id='graph-with-slider'),
dcc.Slider(
id='year-slider',
min=df['year'].min(),
max=df['year'].max(),
value=df['year'].min(),
marks={str(year): str(year) for year in df['year'].unique()},
step=None
)
])
@app.callback(
Output('graph-with-slider', 'figure'),
Input('year-slider', 'value'))
def update_figure(selected_year):
filtered_df = df[df.year == selected_year]
fig = px.scatter(filtered_df, x="gdpPercap", y="lifeExp",
size="pop", color="continent", hover_name="country",
log_x=True, size_max=55)
fig.update_layout(transition_duration=500)
return fig
if __name__ == '__main__':
app.run_server(debug=True)

Recuerde que siempre
puede cambiar el estilo de su figura y la hoja
. Sólo debe cambiar las siguientes lineas
ext_style = "https://cdn.jsdelivr.net/npm/bootswatch@4.5.2/dist/slate/bootstrap.min.css"
app = dash.Dash(external_stylesheets=[ext_style])
fig = px.scatter(filtered_df, x="gdpPercap", y="lifeExp",
size="pop", color="continent", hover_name="country",
log_x=True, size_max=55, template="plotly_dark")

En este ejemplo, la propiedad “
value
” deldcc.Slider
es la entrada de la app y la salida de la app es la propiedad “figure
” deldcc.Graph
. Cada vez que el valor deldcc.Slider
cambia,Dash
llama a la función callbackupdate_figure
con el nuevo valor. La función filtra el dataframe con este nuevo valor, construye un objeto figura y lo devuelve a la aplicaciónDash
.Hay algunos patrones interesantes en este ejemplo:
Utilizamos la biblioteca
Pandas
para cargar nuestrodataframe
al inicio de la aplicación:df = pd.read_csv('...')
. Este dataframedf
está en el estado global de la app y puede ser leído dentro de las funciones callback.La carga de datos en memoria puede ser costosa.
Al cargar los datos de consulta al inicio de la app en lugar de dentro de las funciones callback, nos aseguramos de que esta operación sólo se realiza cuando se inicia el servidor de la app
. Cuando un usuario visita la app o interactúa con ella, esos datos (df
) ya están en memoria. Si es posible, la inicialización costosa (como la descarga o la consulta de datos) debería hacerse en el ámbito global de la app en lugar de dentro de las funciones callback.El callback no modifica los datos originales, sólo crea copias del dataframe filtrando a través de los filtros de pandas
. Esto es importante:los callbacks nunca deben mutar las variables fuera de su ámbito
. Si tus callbacks modifican el estado global, entonces la sesión de un usuario podría afectar a la sesión del siguiente usuario y cuando la aplicación se despliegue en múltiples procesos o hilos, esas modificaciones no se compartirán entre sesiones.Activamos las transiciones con
layout.transition
para dar una idea de cómo evoluciona el conjunto de datos con el tiempo:las transiciones permiten que el gráfico se actualice de un estado a otro de forma suave
, como si estuviera animado, en este casotransition_duration=500
está dado en milésimas de segundos.
Aplicación Dash con múltiples entradas#
En
Dash
, cualquier “Output
” puede tener múltiples componentes “Input
”. Aquí hay un ejemplo simple que une cincoInputs
(la propiedad value de dos componentesdcc.Dropdown
, dos componentesdcc.RadioItems
, y un componentedcc.Slider
) a un componenteOutput
(la propiedadfigure
del componenteGraph
). Observe cómoapp.callback
enumera los cinco elementos de entrada después de la salida.
df = pd.read_csv('https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/country_indicators.csv')
df.head()
Country Name | Indicator Name | Year | Value | |
---|---|---|---|---|
0 | Arab World | Agriculture, value added (% of GDP) | 1962 | NaN |
1 | Arab World | CO2 emissions (metric tons per capita) | 1962 | 0.760996 |
2 | Arab World | Domestic credit provided by financial sector (... | 1962 | 18.168690 |
3 | Arab World | Electric power consumption (kWh per capita) | 1962 | NaN |
4 | Arab World | Energy use (kg of oil equivalent per capita) | 1962 | NaN |
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = pd.read_csv('https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/country_indicators.csv')
available_indicators = df['Indicator Name'].unique()
app.layout = html.Div([
html.Div([
html.Div([
dcc.Dropdown(
id='xaxis-column',
options=[{'label': i, 'value': i} for i in available_indicators],
value='Fertility rate, total (births per woman)'
),
dcc.RadioItems(
id='xaxis-type',
options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
value='Linear',
labelStyle={'display': 'inline-block'}
)
], style={'width': '48%', 'display': 'inline-block'}),
html.Div([
dcc.Dropdown(
id='yaxis-column',
options=[{'label': i, 'value': i} for i in available_indicators],
value='Life expectancy at birth, total (years)'
),
dcc.RadioItems(
id='yaxis-type',
options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
value='Linear',
labelStyle={'display': 'inline-block'}
)
], style={'width': '48%', 'float': 'right', 'display': 'inline-block'})
]),
dcc.Graph(id='indicator-graphic'),
dcc.Slider(
id='year--slider',
min=df['Year'].min(),
max=df['Year'].max(),
value=df['Year'].max(),
marks={str(year): str(year) for year in df['Year'].unique()},
step=None
)
])
@app.callback(
Output('indicator-graphic', 'figure'),
Input('xaxis-column', 'value'),
Input('yaxis-column', 'value'),
Input('xaxis-type', 'value'),
Input('yaxis-type', 'value'),
Input('year--slider', 'value'))
def update_graph(xaxis_column_name, yaxis_column_name,
xaxis_type, yaxis_type,
year_value):
dff = df[df['Year'] == year_value]
fig = px.scatter(x=dff[dff['Indicator Name'] == xaxis_column_name]['Value'],
y=dff[dff['Indicator Name'] == yaxis_column_name]['Value'],
hover_name=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'])
fig.update_layout(margin={'l': 40, 'b': 40, 't': 10, 'r': 0}, hovermode='closest')
fig.update_xaxes(title=xaxis_column_name,
type='linear' if xaxis_type == 'Linear' else 'log')
fig.update_yaxes(title=yaxis_column_name,
type='linear' if yaxis_type == 'Linear' else 'log')
return fig
if __name__ == '__main__':
app.run_server(debug=True)

En este ejemplo, la llamada de retorno se ejecuta cada vez que cambia la propiedad value de los componentes
dcc.Dropdown, dcc.Slider
odcc.RadioItems
. Los argumentos de entrada de la llamada de retorno son el valor nuevo o actual de cada una de las propiedades de entrada, en el orden en que fueron especificadas.Aunque sólo un único
Input
cambia a la vez (un usuario sólo puede cambiar el valor de un únicoDropdown
en un momento dado),Dash
recoge el estado actual de todas las propiedadesInput
especificadas y las pasa a su función por usted.Se garantiza que sus funciones callback siempre reciben el estado representativo de la aplicación
.
Aplicación Dash con múltiples salidas#
Hasta ahora todos los
callbacks
que hemos escrito sólo actualizan una propiedad de salida. También podemos actualizar varias a la vez. Puede enumerar todas las propiedades que requiera actualizar enapp.callback
, y devolver ese número de elementos desde elcallback
. Esto es particularmente bueno si dos salidas dependen del mismo resultado intermedio computacionalmente intenso, como una consulta lenta a la base de datos.
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Input(
id='num-multi',
type='number',
value=5
),
html.Table([
html.Tr([html.Td(['x', html.Sup(2)]), html.Td(id='square')]),
html.Tr([html.Td(['x', html.Sup(3)]), html.Td(id='cube')]),
html.Tr([html.Td([2, html.Sup('x')]), html.Td(id='twos')]),
html.Tr([html.Td([3, html.Sup('x')]), html.Td(id='threes')]),
html.Tr([html.Td(['x', html.Sup('x')]), html.Td(id='x^x')]),
]),
])
@app.callback(
Output('square', 'children'),
Output('cube', 'children'),
Output('twos', 'children'),
Output('threes', 'children'),
Output('x^x', 'children'),
Input('num-multi', 'value'))
def callback_a(x):
return x**2, x**3, 2**x, 3**x, x**x
if __name__ == '__main__':
app.run_server(debug=True)

No siempre es una buena idea combinar las salidas, aunque se pueda. Si los
Outputs
dependen de algunas pero no todas los mismosInputs
, mantenerlas separadas puede evitar actualizaciones innecesarias. Si tienen los mismosInputs
pero hacen cálculos independientes con estas entradas,mantener las devoluciones de llamada separadas puede permitir que se ejecuten en paralelo
.
Dash App con callbacks encadenados#
También puedes encadenar salidas y entradas.
La salida de una función callback puede ser la entrada de otra función callback
. Este patrón puede ser utilizado para crearUIs
dinámicas donde un componente de entrada actualiza las opciones disponibles del siguiente componente de entrada
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
all_options = {
'America': ['New York City', 'San Francisco', 'Cincinnati'],
'Canada': [u'Montréal', 'Toronto', 'Ottawa']
}
app.layout = html.Div([
dcc.RadioItems(
id='countries-radio',
options=[{'label': k, 'value': k} for k in all_options.keys()],
value='America'
),
html.Hr(),
dcc.RadioItems(id='cities-radio'),
html.Hr(),
html.Div(id='display-selected-values')
])
@app.callback(
Output('cities-radio', 'options'), # <- as option
Input('countries-radio', 'value'))
def set_cities_options(selected_country):
return [{'label': i, 'value': i} for i in all_options[selected_country]]
@app.callback(
Output('cities-radio', 'value'), # <- as value
Input('cities-radio', 'options')) # <- as option
def set_cities_value(available_options):
return available_options[0]['value'] # <- return first city value from the list
@app.callback(
Output('display-selected-values', 'children'),
Input('countries-radio', 'value'),
Input('cities-radio', 'value'))
def set_display_children(selected_country, selected_city):
return u'{} is a city in {}'.format(
selected_city, selected_country,
)
if __name__ == '__main__':
app.run_server(debug=True)

El primer
callback
actualiza las opciones disponibles en el segundo componentedcc.RadioItems
basándose en el valor seleccionado en el primer componentedcc.RadioItems
.dcc.RadioItems
es uncomponente para mostrar un conjunto de botones de radio (u opciones)
. Losusuarios pueden seleccionar una opción del conjunto
.El segundo
callback
establece un valor inicial cuando la propiedad options cambia: lo establece al primer valor de ese array de opciones.La última llamada de retorno muestra el valor seleccionado de cada componente. Si cambia el valor del componente countries
dcc.RadioItems
,Dash
esperará hasta que se actualice el valor del componentecities
antes de llamar alcallback
final. Esto evita que suscallbacks
sean llamados con un estado inconsistente como con “America
” y “Montréal
”.
Dash App con Estado#
En algunos casos, puede tener un patrón de tipo “formulario” en su aplicación. En esta situación, es posible que quieras
leer el valor del componente de entrada, pero sólo cuando el usuario haya terminado de introducir toda su información en el formulario
. Adjuntar una llamada de retorno a los valores de entrada directamente puede tener este aspecto:
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Input(id="input-1", type="text", value="Montréal"),
dcc.Input(id="input-2", type="text", value="Canada"),
html.Div(id="number-output"),
])
@app.callback(
Output("number-output", "children"),
Input("input-1", "value"),
Input("input-2", "value"),
)
def update_output(input1, input2):
return u'Input 1 is "{}" and Input 2 is "{}"'.format(input1, input2)
if __name__ == "__main__":
app.run_server(debug=True)

En este ejemplo,
la función callback se dispara cada vez que cambia alguno de los atributos descritos por la entrada Input
. Pruébelo usted mismo introduciendo datos en las entradas anteriores. El estado le permite pasar valores adicionales sin disparar las devoluciones de llamada. Aquí está el mismo ejemplo anterior pero con eldcc.Input
comoState
y un botón comoInput
. Recuerde que, la letra"u"
delante de los valores del stirng significa que la cadena esUnicode
.
Actualizar gráficos al deslizar el cursor#
Actualicemos nuestro ejemplo de indicadores mundiales,
actualizando las series de tiempo cuando pasamos por encima de los puntos de nuestro gráfico de dispersión
. la opciónpadding
en el dash es utilizada para configurar el área de relleno en los cuatro lados de un elemento a la vez (ver padding).
import pandas as pd
df = pd.read_csv("https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/country_indicators.csv")
df.head()
Country Name | Indicator Name | Year | Value | |
---|---|---|---|---|
0 | Arab World | Agriculture, value added (% of GDP) | 1962 | NaN |
1 | Arab World | CO2 emissions (metric tons per capita) | 1962 | 0.760996 |
2 | Arab World | Domestic credit provided by financial sector (... | 1962 | 18.168690 |
3 | Arab World | Electric power consumption (kWh per capita) | 1962 | NaN |
4 | Arab World | Energy use (kg of oil equivalent per capita) | 1962 | NaN |
En este ejemplo,
display:inline-block
permite establecer un ancho y una altura en el elemento. Elpadding
de un elemento es el espacio entre su contenido y su borde.
import dash
from dash import dcc
from dash import html
import pandas as pd
import plotly.express as px
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
df = pd.read_csv('https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/country_indicators.csv')
available_indicators = df['Indicator Name'].unique()
app.layout = html.Div([
html.Div([
html.Div([
dcc.Dropdown(
id='crossfilter-xaxis-column',
options=[{'label': i, 'value': i} for i in available_indicators],
value='Fertility rate, total (births per woman)'
),
dcc.RadioItems(
id='crossfilter-xaxis-type',
options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
value='Linear',
labelStyle={'display': 'inline-block', 'marginTop': '5px'}
)
],
style={'width': '49%', 'display': 'inline-block'}),
html.Div([
dcc.Dropdown(
id='crossfilter-yaxis-column',
options=[{'label': i, 'value': i} for i in available_indicators],
value='Life expectancy at birth, total (years)'
),
dcc.RadioItems(
id='crossfilter-yaxis-type',
options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
value='Linear',
labelStyle={'display': 'inline-block', 'marginTop': '5px'}
)
], style={'width': '49%', 'float': 'right', 'display': 'inline-block'})
], style={
'padding': '10px 5px'
}),
html.Div([
dcc.Graph(
id='crossfilter-indicator-scatter',
hoverData={'points': [{'customdata': 'Japan'}]}
)
], style={'width': '49%', 'display': 'inline-block', 'padding': '0 20'}),
html.Div([
dcc.Graph(id='x-time-series'),
dcc.Graph(id='y-time-series'),
], style={'display': 'inline-block', 'width': '49%'}),
html.Div(dcc.Slider(
id='crossfilter-year--slider',
min=df['Year'].min(),
max=df['Year'].max(),
value=df['Year'].max(),
marks={str(year): str(year) for year in df['Year'].unique()},
step=None
), style={'width': '49%', 'padding': '0px 20px 20px 20px'})
])
@app.callback(
dash.dependencies.Output('crossfilter-indicator-scatter', 'figure'),
[dash.dependencies.Input('crossfilter-xaxis-column', 'value'),
dash.dependencies.Input('crossfilter-yaxis-column', 'value'),
dash.dependencies.Input('crossfilter-xaxis-type', 'value'),
dash.dependencies.Input('crossfilter-yaxis-type', 'value'),
dash.dependencies.Input('crossfilter-year--slider', 'value')])
def update_graph(xaxis_column_name, yaxis_column_name,
xaxis_type, yaxis_type,
year_value):
dff = df[df['Year'] == year_value]
fig = px.scatter(x=dff[dff['Indicator Name'] == xaxis_column_name]['Value'],
y=dff[dff['Indicator Name'] == yaxis_column_name]['Value'],
hover_name=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name']
)
fig.update_traces(customdata=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'])
fig.update_xaxes(title=xaxis_column_name, type='linear' if xaxis_type == 'Linear' else 'log')
fig.update_yaxes(title=yaxis_column_name, type='linear' if yaxis_type == 'Linear' else 'log')
fig.update_layout(margin={'l': 40, 'b': 40, 't': 10, 'r': 0}, hovermode='closest')
return fig
def create_time_series(dff, axis_type, title):
fig = px.scatter(dff, x='Year', y='Value')
fig.update_traces(mode='lines+markers')
fig.update_xaxes(showgrid=False)
fig.update_yaxes(type='linear' if axis_type == 'Linear' else 'log')
fig.add_annotation(x=0, y=0.85, xanchor='left', yanchor='bottom',
xref='paper', yref='paper', showarrow=False, align='left',
text=title)
fig.update_layout(height=225, margin={'l': 20, 'b': 30, 'r': 10, 't': 10})
return fig
@app.callback(
dash.dependencies.Output('x-time-series', 'figure'),
[dash.dependencies.Input('crossfilter-indicator-scatter', 'hoverData'),
dash.dependencies.Input('crossfilter-xaxis-column', 'value'),
dash.dependencies.Input('crossfilter-xaxis-type', 'value')])
def update_y_timeseries(hoverData, xaxis_column_name, axis_type):
country_name = hoverData['points'][0]['customdata']
dff = df[df['Country Name'] == country_name]
dff = dff[dff['Indicator Name'] == xaxis_column_name]
title = '<b>{}</b><br>{}'.format(country_name, xaxis_column_name)
return create_time_series(dff, axis_type, title)
@app.callback(
dash.dependencies.Output('y-time-series', 'figure'),
[dash.dependencies.Input('crossfilter-indicator-scatter', 'hoverData'),
dash.dependencies.Input('crossfilter-yaxis-column', 'value'),
dash.dependencies.Input('crossfilter-yaxis-type', 'value')])
def update_x_timeseries(hoverData, yaxis_column_name, axis_type):
dff = df[df['Country Name'] == hoverData['points'][0]['customdata']]
dff = dff[dff['Indicator Name'] == yaxis_column_name]
return create_time_series(dff, axis_type, yaxis_column_name)
if __name__ == '__main__':
app.run_server(debug=True)
Intente
pasar el mouse por encima de los puntos del gráfico de dispersión de la izquierda
. ¿Observa cómo los gráficos de líneas de la derecha se actualizan en función del punto sobre el que pasa el mouse?.

Dos ejemplos de Dash#
En esta sección estudiaremos
dos ejemplos de app dash
para poner en practica lo estudiado en las dos primeras secciones.El primero es relacionado con mapas y el segundo con series de tiempo financieras
. El objetivo principal es hacer uso de la metodología aprender por ejemplos
Dash App para Mapas#
Iniciamos cargando el
DataFrame
a utlizar en nuestra app. Los datos provienen del archivointro_bees.csv
que contiene información sobreenfermedades que afectan a ciertas colonias de abejas, en determinados estados en USA
. Las columnas de interés en este ejemplo son:
['State', 'ANSI', 'Affected by', 'Year', 'state_code']
El código
ANSI
es el Códigos del Instituto Nacional de Normalización:American National Standards Institute codes (ANSI codes)
import pandas as pd
df = pd.read_csv("https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/intro_bees.csv")
df.head()
Program | Year | Period | State | ANSI | Affected by | Pct of Colonies Impacted | state_code | |
---|---|---|---|---|---|---|---|---|
0 | SURVEY | 2019 | JAN THRU MAR | Alabama | 1 | Disease | 1.8 | AL |
1 | SURVEY | 2019 | JAN THRU MAR | Alabama | 1 | Other | 3.1 | AL |
2 | SURVEY | 2019 | JAN THRU MAR | Alabama | 1 | Pesticides | 0.3 | AL |
3 | SURVEY | 2019 | JAN THRU MAR | Alabama | 1 | Pests_excl_Varroa | 22.7 | AL |
4 | SURVEY | 2019 | JAN THRU MAR | Alabama | 1 | Unknown | 9.0 | AL |
Luego agrupamos nuestro
DataFrame
basados en las columnas de interés y calculamos elporcentaje promedio de colonias afectadas
para esta agrupación'Pct of Colonies Impacted'
df = df.groupby(['State', 'ANSI', 'Affected by', 'Year', 'state_code'])[['Pct of Colonies Impacted']].mean()
df.reset_index(inplace=True)
df.head()
State | ANSI | Affected by | Year | state_code | Pct of Colonies Impacted | |
---|---|---|---|---|---|---|
0 | Alabama | 1 | Disease | 2015 | AL | 0.05 |
1 | Alabama | 1 | Disease | 2016 | AL | 1.20 |
2 | Alabama | 1 | Disease | 2017 | AL | 2.25 |
3 | Alabama | 1 | Disease | 2018 | AL | 1.30 |
4 | Alabama | 1 | Disease | 2019 | AL | 1.80 |
Comenzamos a implementar nuestro
app.layout
que como es sabido, esta componente corresponde al “diseño” de la aplicación y describe el aspecto de la misma.html.H1
recuerde que es una envoltura para el elemento<h1> de HTML5
, elemento de encabezado de primer nivel. Luego de esto escribimos nuestrodcc.Dropdown
con su respectivoid
el cual sera invocado por nuesta funcióncallback
. Eldcc.Dropdown
corresponde a nuestro menu de opciones, en las que colocamos por defectovalue=2015
. Luego escribimos un nuevohtml.Div
para crear un output que entregue como mensaje cual fué el años seleccionado, esta es una clasechildren
, pues depende del input suministrado en elDropdown
. Luego agregamos el componentedcc.Graph
se puede utilizar para renderizar cualquier visualización de datosplotly-powered
, recibe como argumentofigure
. Nótese que se le asgina también unid
el cual será leido por nuestrocallback
app.layout = html.Div([
html.H1("Web Application Dashboards with Dash", style={'text-align': 'center'}),
dcc.Dropdown(id="slct_year",
options=[
{"label": "2015", "value": 2015},
{"label": "2016", "value": 2016},
{"label": "2017", "value": 2017},
{"label": "2018", "value": 2018}],
multi=False,
value=2015,
style={'width': "40%"}
),
html.Div(id='output_container', children=[]),
html.Br(),
dcc.Graph(id='my_bee_map', figure={})
])
Pasamos a implementar nuestra función
callback
. En nuestrocallback
nótese que tenemos dos outputs,output_container
que es tipochildren
, recuerde que el propósito de la propiedad children es permitir a los usuarios anidar componentes, tal y como hacemos enHTML
, en éste casoInput()
permite a un componente father actualizar datos en el componente children. La funciónupdate_graph
recibe una sola componente, esto es porque tenemos un sólo input, dado que los outputs son dos, uestrocallback
debe también retornar dos objetos, los cuales en este caso llamamoscontainer
yfig
.
@app.callback(
[Output(component_id='output_container', component_property='children'),
Output(component_id='my_bee_map', component_property='figure')],
[Input(component_id='slct_year', component_property='value')]
)
def update_graph(option_slctd):
print(option_slctd)
print(type(option_slctd))
container = "The year chosen by user was: {}".format(option_slctd)
dff = df.copy()
dff = dff[dff["Year"] == option_slctd]
dff = dff[dff["Affected by"] == "Varroa_mites"]
fig = px.choropleth(
data_frame=dff,
locationmode='USA-states',
locations='state_code',
scope="usa",
color='Pct of Colonies Impacted',
hover_data=['State', 'Pct of Colonies Impacted'],
color_continuous_scale=px.colors.sequential.YlOrRd,
labels={'Pct of Colonies Impacted': '% of Bee Colonies'},
template='plotly_dark'
)
return container, fig
La siguiente función ya estudiada anteriormente nos permite ejecutar nuestra aplicación, colocamos la opción
debug=True
para poder activar todas las opciones de debug en nuestra app
if __name__ == '__main__':
app.run_server(debug=True)
Así vamos a visualizar nuestra plicación luego de cada uno de los paso mencionados anteriormente

El codigo completo utlizado en este ejemplo es el siguiente
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from dash import Dash, dcc, html, Input, Output
app = Dash(__name__)
df = pd.read_csv("https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/intro_bees.csv")
df = df.groupby(['State', 'ANSI', 'Affected by', 'Year', 'state_code'])[['Pct of Colonies Impacted']].mean()
df.reset_index(inplace=True)
print(df[:5])
app.layout = html.Div([
html.H1("Web Application Dashboards with Dash", style={'text-align': 'center'}),
dcc.Dropdown(id="slct_year",
options=[
{"label": "2015", "value": 2015},
{"label": "2016", "value": 2016},
{"label": "2017", "value": 2017},
{"label": "2018", "value": 2018}],
multi=False,
value=2015,
style={'width': "40%"}
),
html.Div(id='output_container', children=[]),
html.Br(),
dcc.Graph(id='my_bee_map', figure={})
])
@app.callback(
[Output(component_id='output_container', component_property='children'),
Output(component_id='my_bee_map', component_property='figure')],
[Input(component_id='slct_year', component_property='value')]
)
def update_graph(option_slctd):
container = "The year chosen by user was: {}".format(option_slctd)
dff = df.copy()
dff = dff[dff["Year"] == option_slctd]
dff = dff[dff["Affected by"] == "Varroa_mites"]
fig = px.choropleth(
data_frame=dff,
locationmode='USA-states',
locations='state_code',
scope="usa",
color='Pct of Colonies Impacted',
hover_data=['State', 'Pct of Colonies Impacted'],
color_continuous_scale=px.colors.sequential.YlOrRd,
labels={'Pct of Colonies Impacted': '% of Bee Colonies'},
template='plotly_dark'
)
return container, fig
if __name__ == '__main__':
app.run_server(debug=True)
Dash App Financiera#
En esta aplicación
graficáremos el precio de distintos stocks, junto al indicador de análisis técnico, Bollinger Bands
. Este indicador considera para cualquier stock, la media del orden de preferencia, y a esta le suma y resta la desviación estándar para tener la banda. Este indicador en bastante utilizado enanálisis técnico
, sobre todo cuando deseamos conocer posibles sectores de compra y venta.
Para esta app utlizaremos la librería
colorlover
la cual nos permitirá obtener una escala de colores a elegir para nuestrasbollinger bands
. Comenzamos por cargar elDataFrame
que contiene los datos de los stocks de interés:AAPL, TSLA, COKE, YHOO, GOOGL
, los cuales aparecen en nuestra columnaStock
df = pd.read_csv('https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/dash-stock-ticker-demo.csv')
df.head()
Unnamed: 0 | Date | Open | High | Low | Close | Volume | ExDividend | SplitRatio | AdjOpen | AdjHigh | AdjLow | AdjClose | AdjVolume | Stock | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 2017-12-29 | 170.52 | 170.590 | 169.220 | 169.23 | 25643711.0 | 0.0 | 1.0 | 170.52 | 170.590 | 169.220 | 169.23 | 25643711.0 | AAPL |
1 | 1 | 2017-12-28 | 171.00 | 171.850 | 170.480 | 171.08 | 15997739.0 | 0.0 | 1.0 | 171.00 | 171.850 | 170.480 | 171.08 | 15997739.0 | AAPL |
2 | 2 | 2017-12-27 | 170.10 | 170.780 | 169.710 | 170.60 | 21672062.0 | 0.0 | 1.0 | 170.10 | 170.780 | 169.710 | 170.60 | 21672062.0 | AAPL |
3 | 3 | 2017-12-26 | 170.80 | 171.470 | 169.679 | 170.57 | 32968167.0 | 0.0 | 1.0 | 170.80 | 171.470 | 169.679 | 170.57 | 32968167.0 | AAPL |
4 | 4 | 2017-12-22 | 174.68 | 175.424 | 174.500 | 175.01 | 16052615.0 | 0.0 | 1.0 | 174.68 | 175.424 | 174.500 | 175.01 | 16052615.0 | AAPL |
Luego de cargar nuestro
DataFrame
nos disponemos a implementar nuestroapp.layout
o “diseño” de la aplicación, tal como lo hicimos con la aplicación anterior. En este caso usamoshtml.H2
que es una envoltura para el elemento<h2> de HTML5
, elemento de encabezado de segundo nivel, en este caso también agragamos el logo dePlotly
, usted puede agragar el logo de su preferencia.
html.Div([
html.H2('Finance Explorer',
style={'display': 'inline',
'float': 'left',
'font-size': '2.65em',
'margin-left': '7px',
'font-weight': 'bolder',
'font-family': 'Product Sans',
'color': "rgba(117, 117, 117, 0.95)",
'margin-top': '20px',
'margin-bottom': '0'
}),
html.Img(src="https://s3-us-west-1.amazonaws.com/plotly-tutorials/logo/new-branding/dash-logo-by-plotly-stripe.png",
style={
'height': '100px',
'float': 'right'
},
),
])
Luego de esto escribimos nuestro
dcc.Dropdown
con su respectivoid
el cual sera invocado por nuesta funcióncallback
. Eldcc.Dropdown
corresponde a nuestro menu de opciones para los diferentesstocks
, en las que colocamos por defecto una lista con dos stocks['YHOO', 'GOOGL']
. También creamo una división donde colocaremos cada una de las graficas asociadas a cada stock
dcc.Dropdown(
id='stock-ticker-input',
options=[{'label': s[0], 'value': str(s[1])}
for s in zip(df.Stock.unique(), df.Stock.unique())],
value=['YHOO', 'GOOGL'],
multi=True
),
html.Div(id='graphs')
Definimos la función encargada de calcular nuestro indicado de análisis tecnico. En esta definimos el periodo para nuestra media movil
window_size=10
y además de esto el numero de desviaciones estandar a las que deseamos distar de esta medianum_of_std=5
def bbands(price, window_size=10, num_of_std=5):
rolling_mean = price.rolling(window=window_size).mean()
rolling_std = price.rolling(window=window_size).std()
upper_band = rolling_mean + (rolling_std*num_of_std)
lower_band = rolling_mean - (rolling_std*num_of_std)
return rolling_mean, upper_band, lower_band
Definimos ahora nuestra función
callback
la cual tendrá comoOutput
en este caso las figuras correspondiente al indicador para cada stock. El mensaje de encabezado"Select a stock ticker."
aparecerá si en la caja no aparece ningún stock, indicando que debe seleccionarse el simboloticker
del stock de interés. Una vez recibido esteticker
filtramos nuestroDataFame
porStock
que coincida con elInpunt ticker
y seleccionamos para este nuevoDataFrame
las columnas que necesitamos para el indicadorbollinger band
y seleccionamos de la escala de colores el color a utlizar en nuestras bandas de bollinger que será el input de la función encargada de calcular las bandasbbands
, vamos escalando los colores de acuerdo a la banda que se va a dibujar. Vamos a ir agregando agraphs
cada una de las graficas que vamos obteniendo para mostrarlas todas en nuestra app una debajo de la otra. La figuras van indezadas conid=ticker
y son obtenidas al realizar la adición[candlestick] + bollinger_traces
. Los siguiente comandos son usados para las dimensiones del margen en nuestra figura y la ubcación de la leyenda:'margin': {'b': 0, 'r': 10, 'l': 60, 't': 0},
y'legend': {'x': 0}
.
@app.callback(Output('graphs','children'),
[Input('stock-ticker-input', 'value')])
def update_graph(tickers):
graphs = []
if not tickers:
graphs.append(html.H3(
"Select a stock ticker.",
style={'marginTop': 20, 'marginBottom': 20}
))
else:
for i, ticker in enumerate(tickers):
dff = df[df['Stock'] == ticker]
candlestick = {
'x': dff['Date'],
'open': dff['Open'],
'high': dff['High'],
'low': dff['Low'],
'close': dff['Close'],
'type': 'candlestick',
'name': ticker,
'legendgroup': ticker,
'increasing': {'line': {'color': colorscale[0]}},
'decreasing': {'line': {'color': colorscale[1]}}
}
bb_bands = bbands(dff.Close)
bollinger_traces = [{
'x': dff['Date'], 'y': y,
'type': 'scatter', 'mode': 'lines',
'line': {'width': 1, 'color': colorscale[(i*2) % len(colorscale)]},
'hoverinfo': 'none',
'legendgroup': ticker,
'showlegend': True if i == 0 else False,
'name': '{} - bollinger bands'.format(ticker)
} for i, y in enumerate(bb_bands)]
graphs.append(dcc.Graph(
id=ticker,
figure={
'data': [candlestick] + bollinger_traces,
'layout': {
'margin': {'b': 0, 'r': 10, 'l': 60, 't': 0},
'legend': {'x': 0}
}
}
))
return graphs
Así vamos a visualizar nuestra plicación luego de cada uno de los paso mencionados anteriormente

El código completo de la app lo presentamos a continuación. Ejecútela desde su terminal o editor
VS Code
por ejemplo. Antes debe instalarcolorlover
por medio de
pip install colorlover
from dash import Dash, dcc, html, Input, Output
import colorlover as cl
import datetime as dt
import flask
import os
import pandas as pd
import time
app = Dash(__name__)
server = app.server
app.scripts.config.serve_locally = False
colorscale = cl.scales['9']['qual']['Paired']
df = pd.read_csv('https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/dash-stock-ticker-demo.csv')
app.layout = html.Div([
html.Div([
html.H2('Finance Explorer',
style={'display': 'inline',
'float': 'left',
'font-size': '2.65em',
'margin-left': '7px',
'font-weight': 'bolder',
'font-family': 'Product Sans',
'color': "rgba(117, 117, 117, 0.95)",
'margin-top': '20px',
'margin-bottom': '0'
}),
html.Img(src="https://s3-us-west-1.amazonaws.com/plotly-tutorials/logo/new-branding/dash-logo-by-plotly-stripe.png",
style={
'height': '100px',
'float': 'right'
},
),
]),
dcc.Dropdown(
id='stock-ticker-input',
options=[{'label': s[0], 'value': str(s[1])}
for s in zip(df.Stock.unique(), df.Stock.unique())],
value=['YHOO', 'GOOGL'],
multi=True
),
html.Div(id='graphs')
], className="container")
def bbands(price, window_size=10, num_of_std=5):
rolling_mean = price.rolling(window=window_size).mean()
rolling_std = price.rolling(window=window_size).std()
upper_band = rolling_mean + (rolling_std*num_of_std)
lower_band = rolling_mean - (rolling_std*num_of_std)
return rolling_mean, upper_band, lower_band
@app.callback(Output('graphs','children'),
[Input('stock-ticker-input', 'value')])
def update_graph(tickers):
graphs = []
if not tickers:
graphs.append(html.H3(
"Select a stock ticker.",
style={'marginTop': 20, 'marginBottom': 20}
))
else:
for i, ticker in enumerate(tickers):
dff = df[df['Stock'] == ticker]
candlestick = {
'x': dff['Date'],
'open': dff['Open'],
'high': dff['High'],
'low': dff['Low'],
'close': dff['Close'],
'type': 'candlestick',
'name': ticker,
'legendgroup': ticker,
'increasing': {'line': {'color': colorscale[0]}},
'decreasing': {'line': {'color': colorscale[1]}}
}
bb_bands = bbands(dff.Close)
bollinger_traces = [{
'x': dff['Date'], 'y': y,
'type': 'scatter', 'mode': 'lines',
'line': {'width': 1, 'color': colorscale[(i*2) % len(colorscale)]},
'hoverinfo': 'none',
'legendgroup': ticker,
'showlegend': True if i == 0 else False,
'name': '{} - bollinger bands'.format(ticker)
} for i, y in enumerate(bb_bands)]
graphs.append(dcc.Graph(
id=ticker,
figure={
'data': [candlestick] + bollinger_traces,
'layout': {
'margin': {'b': 0, 'r': 10, 'l': 60, 't': 0},
'legend': {'x': 0}
}
}
))
return graphs
if __name__ == '__main__':
app.run_server(debug=True)
Conclusión
Por medio de estas dos aplicaciones se ha abordado cada concepto básico relacionado con el diseño de una app utilizando
Dash
yPlotly
teniendo en cuenta lo estudiado en secciones anteriores. Ahora procedemos a estudiar como podemos desplegar nuestra aplicación enDocker
.
Despliegue de Dash App usando Docker#
Introducción
Docker
yDash
son herramientas útiles paraalojar aplicaciones en diversos entornos
.Dockerizar
una imagen paraDash
resulta conveniente paradesplegar tableros de control (dashboards
) en múltiples escenarios. En esta sección, se explica cómoDockerizar Dash en una imagen Docker
. El proceso comienza con el uso de una aplicaciónDash
probada localmente en la sección anterior. Luego,se crea un Dockerfile, que contiene instrucciones para construir un contenedor Docker que hospedará el dashboard
.
Una vez que haya preparado su
Dash
, puede empezar aDockerizarlo
creando un archivo nombradoDockerfile
(Dockerfile, sin ninguna extensión). ElDockerfile representa una imagen Docker
y contieneinstrucciones sobre las operaciones a realizar cuando se construye un contenedor
.A continuación presentamos el
Dockerfile
usado para Dockerizar una aplicaciónDash
que reposa en el archivoindex.py
. Cada uno de los siguientes archivos listados,deben estar contenidos en el mismo directorio
, como se ve en la siguiente imagen.

El objetivo es crear un directorio para nuestro
Dockerfile
el cual contenga la aplicaciónindex.py
, unREADME
y un archivo de requerimientosrequirements.txt
. En este ejemplo se ha creado una carpeta nombradabarplot_fruits
, donde va a reposar la imagendocker
con los archivos mencionados previamente
Dentro del archivo
.py
que usará para su aplicación debe copiar el código deldash
que se va adockerizar
en este ejemplo. A continuación puede copiar el código y colocarlo en el archivoindex.py
.Warning
: Para probar su dashutilice el servidor por defecto para depuración
app.run_server(debug=True)
Para
Dockerizar
su dashboard,antes del último paso de esta sección
, debe cambiar la función que ejecuta el servidor a:
app.run_server(debug=True, host='0.0.0.0', port=9000)
import dash
from dash import dcc
from dash import html
import plotly.express as px
import pandas as pd
ext_style = "https://cdn.jsdelivr.net/npm/bootswatch@4.5.2/dist/darkly/bootstrap.min.css"
app = dash.Dash(external_stylesheets=[ext_style])
df = pd.DataFrame({
"Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
"Amount": [4, 1, 2, 2, 4, 5],
"City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
})
fig = px.bar(df, x = "Fruit", y = "Amount", color = "City", barmode = "group", template = "plotly_dark")
app.layout = html.Div(children=[
html.H1(children = 'Hello Dash'),
html.Div(children='''Dash: A web application framework for your data.'''),
dcc.Graph(
id='example-graph',
figure=fig
)
])
if __name__ == "__main__":
app.run_server(debug=True) # <- For testing purposes
#app.run_server(debug=True, host='0.0.0.0', port=9000) # <- To Dockerize the Dash
Antes de
Dockerizar
su dash, es recomendable crear para este un entorno dedicado, el cual solo se use para crear la imagenDocker
de su aplicación. Para crear el ambiente virtual deminiconda
recuerde que puede usar el gestor de instalación de paquetesconda
. Por ejemplo para crear el entorno virtualdash_venv
conda create --name dash_venv python=3.9
Luego de haber creado el entorno virtual
dash_venv
, el siguiente paso es ejecutar la aplicación de interés, a saberindex.py
dentro del environment. Dado que el entorno se ha creado recientemente, deberá instalar cada librería necesaria. Por ejemplo,dash, plotly, pandas
,….. Para verificar que la aplicación funciona correctamente, desde la consola deminiconda
ubicado siempre en el directorio barplot_fruits donde se encuentre el archivo index.py
debe ejecutar:
python index.py
Al ejecutar la línea anterior surgirán errores asociados con requerimientos de instalación tales como:
dash, plotly, pandas
, etc,. Realice la instalación de cada uno de estos. Luego de finalizada la instalación,verifique que efectivamente la aplicación está funcionando correctamente
.
El siguiente paso es crear nuestro archivo de requerimientos
requirements.txt
. Para esto debe primero que todoubicarse dentro de la carpeta barplot_fruit desde miniconda
. En esta carpeta reposa su aplicación, el archivoindex.py
y además, todos los archivo para su imagenDocker
. Para crear el archivo de requerimientos, dentro de esta carpeta debe ejecutar
pip freeze > requirements.txt
En ocasiones el paso anterior genera conflictos, creando algunas líneas extrañas dentro del archivo
requirements.txt
del tipo@ file:///opt/...
. Si este es su caso, puede solucionar este problema de la siguiente forma. Primero que todo, elimine el archivo de requerimientos actual, esto es, el archivorequirements.txt
. Una vez eliminado, debe generarlo nuevamente usando
pip list --format=freeze > requirements.txt
El siguiente paso es crear nuestro archivo
Dockerfile
que va a generar nuestra imagenDocker
. Para esto, debe crear un archivo nombradoDockerfile
sin ninguna extensión, dentro de la carpeta de su proyectobarplot_fruit
. Puede crearlo usandoVS Code
directamente. Dentro de este archivo debe colocar lo siguiente. Al final se realiza una explicación del contenido de este archivo
FROM python:3.9.17
COPY ./requirements.txt /requirements.txt
RUN pip install --upgrade pip
RUN pip install --no-cache-dir --upgrade -r /requirements.txt
COPY ./index.py /index.py
CMD ["python", "index.py"]
Verifique en el
Dockerfile
, la versión dePython
que aparece en la primera línea, coincide con la versión dePython
que tiene instalada en el entorno virtual creado para este proyecto. Verifique también que el nombre de la aplicacióndash
, que aparece en las dos últimas líneas, coincide con el de su archivo.py
dentro del directorio de su proyecto.
El siguiente proceso consiste en crear un archivo
README
el cual contieneinstrucciones para ejecutar el contenedor con el dashboard
. El siguiente es un ejemplo deREADME
# Execute the following commands to Dockerize the Dash application
docker build -t barplot_fruits .
docker run -h localhost -p 9002:9000 -d --name barplot_fruits barplot_fruits
El último paso para crear la imagen
Docker
es el siguiente.Primero que todo, debe iniciar la aplicación Docker
. Posteriormente, dentro de la carpeta de su proyecto y desdeminiconda
, debe ejecutar el par de líneas indicadas en el archivoREADME
docker build -t barplot_fruits .
docker run -h localhost -p 9002:9000 -d --name barplot_fruits barplot_fruits
Si ningún error ocurrió hasta este momento, usted podrá visualizar dentro de su aplicación Docker, la imagen y y el contenedor asociado a su dashboard, en este caso con el nombre:
barplot_fruits
. Además, podrá ejecutarla haciendo click en los puertos expuestos para sudash
, en este caso:9002:9000
.

En
conclusión
, en unDockerfile
para Dockerizar una aplicación Dash, se debe agregar lo siguiente:Declarar la imagen base
Python
:python:3.9.17
(o la que corresponda)Instalar todas las
dependencias necesarias
, incluyendo las dependencias tanto paraPlotly
como paraDash
Ejecutar antes el
dashboard
que ha construido en unenvironment separado
. Dentro de este environment, contruya el archivo de requerimientos mediante:pip freeze > requirements.txt
Una vez preparado el
Dockerfile
, puedes construir el contenedor y ejecutarlo usando las instrucciones del archivoREADME
. Recuerde quedebe tener iniciada la aplicación Docker
El código del archivo
README
realiza lo siguiente:La primera línea construye un contenedor
Docker
basado en elDockerfile
y lo nombrabarplot_fruits
. Debeasegúrate de incluir "." al final para indicar el directorio del archivo Docker
.Una vez construido el contenedor
Docker
, la segunda línea ejecuta la orden paraexponer la aplicación Dash en localhost:9002
.9002:9000 significa mapear el puerto 9000 en el contenedor al puerto 9002 en tu entorno local
.La razón para mapear el puerto 9000 del contenedor es porque
se declaró la aplicación Dash en el Puerto 9000 en el script Python
.Para
exponer la aplicación Dash
, debeestablecer el host = '0.0.0.0' en el entorno del contenedor
! No funcionará si lo pones en127.0.0.1
.
Lista de Dockerfiles#
Dockerfile
FROM python:3.9.17
COPY ./requirements.txt /requirements.txt
RUN pip install --upgrade pip
RUN pip install --no-cache-dir --upgrade -r /requirements.txt
COPY ./index.py /index.py
CMD ["python", "index.py"]
index.py
import dash
from dash import dcc
from dash import html
import plotly.express as px
import pandas as pd
ext_style = "https://cdn.jsdelivr.net/npm/bootswatch@4.5.2/dist/darkly/bootstrap.min.css"
app = dash.Dash(external_stylesheets=[ext_style])
df = pd.DataFrame({
"Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
"Amount": [4, 1, 2, 2, 4, 5],
"City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
})
fig = px.bar(df, x = "Fruit", y = "Amount", color = "City", barmode = "group", template = "plotly_dark")
app.layout = html.Div(children=[
html.H1(children = 'Hello Dash'),
html.Div(children='''Dash: A web application framework for your data.'''),
dcc.Graph(
id='example-graph',
figure=fig
)
])
if __name__ == "__main__":
app.run_server(debug=True, host='0.0.0.0', port=9000)
requirements.txt
ansi2html==1.8.0
certifi==2023.7.22
charset-normalizer==3.3.0
click==8.1.7
colorama==0.4.6
dash==2.14.0
dash-core-components==2.0.0
dash-html-components==2.0.0
dash-table==5.0.0
Flask==2.2.5
idna==3.4
importlib-metadata==6.8.0
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.3
nest-asyncio==1.5.8
numpy==1.26.1
packaging==23.2
pandas==2.1.1
plotly==5.17.0
python-dateutil==2.8.2
pytz==2023.3.post1
requests==2.31.0
retrying==1.3.4
six==1.16.0
tenacity==8.2.3
typing_extensions==4.8.0
tzdata==2023.3
urllib3==2.0.7
Werkzeug==2.2.3
zipp==3.17.0
README
# Execute the following commands to Dockerize the Dash application
docker build -t barplot_fruits .
docker run -h localhost -p 9002:9000 -d --name barplot_fruits barplot_fruits
Observación
Dockerizar un tablero Dash es muy fácil
, sólo tienes que añadir un Dockerfile con un par de líneas de instrucciones, construir un contenedor con él, ¡y ejecutarlo!
A continuación se muestran
outputs en consola
al ejecutar elDockerfile
, para crear la imagenDocker



Si desea desplegar la aplicación, debe dirigirse a la aplicación
Docker
. Dentro de esta debe buscar la imagen creada en el botónImages
. Posteriormente, en contenedores, podrá visualizar el contenedor creado, a saber (barplot_fruits
), y a la derecha los puertos donde se ejecuta el dash en eldaemon
. Haga click sobre este puerto para visualizar sudashboard

Render y Dash Tool#
Introducción
Render
es una plataforma en la nube que ofrece servicios de alojamiento web y despliegue de aplicaciones. Permite a los desarrolladores implementar fácilmente aplicaciones web, sitios estáticos y API en la nube de manera rápida y sencilla.Render
proporciona características como escalabilidad automática, integración continua y despliegue continuo, seguridad y monitoreo avanzado.También ofrece una interfaz de usuario intuitiva con costos razonables, y sin tarifas de inicio. En resumen,
Render
es una plataforma que simplifica el proceso de despliegue y administración de aplicaciones web y servicios en la nube.
El primer paso consiste en crearse una cuenta en Render. Es recomendable utilizar su cuenta de
GitHub
para crear esta cuenta
El segundo paso consiste en verificar que su aplicación funciona correctamente. Para este ejemplo de despliegue en
Render
, necesitaremos nombrar la aplicación comoapp.py
. Luego que cambien el nombre de la aplicación, verifique que funciona correctamente. Para esto, con su entorno activado, siguiendo el mismo ejemplo de la sección anterior, ejecute en la terminal la siguiente orden.python app.py
Luego en su navegador visite http://127.0.0.1:8050/ para ver la aplicación.
Recuerde que la aplicación es la siguiente
import dash from dash import dcc from dash import html import plotly.express as px import pandas as pd ext_style = "https://cdn.jsdelivr.net/npm/bootswatch@4.5.2/dist/darkly/bootstrap.min.css" app = dash.Dash(external_stylesheets=[ext_style]) df = pd.DataFrame({ "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"], "Amount": [4, 1, 2, 2, 4, 5], "City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"] }) fig = px.bar(df, x = "Fruit", y = "Amount", color = "City", barmode = "group", template = "plotly_dark") app.layout = html.Div(children=[ html.H1(children = 'Hello Dash'), html.Div(children='''Dash: A web application framework for your data.'''), dcc.Graph( id='example-graph', figure=fig ) ]) if __name__ == "__main__": app.run_server(debug=True)
El siguiente paso es crear un nuevo directorio con el nombre que usted decida, por ejemplo
DeployWithRender
y dentro de esta carpeta, debe crear otro directorio, el cual nombraremossrc
el cual va a contener el archivo con nuestra aplicaciónapp.py
. Si abre la aplicación desdeVSCode
debe verse de la siguiente forma

El siguiente paso es instalar dash-tools utilizando la siguiente línea de comando desde su entorno virtual
pip install dash-tools
El siguiente paso requiere del uso del cliente de
Git
. Si no lo tiene instalado, realice la instalación desde el siguiente link Getting-Started-Installing-Git. Luego de haber instaladoGit
desde la línea de comandos, por ejemplo, deAnaconda Powershell
ejecute los siguientes comandos deGit
. Recuerde que debe estar desde la terminal, ubicado dentro de la carpeta creadaDeployWithRender
git init
Luego para iniciar
dashtools
dashtools gui


El siguiente paso es copiar dentro de la ventana
Deploy
la ubicación de la carpeta creada para el proyecto. En este caso la carpeta nombradaDeployWithRender
. A la derecha podrá visualizar todos los archivos que debe preparar antes de realizar el despliegue de su aplicación. Posterior a esto se activará el botónDeploy to Render
. Haga click enGenerate random name
para asignar un nombre a su aplicación

Luego de haber creado el nombre aleatorio, podrá generar los archivos:
render.yaml
yrequirements.txt
. Solo debe hacer click sobre el botón para generar cada archivo que aparece al lado derecho de cada nombre

Luego debajo de la instancia de
Dash
en su aplicación. Agregue la líneaserver = app.server
tal como lo indicaRender
. Esto es, la aplicación debería verse de la siguiente formaimport dash from dash import dcc from dash import html import plotly.express as px import pandas as pd ext_style = "https://cdn.jsdelivr.net/npm/bootswatch@4.5.2/dist/darkly/bootstrap.min.css" app = dash.Dash(external_stylesheets=[ext_style]) server = app.server # <- For Render df = pd.DataFrame({ "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"], "Amount": [4, 1, 2, 2, 4, 5], "City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"] }) fig = px.bar(df, x = "Fruit", y = "Amount", color = "City", barmode = "group", template = "plotly_dark") app.layout = html.Div(children=[ html.H1(children = 'Hello Dash'), html.Div(children='''Dash: A web application framework for your data.'''), dcc.Graph( id='example-graph', figure=fig ) ]) if __name__ == "__main__": app.run_server(debug=True)
Va a notar en el Dashboard de Render que aparece el check en verde para
Code exists: server = app.server in src/app.py

Ahora debe hacer un
Push
enGitHub
con el proyecto creadoDeployWithRender
. Para esto, diríjase a su cuenta deGitHub
y en la pestañaYour repositories
haga click enNew
. Luego, abra una nueva terminal, y ubíquese dentro de la carpetaDeployWithRender
. Dentro de esta carpeta, pegue los comandos de Git, que se han generado al crear el repositorio, como se ve en las siguientes imágenes. HagaEnter
en la última línea de código pegada.




El siguiente paso es hacer un
Push
con todos los archivos asociados al proyectoDeployWithRender
creado para la aplicación. Para esto hacemos uso de las siguientes líneas de comandosGit
. Su repositorio deGit
debe visualizarse tal como aparece en la siguiente imagengit add . git commit -m "Adding DeployWithRender Files" git push

El siguiente paso es hacer click en
Deploy to Render
desde el Dashboard de Render, tal como se muestra en la siguiente imagen. Verifique que cada uno de los requerimientos para el despliegue aparecen con sus respectivos checks en verde. Posterior a esto, asigne un nombreBlueprint
, en este caso para identificar la aplicación, hemos utilizado el mismo nombre del repositorio enGitHub
. Luego haga click enApply
. El proceso puede tomar algunos minutos, por favor, sea paciente.


Haga click ahora en
Create web service ...
. Podrá ver el link de la página web en la parte superior izquierda, tal como se observa en la siguiente imagen. En este caso el link generado con la aplicación es el siguiente barbeque-talk-tuba-z58u.

Para realizar un cambio en su aplicación debe realizar un
commit
nuevamente con estos cambios, y además, desde el Dashboard de Render, hacer luego click enDeploy latest commit
tal como aparece en la siguiente imagen. Esto es, debe repetir el ítem 10

Los pasos abordados en esta sección fueron tomados del tutorial de CharmingData. Pueden visitar el sitio web oficial charming-data.circle.so donde podrán encontrar, en esta gran comunidad, más tutoriales sobre
Dash Plotly
.
Ejercicio para entregar#
Dockerizar
los dashboard de los dos ejemplos estudiados en la secciónDos ejemplos de Dash
. Esto es, crear dos imágenesDocker
para losDash
asociados con:Dash App para Mapas
yDash App Financiera
.Posteriormente, realice cambios en el (
back/front end
) de los dosDashboards
teniendo en cuenta los diferentes templates usados en esta sección. Por ejemplo,Agregue a los dashboard
nuevos estilos
: Cambiar título, logo, color de fondo,….. Además, agregué un nuevo Dropdown para la columnaAffected by
. Agregue divisiones con diagramas descriptivos para cada una de las columnas deldataframe
. Realice agrupación porState, Affected by, Year
y realice gráficos descriptivos que entreguen información valiosa.Agregue además de la ventana de selección de stocks, un nuevo
Dropdown
, el cual le permita por medio de un menú de opciones,seleccionar entre 4 indicadores de análisis técnico
(ver Commonly Used Technical Indicators; Technical Indicators Mathematical Description; 7 Technical Indicators to Build a Trading Toolkit, Best Day Trading Indicators for Beginners), por ejemplo:On-balance volume (OBV)
Accumulation/distribution (A/D) line
Average directional index
Aroon oscillator
Moving average convergence divergence (MACD)
Relative strength index (RSI)
Stochastic oscillator
Cada uno de estos indicadores cuenta con parámetros que pueden modificarse desde un
Dropdown
, por ejemplo, en el caso de lamedia movil
, agregue unDropdown
para seleccionar el periodo. Para lasBollinger Bands
, agregue otroDropdown
para, además del periodo de la media móvil, agregar, el número de desviaciones estándar que se desviará de la media cada banda, etc,…Asegúrese de que
todos los indicadores seleccionados aparezcan en el mismo candlestick
, esto es fundamental para la toma de decisiones. Por ejemplo, en un solo chart, el objetivo es que el inversionista pueda obtener un mínimo de 4 confirmaciones, por medio del análisis visual de cada uno de los indicadores suministrados por el Dashboard, antes de tomar una decisión de compra o venta (long/short
). Por lo tanto,debe visualizar todos los 4 indicadores en un solo plot
.