#!/usr/bin/env python
# coding: utf-8
# *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.*
#
#
# # Interaktivní vizualizace a aplikace
#
# Při práci s daty je mnoho příležitostí, kdy se hodí interaktivita. Při vizualici se hodí zvětšování / zmenšování měřítka, výběr podoblasti, ukázání vykreslených hodnot apod. Nebo při datové analý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](https://plotly.com/python/), resp. především [plotly express](https://plotly.com/python/plotly-express/), a [streamlit](https://www.streamlit.io/).
#
# 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](http://github.com/pyviz/holoviews) nebo [altair](http://github.com/altair-viz/altair). Na "dashboarding" pak [dash](http://github.com/plotly/dash), [panel](https://panel.holoviz.org/), [voila](http://github.com/QuantStack/voila), [vizro](https://github.com/mckinsey/vizro) nebo [justpy](https://justpy.io).
#
# Velmi atraktivní novinkami jsou [JupyterLite](https://github.com/jupyterlite/jupyterlite) a [PyScript](https://pyscript.net). Oba projekty těží z možnosti spustit Python kód přímo ve webovém prohlížeči, konkrétně v jeho virtuálním stroji, díky technologie Web Assembly.
# * JupyteLite umožňuje spustit Jupyter notebooky v prohlížeči, bez nutnosti instalace Pythonu, a to včetně knihoven na zpracováni dat jako jsou NumPy, Pandas apod. Více se můžeš dozvědět také z přednášky na pražském PyData meetup: [Jeremy Tuloup - JupyterLite: Jupyter ❤️ WebAssembly ❤️ Python (slides, video)](https://pydata.cz/#jeremy-tuloup---jupyterlite-jupyter-%EF%B8%8F-webassembly-%EF%B8%8F-python-slides-video).
# * PyScript umožňuje vložit Python kód přímo do HTML kódu a tímto způsobem vytvářet interaktivní webové aplikace přímo V Pythonu. PyScript tak vlastně "nahrazuje" JavaScript.
#
# Každý z těchto nástrojů má, jako obvykle, své výhody a nevýhody. Nejrozšířenějším nástrojem je [Dash](http://github.com/plotly/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](https://www.youtube.com/watch?v=dewrzMPPLDU). 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](https://voila.readthedocs.io/en/stable/using.html).
#
# Dvě největší výhody Streamlitu jsou rychlost (jednoduchost) vývoje aplikace a atraktivní výchozí vzhled. Streamlit také (nedávno) přidal možnost vzájemné interakce mezi widgety pomocí callback funkcí. Pro Streamlit lze také poměrně snadno vytvářet nové komponenty, důkazem toho budiž [galerie komponent](https://streamlit.io/components).
#
# Pár článků či přednášek, které se tématu týkají:
# * [Dash, Voila, Panel, & Streamlit—Our Thoughts on the Big Four Dashboarding Tools](https://quansight.com/post/dash-voila-panel-streamlit-our-thoughts-on-the-big-four-dashboarding-tools)
# * [Pure Python Web Development](https://metaperl.github.io/pure-python-web-development/intro.html) - velký přehled knihoven pro webový vývoj v Pythonu.
# * [Streamlit - The fastest way to build and share data science apps](https://www.youtube.com/watch?v=sdgTYy3BJiM)
# * [How to Build a Reporting Dashboard using Dash and Plotly](https://towardsdatascience.com/how-to-build-a-complex-reporting-dashboard-using-dash-and-plotl-4f4257c18a7f)
# * [Turn any Notebook into a Deployable Dashboard | SciPy 2019 | James Bednar](https://www.youtube.com/watch?v=L91rd1D6XTA)
#
# ## Pro a proti
#
# 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?
# * Na malou aplikaci pro omezený počet uživatelů (dashboard pro kolegy).
# * Na rychlý vývoj prototypu.
#
# A co když chceme budovat velkou (webovou) aplikaci?
# * Zadáme vývojářskému týmu, aby v moderních JavaScript nástrojích typu React nebo Vue.js pro nás vytvořil krásný a rychlý "front-end", zatímco my vytvoříme v Pythonu "back-end", který s front-endem bude komunikovat např. pomocí JSON API. To uvidíme i v naší lekci o API.
# * Když takový tým nemáme, naučíme se programovat v JavaScriptu ... Ne, raději v TypeScriptu ... Zkusíme PyScript ...
# * ... nakonec najmeme front-end vývojářský tým pokud je to možné :-)
#
# ## Instalace a import grafických knihoven
#
# Pokud nemáte nainstalovanou knihovnu plotly, odkomentujte a spusťte příslušné řádky.
# In[1]:
# instalace plotly
# %pip install plotly
# Pro plotly express se vžila zkratka `px`, kterou použijeme i my.
# In[2]:
import plotly.express as px
# In[3]:
import plotly.io as pio
# from https://github.com/microsoft/vscode-jupyter/issues/6999
# This ensures Plotly output works in multiple places:
# plotly_mimetype: VS Code notebook UI
# notebook: "Jupyter: Export to HTML" command in VS Code
# See https://plotly.com/python/renderers/#multiple-renderers
pio.renderers.default = "plotly_mimetype+notebook"
# notebook-only does not work in Jupyter Lab
# pio.renderers.default = "notebook"
# ## Interaktivní vizualizace dat
#
# 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í.
# ### Rybí míry
#
# 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čí :)
# In[4]:
import pandas as pd
# In[5]:
fish_data = pd.read_csv("fish_data.csv", index_col=0)
# In[6]:
species_cs = {
"Bream": "Cejn",
"Roach": "Plotice",
"Whitefish": "Bílá ryba",
"Parkki": "Karas",
"Perch": "Okoun",
"Pike": "Štika",
"Smelt": "Koruška",
}
fish_data = fish_data.assign(Species=fish_data["Species"].map(species_cs))
# 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`.
# In[7]:
px.scatter_matrix(fish_data)
# To vůbec není špatné na prvotní orientaci. Už teď je vidět, že tam máme kategorickou 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.
# In[8]:
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.
# In[9]:
px.box(fish_data, x="Species", color="Species", y="Height", points="all", notched=False)
# In[10]:
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é.
# In[11]:
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ž Height a Width. Zkuste změnit typ marginálních grafů.
# ## Co s tím dál?
# ### Report pro šéfa a šéfovou
#
# 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.
# In[12]:
# Odkomentováním se spustí příkaz v příkazové řádce (díky vykřičníku)
# Možná se soubor 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`:
# In[13]:
# !jupyter nbconvert dashboardy-1.ipynb --to html --no-input
# ### Analýza nových dat
#
# 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.
# In[14]:
penguins = pd.read_csv("penguins_size_nona.csv")
# ## Vytváříme aplikaci
#
# 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:
# 1. Načíst data z csv souboru.
# 2. Vykreslit scatter matrix, kde budu moct zvolit dimenze, sloupec pro barvu a průhlednost.
# 3. Pro vybraný sloupec zobrazit distribuci vybraného sloupce pomocí histogramu, box plotu nebo violin plotu.
# ### Příprava v notebooku
#
# Pojďme to nejprve načrtnout tady v notebooku. Jako první si připravíme uživatelské vstupy.
# In[15]:
# 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.
# In[16]:
# načtení dat
data = pd.read_csv(data_file_path)
# In[17]:
# scatter matric plat
px.scatter_matrix(data, dimensions=dimensions, color=color, opacity=opacity)
# In[18]:
# 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:
# In[19]:
get_ipython().run_line_magic('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:
# * Aplikaci píšeme v podstatě jako lineární skript (zdrojový kód samozřejmě můžeme strukturovat do funkcí / modulů / tříd dle vlastního uvážení, streamlit ale bude aplikaci vždy spouštět krok po kroku jako ten skript).
# * Uživatelské vstupy načítáme z návratové hodnoty funkcí `st.nějaký_widget`, Streamlit se postará o to, aby widget správně fungoval a návratová hodnota byla vždy ta aktuální.
# * Prvky aplikace (výstupy) zobrazíme uživateli pomocí `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.
#
# ### Spuštění
#
# Streamlit ještě nejspíš nemáš nainstalovaný. Instaluje se běžným způsobem přes pip:
#
# pip install streamlit==1.28.2
#
# případně pokud používáš conda
#
# conda install -c conda-forge streamlit=1.28.2
#
# Na svém počítači si pak aplikaci 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.
# ## Publikujeme na internet
#
# 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 [Streamlit Cloud](https://streamlit.io/cloud), což je možná nejjednodušší způsob publikace Streamlit aplikace z GitHub repozitáře. Oproti obecnějším službám má pochopitelně méně možností a funguje pouze pro Streamlit.
#
# Pro sofistikovanější aplikace je pak možné použít některou z PaaS (Platform as a Service) služeb typu Render, Heroku, AWS Elastic Beanstalk, Google App Engine, Digital Ocean Apps. Některé z těchto služeb mají i zajímavé bezplatné plány nebo kredit pro nové uživatele.
# ### Registrace na Streamlit Cloud
#
# Než začneme, je potřeba:
# 1. Github účet a Git klient: viz [README - Příprava](../README.md#příprava).
# 2. Použij svůj GitHub účet pro registraci na Streamlit Cloud: https://share.streamlit.io/signup
#
#
#
# ### Specifikace prostředí
#
# Aby bylo jasné, jaké Python balíčky jsou potřeba pro naši aplikaci a tím si ji kdokoli mohl spustit, vytvoříme soubor [`requirements.txt`](https://pip.pypa.io/en/stable/reference/requirements-file-format/). Ten může použít buď lidský uživatel nebo platforma typu Streamlit Cloud.
#
# V souboru `requirements.txt` potřebujeme mít (alespoň) základní balíčky pro spuštění aplikace:
# ```
# pandas==2.1.3
# streamlit==1.28.2
# plotly==5.18.0
# ```
# * Je lepší specifikovat konkrétní verzi, protože novější nebo starší verze nemusí být kompatibilní.
# * Ideální je specifikovat všechny závislosti včetně "tranzitivních", tj. závislosti závislostí (... závislostí ...). Pro zjednodušení tohoto úkolu existují pomocné nástroje, např. [Poetry](https://python-poetry.org), [pip-tools](https://pypi.org/project/pip-tools) a další. My si zatím vystačíme s jednoduchým `requirements.txt` souborem.
#
# Tento soubor umí použít `pip`: Pro instalaci balíčků stačí spustit
# ```
# python -m pip install -r requirements.txt
# ```
# ### Publikace na GitHub
#
# #### 1. Vytvoř nový GitHub projekt:
#
# * Vytvoř nový projekt na [github.com](https://github.com)
#
#
#
# * Vyber vhodné jméno.
# * Můžeš použít soukromý i veřejný projekt.
# * Přidej Python `.gitignore` soubor z nabídky.
# * Můžeš přidat i README soubor.
#
# #### 2. Naklonuj projekt k sobě na počítač
#
# Po vytvoření projektu se objeví instrukce na naklonování (nahrání) projektu na tvůj počítač. Použij například `gh` v příkazové řádce.
#
# #### 3. Přidej soubory s aplikací
#
# Do projektu přidej soubory s aplikací, tedy `app.py` a `requirements.txt`. Poté je přidej do Gitu a udělej commit:
#
# ```
# git add app.py requirements.txt
# git commit -m "První verze aplikace"
# ```
#
# #### 4. Nahraj na GitHub
#
# Nahraj změny na GitHub pomocí `git push`.
# ```
# git push
# ```
# ### Go-live
#
# Jakmile máme projekt na GitHubu, je snadné ho publikovat na Streamlit Cloud. Protože jsme pro registraci na Streamlit Cloud použili náš GitHub účet, má Streamlit přístup k našim repozitářům. (Pokud ne, můžeme přístup udělit dodatečně.)
#
# Pro vytvoření nové aplikace klikni na „New app“, poté vyplň jaký repozitář se má použít a jméno souboru s aplikací - pro nás to je `app.py`.
#
# Vyber také v sekci Advanced settings verzi Pythonu 3.11.
#
#
#
# Podrobný návod najdeš na https://docs.streamlit.io/streamlit-cloud/get-started/deploy-an-app.
#
# Za chvilku by tvoje aplikace měla být dostupná na internetu 🎉
#
# **Ú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 nahraj (`git push`) na GitHub. Tvoje změna by se měla (s drobným zpožděním) projevit i v online verzi.