Skip to content
Pradel edited this page Apr 20, 2020 · 2 revisions

Bienvenid@ al wiki de este proyecto. El objetivo es construir tableros de análisis de datos de una manera más rápida y que se puedan visualizar correctamente tanto en computadoras, como en dispositivos móviles (responsivo). Para esto se usó el framework de python Dash y la biblioteca para para construir visualizaciones y gráficas plotly. También se usa una hoja de estilos de CSS, que es la responsable de la responsividad de la aplicación.

De la misma manera en la parte final se explica como incluir una autenticación muy básica con una de las bibiliotecas de Dash, pero se debe de tomar en cuenta que es una autenticación débil y de ser necesario se deben de reforzar los métodos de seguridad para entrar al tablero que el usuario construya.

1. Cómo iniciar este proyecto.

  1. Clona este repositorio (aquí un tutorial).

  2. Se recomienda diseñar primero en papel el tablero que se quiere construir. El template contiene un header básico con el título del tablero y el logo de GitHub. Consta también de una cuadrícula de 3 filas por 3 columnas para colocar las gráficas requeridas. Esta configuración puede ser modificada (revisar la sección 3).

  3. De la misma manera se recomienda revisar la documentación básica de Dash y la de plotly, así como elegir las gráficas y visualizaciones adecuadas al proyecto. Para ello se puede consultar la siguiente visualización de A. Abela o el siguiente Catálogo de visualizaciones.

2. Construir gráficas en plotly adaptadas a Dash.

Para este propósito se creó un jupyter notebook en el repositorio de este proyecto. Todas las gráficas construídas ahí están adaptadas para poderse incluir en un tablero de Dash. Dicho esto, cabe notar que es posible construir gráficas en plotly usando sintaxis distintas, aunque el resultado será el mismo, dependerá siempre de las necesidades del usuario.

Se exploran dos ejemplos para construir gráficas. Uno es usando el paquete plotly.graph_objects que trata a las figuras construídas como clases jerárquicas llamadas Objetos Gráficos. En el segundo ejemplo se usa el módulo plolty.express que es una API de alto nivel de exploración de datos y generación de gráficas.

2.1 Ejemplo usando plotly.graph_objects

Se toma un ejemplo del notebook ya mencionado para construir una gráfica de líneas. Para ello se necesita un dataframe (previamente limpio y procesado) con dos columnas que fungirán como el eje x y el eje y de la gráfica. O bien se puede incluir en el mismo código dos listas correspondientes al eje x y el eje y. Claro que esto último no se considera una buena práctica, sobre todo si los datos a usar son confidenciales o el volúmen de los datos es muy grande.

Usando el módulo plotly.graph_objects se construye un diccionario que será la figura que usará plotly para construir la gráfica. Este diccionario consta de dos llaves: data y layout. La primera guarda los valores que describen el trazo o trazos de la figura en forma de listas, así como propiedades específicas al tipo de trazo. La segunda guarda un diccionario que especifica las propiedades que personalizan la figura, como la fuente, título, márgenes, ejes, leyendas, etc.

El diccionario de la figura será el que se pasará a Dash para poder incluir las gráficas en el tablero. De manera que queda como sigue:

figura = {'data': [data_lineas],
          'layout': layout_lineas}

Donde la llave data, para este ejemplo de gráfica de líneas se construye usando la función Scatter del módulo de plotly y la llave layout usa la función Layout del mismo modo. Antes es necesario incluir las bibliotecas necesarias.

import plotly.graph_objects as go
import pandas as pd

df=pd.read_csv('mis_datos.csv')

data_lineas=go.Scatter(x=df['EjeX'],                 #Columna del dataframe con datos del eje x
                       y=df['EjeY'],                 #Columna del dataframe con datos del eje y
                       mode='lines+markers',         #Se dibujarán líneas con marcadores con configuración default
                       line={'color': 'firebrick',   #Personalización de color y grosor de la línea
                             'width': 4})

layout_lineas=go.Layout(title={'text': 'Importe generado por año'}, #Diccionario con personalizaciones
                        xaxis={'nticks': 5})

Lo anterior produce la siguiente gráfica

plotly_lineas

2.2 Ejemplo usando plotly.express

Como ya se mencionó plotly express es un API de alto nivel para explorar datos y crear gráficas. Las funciones de este módulo también regresan figuras llamadas "objetos gráficos", tal como plotly.graph_objects.

Se construye una gráfica de pie usando este módulo. Para construir una figura sólo es necesario importar el módulo que construye la figura correspondiente y agregar los parámetros y configuraciones necesarias. En este caso se importará la función pie.

import plotly.express as px
import pandas as pd

df=pd.read_csv('mis_datos.csv')

figura_pie=px.pie(df,                                 #Dataframe
                  values='ColumnaDataframe_valores',  #Valores del dataframe a graficar
                  names='ColumnaDataframe_nombres',   #Nombres que usan los valores del dataframe
                  color_discrete_sequence=px.colors.sequential.RdBu)  #Paleta de colores precargada

Lo anterior produce la siguiente gráfica

plotly_pie

El dataset que se usó para construir esta gráfica usó años como los nombres de las categorías (names) y valores de ventas por cada uno de esos años (values),

La figura figura_pie es la que se pasa a Dash para incluirla en el tablero.

3. Construir un tablero de Dash.

Dash es un framework de python. Propiamente sirve para construir aplicaciones web, y se usa en este proyecto para construir un tablero de análisis de datos.

Un proyecto de Dash consta principalmente de un componente llamado layout. Puede constar de una segunda parte para hacer la app interactiva (botones, filtros, etc). Pero en este demo sólo se verá la primera parte para construir un tablero básico y estático.

Se recomienda construir un ambiente virtual en el folder raíz del proyecto para así instalar todas las dependencias, incluídas las de Dash. Se puede consultar cómo instalar Dash aquí.

3.1 Estructura del layout

Se debe de crear un archivo de python app.py que es donde se construye el layout principal de la aplicación.

El layout está compuesto como un árbol de componentes. Estos componentes pueden ser de HTML y se encuentran en la biblioteca dash_html_components. Cada uno de ellos tiene una etiqueta, tal cual se hace en HTML. Por ejemplo, si se quiere escribir un título en HTML, se escribe así,

<h1> Hola mundo </h1>

Mientras que en Dash, la sintaxis es la siguiente,

html.H1('Hola mundo')

Existen otros componentes de alto nivel generados con JavaScript, HTML y CSS a través del framework React.js. Éstos se encuentran en la biblioteca dash_core_components

El primer paso para contruir la aplicación web en dash (en este caso el tablero) es importar las bibliotecas necesarias e inicializar la app de dash:

import dash
import dash_core_components as dcc
import dash_html_components as html

app = dash.Dash(__name__)

Después se construye el layout de la aplicación, usando la sintaxis de Dash, pero tal cual usando las etiquetas de HTML conocidas.

app.layout = html.Div([html.Div([html.H1('Título del tablero', className='a', id='a'),
                                 html.Img(src=app.get_asset_url('logo.png'), alt='logo',
                                          className='logo')], className='header', id='header'),
                       html.Div([html.Div([html.Div('un contenedor', className='contenedor'),
                                           html.Div(dcc.Graph)], className='row')],
                                className='grid', id='grid')], className='container', id='container')

En este ejemplo se construyó un header dentro de un div de html y un contenedor junto con una gráfica (dcc.Graph) en otro div. En el header se puso una imágen que debe de estar guardada en un folder llamado assets para que Dash pueda tomar de allí la imagen. Este folder debe de estar en el directorio raíz del proyecto junto con el archivo app.py.

Posteriormente se escribe la instrucción para ejecutar el código escrito en el archivo.

if __name__ == '__main__':
    app.run_server(debug=True)

3.1.1 Ejemplo

Ahora bien, usando la gráfica de líneas que se construyó en la sección se muestra el código para construir un tablero muy básico y estático de dash

# Bibliotecas de dash
import dash
import dash_core_components as dcc
import dash_html_components as html

# Se inicializa la app de dash, el archivo .py que contiene estas instrucciones se debe de llamar app.py
app = dash.Dash()

# Layout de dash, consta de un div de html con el título de la app y la figura creada en plotly, en este caso es
# fig_lineas
app.layout = html.Div([html.H1('Hola mundo', className='titulo'),
                       html.Div([dcc.Graph(figure=figura_lineas)],
                               className='contenedor')])

# Correr la app
app.run_server(debug=True)

Obsérvese como al componente dcc.Graph se le pasa la figura construída mediante dcc.Graph(figure=figura_lineas).

El bloque anterior de código produce la siguiente web app, que corre en local en la dirección http://127.0.0.1:8050/

ejemplo_dash

En las siguiente secciones se verá como personalizar los tableros reescribiendo el index de HTML y agregando una hoja de estilos de CSS.

3.2 Agregar una hoja de estilos de CSS

Se pueden agregar hojas de estilo de CSS de dos maneras. Una es usando una hoja externa que se aloje en algún repositorio e incluirla en el código, o bien en el folder assets que se crea en el directorio raíz del proyecto se agregará localmente la hoja de estilos.

Para agregar una hoja externa, basta con incluir la url en la definición de la app de dash,

import dash
import dash_html_components as html
import dash_core_components as dcc

app=dash.Dash(__name__, assets_external_path='http://direccion.hoja.externa')
app.scripts.config.serve_locally=False

De manera local, sólo basta con ir dando estilos a los elementos de dash en la hoja CSS correspondiente. Como se puede observar en el ejemplo básico de tablero, cada elemento de la biblioteca html de dash puede tener un className que es lo que se coloca en la configuración de la hoja de CSS.

Por ejemplo, en el tablero, se tiene el siguiente elemento,

html.H1('Título del tablero', className='titulo')

para personalizar el título mediante CSS, se agrega en la hoja de estilos del folder assets, el siguiente bloque de código

.titulo {
   color: 'grey';
   font-size: 16px;
   background-color: 'yellow';
}

Lo anterior personaliza el tamaño de la fuente, el color de la fuente y el color de fondo del elemento. De esta manera se ha personalizado el título del tablero. Esto se puede hacer con cada uno de los elementos html del layout de dash. También es posible tener muchas hojas de estilo de CSS con diferentes propósitos.

En el demo de tablero construído en este proyecto, la hoja de estilos usada esta basada y ligeramente modificada en esta hoja de estilos creada por Chris Parmer. La finalidad de usar esta hoja de estilos en particular es poder obtener un tablero responsivo , que se pudiera visualizar en dispositivos móviles. Esto se logra agregando media queries al CSS y especificando los cambios de acuerdo al tamaño de la pantalla del dispositivo en cuestión.

Se recomienda ampliamente estudiar como trabajar una hoja de estilos de CSS si no se tienen conocimientos previos, ya que de esto depende la personalización de tu tablero y básicamente que tan atractivo sea visualmente.

3.3 Cambiar el template de HTML

Existen otro tipo de elementos que se dan por default cuando se construye por primera vez una applicación web en Dash, como por ejemplo el favicon. Para poder personalizar esto, un camino es reescribir o modificar el template de HTML. Esto se debe de agregar como un script después de definir nuestra app de dash, usando la función app.index_string.

Es posible con este método escribir el título de la app, es decir el texto que aparece en la pestaña del navegador, el autor, y algunos otros metadatos. También aquí se define la responsividad de la página mediante el siguiente bloque de código

    <meta name="viewport" content="width=device-width, initial-scale=1">

3.4 Template del tablero.

Recopilando lo visto en las secciones 3.2 y 3.3, se construyó el template del tablero de dash. Primero se reescribió el template de HTML, agregando una fuente de texto externa (google font); se agregó responsividad usando el bloque de código visto en la sección anterior; y se agregó un autor y título de la app.

Como ya se mencionó anteriormente la hoja de estilos de CSS local está basada en una creada por Chris Parmer que proporciona responsividad a la app. Esta se puede encontrar y consultar en el folder assets del directorio raíz del repositorio. Esta hoja de estilos crea una cuadrícula de hasta 12 columnas, pero para este tablero se decidió usar una cuadrícula de 3 filas por 3 columnas, que al verse en dispositivos móviles se vuelve una cuadrícula de 6 filas por una columna.

El código para generar el template (sin gráficas) es el siguiente:

import dash
import dash_html_components as html  # Componentes html para usar en dash

# Inicializar la app de dash
app = dash.Dash(__name__)

# -----------------------------------------  HTML ----------------------------------------------#
# Personalización del template de html (head, fuente de texto, favicon, etc.).
app.index_string = '''
<!DOCTYPE html>
<html>  
<head>
    <!-- Se usan google fonts, cambiar a demanda la url de la fuente y modificar en el css -->
    <link href="https://fonts.googleapis.com/css?family=Sen&display=swap" rel="stylesheet">

    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="author" content="pradel">

    <!-- Cambiar el título de la app (el que aparece en la pestaña del navegador) -->
    <title>Título</title>

    <!-- Agregar un favicon (en el folder de assets) a la app -->
    {%favicon%}
    {%css%}
</head>
<body>
{%app_entry%}
{%config%}
{%scripts%}
{%renderer%}
</body>
</html>'''

# Construir layout
app.layout = html.Div([html.Div([html.H1('Título del tablero', className='a', id='a'),
                                 html.Img(src=app.get_asset_url('logo.png'), alt='logo',
                                          className='logo')], className='header', id='header'),
                       html.Div([html.Div([html.Div('four', className='four columns'),
                                           html.Div('eight', className='eight columns')], className='row'),
                                 html.Div([html.Div('five', className='five columns'),
                                           html.Div('seven', className='seven columns')], className='row'),
                                 html.Div([html.Div('six', className='six columns'),
                                           html.Div('seven', className='six columns')], className='row')],
                                className='grid', id='grid')], className='container', id='container')

if __name__ == '__main__':
    app.run_server(debug=True)

Para agregar las gráficas al tablero, se deben de seguir las instrucciones de la sección 3.1, previa construcción de estas usando plotly. La app principal de este proyecto ya contiene las gráficas, es el archivo app.py y para poderlo visualizar una vez instaladas todas las dependencias y clonado el repositorio, se puede correr en una terminal usando la instrucción

python app.py

Esto abrirá una página en tu navegador en la dirección http://127.0.0.1:8050/.

4. Autenticación básica.

Dash proporciona una autenticación básica, es decir, usando un usuario y un password para poder entrar al tablero. Si los datos que se usan son confidenciales, se recomienda usar una autenticación más fuerte, dependiendo de en dónde se desplegará la app.

Para usar la autenticación básica se necesita incluir la biblioteca dash auth y definir el usuario y el password como un diccionario en el código de dash. Sin embargo esta no es una buena práctica, por lo que en este proyecto se recomienda usar variables de entorno. Para ello se necesita la biblioteca os y definir las variables de entorno en un archivo .sh que no deberá de estar versionado en el repositorio, si no solamente mantenerlo en local. Es decir, si se quiere compartir la llave de acceso del repositorio a otra persona, se debe de pasar el archivo .sh por un medio seguro, o bien pasar las claves y que el siguiente usuario cree su propio archivo. A la larga esto no suena tan práctico, pero esto se deja a consideración del usuario, ya que la manera en la que se autentique la app depende mucho del despliegue de la misma.

Por ejemplo llamaré a mi archivo local que contiene las llaves de acceso credentials.sh. Este archivo contendrá las siguientes credenciales:

export USER=root
export PASSWORD=admin

y en el código de dash, lo que se incluirá será lo siguiente

import os
import dash
import dash_auth
import dash_core_components as dcc 
import dash_html_components as html 


VALID_USERNAME_PASSWORD_PAIRS = {os.environ['USER']: os.environ['PASSWORD']}

De esta manera antes de mostrar el tablero se pedirá el usuario y password previamente definido. Se puede consultar esta parte de la documentación de Dash para conocer más acerca de la autenticación básica.

5. Uso avanzado

Es posible crear aplicaciones web más complejas que el template aquí construído. Como siempre para esto se recomienda leer la documentación. Dash cuenta con otras bibliotecas de libre uso para construir otro tipo de elementos como un visor de moléculas usando la biblioteca Dash Bio. O bien al tablero se le puden agregar callbacks para hacer los componentes interactivos. Como se puede ver las posibilidades son muchas para poder obtener una aplicación web personalizada y atractiva visualmente.