Streamlit - Basic

  • Streamlit és un framework per crear aplicacions web per analitzar dades.

    Introducció

    Streamlit és un framework per crear aplicacions web per analitzar dades.

    • Les aplicacions de Streamlit són scripts de Python que s’executen de dalt a baix.
    • Cada vegada que un usuari obre una pestanya del navegador apuntant a la teva aplicació, l’script s’executa i s’inicia una sessió nova.
    • A mesura que l’script s’executa, Streamlit dibuixa la seva sortida en directe en un navegador.
    • Cada vegada que un usuari interactua amb un widget, el teu script es torna a executar i Streamlit redibuixa la seva sortida al navegador. El valor de sortida d’aquest widget coincideix amb el valor nou durant aquesta reexecució.
    • Els scripts utilitzen la memòria cau de Streamlit per evitar recalcular funcions costoses, de manera que les actualitzacions es produeixen molt ràpidament.
    • Session State et permet desar informació que persisteix entre reexecucions quan necessites més que un simple widget.
    • Les aplicacions de Streamlit poden contenir múltiples pàgines, que es defineixen en fitxers .py separats.

    Script

    Crea un projecte streamlit-basic amb uv:

    uv init streamlit-basic
    cd streamlit-basic
    uv add streamlit

    Modifica el fitxer main.py:

    import streamlit as st
    
    st.write("Hello, world!")

    Després l’executes amb streamlit run:

    uv run streamlit run main.py

    Tan bon punt executes l’script com es mostra a dalt, s’aixecarà un servidor local de Streamlit i la teva app s’obrirà en una pestanya nova del navegador per defecte. L’app és el teu llenç, on dibuixaràs gràfics, text, ginys, taules i més.

    El que es mostra a l’app depèn de tu. Per exemple, st.text escriu text en brut a la teva app.

    Flux de desenvolupament

    Cada vegada que vulguis actualitzar la teva app, desa el fitxer font. Quan ho facis, Streamlit detecta si hi ha canvis i et pregunta si vols tornar a executar l’app. Tria “Always rerun” a la part superior dreta per actualitzar automàticament la teva app cada vegada que canviïs el codi font.

    Això et permet treballar en un bucle interactiu ràpid: escrius una mica de codi, el deses, ho proves en viu, tornes a escriure codi, el deses, ho proves, i així successivament fins que estiguis satisfet amb els resultats. Aquest bucle ajustat entre codificar i veure resultats en viu és una de les maneres en què Streamlit et fa la vida més fàcil.

    Flux de dades

    L’arquitectura de Streamlit et permet escriure apps de la mateixa manera que escrius scripts Python normals. Per aconseguir-ho, les apps de Streamlit tenen un flux de dades únic: cada vegada que alguna cosa s’ha d’actualitzar a la pantalla, Streamlit torna a executar tot l’script de Python de dalt a baix.

    Això pot passar en dues situacions:

    • Sempre que modifiques el codi font de l’app.

    • Sempre que un usuari interactua amb els ginys de l’app. Per exemple, en arrossegar un control lliscant, entrar text en una caixa d’entrada o fer clic en un botó.

    Sempre que un callback es passa a un widget a través del paràmetre on_change (o on_click), el callback s’executa abans de la resta de l’script. Per a detalls sobre la API de callbacks, consulta la Session State API Reference Guide.

    I per fer que tot això sigui ràpid i fluid, Streamlit fa molta feina per tu en segon pla. Una peça clau és el decorador @st.cache_data, que permet evitar certs càlculs costosos quan l’app es torna a executar.

    Mostrar i estilitzar dades

    Hi ha diverses maneres de mostrar dades (taules, arrays, dataframes) en aplicacions de Streamlit.

    A continuació, es presenten magic i st.write(), que es poden utilitzar per escriure qualsevol cosa, des de text fins a taules.

    Després d’això, vegem els mètodes dissenyats específicament per visualitzar dades.

    Utilitzar magic

    També pots escriure a la teva aplicació sense cridar cap mètode de Streamlit.

    Streamlit suporta “ordres màgiques” (magic commands), la qual cosa significa que no cal utilitzar st.write() en absolut!

    Crea el fitxer test.py

    import streamlit as st
    import pandas as pd
    df = pd.DataFrame({
      'first column': [1, 2, 3, 4],
      'second column': [10, 20, 30, 40]
    })
    
    df
    streamlit run test.py

    Cada vegada que Streamlit veu una variable o un valor literal en la seva pròpia línia, automàticament l’escriu a la teva aplicació utilitzant st.write().

    Per a més informació, consulta la documentació sobre ordres màgiques.

    Escriure un dataframe

    Juntament amb les ordres màgiques, st.write() és el “ganivet suís” de Streamlit. Pots passar gairebé qualsevol cosa a st.write(): text, dades, gràfics d’Altair, i molt més. No et preocupis, Streamlit ho entendrà i renderitzarà les coses de la manera correcta.

    Hi ha altres funcions específiques per a dades com st.dataframe() i st.table() que també pots utilitzar per mostrar dades. Vegem quan utilitzar aquestes funcionalitats i com afegir colors i estils als teus marcs de dades.

    Potser et preguntes: “per què no utilitzaria sempre st.write()?” Hi ha diverses raons:

    • Magic i st.write() inspeccionen el tipus de dades que has passat i després decideixen com renderitzar-ho millor a l’aplicació. De vegades vols dibuixar-ho d’una altra manera. Per exemple, en lloc de dibuixar un dataframe com una taula interactiva, potser vols dibuixar-lo com una taula estàtica utilitzant st.table(df).

    • La segona raó és que altres mètodes retornen un objecte que es pot utilitzar i modificar, sigui afegint-hi dades o reemplaçant-lo.

    • Finalment, si utilitzes un mètode de Streamlit més específic, pots passar arguments addicionals per personalitzar el seu comportament.

    PENDENT exemple style

    Dibuixar gràfics i mapes

    Streamlit suporta diverses biblioteques populars de gràfics de dades com Altair, deck.gl, i més.

    En aquesta secció, afegiràs un gràfic de barres, un gràfic de línies i un mapa a la teva aplicació.

    Dibuixar un gràfic de línies

    Pots afegir fàcilment un gràfic de línies a la teva aplicació amb st.line_chart().

    import streamlit as st
    import numpy as np
    import polars as pl
    
    df = pl.DataFrame({
        "year": range(2000, 2030),
        "sales": np.random.rand(30) * 30000
    })
    
    st.line_chart(df, x="year", y="sales")

    Dibuixar un mapa

    Amb st.map() pots mostrar punts de dades en un mapa.

    Utilitzem Numpy per generar algunes dades de mostra i dibuixar-les en un mapa de Barcelona.

    import streamlit as st
    import numpy as np
    import polars as pl
    
    df = pl.DataFrame({
        "lat": np.random.randn(1000) / 50 + 41.38,
        "lon": np.random.randn(1000) / 50 + 2.15,
    })
    
    st.map(df)

    Widgets

    Quan hagis aconseguit que les dades o el model estiguin en l’estat que vols explorar, pots afegir widgets com st.slider(), st.button() o st.selectbox().

    És molt senzill: tracta els “widgets” com a variables:

    import streamlit as st
    
    x = st.slider('x')  # 👈 this is a widget
    st.write(x, 'squared is', x * x)

    En la primera execució, l’aplicació anterior hauria de mostrar el text “0 al quadrat és 0”. Després, cada vegada que un usuari interactua amb un giny, Streamlit simplement torna a executar el teu script de dalt a baix, assignant l’estat actual del “widget” a la teva variable en el procés.

    Per exemple, si l’usuari mou el control lliscant a la posició 10, Streamlit tornarà a executar el codi anterior i assignarà 10 a x en conseqüència. Així doncs, ara hauries de veure el text “10 al quadrat és 100”.

    Els widgets també es poden accedir per clau, si tries especificar una string per utilitzar-la com a clau única del widget:

    import streamlit as st
    
    st.text_input("Your name", key="name")
    
    # You can access the value at any point with:
    st.session_state.name
    

    Cada widget amb una clau s’afegeix automàticament a Session State.

    Per a més informació sobre Session State, la seva associació amb l’estat dels widgets i les seves limitacions, consulta la Guia de referència de l’API de Session State.

    Utilitza caselles de selecció per mostrar/amagar dades

    Un cas d’ús per a les caselles de selecció és amagar o mostrar un gràfic o secció específica en una aplicació.

    st.checkbox() accepta un únic argument, que és l’etiqueta del widget.

    En aquest codi, la casella de selecció s’utilitza per alternar una instrucció condicional:

    import streamlit as st
    import numpy as np
    import polars as pl
    
    if st.checkbox('Show dataframe'):
        df = pl.DataFrame({
            "a": np.random.randn(20),
            "b": np.random.randn(20)
        })
        df

    Utilitza un selectbox per a opcions

    Utilitza st.selectbox per triar d’una sèrie. Pots escriure les opcions que vulguis, o passar un array o columna de dataframe.

    import streamlit as st
    import polars as pl
    
    df = pl.DataFrame({
        'first column': [1, 2, 3, 4],
        'second column': [10, 20, 30, 40]
    })
    
    option = st.selectbox(
        'Which number do you like best?',
        df['first column'])
    
    'You selected: ', option

    Layout

    Streamlit facilita organitzar els teus widgets en una barra lateral esquerra amb st.sidebar.

    Cada element que es passa a st.sidebar s’enganxa a l’esquerra, cosa que permet als usuaris centrar-se en el contingut de la teva aplicació mentre encara tenen accés als controls de la interfície d’usuari.

    Per exemple, si vols afegir un selectbox i un slider a una barra lateral, utilitza st.sidebar.slider i st.sidebar.selectbox en lloc de st.slider i st.selectbox:

    import streamlit as st
    
    # Add a selectbox to the sidebar:
    add_selectbox = st.sidebar.selectbox(
        'How would you like to be contacted?',
        ('Email', 'Home phone', 'Mobile phone')
    )
    
    # Add a slider to the sidebar:
    add_slider = st.sidebar.slider(
        'Select a range of values',
        0.0, 100.0, (25.0, 75.0)
    )

    Més enllà de la barra lateral, Streamlit ofereix diverses altres maneres de controlar el layout de la teva aplicació.

    st.columns et permet col·locar widgets un al costat de l’altre, i st.expander et permet conservar espai amagant contingut gran.

    import streamlit as st
    
    left_column, right_column = st.columns(2)
    # You can use a column just like st.sidebar:
    left_column.button('Press me!')
    
    # Or even better, call Streamlit functions inside a "with" block:
    with right_column:
        chosen = st.radio(
            'Sorting hat',
            ("Gryffindor", "Ravenclaw", "Hufflepuff", "Slytherin"))
        st.write(f"You are in {chosen} house!")

    Mostra el progrés

    Quan afegeixes càlculs de llarga durada a una aplicació, pots utilitzar st.progress() per mostrar l’estat en temps real

    import streamlit as st
    import time
    
    'Starting a long computation...'
    
    # Add a placeholder
    latest_iteration = st.empty()
    bar = st.progress(0)
    
    for i in range(100):
        # Update the progress bar with each iteration.
        latest_iteration.text(f'Iteration {i + 1}')
        bar.progress(i + 1)
        time.sleep(0.1)
    
    '...and now we\'re done!'

    Memòria cau

    La memòria cau permet que la teva aplicació sigui responsiva fins i tot quan carrega dades des del web, manipula conjunts de dades grans o realitza càlculs costosos.

    La idea bàsica darrere de la memòria cau és emmagatzemar els resultats de crides de funcions costoses i retornar el resultat en memòria cau quan es tornen a produir les mateixes entrades. Això evita l’execució repetida d’una funció amb els mateixos valors d’entrada.

    Per posar en memòria cau una funció a Streamlit, has d’aplicar-hi un decorador de memòria cau.

    Tens dues opcions:

    • st.cache_data és la manera recomanada de posar en memòria cau càlculs que retornen dades. Utilitza st.cache_data quan utilitzis una funció que retorna un objecte de dades serialitzable (p. ex. str, int, float, DataFrame, dict, list). Crea una nova còpia de les dades en cada crida de funció, fent-la segura contra mutations and reace conditions. El comportament de st.cache_data és el que vols en la majoria dels casos: així que si tens dubtes, comença amb st.cache_data i mira si funciona!

    • st.cache_resource és la manera recomanada de posar en memòria cau recursos globals com models de ML o connexions de bases de dades. Utilitza st.cache_resource quan la teva funció retorni objectes no serialitzables que no vols carregar múltiples vegades. Retorna el mateix objecte en memòria cau, que es comparteix entre totes les reexecucions i sessions sense còpia ni duplicació. Si mutes un objecte que està en memòria cau utilitzant st.cache_resource, aquesta mutació existirà en totes les reexecucions i sessions.

    @st.cache_data
    def long_running_function(param1, param2):
        return

    En l’exemple anterior, long_running_function està decorada amb @st.cache_data.

    Com a resultat, Streamlit anota el següent:

    • El nom de la funció ("long_running_function").
    • El valor de les entrades (param1, param2).
    • El codi dins de la funció.

    Abans d’executar el codi dins de long_running_function, Streamlit comprova la seva memòria cau per trobar un resultat guardat prèviament. Si troba un resultat en memòria cau per a la funció i els valors d’entrada donats, retornarà aquest resultat en memòria cau i no tornarà a executar el codi de la funció. En cas contrari, Streamlit executa la funció, guarda el resultat a la seva memòria cau i continua amb l’execució de l’script. Durant el desenvolupament, la memòria cau s’actualitza automàticament a mesura que canvia el codi de la funció, assegurant que els últims canvis es reflecteixin a la memòria cau.

    Per a més informació sobre els decoradors de memòria cau de Streamlit, els seus paràmetres de configuració i les seves limitacions, consulta Caching.

    Session State

    Session State proporciona una interfície semblant a un diccionari on pots guardar informació que es conserva entre reexecucions d’scripts.

    Utilitza st.session_state amb notació de clau o atribut per emmagatzemar i recuperar valors. Per exemple, st.session_state["my_key"] o st.session_state.my_key.

    Recorda que els widgets gestionen el seu propi estat per si mateixos, així que no sempre necessitaràs utilitzar Session State!

    Què és una sessió?

    Una sessió és una única instància de visualització d’una aplicació. Si visualitzes una aplicació des de dues pestanyes diferents del teu navegador, cada pestanya tindrà la seva pròpia sessió. Així doncs, cada visualitzador d’una aplicació tindrà un Session State vinculat a la seva visualització específica. Streamlit manté aquesta sessió a mesura que l’usuari interactua amb l’aplicació. Si l’usuari refresca la pàgina del seu navegador o recarrega l’URL de l’aplicació, el seu Session State es reinicia i comença de nou amb una sessió nova.

    Exemples d’ús de Session State

    Aquí tens una aplicació senzilla que compta el nombre de vegades que s’ha executat la pàgina.

    Cada vegada que fas clic al botó, l’script es tornarà a executar.

    import streamlit as st
    
    if "counter" not in st.session_state:
        st.session_state.counter = 0
    
    st.session_state.counter += 1
    
    st.header(f"This page has run {st.session_state.counter} times.")
    st.button("Run it again")
    • Primera execució: La primera vegada que l’aplicació s’executa per a cada usuari, Session State és buit. Per tant, es crea un parell clau-valor ("counter":0). A mesura que l’script continua, el comptador s’incrementa immediatament ("counter":1) i es mostra el resultat: “Aquesta pàgina s’ha executat 1 vegades.” Quan la pàgina s’ha renderitzat completament, l’script ha acabat i el servidor de Streamlit espera que l’usuari faci alguna cosa. Quan aquest usuari fa clic al botó, comença una reexecució.

    • Segona execució: Com que “counter” ja és una clau a Session State, no es reinicialitza. A mesura que l’script continua, el comptador s’incrementa ("counter":2) i es mostra el resultat: “Aquesta pàgina s’ha executat 2 vegades.”

    Hi ha alguns escenaris comuns on Session State és útil. Com s’ha demostrat més amunt, Session State s’utilitza quan tens un procés progressiu que vols construir d’una reexecució a la següent. Session State també es pot utilitzar per evitar recàlculs, de manera similar a la memòria cau. Tot i així, les diferències són importants:

    • La memòria cau associa valors emmagatzemats a funcions i entrades específiques. Els valors en memòria cau són accessibles a tots els usuaris en totes les sessions.

    • Session State associa valors emmagatzemats a claus (strings). Els valors en Session State només estan disponibles en la sessió única on es van guardar.

    Si tens generació de nombres aleatoris a la teva aplicació, probablement utilitzaries Session State. Aquí tens un exemple on les dades es generen aleatòriament al principi de cada sessió. En guardar aquesta informació aleatòria a Session State, cada usuari obté dades aleatòries diferents quan obre l’aplicació, però no canviaran constantment mentre hi interactuen.

    Si obres l’aplicació en una nova pestanya per començar una sessió nova, veuràs dades diferents!

    import streamlit as st
    import polars as pl
    import numpy as np
    
    if "df" not in st.session_state:
        st.session_state.df = pl.DataFrame({
            "x": np.random.randn(20),
            "y": np.random.randn(20)
        })
    
    st.header("Choose a datapoint color")
    color = st.color_picker("Color", "#FF0000")
    st.divider()
    st.scatter_chart(st.session_state.df, x="x", y="y", color=color)

    Si estàs obtenint les mateixes dades per a tots els usuaris, probablement posaries en memòria cau una funció que recupera aquestes dades. D’altra banda, si obtens dades específiques d’un usuari, com ara consultar la seva informació personal, potser voldries guardar-les a Session State. D’aquesta manera, les dades consultades només estan disponibles en aquella sessió única.

    Com s’ha esmentat anteriorment, Session State també està relacionat amb els widgets. Els widgets són màgics i gestionen el seu estat silenciosament pel seu compte. Com a característica avançada, però, pots manipular el valor dels widgets dins del teu codi assignant-los claus. Qualsevol clau assignada a un widget es converteix en una clau a Session State vinculada al valor del widget. Això es pot utilitzar per manipular el widget. Després d’acabar d’entendre els conceptes bàsics de Streamlit, consulta la guia sobre Widget behavior per aprofundir en els detalls si t’interessa.

    Connexions

    Com s’ha indicat més amunt, pots utilitzar @st.cache_resource per posar connexions en memòria cau. Aquesta és la solució més general que et permet utilitzar gairebé qualsevol connexió de qualsevol biblioteca de Python.

    No obstant això, Streamlit també ofereix una manera convenient de gestionar algunes de les connexions més populars, com SQL!

    st.connection s’encarrega de la memòria cau per tu, així que pots gaudir de menys línies de codi.

    Obtenir dades de la teva base de dades pot ser tan fàcil com:

    import streamlit as st
    
    conn = st.connection("my_database")
    df = conn.query("select * from my_table")
    st.dataframe(df)

    Per descomptat, potser et preguntes on van el teu nom d’usuari i contrasenya. Streamlit té un mecanisme convenient per a la gestió de secrets.

    Per ara, vegem com st.connection funciona molt bé amb els secrets. Al directori del teu projecte local, pots desar un fitxer .streamlit/secrets.toml. Deses els teus secrets al fitxer toml i st.connection simplement els utilitza!

    Per exemple, si tens un fitxer d’aplicació main.py, el directori del teu projecte podria tenir aquest aspecte:

    project/
    ├── .streamlit/
    │   └── secrets.toml # Make sure to gitignore this!
    └── main.py

    Per a l’exemple SQL anterior, el teu fitxer secrets.toml podria tenir aquest aspecte:

    [connections.postgresql]
    dialect = "postgresql"
    host = "localhost"
    port = "5432"
    database = "xxx"
    username = "xxx"
    password = "xxx"

    PENDENT: moure a streamlit/database:

    Com que no vols fer commit del teu fitxer secrets.toml al repositori, hauràs d’aprendre com el teu servidor gestiona els secrets quan estiguis preparat per publicar la teva aplicació.

    Cada plataforma de servidor pot tenir una manera diferent perquè hi passis els teus secrets. Si utilitzes Streamlit Community Cloud, per exemple, cada aplicació desplegada té un menú de configuració on pots carregar els teus secrets.

    Pàgines

    A mesura que les aplicacions creixen, resulta útil organitzar-les en múltiples pàgines. Això fa que l’aplicació sigui més fàcil de gestionar com a desenvolupador i més fàcil de navegar com a usuari. Streamlit proporciona una manera potent de crear aplicacions multipàgina utilitzant st.Page i st.navigation.

    Simplement crea les teves pàgines i connecta-les amb navegació de la manera següent:

    • Crea un script de punt d’entrada que defineixi i connecti les teves pàgines
    • Crea fitxers Python separats per al contingut de cada pàgina
    • Utilitza st.Page per definir les teves pàgines i st.navigation per connectar-les

    Aquí tens un exemple d’una aplicació de tres pàgines:

    import streamlit as st
    
    # Define the pages
    main_page = st.Page("main_page.py", title="Main Page", icon="🎈")
    page_2 = st.Page("page_2.py", title="Page 2", icon="❄️")
    page_3 = st.Page("page_3.py", title="Page 3", icon="🎉")
    
    # Set up navigation
    pg = st.navigation([main_page, page_2, page_3])
    
    # Run the selected page
    pg.run()
    import streamlit as st
    
    # Main page content
    st.markdown("# Main page 🎈")
    st.sidebar.markdown("# Main page 🎈")
    import streamlit as st
    
    st.markdown("# Page 2 ❄️")
    st.sidebar.markdown("# Page 2 ❄️")
    import streamlit as st
    
    st.markdown("# Page 3 🎉")
    st.sidebar.markdown("# Page 3 🎉")

    Ara executa streamlit run main.py i visualitza la teva nova aplicació multipàgina!

    El menú de navegació apareixerà automàticament, cosa que permet als usuaris canviar entre pàgines. Aplicacions multipàgina t’ensenya com afegir pàgines a la teva aplicació, incloent com definir pàgines, estructurar i executar aplicacions multipàgina, i navegar entre pàgines.

    Components personalitzats

    Si no pots trobar el component adequat dins de la biblioteca de Streamlit, prova els components personalitzats per estendre la funcionalitat integrada de Streamlit.

    Explora i navega pels components populars creats per la comunitat a la galeria de components.

    Si et dediques al desenvolupament frontend, pots construir el teu propi component personalitzat amb l’API de components de Streamlit.

    Servei de fitxers estàtics

    Com vas aprendre als fonaments de Streamlit, Streamlit executa un servidor al qual es connecten els clients. Això significa que els espectadors de la teva aplicació no tenen accés directe als fitxers que són locals a la teva aplicació. La major part del temps, això no importa perquè les ordres de Streamlit ho gestionen per tu.

    Quan utilitzes st.image(<ruta-a-imatge>), el teu servidor de Streamlit accedirà al fitxer i gestionarà l’allotjament necessari perquè els espectadors de la teva aplicació puguin veure-la. No obstant això, si vols una URL directa a una imatge o fitxer, hauràs d’allotjar-lo. Això requereix establir la configuració correcta i col·locar els teus fitxers allotjats en un directori anomenat static.

    Per exemple, el teu projecte podria tenir aquest aspecte:

    project/
    ├── static/
    │   └── dog.png
    └── main_app.py

    Per saber-ne més, llegeix la guia sobre servei de fitxers estàtics.

    Proves d’aplicacions

    Una bona higiene de desenvolupament inclou provar el teu codi. Les proves automatitzades et permeten escriure codi de més qualitat, més ràpidament! Streamlit té un framework de proves integrat que et permet construir proves fàcilment. Utilitza el teu framework de proves favorit per executar les teves proves.

    Quan proves una aplicació de Streamlit, simules l’execució de l’aplicació, declares l’entrada de l’usuari i inspecciones els resultats. Pots utilitzar fluxos de treball de GitHub per automatitzar les teves proves i rebre alertes instantànies sobre canvis que trenquen el codi. Aprèn més a la guia sobre proves d’aplicacions.

    Community Cloud

    Després d’haver construït una app amb Streamlit, és hora de compartir-la! Per ensenyar-la al món pots utilitzar la Streamlit Community Cloud per desplegar, gestionar i compartir la teva app de franc.

    Funciona en 3 passos senzills:

    • Posa la teva app en un repositori públic de GitHub
    • Inicia sessió a share.streamlit.io
    • Fes clic a “Deploy an app” i enganxa l’URL del teu GitHub

    Això és tot! 🎈 Ara tens una app desplegada públicament que pots compartir amb el món. Clica per saber més sobre com utilitzar Streamlit Community Cloud.

    Activitats

    Mira aquest lloc web i fes alguns dels exemples: Learn Streamlit