Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Streamlit - stacja badawcza w przeglądarce

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 streamlit

Najważniejsza zasada: skrypt jest stroną

Zapamię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.py

Streamlit 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ę.

Widżety - i druga ważna zasada

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.

Wykresy - pokaż, nie opisuj

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.

Układ strony - kolumny i zakładki

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.

Cache - nie licz dwa razy tego samego

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).

Wszystko razem - kompletna stacja

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ą.

Przejdź do CodeWorlds