Scopri NiceGUI, un semplice framework UI basato su Python che funziona perfettamente con il tuo browser web o come app desktop. Che tu stia creando piccole app Web, dashboard o giocando con progetti di robotica, NiceGUI semplifica il compito con la sua interfaccia semplice e molte funzionalità.
L'obiettivo di questo post è convincerti a provarlo elencando i pro e i contro di questa libreria mostrandoti come creare e distribuire un'app NiceGUI. (Questo non è un post sponsorizzato, mi piace semplicemente la biblioteca 🙃)
Streamlit e NiceGUI: perché cambiare?
Sebbene Streamlit sia utile per creare app interattive, può essere complicato gestire eventi e stati, soprattutto per progetti più grandi. NiceGUI è diverso. Ti consente di controllare direttamente gli stati e le interazioni, senza bisogno di passaggi aggiuntivi o soluzioni alternative.
Gestione semplice dello Stato
NiceGUI semplifica la gestione degli stati. A differenza di Streamlit, che può ripristinare gli stati in modo imprevisto, NiceGUI mantiene le cose stabili, sia che si tratti dello stato iniziale o delle modifiche apportate dagli utenti. È possibile utilizzare i callback per gestire le interazioni dell'utente in modo basato sugli eventi senza essere infastiditi dall'aggiornamento dell'intera pagina e dalla perdita dei dati sullo stato.
Molte funzionalità
NiceGUI ha molte funzioni interessanti:
- Pulsanti, interruttori, cursori, input e altro per l'interazione.
- Modi semplici per organizzare le cose sullo schermo.
- Grafici, tabelle e persino scene 3D per le immagini.
- Integrazione con librerie di visualizzazione dati come Matplotlib o Plotly.
- Personalizza facilmente colori e stili.
- Strumenti per aiutare con la codifica e il test.
- Gli sviluppatori principali sono sempre disponibili a rispondere alle domande e sono molto ricettivi ai feedback sul loro spazio GitHub.
- Basati sui framework più diffusi: FastAPI, Vue3, Tailwind, Quasar.
- Tutto il loro sito è realizzato con la libreria NiceGUI: https://nicegui.io/documentation
Limitazioni
Sebbene NiceGUI sia eccezionale, vale la pena notare che le dimensioni ridotte della comunità potrebbero essere un po' limitanti. Ha anche una curva di apprendimento leggermente più lunga rispetto ai framework più popolari come Streamlit. È preferibile acquisire familiarità con CSS e Tailwind CSS per sfruttare al massimo le funzionalità della libreria. Inoltre, la conoscenza di FastAPI, Vue e Quasar può fornirti maggiore flessibilità ed estendere ciò che puoi implementare.
Ora esploriamo alcune funzionalità di NiceGUI e quindi creiamo e distribuiamo un'app demo.
Applicazione di base
Per prima cosa installa NiceGUI:
pip install nicegui(highcharts)
Partiamo da un esempio tratto dalla documentazione principale:
# https://nicegui.io/documentation/section_data_elements
from nicegui import ui
from random import randomchart = ui.highchart({
'title': False,
'chart': {'type': 'bar'},
'xAxis': {'categories': ('A', 'B')},
'series': (
{'name': 'Alpha', 'data': (0.1, 0.2)},
{'name': 'Beta', 'data': (0.3, 0.4)},
),
}).classes('w-full h-64')
def update():
chart.options('series')(0)('data')(0) = random()
chart.update()
ui.button('Update', on_click=update)
ui.run()
Qui, il modulo dell'interfaccia utente è ciò che ti consentirà di creare un elemento dell'interfaccia utente.
In questo esempio, creiamo prima un elemento highchart, gli assegniamo le classi tailwind w-full e h-64. w-full gli farà utilizzare l'intero schermo orizzontalmente in modo di risposta e h-64 specifica l'altezza.
Quando facciamo clic sul pulsante, viene attivata una funzione di callback. Questa richiamata aggiornerà i dati utilizzati per il grafico e quindi li riprodurrà in modo fluido.
Puoi anche modificare la richiamata per aggiungere nuove barre:
def update():
chart.options("xAxis")("categories").append(random.choice(string.ascii_uppercase))
for series in chart.options('series'):
series("data").append(random.random())
chart.update()
Inoltre, tieni presente che aggiornare la pagina non ti fa perdere i dati! Non puoi farlo con alcune altre librerie dell'interfaccia utente Python. Il motivo per cui funziona in questo modo qui è che i dati sono condivisi tra tutti gli utenti, ma ci sono molti modi per mantenere i dati specifici dell'utente come l'oggetto app.storage.user o app.storage.browser (se racchiusi attorno a un @ui.page
decoratore).
Ma cosa succede se desideri aggiornare l'interfaccia utente con un timer ricorrente? facile ! Basta cambiare l'elemento del pulsante in ui.timer
ui.timer(5, callback=lambda: (update(), ui.notify("Data Updated")))
Ora, creiamo un'app demo che consenta agli utenti di scegliere una categoria e quindi di generare un fatto casuale su Chuck Norris.
Innanzitutto, ecco il codice principale:
import requests # Importing the requests library to make HTTP requests
from nicegui import ui # Importing UI components from the NiceGUI library
from nicegui_app.header import add_head_html # Importing a function to add HTML head content# List of categories for Chuck Norris facts
CATEGORIES = (
"animal",
"career",
"celebrity",
"dev",
"fashion",
"food",
"money",
"movie",
"music",
"science",
"sport",
"travel",
)
# Class to handle Chuck Norris facts
class Fact:
def __init__(self):
self.fact = None # Initialize the fact attribute to None
# Method to update the fact based on a given category
def update_fact(self, category):
url = f"https://api.chucknorris.io/jokes/random?category={category}" # URL to Chuck Norris API
for i in range(10): # Try up to 10 times to fetch a valid fact
result = requests.get(url) # Make a GET request to the Chuck Norris API
if result.status_code == 200: # If the request is successful
result_json = result.json() # Parse the JSON response
if self.fact != result_json("value"): # If the fetched fact is different from the current one
self.fact = result_json("value") # Update the fact attribute
break # Exit the loop
# Function to generate the Chuck Norris fact UI
def chuck():
add_head_html() # Add HTML head content for the NiceGUI app
default_value = CATEGORIES(0) # Default category for Chuck Norris facts
fact = Fact() # Create an instance of the Fact class
fact.update_fact(default_value) # Update the fact using the default category
# Create a grid layout with 12 columns
with ui.grid(columns=12).classes("w-full"):
# Column for category selection
with ui.column().classes("col-span-4 sm:col-span-2 space-x-0"):
ui.label("Pick a fact category:") # Display a label for category selection
# Radio button group for selecting categories
category = ui.radio(
CATEGORIES,
value=default_value,
on_change=lambda _: fact.update_fact(category.value), # Update the fact when the category changes
).classes("w-full")
# Button to regenerate the fact for the selected category
ui.button(
"⟳ Re-Generate", on_click=lambda _: fact.update_fact(category.value)
)
# Column for displaying the Chuck Norris fact
with ui.column().classes(
"flex col-span-8 sm:col-span-10 w-full justify-center mx-auto max-w-screen-md"
):
# Label to display the Chuck Norris fact, bound to the fact attribute of the Fact instance
ui.label().bind_text_from(fact, "fact").classes(
"text-lg sm:text-3xl text-gray-800 bg-gray-100 rounded-lg shadow-lg p-6"
)
Ora analizziamolo passo dopo passo:
Per prima cosa effettuiamo le importazioni necessarie e definiamo le possibili categorie.
Quindi, definiamo la classe che memorizzerà e aggiornerà il nostro fatto casuale:
class Fact:
def __init__(self):
self.fact = None # Initialize the fact attribute to None# Method to update the fact based on a given category
def update_fact(self, category):
url = f"https://api.chucknorris.io/jokes/random?category={category}" # URL to Chuck Norris API
for i in range(10): # Try up to 10 times to fetch a valid fact
result = requests.get(url) # Make a GET request to the Chuck Norris API
if result.status_code == 200: # If the request is successful
result_json = result.json() # Parse the JSON response
if self.fact != result_json("value"): # If the fetched fact is different from the current one
self.fact = result_json("value") # Update the fact attribute
break # Exit the loop
Questa classe memorizza il fatto nell'attributo “fact” e dispone di un metodo update_fact che richiama l'API dei fatti di Chuck Norris. https://api.chucknorris.io
Successivamente, definiamo la nostra pagina nella funzione “chuck”. NiceGUI adotta un approccio modulare che ti consente di definire la tua app su più moduli e file Python.
Definiamo un'istanza della nostra classe di dati fact = Fact()
Questa è un'istanza specifica per ciascun utente. Successivamente, inizializziamo il fatto utilizzando il metodo update_fact.
Ora iniziamo a definire i nostri elementi dell'interfaccia utente.
Definiamo una griglia con due colonne:
- Una prima colonna che contiene le nostre opzioni di categoria e il pulsante Genera. Questo ha le seguenti classi tailwind: col-span-4 sm:col-span-2. Vuol dire che per schermi molto piccoli utilizzerà 4/12 dello schermo, altrimenti ne utilizzerà 2/12. Ciò fa sì che il design funzioni anche nei telefoni cellulari.
- Una seconda colonna dove mostreremo il fatto.
Per la prima colonna:
- Un menu radio ui.radio.
- Un pulsante per generare un fatto casuale.
Entrambi gli elementi, quando cliccati o modificati, utilizzeranno un callback che chiama fact.update_fact
Per la seconda colonna:
- Abbiamo un ui.label a cui associa il suo valore
fact.fact
quindi ogni volta che questa variabile cambia, aggiornerà automaticamente il display.
L'etichetta ha le seguenti classi tailwind: text-lg sm:text-3xl Questo fa sì che il testo sia più piccolo su schermi piccoli.
Questo ti dà la seguente app:
Pulito! Giusto?
Distribuzione
Distribuire tale app è facile! Utilizzando CloudRun per esempio. Devi solo creare un Dockerfile e quindi eseguire le seguenti istruzioni gcloud:
PROJECT_ID=$(gcloud config get-value project)
REPO="demo"
LOCATION="europe-west1"
IMAGE="nicegui_app"
SERVICE_NAME="nicegui-app"
VERSION="0.0.1"
GAR_TAG=$LOCATION-docker.pkg.dev/$PROJECT_ID/$REPO/$IMAGE:$VERSION# Create repository
gcloud artifacts repositories create $REPO --repository-format=docker \
--location=$LOCATION --description="Docker repository" \
--project=$PROJECT_ID || true # If fails because already exist then its fine
# Build image
gcloud builds submit --tag $GAR_TAG
# Deploy Cloud run
gcloud run deploy $SERVICE_NAME --image=$GAR_TAG --max-instances=1 --min-instances=0 --port=8080 \
--allow-unauthenticated --region=europe-west1 --memory=0.5Gi --cpu=1 -q --no-cpu-throttling --session-affinity
Questo crea l'immagine docker utilizzando la build cloud e quindi la distribuisce su CloudRun.
Le uniche opzioni chiave qui sono: ” — no-cpu-throttling — session-affinity” Ciò consente allo stesso utente di essere instradato sullo stesso contenitore quando possibile e mantiene attiva la CPU tra una richiesta e l'altra. Puoi provarlo qui: https://nicegui-app-dfmj3maizq-ew.a.run.app/
Insomma
NiceGUI è un'ottima scelta se desideri creare interfacce utente in modo rapido e semplice con Python. Ti aiuterà a creare potenti app Python in cui mantieni il pieno controllo dello stato interno e che puoi testare e distribuire facilmente. Si spera che possa consentirti di esprimere la tua creatività nei tuoi progetti di data science senza essere limitato dagli strumenti.
Ciò che è stato mostrato qui è solo una piccola parte di ciò che puoi fare con NiceGUI. Puoi saperne di più seguendo i link sottostanti.
Risorse:
Fonte: towardsdatascience.com