Na naucse.python.cz bohužel nefunguje zobrazování interaktivních plotly grafů. Pro zobrazení včetně grafů můžeš použít nbviewer: https://nbviewer.jupyter.org/github/coobas/pydataladies-dashboard/blob/main/notebooks/dashboardy-1.ipynb nebo si notebook pustit lokálně. Všechny soubory pohromadě najdeš v repozitáři https://github.com/coobas/pydataladies-dashboard.
Při práci s daty je mnoho příležitostí, kdy se hodí interaktivita. Při vizualici se hodí zvětšování / změnšování měřítka, výběr podoblasti, ukázání vykreslených hodnot apod. Nebo při datové anlýze obecně se může hodit interaktivně v notebooku měnit nějaký parametr (třeba hyperparametr pro strojové učení). Anebo chceme dát výsledky naší skvělé analýzy k dispozici "netechnickým" kolegům nebo kamarádům, kteří (zatím) nedokáží Jupyter notebook spustit.
Tady si ukážeme, jak si s takovými úkoly poradit pomocí dvou nástrojů: plotly, resp. především plotly express, a streamlit.
Existují i další nástroje, které poskytují podobné možnosti. Podrobný přehled najdete na https://pyviz.org/tools.html. Na interaktivní vizualizace jsou to především holoviews nebo altair. Na "dashboarding" pak dash, panel, voila nebo justpy.
Každý z těchto nástrojů má, jako obvykle, své výhody a nevýhody. Nejrozšířenějším nástrojem je Dash ze stejné dílny jako plotly, který poskytuje i enterprise řešení pro provoz aplikací. Dash je určitě dobrou volbou, jak se můžete dozvědět i na přednášce z pražského PyData Meetupu. Panel (a také Voila) se od Dash liší tím, že je lze použít i v Jupyter notebooku a pak notebook použít přímo jako aplikaci. Největší přednost voila
je jednoduchý způsob, jak udělat dashboard přímo z notebooku: viz dokumentace.
Dvě největší výhody Streamlitu jsou rychlost (jednoduchost) vývoje aplikace a atraktivní výchozí vzhled.
Pár článků či přednášek, které se tématu týkají:
Je potřeba ale říct, že všechny zmíněné přístupy mají své výrazné nevýhody a limity a nehodí se pro velké a složité aplikace. Možnosti interakcí v aplikaci jsou omezené a také mohou být pomalé. Robustní škálování pro mnoho uživatelů (velký provoz) je obecně složitější. Kdy tedy především použít, co si tady ukážeme?
A co když chceme budovat velkou (webovou) aplikaci?
Pokud nemáte nainstalovanou knihovnu plotly, odkomentujte a spusťte příslušné řádky.
# instalace plotly
# %pip install plotly
Pro plotly express se vžila zkratka px
, kterou použijeme i my.
import plotly.express as px
Pojďme si zkusit trochu více prohlédnout data, se kterými jsme pracovali v předchozích lekcích na strojové učení.
Začněme rozměry ryb, na kterých jsme ukazovali regresi a klasifikaci. Určitě stojí za to si data nejprve trochu prohlédnout. (Jen si asi nenakreslíme přímo vzhled ryb, na to nám data nestačí :)
import pandas as pd
fish_data = pd.read_csv("fish_data.csv", index_col=0)
A místo klasického zobrazování čísel si zkusíme rovnou data vykreslit do grafu. Víme (tušíme), že v datech je spousta sloupců. Můžeme si je nechat vykreslit všechny pomocí scatter_matrix
.
px.scatter_matrix(fish_data)
To vůbec není špatné na prvotní orientaci. Už teď je vidět, že tam máme katogorickou proměnnou Species, nějaké spojité proměnné s rozměry a nepodstatné ID. Vidíme také, že některé proměnné spolu hodně korelují.
Už teď bychom mohli využít interaktivních prvků: zkuste si najet kurzorem na body v grafu nebo použít nástroje na změnu měřítka nebo výběr dat, které se zobrazí v pravém horním rohu. Ještě lepší bude ale trochu graf zlepšit: Zahodit ID a druhy si označit barvou.
px.scatter_matrix(
fish_data,
dimensions=["Weight", "Length1", "Length2", "Length3", "Height", "Width"],
color="Species",
opacity=1,
hover_data=["Species"],
)
Tady nám kromě barevnosti přibyla vpravo legenda. A dokonce legenda interaktivní! Jednoduchým kliknutím můžeme schovat / zobrazit jednotlivé kategorie, dvouklikem můžeme zobrazit jen jednu kategorii. Zkuste si to! Užitečné může být i vybírání dat - Box Select nebo Lasso Select.
Úkol: Použijte pro barvu sloupec Weight, symboly udělejte částečně průhledné pomocí argumentu opacity
(rozsah 0 - 1) a v legendě, zobrazované, když se najede kurzorem na určitý bod, nechť se zobrzují všechny sloupce (pomůže argument hover_data
).
Když se pak chceme třeba podívat na statistické vlastnosti jedné konkrétní proměnné (sloupce), můžeme použít některou z funkcí na zobrazení rozdělovací funkce, resp. některých jejích vlastností (momentů).
Začít můžeme poměrně častým box plotem. Bonus plotly je hlavně v interaktivním zobrazení číselných hodnot: mediánu a kvantilů, a také identifikaci (pravděpodobně) odlehlých hodnot.
px.box(fish_data, x="Species", color="Species", y="Height", points="all", notched=False)
px.histogram(fish_data, color="Species", x="Height", opacity=0.5)
Pro zobrazení vztahu dvou proměnných může být ještě užitečné podívat se na hustotu bodů v ploše pomocí kontur. U tohoto grafu můžeme po stranách zobrazit i tzv. marginální rozdělení: nejpravděpodobnější rozdělení jedné proměnné v závislosti na druhé.
px.density_contour(
fish_data,
color="Species",
x="Height",
y="Length3",
marginal_x="histogram",
marginal_y="box",
)
Úkol: Zkuste si zobrazit v grafech jiné veličiny (jiné sloupce) než jen Height a Width. Zkuste změnit typ marginálních grafů.
Máme i kolegy, kteří (ještě) nepoužívají Python a přesto by ocenili, kdyby mohli místo statického reportu dostat report s takto krásnými a interaktivními vizualizacemi. Pro tento účel se hodí export notebooku do html pomocí nbconvert
.
V příkazovém řádku spustíme nbconvert
pomocí příkazu jupyter nbconvert
. Pro export do html pak přidáme --to html
, nesmíme zapomenout zadat který notebook (tj. soubor) chceme vlastně konvertovat.
# Odkomentováním se spustí příkaz v příkazové řádce (díky vykřičníku)
# Možná se seoubor u tebe jmenuje jinak než dashboardy-1, v takovém použij aktuální jméno souboru
# !jupyter nbconvert dashboardy-1.ipynb --to html
Můžeme také exportovat jen výstupy a "utajit" zdrojový kód pomocí --no-input
:
# !jupyter nbconvert dashboardy-1.ipynb --to html --no-input
Všem se naše vizualizace líbily, a jelikož je potřeba analyzovat další data, dostali jsme to za úkol my. Tentokrát se nejedná o ryby, ale o tučňáky.
Úkol: Vyber si z grafů ten, který se ti nejvíc líbí, a místo rybích dat použij tučňáky.
penguins = pd.read_csv("penguins_size_nona.csv")
Z naší práce v notebooku vykrystalizoval velice častý vzor: Podobné vizualizace a analýzy, v nichž se mění data a několik klíčových parametrů. Příležitost vytvořit aplikaci, která toto umožní nám a okruhu poučených uživatelů.
Pojďme si nadefinovat naší jednoduchou aplikaci:
Pojďme to nejprve načrtnout tady v notebooku. Jako první si připravíme uživatelské vstupy.
# vstup 1: výběr datové sady
data_file_path = "penguins_size_nona.csv"
# vstup 2: výběr parametrů scatter matrix
dimensions = ['culmen_length_mm', 'culmen_depth_mm', 'flipper_length_mm', 'body_mass_g']
color = "sex"
opacity = 0.5
# výběr sloupce pro zobrazení rozdělení dat
interesting_column = "body_mass_g"
# výběr funkce pro zobrazení rozdělovací funkce
dist_plot = px.violin
A tohle už je pak naše aplikace: Použili jsme stejné funkce a parametry jako na začátku práce s plotly, jen jsme je parametrizovali pomocí vstupů z předchozího bloku.
# načtení dat
data = pd.read_csv(data_file_path)
# scatter matric plat
px.scatter_matrix(data, dimensions=dimensions, color=color, opacity=opacity)
# zobrazení rozdělovací funkce
dist_plot(data, x=interesting_column, color=color)
A teď z toho pojďme udělat interaktivní webovou aplikaci! To nebudeme dělat přímo tady v notebooku, ale v "obyčejném" .py souboru s Python kódem.
Aplikaci máme připravenou v souboru app.py
, tady v notebooku si soubor můžeme prohlédnout:
%cat ../app.py
Základem je, že uživatelské vstupy jsme předělali z podoby proměnná = hodnota
do podoby proměnná = st.vhodný_widget(...)
. Toto je způsob vytváření streamlit aplikace:
st.nějaký_widget
, Streamlit se postará o to, aby widget správně fungoval a návratová hodnota byla vždy ta aktuální.st.write
.Widgets - pomocné "věcičky": V uživatelských grafických rozhraních (GUI) se používají widgety: nástroje na vybrání možností, hodnoty proměnné, zadání textu nebo datumu apod.
Streamlit ještě nejspíš nemáš nainstalovaný. Instaluje se běžným způsobem přes pip:
pip install streamlit
případně pokud používáš conda
conda install -c conda-forge streamlit
Na svém počítači si pak apikaci spustíš příkazem streamlit run
s názvem souboru s aplikací. V našem případě tedy
streamlit run app.py
Pokud je vše v pořádku, zobrazí se něco takovéhoto:
You can now view your Streamlit app in your browser.
Network URL: http://192.168.2.103:8800
External URL: http://85.207.123.46:8800
Dle instrukcí otevři odkaz (ten první) v prohlížeči. Je velká pravděpodobnout, že se objeví naše právě vytvořená aplikace na vizualizaci dat.
V principu bychom mohli spustit aplikaci u sebe na počítači tak, aby ji mohli používat i další uživatelé. Na vnitřní síti (domácí, pracovní) by to bylo snadné (i když na pracovní síti a pracovním počítači by tomu mohla bránit bezpečnostní nastavení), přístup z vnějšího internetu by už byl komplikovanější.
Naštěstí nejsme v podobné situaci sami :) Takže existují více či méně složité a sofistikované způsoby, jak aplikaci spustit na nějakém serveru (v cloudu) a zpřístupnit z internetu. My si ukážeme, jak to funguje na Heroku. Podobné služby nabízí třeba AWS (Elastic Beanstalk), Google App Engine nebo Dokku on Digital Ocean. Výhodou Heroku je jednoduchost a možnost bezplatných služeb, nevýhodou pak rychle rostoucí cena a omezené možnosti.
Existuje také možnost publikovat aplikaci pomocí Streamlit Sharing. Tato služba nabízí ještě jednodušší publikaci z veřejných GitHub repozitářů, nemá ale tolik možností jako např. Heroku.
Budeme postupovat v podstatě podle průvodce Getting started with Python.
Než začneme, je potřeba:
git config --global user.name "Moje Jméno"
git config --global user.email "muj@email.com"
Instalaci ověříme v příkazové řádce pomocí:
Git:
git config --list
Mělo by se objevit něco na způsob
user.name=Moje Jméno
user.email=muj@email.com
Heroku:
heroku --version
Tady by mělo být výstupem zhruba
heroku/7.39.2 darwin-x64 node-v12.13.0
Teď budeme chvilku pracovat v příkazové řádce. Nejprve je potřeba vytvořit novou složku pro publikovanou aplikaci a nakopírovat tam soubory app.py
, requirements.txt
, runtime.txt
a Procfile
.
A teď už v příkazové řádce, kde aktuální složka musí být ta nově vytvořená, kam jsi zkopírovala soubory:
Vytvoř Git repozitář:
git init
Heroku potřebuje soubor s názvem Procfile
. Ten velice jednoduše říká, co že to vlastně chceme spustit. Bude tam příkaz streamlit run
(tak jako jsme spouštěli aplikaci lokálně) s pár přepínači navíc. Pro Procfile
musí obsahovat tento řádek:
web: streamlit run --server.headless 1 -server.port $PORT app.py
Je určitě dobré specifikovat verzi Pythonu, jinak se použije výchozí (v době psaní je to 3.6). V souboru runtime.txt
na to stačí řádka python-3.8.10
.
Dalším souborem, který potřebujeme, je requirements.txt
. O tom jste už možná slyšeli(y) - obsahuje seznam Python balíčků, které potřebuje daný Python projekt. Heroku tento soubor použije, aby před spuštěním aplikace nainstaloval vše potřebné. Pro náš dashboard musí být v requirements.txt
toto:
pandas==1.2.4
streamlit==0.82.0
plotly==4.14.3
Soubory už máme připravené, potřebujeme je teď přidat do Git repozitáře. Na to použij tyto dva příkazy:
git add app.py Procfile runtime.txt requirements.txt
git commit -v -m "první verze dashboardu"
A teď už můžeme publikovat. Tedy nejdříve se přihlásit pomocí
heroku login
(Postupujte dle pokynů - otevře se přihlašovací stránka ve webovém prohlížeči, která vás vyzve k zadání přihlašovacích údajů.)
Pak ještě vytvořit Heroku aplikaci pomocí
heroku create
A nakonec už opravdu vypustit aplikaci na internet pomocí
git push heroku master
Pokud vše půjde dobře, tento krok bude chvíli trvat. Postupně se bude vypisovat, co pro nás Heroku dělá:
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 4 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 940.72 KiB | 2.40 MiB/s, done.
Total 4 (delta 2), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Python app detected
remote: -----> Installing python-3.8.6
remote: -----> Installing pip 20.1.1, setuptools 47.1.1 and wheel 0.34.2
remote: -----> Installing SQLite3
remote: -----> Installing requirements with pip
remote: Collecting pandas==1.1.4
remote: Downloading pandas-1.1.4-cp36-cp36m-manylinux1_x86_64.whl (9.5 MB)
remote: Collecting streamlit==0.71.0
remote: Downloading streamlit-0.71.0-py2.py3-none-any.whl (7.4 MB)
remote: Collecting plotly==4.13.0
remote: Downloading plotly-4.13.0-py2.py3-none-any.whl (13.1 MB)
...
Nakonec by se mělo objevit něco jako
remote: -----> Launching...
remote: Released v6
remote: https://warm-sierra-79844.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/warm-sierra-79844.git
Důležitý je odkaz pod řádkem "Released v6". To je totiž adresa, na které je náš dashboard dostupný "odkudkoli z internetu". Buď si ji zkopírujte do prohlížeče nebo použijte příkaz heroku open
.
Úkol 1: Pošli odkaz na tvou běžící aplikaci :)
Úkol 2: Pomocí st.title
přidej titulek (název) aplikace. Vyzkoušej u sebe lokálně, pak změnu commituj do gitu a aktualizuj aplikaci na Heroku (pomocí git push heroku master
).