Zebrałeś dane, @name, policzyłeś statystyki - ale jak pokazać je reszcie ekspedycji, która nie umie czytać kodu? Postawimy interaktywną stację badawczą: stronę, na której każdy przesunie suwak i sam zobaczy wykresy. Streamlit robi to bez ani jednej linijki HTML.
1pip install streamlitZapamiętaj tę jedną rzecz, a cała reszta lekcji stanie się oczywista. W Streamlicie piszesz zwykły skrypt Pythona od góry do dołu, a każde wywołanie
st.coś(...) dorysowuje kolejny element strony. Nie ma szablonów, nie ma serwera do napisania - skrypt jest stroną.1# app.py
2import streamlit as st
3import pandas as pd
4
5st.title('Stacja Safari')
6st.write('Interaktywna analiza danych z rezerwatu')
7
8data = pd.DataFrame({
9 'species': ['Lion', 'Elephant', 'Cheetah', 'Giraffe', 'Zebra'],
10 'population': [120, 450, 85, 200, 380],
11 'endangered': [True, False, True, False, False]
12})
13
14st.dataframe(data)Czytaj ten kod jak stronę:
st.title to nagłówek, st.write to akapit, st.dataframe wstawia interaktywną tabelę. Kolejność w skrypcie = kolejność na stronie. Uruchamiasz to nie przez python, lecz komendą Streamlita:1streamlit run app.pyStreamlit otworzy przeglądarkę i pokaże Twoją stację. Od tej pory każdy zapis pliku odświeża stronę - piszesz jak zwykły skrypt, a widzisz jak aplikację.
Teraz najważniejszy mechanizm Streamlita. Gdy użytkownik ruszy suwakiem albo wybierze coś z listy, Streamlit uruchamia cały skrypt od nowa, od góry do dołu - a widżet zwraca aktualnie wybraną wartość. Dzięki temu nie piszesz żadnej obsługi zdarzeń: po prostu czytasz wartość widżetu jak zwykłą zmienną.
1import streamlit as st
2
3st.sidebar.title('Filtry')
4
5species = st.sidebar.selectbox(
6 'Wybierz gatunek:',
7 ['Wszystkie', 'Lion', 'Elephant', 'Cheetah']
8)
9
10min_population = st.sidebar.slider(
11 'Minimalna populacja:', min_value=0, max_value=1000, value=100
12)
13
14show_endangered = st.sidebar.checkbox('Tylko zagrożone', value=False)Zwróć uwagę:
species to nie żaden callback - to po prostu gatunek wybrany w tej chwili w liście. Przy każdej zmianie skrypt rusza od nowa, a species ma nową wartość, której użyjesz do przefiltrowania danych niżej. st.sidebar odkłada widżety do bocznego panelu, żeby nie zaśmiecały głównego widoku - to naturalne miejsce na filtry.Dane w tabeli mówią mało; badacza przekonuje wykres. Streamlit przyjmuje wykresy z bibliotek, które już znasz, i wyświetla je jedną komendą.
1import plotly.express as px
2
3# Interaktywny wykres Plotly
4fig = px.bar(data, x='species', y='population', color='endangered',
5 title='Populacje gatunków')
6st.plotly_chart(fig)
7
8# Wbudowane, najkrótsze wykresy Streamlita
9st.bar_chart(data.set_index('species')['population'])Masz dwie drogi:
st.plotly_chart bierze gotowy wykres z Plotly (pełna kontrola, interaktywność), a st.bar_chart rysuje prosty wykres jednym wywołaniem, gdy nie potrzebujesz szczegółów. Zasada: zacznij od wbudowanych, sięgnij po Plotly, gdy poczujesz ich ograniczenia.Domyślnie elementy układają się jeden pod drugim. Żeby stacja wyglądała jak pulpit, a nie jak długa lista, rozkładasz je w kolumny i zakładki.
1col1, col2, col3 = st.columns(3)
2with col1:
3 st.metric('Gatunki', 150, delta=5)
4with col2:
5 st.metric('Populacja', '12 500', delta=-200)
6with col3:
7 st.metric('Zagrożone', 23, delta=2, delta_color='inverse')
8
9tab1, tab2 = st.tabs(['Dane', 'Wykresy'])
10with tab1:
11 st.dataframe(data)
12with tab2:
13 st.bar_chart(data.set_index('species')['population'])Konstrukcja
with col1: znaczy "wszystko w tym bloku trafia do pierwszej kolumny". st.metric pokazuje pojedynczą liczbę z trendem (delta) - idealne do najważniejszych wskaźników na górze pulpitu. Zakładki (st.tabs) chowają wykresy pod danymi, żeby użytkownik sam wybierał, co ogląda.Pamiętasz drugą zasadę: każda interakcja uruchamia skrypt od nowa. To wygodne, ale gdyby przy każdym ruchu suwakiem od nowa wczytywać wielki plik CSV, stacja by się wlokła. Cache każe Streamlitowi zapamiętać wynik funkcji i nie liczyć go ponownie.
1@st.cache_data
2def load_data():
3 return pd.read_csv('large_safari_data.csv')
4
5data = load_data()
6st.dataframe(data)Dekorator
@st.cache_data sprawia, że plik wczytuje się raz - przy kolejnych przebiegach skryptu Streamlit sięga po zapamiętany wynik. To najważniejsza optymalizacja w Streamlicie: nakładaj cache na wszystko, co jest wolne i się nie zmienia (wczytywanie danych, ciężkie obliczenia).Zbierzmy poznane elementy w jednej działającej stacji. Przeczytaj kod od góry i zauważ, jak każdy fragment odpowiada zasadom z tej lekcji: cache na wczytywaniu danych, suwak w panelu bocznym filtrujący dane, wskaźniki na górze i dwa wykresy obok siebie.
1# safari_dashboard.py
2import streamlit as st
3import pandas as pd
4import plotly.express as px
5
6st.set_page_config(page_title='Safari Dashboard', page_icon='', layout='wide')
7
8st.title('Safari Species Dashboard')
9
10# Sidebar filters
11st.sidebar.header('Filtry')
12min_pop = st.sidebar.slider('Min populacja', 0, 500, 50)
13
14# Load data
15@st.cache_data
16def load_data():
17 return pd.DataFrame({
18 'species': ['Lion', 'Elephant', 'Cheetah', 'Giraffe', 'Zebra'] * 3,
19 'population': [120, 450, 85, 200, 380, 130, 460, 80, 210, 390, 125, 455, 82, 205, 385],
20 'year': [2021]*5 + [2022]*5 + [2023]*5,
21 'habitat': ['Savanna', 'Forest', 'Savanna', 'Savanna', 'Savanna'] * 3
22 })
23
24data = load_data()
25filtered = data[data['population'] >= min_pop]
26
27# Metrics
28col1, col2, col3 = st.columns(3)
29col1.metric('Gatunki', filtered['species'].nunique())
30col2.metric('Łączna populacja', filtered['population'].sum())
31col3.metric('Średnia populacja', f"{filtered['population'].mean():.0f}")
32
33# Charts
34col1, col2 = st.columns(2)
35
36with col1:
37 fig = px.bar(filtered, x='species', y='population', color='year',
38 title='Populacje według gatunku')
39 st.plotly_chart(fig, use_container_width=True)
40
41with col2:
42 fig = px.pie(filtered, values='population', names='species',
43 title='Udział w populacji')
44 st.plotly_chart(fig, use_container_width=True)
45
46# Data table
47st.subheader('Dane')
48st.dataframe(filtered, use_container_width=True)Prześledź przepływ:
load_data jest w cache, więc ciężkie dane wczytują się raz; min_pop z suwaka filtruje je przy każdym ruchu, a wskaźniki i wykresy przeliczają się od nowa na przefiltrowanym zbiorze. To cała stacja - mniej niż 40 linii, żadnego HTML.Pamiętaj z tej lekcji dwie zasady, a resztę dopowie dokumentacja: skrypt czytany od góry na dół jest stroną, a każda interakcja uruchamia go od nowa - widżety to po prostu zmienne z aktualnie wybraną wartością.