Каждый исследователь, студент или преподаватель рано или поздно сталкивается с необходимостью создавать интерактивные и красивые отчеты, которые позже следует приложить к статье, сдать на проверку или поделиться со студентами. Все чаще в топовых ВУЗах приевшиеся методички заменяют на Jupiter ноутбуки, а возможность сварганить красивый отчет "на коленке" прельщает огромное количество студентов.
Выделим основные недостатки отчетов в Jupiter Notebook:
Много кода. В большинстве отчетов важны таблицы, графики и выводы, а не куски кода, которые помогли эти данные получить и составляют, как правило, более половины отчета.
Сложность в интерактивной демонстрации. Для полноценной работы Jupiter Notebook необходимо иметь приложение и интерпретатор питон (или онлайн сервис).
Streamlit
Это low-code фреймворк, созданные для исследователей, которые используют python. Благодаря встроенному набору элементов можно быстро накидать свой отчет или веб приложение, а главное поделиться им с другими, развернув его в облаке всего за пять минут!
Установка
Устанавливается streamlit через pip:
pip install streamlit
После установки можно запустить пример, введя в терминале команду:
streamlit
Когда приложение запустится, в терминале будет приветственное сообщение и адрес, причем окно в браузере, скорее всего, откроется самостоятельно.
На страничке мы видим ссылку на сайт и много других полезных ссылок, которые пригодятся во время создания своего приложения.
Создаем свой отчет
Все начитается с того, что нужно установить и импортировать streamlit
import streamlit as st
Я хочу сделать так, чтобы в одном проекте можно было переключаться между разными отчетами, которые будут представлять отдельные странички. Для этого используется виджет sidebar:
page = st.sidebar.selectbox("Выбрать страницу",
["Тяжелые хвосты распределений",
"Iris Dataset"])
Здесь первый параметр является заголовком виджета, а список содержит варианты выбора. Когда пользователь меняет свой выбор, пременной page
присваивается соответствующее значение из списка.
Чтобы переключать страницы, нужно лишь использовать условный оператор if
:
if page == "Тяжелые хвосты распределений":
st.header("""Демонстрация Fisher's Iris датасета""")
elif page == "Iris Dataset":
st.header("""Сгенерировать N случайных событий из распределения Фреше с функцией распределения:""")
Для формирования заголовка используется виджет st.header
Так же есть возможность использовать latex:
st.latex(r'''
F(x) = exp(-(\gamma x)^{-1/\gamma}1\{x>0\})
''')
Итак, код для отображения страницы "Тяжелые хвосты распределений":
def main():
page = st.sidebar.selectbox("Выбрать страницу", ["Тяжелые хвосты распределений", "Iris Dataset"])
if page == "Тяжелые хвосты распределений":
st.header("""Сгенерировать N случайных событий из распределения Фреше с функцией распределения:""")
st.latex(r'''
F(x) = exp(-(\gamma x)^{-1/\gamma}1\{x>0\})
''')
st.text("Для получения результата:")
st.markdown("* Сгенерируем N нормально распределенных случайных величин $U_i$ [0,1] (нулевое среднее и единичная диспресия).")
st.markdown("* Вычислим N cлучайных величин с распределением Фреше по формуле:")
st.latex(r'''
X_i=\dfrac{1}{\gamma}\left(-lnU_i)^{-\gamma}\right)
''')
mu, sigma = 0, 1 # mean and standard deviation
gamma = st.slider('Желаемая гамма', 0.25, 2.25, 0.5, 0.25)
N = st.number_input("Желаемое N", 100, 10000, 10000)
U = np.abs(np.random.normal(mu, sigma, N))
X = 1 / gamma * (-np.log(U)) ** (-gamma)
X2 = X[X < 20]
fig, ax = plt.subplots()
count, bins, ignored = plt.hist(X2, 100, density=True)
plt.plot(bins,
np.exp(- (gamma * bins) ** (-1 / gamma)) * (1 / gamma) * (gamma * bins) ** (-1 / gamma - 1) * gamma,
linewidth=2, color='r')
st.pyplot(fig)
Кэширование данных
Каждый раз, когда пользователь нажимает что-то в интерфейсе весь скрипт выполняется заново. Это не очень хорошо, если мы скачиваем какие-то датасеты и работаем с ML моделями. Специально для этого есть две аннотации:
st.cache_data
- используется для кеширования загружаемых датасетов.st.cache_resource
- используется для ML моделей.
Так, чтобы загрузить известный датасет ирисов, напишем функцию с аннотацией st.cache_data:
@st.cache_data
def load_data():
if not os.path.isfile("data/iris.csv"):
# Download the Iris Fisher dataset
url = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
response = requests.get(url)
data = response.text
# Save the dataset to a local file
with open("data/iris.csv", "w") as file:
file.write(data)
# Load the dataset into a pandas DataFrame
df = pd.read_csv("data/iris.csv", header=None,
names=["sepal_length", "sepal_width", "petal_length", "petal_width", "class"])
return df
Я поместил датсет в папку data
не спроста, она нам потом понадобиться.
Отобразим его на соответствующей странице, используя st.pyplot
:
elif page == "Iris Dataset":
st.header("""Демонстрация Fisher's Iris датасета""")
df = load_data()
# Plotting the dataset
fig, ax = plt.subplots()
plt.scatter(df['sepal_length'], df['sepal_width'], c='blue', label='Iris-setosa')
plt.scatter(df['sepal_length'], df['petal_width'], c='red', label='Iris-versicolor')
plt.scatter(df['sepal_length'], df['petal_length'], c='green', label='Iris-virginica')
plt.xlabel('sepal_length')
plt.ylabel('sepal_width')
plt.title('Iris Fisher Dataset')
plt.legend()
st.pyplot(fig)
Запуск приложения
Для запуска проекта можно рассмотреть два варианта:
-
Запустить командой
streamlit run app.py,
через параметр--server.port=8057
можно указать, какой порт будет слушать приложение.Не забываем в нашем файле указать точку входа:
if __name__ == "__main__": main()
-
Для любителей запускать всего через
python main.py:
Создадим отдельный файл main.py и обозначим точку входа, где пропишем, что нужно запустить и с каким портом:
from streamlit.web.cli import main import sys if __name__ == "__main__": # Set prog_name so that the Streamlit server sees the same command line # string whether streamlit is called directly or via `python -m streamlit`. sys.argv = ["streamlit", "run", "app.py", ""] sys.exit(main(prog_name="streamlit"))
В итоге получаем красивый отчет:
Разворачиваем в облаке
Нам осталось самое интересное. То, ради чего мы вообще все это затеяли: сделать наш отчет общедоступным. Есть несколько вариантов, как это сделать:
Воспользоваться Streamlit Community Cloud - облако от создателей данного фреймворка.
Через хостинг у облачных провайдеров. Это довольно затратный и сложный метод для такой задачи, поэтому его опустим.
Разворачивание в облаке через пуш в GIT. Это такие сервисы, как Heroku и Amvera.
Amvera Cloud
Переходим на страничку входа и создаем аккаунт, если его ещё нет.
-
Нажимаем на кнопку "Создать" и вводим название проекта и тариф. Для большинтства проектов подойдет "Начальный"
На ПК переходим в папку с нашим проектом. Создаем там GIT репозиторий командой
git init
На странице проекта находим инструкцию, как подключиться к удаленному репозиторию. Для этого нужно выполнить
git remote add amvera <адрес удаленного репозитория>
-
Генерируем инструкцию для облака, как развернуть наше приложение:
Переходим на страницу генератора инструкций, которая, кстати, тоже написана с помощью streamlit.
Указываем, что мы используем python, обязательно иметь файл requirements.txt, где указаны все используемые библиотеки (в том числе и streamlit).
Если локально запускали все через команду
streamlit run app.py
, то ставим галку на "укажу свою" и прописываем эту команду.Тут ещё есть поле "Введите mountpoint", где указывается, где будут храниться данные, которые не стираются после перезапуска или остановки проекта. Так, если вы собираете какую-то статистику или собираетесь хранить данные, то их слудует класть в отдельную папку, путь до которой указывается в этом поле. Я не хочу аждый раз при перезапуске проекта скачивать заново весь датесет, поэтому положил его в папку
data
и указал этот путь в конфигурации.Нажимаем на кнопку Generate YAML. Добавляем полученный файл amvera.yml в корень нашего проекта.
-
Моя папка с проектом выглядит следующим образом (venv у вас может отсутствовать)
Заносим наши изменения в репозиторий, выполнив:
git add .
git commit -m "Initial commit"
git push amvera master
-
Ждем статуса "Успешно развернуто на странице проекта
Переходи по ссылке, указанной на этой же странице, у меня это https://streamlit-amvera-services.amvera.io и наслаждаемся нашим отчетом.
(Опционально) В разделе "Настройки" можно привязать свое доменное имя.
Вот такими простыми действиями мы развернули наш отчет и сделали его публичным. При этом, чтобы сэкономить, можно включать и выключать проект, нажимая на символ паузы. Деньги со счета будут списываться только в то время, когда проект включен.
Data4
А можно ли выводить видеозаписи и загружать/выгружать файлы с компьютера?