En tant que Senior consultant data scientist, je suis bien conscient de l'importance de résumer mon travail en Dashboards et Apps.
Cela me permet de vulgariser mes algorithmes et mon travail et de les présenter sous forme de graphiques intuitifs pour une compréhension meilleure et plus rapide. Dans cet article, nous passerons en revue l'un des outils et des librairies python les plus connus utilisés pour concevoir des dashboards et des applications.
Le sommaire est le suivant :
- Dash by Plotly
- Streamlit
- Bokeh
- Elastic stack
- Déploiement Heroku
Dash by Plotly
Dash est un outil open-source développé par Plotly. Il permet d'insérer plusieurs types de widgets avec la possibilité de choisir la disposition et le style puisque le layout de dash est basé sur HTML et permet le styling CSS.
L'installation se fait en exécutant la command-line suivante :
pip install dash
pip install dash_core_components
pip install dash_html_componentsLe layout d'une application dash est un arbre hiérarchique de composants, un mélange entre des éléments HTML et des graphiques construits via :
- La librairie dash_html_components fournit des classes pour toutes les balises HTML, et les keyword arguments décrivent les attributs HTML tels que style, className et id. En utilisant cette librairie, nous pouvons ajouter des éléments HTML tels que
Div, H1, P,... etc. Pour plus de détails, je vous conseille de consulter sa documentation. - La librairie dash_core_components génère des composants de plus haut niveau tels que des contrôles et des graphiques et utilise la syntaxe de Plotly. Par exemple, nous pouvons insérer un
Button, Dropdown, Slider,DatePickerRange, ... etc.. Pour plus de détails, veuillez visiter le site officiel.
Une simple app Dash peut être développée avec les lignes python suivantes :
import dash
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash(__name__)
app.title='Hello World'
app.layout = html.Div(children=[
html.H1(children='Hello Dash!', style={'textAlign':
'center', 'color': '#7FDBFF'}),
html.Div(children='''
Dash: A web application framework for Python.
'''),
dcc.Graph(
id='example-graph',
figure={
'data': [
{'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar',
'name': 'SF'},
{'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar',
'name': u'Montréal'},
],
'layout': {
'title': 'Dash Data Visualization'
}
}
),
])
if __name__ == '__main__':
app.run_server(debug=True)L'option debug=True permet de prendre en compte les modifications récentes sans avoir à relancer l'app.
Pour exécuter l'app, nous utilisons la command-line suivante :
python app_file.pyVous obtenez l'app suivante qui tourne sur http://127.0.0.1:8050/ :

Styling
Il est possible d'ajouter un fichier CSS qui écrase le style de base de l'app, vous permettant de personnaliser vos graphiques et éléments HTML. Pour ce faire, la structure du dossier doit être la suivante :
app.py
assets/
|-- style.css
|-- custom-script.js
|-- img.png
|-- background.jpg
|-- favicon.icoIl est obligatoire de placer le fichier CSS et toutes les autres images insérées dans un dossier appelé assets afin d'être lus par Dash. Une fois cela fait, il suffit de spécifier la feuille de style en utilisant les lignes python suivantes :
external_stylesheets=["assets/style.css"]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)Bootstrap
Lors de la construction d'une dash-app, je préfère personnellement travailler avec Bootstrap. C'est une librairie python pour Plotly Dash, contenant des éléments stylisés et avancés.
L'installation se fait en utilisant la command-line suivante :
pip install dash-bootstrap-componentsIl est important d'inclure le thème bootstrap comme l'une des feuilles de style :
external_stylesheets=["assets/style.css", dbc.themes.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)Bootstrap contient de nombreux éléments tels que DropDownMenu, Navbar, Progress, Button, ... etc. L'un des éléments les plus utiles est Layout, qui permet de structurer le dashboard via des Rows et Columns, ce qui est très utile pour la structure de l'app.
Pour plus de détails, n'hésitez pas à visiter la documentation officielle.
Callbacks
Comme toute autre app, il est important de permettre l'interactivité entre les graphiques et cela se fait via des fonctions callback.
Chaque élément inséré possède deux features importantes
- id : appellation unique de l'élément
- properties : varient d'un élément à un autre
Lier deux éléments dans une app se fait comme suit :

Dans ce cas particulier, le premier élément affecte le second : la property_1 du premier élément sélectionnée via son id_1 impacte la property_2 du second accédée via son id_2.
from dash.dependencies import Input, Output
@app.callback(
Output(component_id='id_2', component_property='property_2'),
[Input(component_id='id_1', component_property='property_1')]
)
def callback_function(input_value):
"""
What to do
"""NB : il est possible de prendre plusieurs Inputs dans la fonction callback.
Cache
Lors du développement d'une app, il est très important d'avoir des éléments en Cache afin de faciliter le chargement et d'accélérer l'interactivité, Cache permet de le faire.
Dash ne supporte pas de feature de cache spécifique, mais une façon de contourner ce problème est d'utiliser des global variables en python.
Tabs
Les Tabs dans Dash peuvent être insérés via le composant dcc.Tab, où ses children sont les éléments composant le tab.
mport dash_html_components as html
import dash_core_components as dcc
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Tabs([
dcc.Tab(label='1st Tab', children=[
dcc.Graph(),
###
]),
dcc.Tab(label='2nd Tab', children=[
dcc.Graph(),
###
]),
dcc.Tab(label='3rd Tab', children=[
dcc.Graph(),
###
]),
])
])Gallery
Dash a une gallery où vous pouvez parcourir et découvrir d'autres dashboards, c'est une bonne base et une source d'inspiration.
Streamlit
Streamlit est un framework d'app open-source développé pour créer des dashboards ML, principalement, de manière très rapide et efficace en utilisant python. L'installation est très simple et peut être effectuée via la command-line suivante :
pip install streamlitComparé à Dash, Streamlit offre une meilleure gestion du Cache, comme développé dans les sections suivantes, et permet ainsi des itérations de développement plus rapides via le processus suivant :

Une fois votre fichier créé, vous pouvez taper cette command-line qui exécutera votre application sur http://localhost:8501
streamlit run file.pyComme dans Dash, il est possible de choisir le mode Always re-run pour obtenir les modifications en live.
La galerie de widgets de Streamlit contient de nombreux éléments qui peuvent tous être insérés via une ligne de code : Markdown, SelectBox, Slider, Plot, etc. Notez que les widgets peuvent être insérés soit dans la one-page area, soit sur la sidebar et que l'insertion se fait selon un vertical stacking :
import streamlit as st
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn import datasets
from sklearn.decomposition import PCA
import pandas as pd
img=mpimg.imread('imgs/streamlite_funct.png')
iris = datasets.load_iris()
feature_names=['sepal length (cm)',
'sepal width (cm)',
'petal length (cm)',
'petal width (cm)']
database=pd.DataFrame(iris.data, columns=feature_names)
database["class"]=iris.target
# plot the first three PCA dimensions
fig = plt.figure(1, figsize=(8, 6))
ax = Axes3D(fig, elev=-150, azim=110)
X_reduced = PCA(n_components=3).fit_transform(iris.data)
ax.scatter(X_reduced[:, 0], X_reduced[:, 1], X_reduced[:, 2], c=iris.target,
cmap=plt.cm.Set1, edgecolor='k', s=40)
ax.set_title("First three PCA directions")
ax.set_xlabel("1st eigenvector")
ax.w_xaxis.set_ticklabels([])
ax.set_ylabel("2nd eigenvector")
ax.w_yaxis.set_ticklabels([])
ax.set_zlabel("3rd eigenvector")
ax.w_zaxis.set_ticklabels([])
def main():
########### Sidebar ##############################
st.sidebar.markdown("# Hello World")
st.sidebar.selectbox('Select a tool', ["Dash", "Kibana", "Streamlit", "Bokeh"])
st.markdown("## Multiselection")
st.multiselect('Select a tool', ["Dash", "Kibana", "Streamlit", "Bokeh"])
st.markdown("## Radio buttons")
st.radio('Select a tool', ["Dash", "Kibana", "Streamlit", "Bokeh"])
st.markdown("## Slider")
st.slider('Select a Number', min_value=1, max_value=4, value=1)
st.markdown("## Image")
st.image(img, width=500)
st.markdown("## DataBase")
st.dataframe(database)
st.markdown("## Plot")
st.write(fig)
if __name__ == "__main__":
main()Nous obtenons l'app suivante :

La fonction st.write est très importante et peut être utilisée pour insérer de nombreux éléments python. Pour plus de détails, je vous conseille de lire la documentation de streamlit.
Interactivité : Chaque élément peut être assigné à une variable qui représente sa valeur actuelle, qui peut ensuite être utilisée pour mettre à jour un autre élément et donc l'interactivité.
Cache
Le Cache est généralement utilisé pour stocker des données qui sont constantes et qui ne changent pas, quels que soient les choix effectués sur l'app. Nous définissons très souvent des fonctions dans l'app où il n'est pas utile qu'elles soient re-exécutées à chaque fois que l'app est rafraîchie, nous pouvons les mettre en cache via le code python suivant :
@st.cache
def function_1():
####Tabs
Dans de nombreuses apps, les Tabs peuvent être très importants : une façon de le faire dans Streamlit est d'ajouter une selectbox dans la sidebar dont le choix affectera la structure du dashboard et cela en utilisant des if statements sur la valeur de la box.
st.sidebar.markdown("Tabs")
tab=st.sidebar.selectbox('Select a Tab', ["Home", "Documentation", "Partners", "Contact"])
if tab=="Home":
#Develop the one_pager
##
elif tab=="Documentation":
###
elif tab=="Partners":
###
elif tab=="Contact":
###
Health app, Streamlit
Lorsque j'ai commencé à découvrir Streamlit, j'ai décidé de le mettre en pratique en développant une simple app health permettant de me lancer dans le bain.

Vous pouvez visiter l'app via cette url, le script est hébergé dans ce repository git. Pour plus d'apps, vous pouvez visiter la gallery officielle.
Bokeh
Bokeh est une librairie python qui permet de créer un dashboard interactif également. Elle peut être installée via la command-line suivante :
pip install bokehL'app ci-dessous, par exemple, peut être créée avec le script python suivant :

from bokeh.io import show, curdoc
from bokeh.plotting import figure, ColumnDataSource
from bokeh.layouts import row, column
from bokeh.models.widgets import Tabs, Panel
from bokeh.models import Slider, CheckboxGroup, RadioGroup, Button, CustomJS
#data source
x = [x*0.005 for x in range(0, 200)]
y = x
source = ColumnDataSource(data=dict(x=x, y=y))
#Plots
plot_1 = figure(plot_width=400, plot_height=400)
plot_1.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
plot_2=figure(tools='box_zoom, lasso_select')
plot_2.circle(x=[1,2,3,4,5], y=[2,3,1,1,2])
plot_2.background_fill_color = 'black'
plot_3=figure(tools='box_zoom, lasso_select')
plot_3.circle(x=[1,2,3,4,5], y=[2,3,1,1,2])
#widgets
slider = Slider(start=0.1, end=4, value=1, step=.1, title="power")
button = Button(label='Click')
checkbox = CheckboxGroup(labels=['Kibana', 'Bokeh', 'Streamlit', 'Dash'])
radio = RadioGroup(labels=['Kibana', 'Bokeh', 'Streamlit', 'Dash'])
#Interactivity
callback = CustomJS(args=dict(source=source), code="""
var data = source.data;
var f = cb_obj.value
var x = data['x']
var y = data['y']
for (var i = 0; i < x.length; i++) {
y[i] = Math.pow(x[i], f)
}
source.change.emit();
""")
slider.js_on_change('value', callback)
#Plots zoom-linking
plot_2.x_range=plot_3.x_range
plot_2.y_range=plot_3.y_range
#Tabs
first=Panel(child=row(column(slider, button, checkbox, radio), plot_1), title='first')
second=Panel(child=row(plot_2,plot_3), title='second')
tabs=Tabs(tabs=[first, second])
#App
curdoc().add_root(tabs)
show(tabs)Notez qu'une fois la figure plot définie, nous utilisons la syntaxe plot.graph pour lui assigner le graphique souhaité. Les données sont gérées via ColumnDataSource et le layout via row, column. Nous personnalisons les widgets ajoutés, Slider, CheckboxGroup, RadioGroup, Button, et les lions aux graphiques via le callback JS CustomJS. Pour exécuter votre app, sur http://localhost:5006/myapp, vous pouvez utiliser la command-line suivante :
bokeh serve --show myapp.pyGallery
Comme tous les autres outils, Bokeh a une gallery très riche pour commencer.
Elastic stack
Elasticsearch
Elasticsearch est un type spécial d'indexation de tables qui offre un moteur de recherche plus rapide. Nous pouvons transformer une database pandas en Elasticbase et ensuite la visualiser via Kibana, qui est l'outil de visualisation de la stack Elastic. Vous devez d'abord télécharger Kibana & Elasticsearch en fonction de votre OS.
Une fois installé, nous voudrons indexer correctement notre dataframe pandas via elasticsearch. Pour ce faire, nous devons d'abord lancer les deux services elasticsearch et kibana via les command-lines :
./elasticsearch-7.6.1/bin/elasticsearch
./kibana-7.6.1/bin/kibanaUne fois Kibana lancé, nous pouvons utiliser ce script python pour envoyer les données aux services Elasticsearch
import pandas as pd
from elasticsearch import Elasticsearch
# Database loading and service openning
database=pd.read_excel("data/test_db.xlsx")
es_client = Elasticsearch(http_compress=True)
#Elasticsearch does not accept NAN values
print(database.isna().sum().sum())
df=database.copy()
INDEX="laposte" #Its name in Elasticsearch (laposte for example)
TYPE= "record"
def rec_to_actions(df):
import json
for record in df.to_dict(orient="records"):
yield ('{ "index" : { "_index" : "%s", "_type" : "%s" }}'% (INDEX, TYPE))
yield (json.dumps(record, default=int))
e = Elasticsearch()
r = e.bulk(rec_to_actions(df))
#Verify if everything went fine
print(not r["errors"])Kibana
Le service kibana est lancé en local host sur le port 5601, nous pouvons le visiter dans un navigateur via l'adresse localhost:5601. Une fois sur la page principale, nous pouvons cliquer sur Dashboard et Create dashboard comme suit :

Nous pouvons maintenant ajouter des widgets via ces étapes :

Le graphique inséré peut être positionné via le curseur, ce qui rend le layout facile à personnaliser. Notez la présence d'une barre de recherche où les données sont indexées via Elasticsearch, ce qui rend le querying moins chronophage et ajoute plus d'interactivité au dashboard, en particulier lorsqu'il s'agit de grandes databases. L'interactivité est automatiquement gérée dans kibana.
Tabs
Les Tabs dans Kibana peuvent être créés via des liens embarqués dans les widgets markdown. Vous créez d'abord tous les tabs chacun dans un dashboard différent, puis vous ajoutez dans chacun les liens embarqués vers les autres.
Gallery
N'hésitez pas à visiter la gallery officielle de kibana.
Déploiement Heroku
Une fois votre app développée, vous pouvez l'héberger en ligne pour qu'elle puisse être accessible par n'importe qui via une Url. Une façon de le faire est d'utiliser Heroku qui propose ce service gratuit avec certaines limitations.
Vous devez d'abord vous inscrire puis créer une app heroku en ligne qui sera liée à votre repository git. Le repo doit avoir la structure suivante :
.
├── app.py
├── requirements.txt
├── setup.sh
└── ProcfileVous pouvez consulter mon repository git pour plus d'informations. Sur votre dossier git local, exécutez les command-lines suivantes :
heroku create
git push heroku master
heroku ps:scale web=1
heroku openVotre app sera en veille constante à chaque push que vous faites dans votre git afin de prendre en compte les derniers changements.
Conclusion
Les apps et dashboards sont une phase très importante et décisive de chaque projet, ils permettent de résumer notre travail et de le rendre plus accessible à l'utilisateur via une interface intuitive. L'utilisation de chaque technologie dépend principalement de votre livraison et de vos deadlines : certains outils offrent plus de flexibilité, d'autres sont plus rapides à développer :

De mon point de vue personnel, si toutes les conditions sont réunies, Dash peut être la meilleure option à choisir.
