{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Python для сбора и анализа данных \n", "\n", "*Алла Тамбовцева, НИУ ВШЭ*\n", "\n", "## Порядок создания приложения с помощью `streamlit` " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Шаг 1: установка библиотеки\n", "\n", "Устанавливаем библиотеку `streamlit`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!pip install streamlit" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если при установке возникает ошибка, два пути:\n", " \n", "* прочитать в сообщении об ошибке, из-за установки каких зависимостей (других библиотек для успешной работы `streamlit`) возникают проблемы и попробовать установить их отдельно;\n", "\n", "* поставить более раннюю версию `streamlit` (например, версия 0.62), которая требует установки меньшего числа вспомогательных библиотек.\n", "\n", "Ради экономии времени мы пойдем по второму пути. Это не очень классно, потому что так мы теряем многие интересные возможности новых версий, но для простых приложений этого будет достаточно:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!pip install streamlit==0.62" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Шаг 2: создание исполняемого файла с кодом для приложения\n", "\n", "Возвращаемся на главную страницу *Home Page* в *Jupyter Notebook*, создаем новый текстовый файл (*New – Text file*), переименовываем его в `myapp.py`, вписываем в него следующие строки и сохраняем изменения:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import streamlit as st\n", "st.title(\"Salaries in US universities\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Этот код импортирует библиотеку и добавит на страницу с приложением заголовок с введенным текстом." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Важно:** проверьте, что вы создали текстовый файл (не ipynb-файл) и что в конце названия этого файла стоит расширение `.py`. \n", "\n", "Что такой исполняемый файл? Файл с программой на Python, которую интерпретатор этого языка может считать и выполнить. Ранее мы сохраняли код внутри ячейки Jupyter Notebook, теперь мы можем код из этой ячейки «вынести» в отдельный файл безо всяких излишеств. \n", "\n", "Почему ipynb-файл не подходит? Файл с расширением `.ipynb` предназначен для хранения красивого размеченного текста и кода в виде ячеек с возможностью последующего запуска кода из этих ячеек в Jupyter или аналогичной среде, не для обработки и исполнения кода на «чистом» Python. Формально ipynb-файл – текстовый файл, который внутри выглядит как сложная JSON-строка. \n", "\n", "Для сравнения. Внутри созданного нами файла `myapp.py` только две строки кода, больше ничего. А если создать аналогичный ipynb-файл с одной ячейкой с теми же строками кода, изнутри он будет выглядеть так:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{\n", " \"cells\": [\n", " {\n", " \"cell_type\": \"code\",\n", " \"execution_count\": null,\n", " \"metadata\": {},\n", " \"outputs\": [],\n", " \"source\": [\n", " \"import streamlit as st\\n\",\n", " \"st.title(\\\"Salaries in US universities\\\")\"\n", " ]\n", " }\n", " ],\n", " \"metadata\": {\n", " \"kernelspec\": {\n", " \"display_name\": \"Python 3\",\n", " \"language\": \"python\",\n", " \"name\": \"python3\"\n", " },\n", " \"language_info\": {\n", " \"codemirror_mode\": {\n", " \"name\": \"ipython\",\n", " \"version\": 3\n", " },\n", " \"file_extension\": \".py\",\n", " \"mimetype\": \"text/x-python\",\n", " \"name\": \"python\",\n", " \"nbconvert_exporter\": \"python\",\n", " \"pygments_lexer\": \"ipython3\",\n", " \"version\": \"3.7.4\"\n", " }\n", " },\n", " \"nbformat\": 4,\n", " \"nbformat_minor\": 2\n", "}\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Шаг 3: запуск исполняемого файла с приложением\n", "\n", "Исполняемые файлы запускаются из командной строки (терминала). \n", "\n", "* На Windows: заходим в *Пуск* в папку *Anaconda*, находим *Anaconda Command Prompt*, запускаем.\n", "* На Mac: находим в *Launchpad* или через поиск *Терминал* (обычно в папке *Другие*), запускаем.\n", "\n", "**Важно:** это должно быть новое окно командной строки, не то окно, которое открывается при запуске Jupyter Notebook. Если выполнять последующие действия в окне терминала, где выдаются сообщение о процессах Jupyter Notebook, ничего не сработает, плюс, Jupyter перестанет исполнять команды и сохранять изменения в файлах (мы «перебьем» своим вмешательством соединение Jupyter с ядром Python).\n", "\n", "После запуска командной строки в окне вводим строку и нажимаем *Enter*:\n", "\n", " streamlit run myapp.py\n", " \n", "При первом запуске обычно запрашивается e-mail, его можно пропустить, просто нажав *Enter*. Если все нормально, в командной строке будет указана ссылка на страницу с приложением на компьютере (например, `http://localhost:8501`), плюс, скорее всего, эта страница откроется в новой вкладке браузера. Пока это просто страница с заголовком.\n", " \n", "Если выводится ошибка вида `File does not exist`, а файл `myapp.py` точно создан, проверьте, в какой папке он сохранен. Три пути решения:\n", "\n", "* смотрим, из какой папки запускается командная строка (путь перед `>` или долларом в строке, где мы вводили команду с `run`), перемещаем/копируем файл `myapp.py` туда; туда же потом надо будет сохранить файлы с данными для работы;\n", "\n", "* находим файл `myapp.py` на компьютере, забираем из свойств файла полный путь к нему и запускаем приложение, указав этот путь в кавычках (тогда потом придется полностью прописывать пути ко всем файлам с данными):\n", "\n", " streamlit run \"C://Users/student/Documents/myapp.py\" \n", " \n", "* узнаем, какая папка является рабочей, переходим к ней в командной строке и потом снова запускаем строку с `run`, например:\n", "\n", " cd \"C://Users/student/Documents\"\n", " streamlit run myapp.py\n", " \n", "Здесь `cd` – команда для того, чтобы сделать папку рабочей (от *current directory*). Это довольно удобное решение, потому что тогда мы сможем спокойно хранить все необходимые файлы в этой папке и не перемещать их туда, куда «удобнее» командной строке.\n", "\n", "Рабочая папка – папка, где находится файл `myapp.py`. Раз мы создаем его через Jupyter, если рядом с этим файлом есть ipynb-файл, в нем можно запустить код для получения пути к этой папке:\n", "\n", " import os\n", " os.getcwd()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Шаг 4: редактируем приложение\n", "\n", "Открываем файл `myapp.py` и делаем приложение более осмысленным. Наше приложение будет предлагать пользователю выбрать столбец из файла `Salaries.csv` и выводить на экран таблицу с описательными статистиками. \n", "\n", "Для начала загрузим и подготовим данные – добавим в `myapp.py` следующие строки:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import streamlit as st\n", "import pandas as pd\n", "\n", "dat = pd.read_csv(\"Salaries.csv\")\n", "dat.rename(columns = {\"yrs.since.phd\" : \"phd\", \n", " \"yrs.service\" : \"service\"}, inplace = True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь добавим выпадающее меню – `selectbox()` со списком опций – названиями нескольких столбцов:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "selected = st.selectbox(\"Choose a variable\", [\"salary\", \"service\", \"phd\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Итого: в файле `myapp.py` должны быть следующие строки:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import streamlit as st\n", "import pandas as pd\n", "\n", "dat = pd.read_csv(\"Salaries.csv\")\n", "dat.rename(columns = {\"yrs.since.phd\" : \"phd\", \n", " \"yrs.service\" : \"service\"}, inplace = True)\n", "\n", "st.title(\"Salaries in US universities\")\n", "selected = st.selectbox(\"Choose a variable\", [\"salary\", \"service\", \"phd\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Перезагружаем страницу с приложением (обновляем страницу в браузере) и смотрим на изменения. Теперь на странице должен быть заголовок и меню для выбора столбца. Осталось подставить выбранное пользователем значение `selected` для выбора столбца и запросить по нему статистики через метод `.describe()`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "selected_table = dat[selected].describe()\n", "\n", "# выносим саму таблицу на страницу\n", "st.table(selected_table)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Итого в файле `myapp.py` должны быть следующие строки:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import streamlit as st\n", "import pandas as pd\n", "\n", "dat = pd.read_csv(\"Salaries.csv\")\n", "dat.rename(columns = {\"yrs.since.phd\" : \"phd\", \n", " \"yrs.service\" : \"service\"}, inplace = True)\n", "\n", "st.title(\"Salaries in US universities\")\n", "selected = st.selectbox(\"Choose a variable\", [\"salary\", \"service\", \"phd\"])\n", "\n", "selected_table = dat[selected].describe()\n", "st.table(selected_table)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Для более продвинутого приложения можно добавить график и написать условие на тип столбца – если тип текстовый, строится столбиковая диаграмма, если числовой – гистограмма." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 2 }