Streamlit: costruire una Web App in pochi minuti

Sviluppare web app richiede molte competenze non solo legate alla gestione e manipolazione dei dati, ma sopratutto alla loro visualizzazione. L'utilizzo di software di visualizzazione quali Kibana e Tableau può essere, in alcuni casi, la salvezza per ridurre i tempi di sviluppo. Con Streamlit, un framewrok Python, è possibile sviluppare molto velocemente una web app o una dashboard interattiva senza nessuna competenza di programmazione frontend. Questo tutorial illustrerà come è possibile farlo in pochi minuti.

Share

Reading time: 8 minutes

La creazione di Web App può essere fatta con vari linguaggi di programmazione e framework. Quest’ultimi semplificano molto lo sviluppo di un’applicazione, ma la realizzazione di alcuni componenti, a volte, richiede conoscenze avanzate e l’integrazione di altri linguaggi di programmazione. Oggi è sempre maggiormente richiesta la creazione di dashboard per visualizzare e navigare i dati. Purtroppo, questo task è di secondo piano per i data scientists, il cui lavoro è orientato principalmente all’analisi dei dati. In molti casi si opta per software già pronti all’uso che includono la creazione di dashboard semplicemente con il drag & drop. Un esempio è Kibana, discusso negli articoli Kibana: esploriamo i dati e Kibana: costruire la propria dashboard. Ciò comporta però usare database specializzati, come Elasticsearch, o formattare i dati in modo tale che possano essere letti correttamente dal software.

Streamlit è un framework gratuito, open-source, interamente in python, che consente di costruire rapidamente cruscotti interattivi e applicazioni web di apprendimento automatico senza che sia richiesta alcuna esperienza di sviluppo web front-end. Con una conoscenza base di Python, è possibile creare e condividere web app in poche ore e non settimane o addirittura mesi. Se volete un assaggio delle potenzialità di questo framework potete visitare la galleria di alcuni progetti costruiti dagli utenti.

In questo tutorial, dopo aver visto come installare Streamlit sulla nostra macchina, costruiremo un cruscotto interattivo che visualizza su mappa i prezzi delle case negli Stati Uniti.

Perchè Streamlit?

Qual è la motivazione che dovrebbe spingervi ad usare Streamlit per costruire una web app? Come detto in precedenza ci sono vari tools che permettono l’analisi e la visualizzazione dei dati. Oltre a Kibana, possiamo citare Tableau e Knime. Alcuni di essi però sono a pagamento o hanno delle limitazioni sulla possibilità di adattarsi al codice che si vuole sviluppare.

Streamlit è tutto in python e permette di creare dashboard o applicazioni di dati con poche righe di codice senza bisogno di avere alcuna conoscenza di sviluppo di applicazioni web front-end. Inoltre, è gratis! Quindi, se siete un data scientist, un freelance o, semplicemente, state pensando di sviluppare un’applicazione di analisi dei dati, vi consiglio vivamente di esplorare Streamlit e aggiungerlo al vostro toolkit per la sua semplicità, flessibilità, scalabilità e gratuità.

Come installare Streamlit

Per installare Streamlit vi consiglio di usare Anaconda. Se non lo avete installato è sufficiente visitare la pagina di download di Anaconda e scaricare la versione relativa al vostro sistema operativo.

A questo punto, creiamo un nostro ambiente utilizzando il navigatore di Anaconda.

Seguite le istruzioni dettagliate fornite da Anaconda per creare e gestire il vostro ambiente utilizzando il navigatore Anaconda. L’environment per questo tutorial lo chiameremo streamlit_example. Una volta che l’ambiente è creato, aprite il Terminale nel nuovo ambiente e installate  Streamlit con il seguente comando.

pip install streamlit 

Per verificare che l’installazione sia andata a buon fine digitate il seguente comando nel terminale.

streamlit hello 

Se non ci sono stati problemi si aprirà nel vostro browser la pagina di benvenuto.

Oltre a streamlit installate anche i pacchetti folium, streamlit_folium e geopandas con i seguenti comandi.

pip install folium
pip install streamlit_folium
pip install geopandas 

Prerequisiti

Create subito una directory per il progetto al cui interno ci sarà il file my_first_app.py. Lanciate Streamlit aprendo Anaconda Navigator cliccando su ‘Environments’, poi scegliete l’ambiente che avete creato in precedenza, e cliccate su ‘Open Terminal’. Nel terminale dell’ambiente di anaconda spostatevi nella directory del vostro progetto. Poi digitate il seguente comando per lanciare Streamlit.

streamlit run my_first_app.py 

Si aprirà un nuovo browser on un contenuto vuoto per ora.

Cliccate sull’icona del menu in alto a destra e selezionate ‘Settings’.

Nel finestra dei  Settings, selezionate ‘Run on save’ in modo che ogni volta che si effettua una modifica al codice questa si rifletterà automaticamente nella web app Streamlit.

Datasets

Prima di creare l’app, dobbiamo scaricare i datasets necessari per questo tutorial. Ne utilizzeremo due che sono gratuiti.

Dataset Redfin U.S. Housing Market Data

Collegatevi a Redfin e scorrete la pagina fino alla sezione ‘How it Works’. Scegliete i dati a livello di Country nell’ultimo punto della lista. Ovviamente potete usare anche gli altri dati, ma richiede di modificare il codice per visualizzare i dettagli con granularità differenti.

Dataset U.S. State Boundaries

Visitate public.opendatasoft.com e scorrete in basso fino alla sezione Geographic File Formats. Scaricate il file geojson definisce i confini geografici/coordinate di ogni stato degli Stati Uniti che visualizzeremo con la mappa choropleth. Se non avete familiarità con i file geojson o la mappa choropleth, non preoccupatevi perché nel tutorial vedremo come usarli.

Preparazione dei dati

Spostate i dati nella cartella del vostro progetto e ricopiate il seguente codice nel file my_first_app.

Import Python Libraries
import pandas as pd
import folium 
import geopandas as gpd
from folium.features import GeoJsonPopup, GeoJsonTooltip
import streamlit as st
from streamlit_folium import folium_static

@st.cache
def read_csv(path):
    return pd.read_csv(path, compression='gzip', sep='\t', quotechar='"')
     
#Data prepartion to only retrieve fields that are relevent to this project
housing_price_df=read_csv('state_market_tracker.tsv000.gz')
housing_price_df=housing_price_df[['period_begin','period_end','period_duration','property_type','median_sale_price','median_sale_price_yoy','homes_sold','state_code']]
housing_price_df=housing_price_df[(housing_price_df['period_begin']>='2020-10-01') & (housing_price_df['period_begin']<='2022-03-01')]

#st.write(housing_price_df)  

@st.cache
def read_file(path):
    return gpd.read_file(path)

#Read the geojson file
gdf = read_file('us-state-boundaries.geojson')
#st.write(gdf.head())

#Merge the housing market data and geojson file into one dataframe
df_final = gdf.merge(housing_price_df, left_on="stusab", right_on="state_code", how="outer")
df_final=df_final[['period_begin','period_end','period_duration','property_type','median_sale_price','median_sale_price_yoy','homes_sold','state_code','name','stusab','geometry']]
df_final= df_final[~df_final['period_begin'].isna()]

st.write(df_final.head())  

Nel codice qui sopra, alcune cose importanti da notare/ricordare.

Streamlit legge ed esegue il tuo script dall’alto verso il basso. Ogni volta che qualcosa viene cambiato nel codice o un utente interagisce con l’applicazione (ad esempio applicando dei filtri), Streamlit riesegue l’intero script Python da cima a fondo.

In secondo luogo, Streamlit fornisce un meccanismo di caching che permette alla tua app di rimanere performante quando carica, legge o manipola grandi quantità di dati. Questo viene fatto con il decoratore @st.cache.

In questo caso, per esempio, senza caching, ogni volta che un utente interagisce con l’app e/o l’app viene aggiornata, i dati vengono ricaricati e ricalcolati, il che potrebbe rendere l’app lenta e portare a una scarsa esperienza da parte dell’utente. Con la cache, i dati vengono caricati nell’app solo una volta. La volta successiva che la funzione nella cache viene chiamata, se non è cambiato nulla dall’input della funzione, Streamlit salterà semplicemente l’esecuzione della funzione e, invece, restituirà l’output precedentemente memorizzato nella cache.

Infine, potete usare st.write() per scrivere argomenti all’applicazione. Gli argomenti che volete passare all’app potrebbero essere diverse cose, come un data frame, un grafico, una stringa, una funzione, ecc. Nel codice qui sopra scriviamo il data frame df_final all’app per visualizzare come sono i dati finali.

Quando salvate il vostro codice, nell’app apparirà una tabella che rappresenta df_final. Dopo aver guardato i dati e aver capito bene tutti i campi (potete fare riferimento al dizionario dei dati di Redfin), potete commentare il comando st.write() dal momento che non visualizzeremo questa tabella nell’app finale.

 

Sviluppare l’app Streamlit

Ora che i dati sono pronti, iniziamo a creare l’app usando Streamlit. Per prima cosa, aggiungiamo una barra laterale nella nostra app per visualizzare alcune informazioni introduttive su questa app o un disclaimer. Aggiungeremo anche un titolo e un sottotitolo nell’interfaccia principale dell’app.

#Add sidebar to the app
st.sidebar.markdown("### My first Awesome App")
st.sidebar.markdown("Welcome to my first awesome app. This app is built using Streamlit and uses data source from redfin housing market data. I hope you enjoy!")

#Add title and subtitle to the main interface of the app
st.title("U.S. Real Estate Insights")
st.markdown("Where are the hottest housing markets in the U.S.? Select the housing market metrics you are interested in and your insights are just a couple clicks away. Hover over the map to view more details.") 

Dopo aver salvato il codice, vedrete che anche la web app viene rieseguita/aggiornata automaticamente e assomiglia a quanto segue.

Aggiungiamo quindi alcuni filtri che forniscano agli utenti la flessibilità di filtrare i dati. Inseriamo tre filtri nella stessa riga creando tre colonne come riportato nel seguente codice.

#Create three columns/filters
col1, col2, col3 = st.columns(3)

with col1:
     period_list=df_final["period_begin"].unique().tolist()
     period_list.sort(reverse=True)
     year_month = st.selectbox("Snapshot Month", period_list, index=0)

with col2:
     prop_type = st.selectbox(
                "View by Property Type", ['All Residential', 'Single Family Residential', 'Townhouse','Condo/Co-op','Single Units Only','Multi-Family (2-4 Unit)'] , index=0)

with col3:
     metrics = st.selectbox("Select Housing Metrics", ["median_sale_price","median_sale_price_yoy", "homes_sold"], index=0)
 

Esteticamente molto bello, ma quando gli utenti selezionano le diverse opzioni dei filtri, come fa Streamlit a prendere questi input e filtrare i dati di conseguenza? Per esempio, se un utente vuole guardare il prezzo mediano di vendita di ogni stato in base al mese più recente e solo per le case unifamiliari, come facciamo a passare questi filtri al nostro frame di dati?

Per aggiornare df_final in base alle selezioni dell’utente, utilizzando il seguente codice. Potete scrivere il frame di dati nell’app e provare a cambiare i filtri per controllare che funzionino correttamente (assicuratevi di commentare st.write dopo aver finito di effettuare i tests).

#Update the data frame accordingly based on user input
df_final=df_final[df_final["period_begin"]==year_month]
df_final=df_final[df_final["property_type"]==prop_type]
df_final=df_final[['period_begin','period_end','period_duration','property_type',metrics,'state_code','name','stusab','geometry']]

st.write(df_final)
 

Aggiungere la mappa di Choropleth

Ora che i dati sono pronti, inseriamo la mappa di Choropleth. Usiamo il seguente codice per creare la mappa di Folium che visualizza i dati del mercato immobiliare statunitense per diversi periodi, tipo di proprietà e metriche di valutazione, a seconda dell’input dell’utente.

Nel codice, le righe 2 e 3 iniziano una mappa vuota degli Stati Uniti e impostano la posizione centrale predefinita della mappa a (40, -100). Le linee da 6 a 18 creano la mappa corpuscolare in base all’input dell’utente sui tre filtri. Fai attenzione alla linea 10 che determina l’ombreggiatura di ogni stato in base al parametro ‘metrica’ passato dal terzo filtro.

#Initiate a folium map
m = folium.Map(location=[40, -100], zoom_start=4,tiles=None)
folium.TileLayer('CartoDB positron',name="Light Map",control=False).add_to(m)

#Plot Choropleth map using folium
choropleth1 = folium.Choropleth(
    geo_data='us-state-boundaries.geojson',     #This is the geojson file for the Unite States
    name='Choropleth Map of U.S. Housing Prices',
    data=df_final,                                  #This is the dataframe we created in the data preparation step
    columns=['state_code', metrics],                #'state code' and 'metrics' are the two columns in the dataframe that we use to grab the median sales price for each state and plot it in the choropleth map
    key_on='feature.properties.stusab',             #This is the key in the geojson file that we use to grab the geometries for each state in order to add the geographical boundary layers to the map
    fill_color='YlGn',
    nan_fill_color="White",
    fill_opacity=0.7,
    line_opacity=0.2,
    legend_name='Housing Market Metrics',
    highlight=True,
    line_color='black').geojson.add_to(m)

folium_static(m) 

Il risultato che otterremo è il seguente.

Ottimo! Tuttavia, sarebbe interessante se potessimo anche mostrare alcune informazioni su ogni stato quando gli utenti passano sopra la mappa. Aggiungiamo, quindi, dei tooltip alla mappa inserendo il seguente codice prima di folium_static(m).

#Add tooltips to the map
geojson1 = folium.features.GeoJson(
               data=df_final,
               name='United States Housing Prices',
               smooth_factor=2,
               style_function=lambda x: {'color':'black','fillColor':'transparent','weight':0.5},
               tooltip=folium.features.GeoJsonTooltip(
                   fields=['period_begin',
                           'period_end',
                           'name',
                           metrics,],
                   aliases=["Period Begin:",
                            'Period End:',
                            'State:',
                            metrics+":"], 
                   localize=True,
                   sticky=False,
                   labels=True,
                   style="""
                       background-color: #F0EFEF;
                       border: 2px solid black;
                       border-radius: 3px;
                       box-shadow: 3px;
                   """,
                   max_width=800,),
                    highlight_function=lambda x: {'weight':3,'fillColor':'grey'},
                   ).add_to(m) 
 

Ecco fatto! Avete creato il vostro primo cruscotto interattivo/web app usando Streamlit. Partendo da questo esempio e sfruttando le potenzialità di Streamlit potete pensare di costruire le vostre app interattive in pochissimo tempo.

Tutto il codice è disponibile nel repository github. Se volete usare l’app potete collegarvi a Streamlit Cloud.

Letture consigliate

More To Explore

Python

OpenCV e Streamlit: creare un’app di photo editing

Manipolare le immagini è un task che è molto utile in diversi campi applicativi. OpenCV, una libreria Python, permette facilmente di modificare le immagini a seconda delle nostre esigenze. In questo tutorial scopriamo come costruire una semplice web app mediante Streamlit per applicare alcuni effetti alle nostre foto.

Python

Streamlit: come migliorare l’esperienza utente di una web app

Con Streamlit è possibile creare dashboard interattive in pochissimo tempo. L’interfaccia utente deve però essere intuitiva, semplice da usare ed efficace. In questo tutorial scopriremo come migliorare una web app con poche e semplici trucchi.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Design with MongoDB

Design with MongoDB!!!

Buy the new book that will help you to use MongoDB correctly for your applications. Available now on Amazon!