# Python 12 (streamlit)
Problemy z bibliotekami GUI
- nie zawsze wyglądają dobrze na każdym z systemów operacyjnych
- czasami wymagają osobnego „dopieszczania” pod każdą z platform
- potrafią być niekonsekwentne w budowie (np. patrz – left / right, n/e w TkInter)
Strony WWW?
- w większości wypadków wyglądają bardzo podobnie niezależnie od systemu / przeglądarki
- oparte o dość dobrze opisane standardy i technologie
Jest cała grupa aplikacji, które są tak naprawdę stroną www dostarczoną razem z bardzo „odchudzoną” przeglądarką np. Discord, Slack, WhatsApp, MS Teams, etc. Stąd warto poznać jakiś framework web-owy – jest szansa, że z jego pomocą stworzymy nie tylko stronę, ale również aplikację na komputery stacjonarne.
Streamlit
https://streamlit.io/
Biblioteka / framework stworzona z myślą o budowaniu stron do pracy z danymi, czy machine learning. Stąd też jego mocną stroną są różnej maści panele informacyjne. Umożliwia zbudowanie strony bez potrzeby napisania nawet linijki HTML-a / Javascriptu – wszystko przygotowujemy w Pythonie. Wystarczy zaimportować bibliotekę, skorzystać z gotowych komponentów i uruchomić aplikację poprzez streamlit run nazwa_pliku.py.
Alternatywa dla Streamlit, ale bardziej skomplikowana:

Streamlit
Krok 1. Instalacja w terminalu
pip install streamlit
Krok 2. Import biblioteki
import streamlit as st
Krok 3. Uruchamianie strony w terminalu:
streamlit run nazwa_pliku.py
Podstawowe komponenty
https://docs.streamlit.io/develop/api-reference
st.write("tekst")st.title(),st.header(),st.subheader()st.dataframe()st.text_input()st.line_chart(dataframe),st.bar_chart(dataframe)st.button()st.checkbox()st.multiselect()st.slider()st.image()st.balloons()
Komponenty "tekstowe"
st.write("tekst")
- jeden z najbardziej uniwersalnych komponentów, umożliwia wyświetlanie tekstu, markdownu, ramek danych, obrazków
st.title("tekst")
- umożliwia stworzenie tytułu (H1)
st.header("tekst")
- nagłówek
- można dodać parametr
divider, który doda podkreślenie
st.subheader("tekst")
- H3
Zarówno title, jak i subheader można w prosty sposób zastąpić stosowaniem markdowna w połączeniu z komponentem podstawowym st.write(" # Hello")
Komponenty do wprowadzania / wyboru danych
st.text_input()
- pole do wprowadzania danych
st.slider()
- suwak
- możemy dodać
min_valueimax_value, które ograniczą nam zakres do wyboru
st.checkbox()
- pole do zaznaczenia "ptaszkiem"
st.multiselect()
- umożliwia wybrania kilka elementów z jakiegoś zakresu danych
Wykresy
st.bar_chart()
- wykres słupkowy
st.line_chart()
- wykres liniowy
st.scatter_chart()
- wykres punktowy
Przydatne: https://matplotlib.org/
Matplotlib to biblioteka Pythona do tworzenia wizualizacji danych – wykresów, diagramów i grafik 2D. Jest jedną z najstarszych i najbardziej rozbudowanych bibliotek w tym obszarze, często używaną w połączeniu z NumPy i Pandas.
Najczęściej korzysta się z modułu matplotlib.pyplot, który działa podobnie do poleceń w MATLAB-ie.
Główne cechy Matplotlib
- Różnorodność wykresów – obsługuje m.in. wykresy liniowe, słupkowe, kołowe, punktowe, histogramy, konturowe, trójwymiarowe.
- Elastyczność – pozwala na pełną kontrolę nad wyglądem wykresu: kolorami, stylami linii, czcionkami, osiami, legendami.
- Integracja – dobrze współpracuje z Pandas, NumPy, SciPy, scikit-learn.
- Eksport – umożliwia zapisywanie wykresów w wielu formatach (PNG, SVG, PDF).
- Interaktywność – w połączeniu z Jupyter Notebook można łatwo manipulować wykresami.
Ważne! Streamlit reruns your script from top to bottom every time you interact with your app. Each reruns takes place in a blank slate: no variables are shared between runs. Session State is a way to share variables between reruns, for each user session.
Myślimy o st.session_state jak o pudełku na dane dla tej jednej karty przeglądarki. Co do niego włożymy, nie znika przy klikaniu przycisków (Streamlit na każdą akcję „przelatuje” skrypt od góry, ale Twoje pudełko zostaje).
Przykład:
# Inicjalizacja
if 'key' not in st.session_state:
st.session_state['key'] = 'value'
# Session State also supports attribute based syntax
if 'key' not in st.session_state:
st.session_state.key = 'value'
# Reading
st.write(st.session_state.key)
# Update an item in Session State by assigning it a value:
st.session_state.key = 'value2' # Attribute API
st.session_state['key'] = 'value2' # Dictionary like API
# Delete a single key-value pair
del st.session_state[key]
# Delete all the items in Session state
for key in st.session_state.keys():
del st.session_state[key]
# --------------------------------------------------------------------
st.text_input("Your name", key="name")
# This exists now:
st.session_state.name
Zadanie domowe 1.
Tworzyliśmy tekstową grę polegającą na zgadnięciu liczby z zakresu 1-100. Użytkownik w prostej wersji miał 10 podejść na zgadnięcie. Za każdym z nich dostawał informację czy poszukiwana liczba jest mniejsza, czy większa.
Spróbujcie odtworzyć tę grę w Streamlit-ie. Pamiętajcie o specjalnej zmiennej session_state do przechowywania stanu zmiennych (np. poszukiwanej liczby i pozostałych prób gracza):
https://docs.streamlit.io/develop/api-reference/caching-and-state/st.session_state
Możecie też pobawić się dodatkowymi komponentami np. warning, czy success do wyświetlania informacji użytkownikowi:
https://docs.streamlit.io/develop/api-reference/status/st.success
https://docs.streamlit.io/develop/api-reference/status/st.warning
Ciekawy mógłby być też komponent baloons uruchamiany w sytuacji gdy gracz zgadnie liczbę.
https://docs.streamlit.io/develop/api-reference/status/st.balloons
import streamlit as st
import random
proby_max = 10
st.set_page_config(page_title="Zgadnij liczbę", layout="wide")
st.write("# *Zgadnij liczbę!*")
# Inicjalizacja session_state
if "liczba_losowa" not in st.session_state:
st.session_state.liczba_losowa = random.randint(1, 100)
st.session_state.proby = 0
st.session_state.komunikat = "Wybierz na suwaku liczbę z zakresu 1–100 i traf w losową liczbę!"
st.session_state.gra_zakonczona = False
if "gracz" not in st.session_state:
st.session_state.gracz = ""
if "strzal" not in st.session_state:
st.session_state.strzal = 1
# Dane od gracza (zapisują się do session_state dzięki key=)
st.text_input("Wprowadź swoje imię lub pseudonim:", key="gracz")
if st.session_state.gracz:
st.write(f"## Witaj w grze {st.session_state.gracz}!")
else:
st.write("## Witaj w grze!")
# Slider tylko gdy gra nie jest zakończona
if not st.session_state.get("gra_zakonczona", False):
st.slider("Wybierz liczbę w zakresie 1–100", min_value=1, max_value=100, key="strzal")
else:
st.write("Koniec Gry. Rozpocznij nową grę, aby kontynuować.")
# Komponenty gry
col1, col2, col3 = st.columns(3)
with col1:
# Sprawdź czy gra nie jest zakończona i czy nie przekroczono limitu prób
if not st.session_state.get("gra_zakonczona", False) and st.session_state.proby < proby_max:
if st.button("Sprawdź"):
st.session_state.proby += 1
liczba_gracza = int(st.session_state.strzal)
liczba_randomowa = st.session_state.liczba_losowa
if liczba_gracza < liczba_randomowa:
st.session_state.komunikat = f"Za mało! (próba {st.session_state.proby}/{proby_max})"
elif liczba_gracza > liczba_randomowa:
st.session_state.komunikat = f"Za dużo! (próba {st.session_state.proby}/{proby_max})"
else:
st.session_state.komunikat = f"Trafione! Liczba to {liczba_randomowa}. Użyłeś {st.session_state.proby} prób!"
st.session_state.gra_zakonczona = True
st.balloons()
# Sprawdź czy wykorzystano wszystkie próby
if st.session_state.proby >= proby_max and liczba_gracza != liczba_randomowa:
st.session_state.komunikat = f"Wykorzystałeś wszystkie {proby_max} prób! Prawidłowa odpowiedź to {liczba_randomowa}."
st.session_state.gra_zakonczona = True
else:
st.button("Sprawdź", disabled=True, help="Gra zakończona lub brak prób")
with col2:
if st.button("Nowa gra"):
st.session_state.liczba_losowa = random.randint(1, 100)
st.session_state.proby = 0
st.session_state.komunikat = "Nowa gra rozpoczęta — zgadnij liczbę z zakresu 1–100!"
st.session_state.gra_zakonczona = False
st.rerun()
with col3:
if st.button("Pokaż odpowiedź"):
st.session_state.komunikat = f"Odpowiedź: {st.session_state.liczba_losowa}"
st.session_state.gra_zakonczona = True
st.info(st.session_state.komunikat)
st.metric("Liczba prób", st.session_state.proby)