Введение в визуализацию данных
Что такое визуализация данных?
Визуализация данных — это процесс преобразования чисел и текстовой информации в графики, диаграммы и другие наглядные изображения. Она помогает быстро понять, какие закономерности или тенденции скрываются в данных.
Почему это важно?
- Понятность: Графики проще анализировать, чем таблицы с числами.
- Принятие решений: Руководителям легче принимать решения на основе наглядных диаграмм.
- Презентации: Визуализация делает доклады более интересными и убедительными.
- Поиск ошибок: Графики помогают обнаружить аномалии в данных.
Пример
Представьте, что у вас есть таблица с данными о продажах за год. Если вы построите линейный график, вы сразу увидите, в какие месяцы продажи были самыми высокими.
Популярные библиотеки для визуализации в Python
1. Matplotlib
- Самая старая и гибкая библиотека.
- Подходит для простых графиков.
- Пример кода:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4]
y = [10, 20, 25, 30]
plt.plot(x, y)
plt.show()
2. Seaborn
- Построена на основе Matplotlib, но упрощает создание сложных графиков.
- Пример кода:
import seaborn as sns
import matplotlib.pyplot as plt
data = [10, 20, 30, 40, 50]
sns.barplot(x=['A', 'B', 'C', 'D', 'E'], y=data)
plt.show()
3. Plotly
- Создает интерактивные графики (можно увеличивать, перемещать и настраивать).
- Подходит для работы в веб-приложениях.
- Прост в использовании и поддерживает 3D-графику.
- Пример кода (будет разобран ниже).
Введение в Plotly
Plotly — это библиотека для создания интерактивных графиков в Python. Она особенно удобна для работы с данными в веб-приложениях.
Преимущества Plotly
- Интерактивность: Можно увеличивать графики, перемещать их и выделять области.
- Простота интеграции с веб-приложениями: Работает с Flask и другими фреймворками.
- Поддержка множества типов графиков: Линейные, гистограммы, 3D-графики, тепловые карты и диаграммы на карте мира.
- Удобная работа с большими данными.
Установка Plotly
Перед началом работы необходимо установить библиотеку. Для этого выполните команду в терминале:
pip install plotly
Пример кода с Plotly
Создадим простой интерактивный график:
import plotly.express as px
data = {'Месяц': ['Январь', 'Февраль', 'Март', 'Апрель'],
'Продажи': [100, 150, 200, 250]}
fig = px.line(data, x='Месяц', y='Продажи', title='Продажи по месяцам')
# Сохранить в файл
fig.write_html('graph.html')
print("График сохранен в файле 'graph.html'. Откройте его в браузере.")
Разбор примера:
- Импорт библиотеки: Используем
plotly.express
для простоты кода. - Данные: Создаем словарь с данными о месяцах и продажах.
- График: Функция
px.line()
строит линейный график. Мы передаем данные и указываем, какие столбцы использовать для осей X и Y. - Сохранение графика:
fig.write_html('graph.html')
сохраняет график в файл html.
Задание1
- Установите библиотеку Plotly, если она еще не установлена.
- Постройте диаграмму (гистограмму) с произвольными данными о расходах по категориям за месяц (например, продукты, транспорт, развлечения).
- Экспериментируйте с изменением цветов и подписей осей в графике.
Пример для старта:
import plotly.express as px
data = {'Категория': ['Продукты', 'Транспорт', 'Развлечения'],
'Расходы': [5000, 3000, 2000]}
fig = px.bar(data, x='Категория', y='Расходы', title='Расходы за месяц')
# Сохранить в файл
fig.write_html('graph.html')
print("График сохранен в файле 'graph.html'. Откройте его в браузере.")
Установка и настройка Plotly
Что такое Plotly?
Plotly — это библиотека для построения красивых и интерактивных графиков на Python. Она помогает визуализировать данные в виде диаграмм, карт и других графиков прямо в браузере или в программе.
Установка
Чтобы установить Plotly, нужно ввести команду в терминале:
pip install plotly
Если библиотека уже установлена, но не работает, обновите её:
pip install --upgrade plotly
Быстрая проверка
import plotly
print(plotly.__version__)
Если код выведет версию библиотеки, значит установка прошла успешно.
Создание простых графиков
1. Линейный график
Линейный график помогает показать изменения данных со временем.
import plotly.express as px
data = {'Дни': ['Пн', 'Вт', 'Ср', 'Чт', 'Пт'],
'Продажи': [100, 150, 200, 250, 300]}
fig = px.line(data, x='Дни', y='Продажи', title='Продажи за неделю')
fig.show()
Результат: Линейный график с метками дней на оси X и продажами на оси Y.
2. Столбчатая диаграмма
Используется для сравнения данных по категориям.
fig = px.bar(data, x='Дни', y='Продажи', title='Продажи за неделю')
fig.show()
Результат: Столбцы, показывающие уровень продаж по каждому дню.
3. Круговая диаграмма
Подходит для отображения долей категорий в общем объеме.
data = {'Категория': ['Продукты', 'Одежда', 'Техника'],
'Сумма': [5000, 3000, 2000]}
fig = px.pie(data, names='Категория', values='Сумма', title='Распределение расходов')
fig.show()
Результат: Круговая диаграмма, показывающая долю каждой категории.
Все виды графиков Plotly с примерами
1. Scatter Plot — Точечный график
import plotly.express as px
# Данные
df = px.data.iris()
# Построение графика
fig = px.scatter(df, x='sepal_width', y='sepal_length', color='species', title='Точечный график (Scatter Plot)')
fig.show()
2. Scatter 3D — Трехмерный точечный график
fig = px.scatter_3d(df, x='sepal_width', y='sepal_length', z='petal_length', color='species', title='3D Точечный график (Scatter 3D)')
fig.show()
3. Scatter Polar — Полярный точечный график
fig = px.scatter_polar(df, r='sepal_length', theta='sepal_width', color='species', title='Полярный график (Scatter Polar)')
fig.show()
4. Scatter Ternary — Тернарный точечный график
fig = px.scatter_ternary(df, a='sepal_length', b='sepal_width', c='petal_length', color='species', title='Тернарный график (Scatter Ternary)')
fig.show()
5. Scatter Geo — Географический точечный график
df = px.data.gapminder()
fig = px.scatter_geo(df, locations='iso_alpha', color='continent', hover_name='country', size='pop', projection='natural earth', title='Географический график (Scatter Geo)')
fig.show()
6. Scatter Mapbox — Точечный график на карте Mapbox
# Убедитесь, что установлены необходимые библиотеки
# Вы можете установить их с помощью следующих команд, если они еще не установлены:
# pip install plotly shapely pandas
import plotly.express as px
import plotly.express.data as px_data
import pandas as pd
from shapely.geometry import shape
import numpy as np
import json
# Шаг 1: Загрузка GeoJSON данных
geojson = px_data.election_geojson()
# Шаг 2: Извлечение центроидов каждого округа
districts = []
for feature in geojson['features']:
district_id = feature['id']
district_name = feature['properties']['district']
geom = shape(feature['geometry'])
centroid = geom.centroid
districts.append({
'id': district_id,
'district': district_name,
'longitude': centroid.x,
'latitude': centroid.y
})
# Создание DataFrame
df = pd.DataFrame(districts)
# Шаг 3: Добавление фиктивных данных для демонстрации (например, количество голосов)
np.random.seed(42) # Для воспроизводимости
df['votes'] = np.random.randint(100, 1000, size=len(df))
# Шаг 4: Построение scatter_mapbox графика
fig = px.scatter_mapbox(
df,
lat='latitude',
lon='longitude',
hover_name='district',
hover_data=['votes'],
color='votes',
size='votes',
color_continuous_scale=px.colors.cyclical.IceFire,
size_max=15,
zoom=10,
mapbox_style='carto-positron',
title='Избирательные округа Монреаля - Выборы 2013 года'
)
# Настройка макета графика
fig.update_layout(
margin={"r":0,"t":50,"l":0,"b":0}
)
# Отображение графика
fig.write_html('plot.html')
7. Line Plot — Линейный график
df = px.data.gapminder()
fig = px.line(df, x='year', y='gdpPercap', color='continent', title='Линейный график (Line Plot)')
fig.show()
8. Line 3D — Трехмерный линейный график
fig = px.line_3d(df, x='year', y='gdpPercap', z='pop', color='continent', title='3D Линейный график (Line 3D)')
fig.show()
9. Line Polar — Полярный линейный график
import plotly.express as px
import pandas as pd
# Загрузка набора данных Gapminder
df = px.data.gapminder()
# Предварительная обработка данных
df_grouped = df.groupby(['continent', 'year']).agg({
'gdpPercap': 'mean'
}).reset_index()
# Создание полярного линейного графика
fig = px.line_polar(
df_grouped,
r='gdpPercap',
theta='year',
color='continent',
line_close=False,
markers=True,
color_discrete_sequence=px.colors.qualitative.Dark24,
title='Изменение среднего ВВП на душу населения по континентам (Gapminder)'
)
# Настройка макета графика
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=True,
title='ВВП на душу населения (US$)',
tickprefix="$",
ticksuffix="",
showline=True,
linewidth=2,
linecolor='black',
gridcolor='lightgrey'
),
angularaxis=dict(
rotation=90,
direction="clockwise",
showline=True,
linewidth=2,
linecolor='black',
gridcolor='lightgrey',
tickfont=dict(size=10)
)
),
legend_title_text='Континент',
title_font_size=20,
margin=dict(l=50, r=50, t=100, b=50)
)
# Отображение графика
fig.write_html('plot.html')
10. Line Ternary — Тернарный линейный график
df = px.data.iris()
fig = px.line_ternary(df, a='sepal_length', b='sepal_width', c='petal_length', color='species', title='Тернарный график (Line Ternary)')
fig.show()
11. Line Geo — Географический линейный график
import plotly.express as px
import pandas as pd
# Создание датафрейма
data = {
'City': ['New York', 'London', 'Paris', 'Tokyo', 'Sydney'],
'Latitude': [40.7128, 51.5074, 48.8566, 35.6895, -33.8688],
'Longitude': [-74.0060, -0.1278, 2.3522, 139.6917, 151.2093],
'Order': [1, 2, 3, 4, 5]
}
df = pd.DataFrame(data)
# Построение линии маршрута
fig = px.line_mapbox(
df,
lat='Latitude',
lon='Longitude',
color_discrete_sequence=['red'],
zoom=1,
height=600,
title='Маршрут путешествия: Нью-Йорк -> Лондон -> Париж -> Токио -> Сидней',
mapbox_style='carto-positron'
)
# Добавление маркеров без использования 'marker' словаря
fig.add_trace(
px.scatter_mapbox(
df,
lat='Latitude',
lon='Longitude',
text='City',
hover_name='City',
hover_data={'Latitude': False, 'Longitude': False},
size_max=10, # Максимальный размер маркеров
color_discrete_sequence=['blue'] # Цвет маркеров
).data[0]
)
# Настройка макета графика
fig.update_layout(
margin={"r":0,"t":50,"l":0,"b":0}
)
# Отображение графика
# fig.show()
fig.write_html('plot.html')
12. Line Mapbox — Линейный график на карте Mapbox
fig = px.line_mapbox(df, lat='lat', lon='lon', color='species', zoom=10, mapbox_style='open-street-map', title='Line Mapbox')
fig.show()
13. Area Plot — График областей
df = px.data.gapminder()
fig = px.area(df, x='year', y='pop', color='continent', title='График областей (Area Plot)')
fig.show()
14. Bar Plot — Столбчатый график
fig = px.bar(df, x='continent', y='pop', color='continent', title='Столбчатый график (Bar Plot)')
fig.show()
15. Timeline Plot — Временная шкала
import plotly.express as px
import pandas as pd
# Создание датафрейма с дополнительной информацией
data = {
'Event': [
'Начало Второй мировой войны',
'Распад СССР',
'Первый человек в космосе',
'Создание Интернета',
'Введение евро',
'Начало COVID-19 пандемии',
'Разработка вакцин против COVID-19'
],
'Start': [
'1939-09-01',
'1990-03-11',
'1961-04-12',
'1983-01-01',
'1999-01-01',
'2020-01-01',
'2020-12-01'
],
'Finish': [
'1945-09-02',
'1991-12-25',
'1969-07-24',
'1990-01-01',
'1999-01-01',
'2023-01-01',
'2021-12-31'
],
'Category': [
'Война',
'Политика',
'Космос',
'Технологии',
'Экономика',
'Здоровье',
'Здоровье'
],
'Description': [
'Второй мировой конфликт, начавшийся с нападения Германии на Польшу.',
'Событие, символизирующее конец Холодной войны.',
'Нил Армстронг стал первым человеком, ступившим на Луну.',
'Начало разработки глобальной сети связи.',
'Введение единой валюты для многих европейских стран.',
'Глобальная пандемия, вызванная вирусом SARS-CoV-2.',
'Создание и внедрение вакцин для борьбы с COVID-19.'
]
}
df = pd.DataFrame(data)
df['Start'] = pd.to_datetime(df['Start'])
df['Finish'] = pd.to_datetime(df['Finish'])
# Построение временной шкалы с дополнительной информацией
fig = px.timeline(
df,
x_start='Start',
x_end='Finish',
y='Event',
color='Category',
title='Временная шкала ключевых исторических событий',
labels={'Event': 'Событие', 'Category': 'Категория'},
hover_data={'Description': True, 'Start': False, 'Finish': False}
)
fig.update_yaxes(autorange="reversed")
fig.update_layout(
bargap=0.2,
xaxis_title='Дата',
yaxis_title='Событие',
legend_title='Категория',
margin=dict(l=200, r=50, t=100, b=50)
)
fig.write_html('plot.html')
16. Polar Bar Plot — Полярный столбчатый график
fig = px.bar_polar(df, r='pop', theta='continent', color='continent', title='Полярный столбчатый график (Polar Bar Plot)')
fig.show()
17. Violin Plot — Виолончельный график
fig = px.violin(df, x='continent', y='lifeExp', color='continent', title='Виолончельный график (Violin Plot)')
fig.show()
18. Box Plot — Коробчатый график
fig = px.box(df, x='continent', y='lifeExp', color='continent', title='Коробчатый график (Box Plot)')
fig.show()
19. Histogram — Гистограмма
fig = px.histogram(df, x='lifeExp', color='continent', title='Гистограмма (Histogram)')
fig.show()
20. Pie Plot — Круговая диаграмма
# Убедитесь, что установлены необходимые библиотеки
# Если нет, установите их с помощью следующих команд:
# pip install plotly pandas
import plotly.express as px
import pandas as pd
# Шаг 1: Загрузка набора данных Gapminder
df = px.data.gapminder()
# Выберите год для анализа
selected_year = 2007
# Шаг 2: Фильтрация данных по выбранному году
df_year = df[df['year'] == selected_year]
# Группировка данных по континентам и подсчет общего населения
df_continent = df_year.groupby('continent').agg({
'pop': 'sum'
}).reset_index()
# Добавление столбца с процентным соотношением населения
df_continent['percentage'] = (df_continent['pop'] / df_continent['pop'].sum()) * 100
# Шаг 3: Создание круговой диаграммы
fig = px.pie(
df_continent,
names='continent',
values='pop',
title=f'Распределение населения по континентам в {selected_year} году',
color='continent',
color_discrete_sequence=px.colors.qualitative.Set3,
hole=0.3, # Создание донатной диаграммы
labels={'continent': 'Континент', 'pop': 'Население'}
)
# Добавление процентных значений на диаграмму
fig.update_traces(textposition='inside', textinfo='percent+label')
# Шаг 4: Настройка макета графика
fig.update_layout(
showlegend=True,
legend_title_text='Континент',
margin=dict(l=20, r=20, t=80, b=20)
)
# Отображение графика
# fig.show()
# Опционально: Сохранение графика в HTML файл
fig.write_html('pie_plot_population_2007.html')
21. Treemap — Иерархическое дерево
# Убедитесь, что установлены необходимые библиотеки
# Если нет, установите их с помощью следующих команд:
# pip install plotly pandas
import plotly.express as px
import pandas as pd
# Шаг 1: Загрузка набора данных Gapminder
df = px.data.gapminder()
# Выберите год для анализа
selected_year = 2007
# Шаг 2: Фильтрация данных по выбранному году
df_year = df[df['year'] == selected_year]
# Проверка структуры данных
print(df_year.head())
# Шаг 3: Создание иерархического дерева (Treemap)
fig = px.treemap(
df_year,
path=['continent', 'country'], # Иерархия: Континент -> Страна
values='pop', # Размер блоков пропорционален населению
color='lifeExp', # Цвет блоков соответствует ожидаемой продолжительности жизни
hover_data=['gdpPercap'], # Дополнительная информация при наведении
color_continuous_scale='RdBu', # Цветовая палитра
title=f'Иерархическое дерево населения по странам и континентам в {selected_year} году'
)
# Шаг 4: Настройка макета графика
fig.update_layout(
margin=dict(t=50, l=25, r=25, b=25) # Установка отступов
)
# Шаг 5: Отображение графика
# fig.show()
# Опционально: Сохранение графика в HTML файл
fig.write_html('treemap_gapminder_2007.html')
22. Sunburst — Круговая иерархия
fig = px.sunburst(df, path=['continent', 'country'], values='pop', title='Круговая иерархия (Sunburst)')
fig.show()
23. Icicle — Ледяная диаграмма
fig = px.icicle(df, path=['continent', 'country'], values='pop', title='Ледяная диаграмма (Icicle)')
fig.show()
24. Funnel Plot — Воронка
# Убедитесь, что установлены необходимые библиотеки
# Если нет, установите их с помощью следующих команд:
# pip install plotly pandas
import plotly.express as px
import pandas as pd
# Шаг 1: Создание датафрейма с данными
# В этом примере мы создадим воронку продаж для компании
data = {
'Stage': [
'Посетители сайта',
'Лиды',
'Квалифицированные лиды',
'Предложения отправлены',
'Сделки заключены'
],
'Count': [
10000, # Посетители сайта
2000, # Лиды
500, # Квалифицированные лиды
200, # Предложения отправлены
100 # Сделки заключены
],
'Conversion Rate (%)': [
None, # Для первого этапа конверсия не определяется
20, # Лиды / Посетители сайта
25, # Квалифицированные лиды / Лиды
40, # Предложения отправлены / Квалифицированные лиды
50 # Сделки заключены / Предложения отправлены
]
}
df = pd.DataFrame(data)
# Шаг 2: Построение воронки
fig = px.funnel(
df,
x='Count',
y='Stage',
title='Воронка продаж компании',
labels={'Count': 'Количество клиентов', 'Stage': 'Этап'},
color='Stage', # Цветовая дифференциация по этапам
color_discrete_sequence=px.colors.sequential.Blues # Выбор цветовой палитры
)
# Шаг 3: Настройка макета графика
fig.update_layout(
margin=dict(l=100, r=50, t=100, b=50),
yaxis={'categoryorder':'total ascending'} # Сортировка этапов сверху вниз
)
# Шаг 4: Добавление текстовой информации на график
fig.update_traces(
text=df['Count'],
textinfo='value+percent previous', # Отображение значений и процентной конверсии
texttemplate="%{text}
%{percent previous:.1%}", # Настройка формата текста
textposition='inside', # Позиционирование текста внутри блоков
# insidetextorientation='horizontal' # Удалено, так как вызывает ошибку
)
# Шаг 5: Отображение графика
# fig.show()
# Опционально: Сохранение графика в HTML файл
fig.write_html('funnel_plot_sales.html')
25. Funnel Area Plot — Площадь воронки
fig = px.funnel_area(names=['A', 'B', 'C'], values=[10, 20, 30], title='Площадь воронки (Funnel Area)')
fig.show()
26. Scatter Matrix — Матрица диаграмм рассеяния
fig = px.scatter_matrix(df, dimensions=['sepal_length', 'sepal_width', 'petal_length'], color='species', title='Матрица диаграмм рассеяния (Scatter Matrix)')
fig.show()
27. Parallel Coordinates — Параллельные координаты
df = px.data.iris()
fig = px.parallel_coordinates(df, color='species_id', title='Параллельные координаты (Parallel Coordinates)')
fig.show()
28. Parallel Categories — Параллельные категории
import plotly.express as px
import pandas as pd
# Загрузка набора данных Tips
df = px.data.tips()
# Создание графика параллельных категорий
fig = px.parallel_categories(
df,
dimensions=['sex', 'smoker', 'day', 'time', 'size'],
color='total_bill',
color_continuous_scale=px.colors.sequential.Inferno,
labels={
'sex': 'Пол',
'smoker': 'Курящий',
'day': 'День недели',
'time': 'Время приема пищи',
'size': 'Размер группы',
'total_bill': 'Общая сумма (USD)'
},
title='Параллельные категории набора данных Tips'
)
# Настройка макета
fig.update_layout(
margin=dict(l=50, r=50, t=100, b=50)
)
# Отображение графика
fig.write_html('parallel_categories.html')
29. Choropleth — Картограмма
df = px.data.gapminder()
fig = px.choropleth(df, locations='iso_alpha', color='lifeExp', hover_name='country', title='Картограмма (Choropleth)')
fig.show()
30. Choropleth Mapbox — Картограмма на Mapbox
import plotly.express as px
import json
geojson = px.data.election_geojson()
df = px.data.election()
fig = px.choropleth_mapbox(df, geojson=geojson, locations='district', color='winner',
featureidkey='properties.district',
mapbox_style='carto-positron', zoom=3, center={'lat': 37.0902, 'lon': -95.7129},
title='Картограмма на Mapbox (Choropleth Mapbox)')
fig.show()
31. Density Contour — Контур плотности
fig = px.density_contour(df, x='sepal_length', y='sepal_width', title='Контур плотности (Density Contour)')
fig.show()
32. Density Heatmap — Тепловая карта плотности
fig = px.density_heatmap(df, x='sepal_length', y='sepal_width', title='Тепловая карта плотности (Density Heatmap)')
fig.show()
33. Density Mapbox — Карта плотности на Mapbox
# Убедитесь, что установлены необходимые библиотеки
# Если нет, установите их с помощью следующих команд:
# pip install plotly pandas
import plotly.express as px
import pandas as pd
# Шаг 1: Загрузка набора данных Car Share
df = px.data.carshare()
# Просмотр первых нескольких строк данных
print(df.head())
# Шаг 2: Подготовка данных
# Для карты плотности используем координаты мест отправления поездок
# Столбцы 'centroid_lat' и 'centroid_lon' содержат широту и долготу центроидов районов
# Шаг 3: Создание карты плотности
fig = px.density_mapbox(
df,
lat='centroid_lat',
lon='centroid_lon',
z='car_hours', # Поле, определяющее интенсивность плотности
radius=10, # Радиус влияния каждой точки
center=dict(lat=45.47154, lon=-73.588684), # Центр карты (пример: Сан-Франциско)
zoom=10, # Уровень масштабирования
mapbox_style='carto-positron', # Стиль карты, не требует API ключа
title='Карта плотности мест отправления поездок по аренде автомобилей',
labels={'count': 'Количество поездок'}
)
# Шаг 4: Настройка макета графика
fig.update_layout(
margin={"r":0,"t":50,"l":0,"b":0} # Установка отступов
)
# Шаг 5: Отображение графика
# fig.show()
# Опционально: Сохранение графика в HTML файл
fig.write_html('density_mapbox_carshare.html')
34. Imshow — Изображение
import numpy as np
img = np.random.rand(10, 10)
fig = px.imshow(img, title='Изображение (Imshow)')
fig.show()
Настройка внешнего вида графиков
Изменение цвета графиков
Можно задать цвета вручную:
fig = px.bar(data, x='Категория', y='Сумма', title='Расходы по категориям',
color='Категория', color_discrete_map={'Продукты': 'blue',
'Одежда': 'green',
'Техника': 'red'})
fig.show()
Результат: Каждая категория будет выделена своим цветом.
Добавление подписей
Подписи помогают лучше понять данные.
fig.update_traces(texttemplate='%{y}₽', textposition='outside')
fig.show()
Результат: Над каждым столбцом появится текст с суммой расходов.
Легенды и подписи осей
Легенда — это подсказка, объясняющая цвета или символы на графике. Подписи осей обозначают, что именно показывают оси X и Y.
fig.update_layout(
xaxis_title='Категории',
yaxis_title='Сумма (₽)',
legend_title='Тип расходов'
)
fig.show()
Результат: Под графиком будут добавлены подписи для осей и легенда.
Задание 2.
- Создайте свой график для анализа расходов или доходов за неделю. Используйте разные типы графиков (линейный, столбчатый или круговой).
- Добавьте цвета, подписи и легенды.
- Сохраните график в HTML-файл:
fig.write_html('my_chart.html')
Откройте файл в браузере и проверьте результат.
Работа с подграфиками (subplots)
Что такое подграфики?
Подграфики — это несколько графиков, расположенных в одном окне. Они удобны для сравнения данных или показа разных графиков по одной теме.
Пример создания подграфиков
import plotly.subplots as sp
import plotly.graph_objects as go
# Создаем подграфики: 1 строка, 2 колонки
fig = sp.make_subplots(rows=1, cols=2, subplot_titles=('График 1', 'График 2'))
# Добавляем графики в подграфики
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[10, 15, 20], mode='lines', name='Линия 1'), row=1, col=1)
fig.add_trace(go.Bar(x=['A', 'B', 'C'], y=[5, 10, 15], name='Столбцы'), row=1, col=2)
# Отображаем графики
fig.show()
Результат: Два графика (линейный и столбчатый) в одном окне, расположенные в ряд.
Анимации и интерактивность в графиках
Анимации
Анимации помогают показать, как данные изменяются со временем. Рассмотрим пример графика, который анимируется по кадрам:
import plotly.express as px
data = px.data.gapminder()
fig = px.scatter(data, x='gdpPercap', y='lifeExp', size='pop', color='continent',
hover_name='country', log_x=True, size_max=60, animation_frame='year')
fig.show()
Результат: Анимированный график, показывающий изменения экономических показателей разных стран с течением времени.
Интерактивность
Графики в Plotly автоматически поддерживают интерактивность:
- Наведение мыши для отображения значений.
- Масштабирование с помощью выделения области.
- Перемещение графика для удобства просмотра.
Пример интерактивного графика с фильтром данных:
fig = px.scatter(data, x='gdpPercap', y='lifeExp', color='continent', hover_name='country')
fig.update_traces(marker=dict(size=12))
fig.update_layout(clickmode='event+select')
fig.show()
Результат: Интерактивный график, на котором можно кликать по точкам и получать информацию о них.
Работа с географическими данными и картами
Построение карт
Plotly поддерживает работу с географическими картами. Рассмотрим пример, где отображаются страны по уровню населения:
import plotly.express as px
data = px.data.gapminder()
fig = px.choropleth(data, locations='iso_alpha', color='pop',
hover_name='country', animation_frame='year',
projection='natural earth')
fig.show()
Результат: Интерактивная карта, показывающая численность населения по странам в разные годы.
Отображение точек на карте
Если нужно показать отдельные точки на карте, например, расположение городов:
fig = px.scatter_geo(data, locations='iso_alpha', color='continent',
hover_name='country', size='pop', projection='orthographic')
fig.show()
Результат: Глобус с точками, обозначающими страны и их население.
Задание 3.
- Создайте подграфик из двух графиков: линейного и круговой диаграммы.
- Постройте анимированный график, показывающий изменения температуры в вашем городе по месяцам.
- Постройте карту с отображением точек для нескольких городов и их численности населения.
Введение в Pandas и Plotly
Что такое Pandas?
Pandas — это библиотека для работы с данными в Python. Она помогает хранить данные в удобной таблице, похожей на Excel, и быстро выполнять анализ.
Что такое DataFrame?
DataFrame — это основная структура данных в Pandas. Представляет собой таблицу с колонками и строками.
- Колонки содержат категории данных (например, ‘Дата’ или ‘Цена’).
- Строки содержат записи (например, данные за конкретный день).
Установка библиотек
Перед началом работы установите нужные библиотеки:
pip install plotly pandas
Проверьте версии библиотек:
import plotly
import pandas as pd
print("Plotly version:", plotly.__version__)
print("Pandas version:", pd.__version__)
Результат: Будут показаны версии Plotly и Pandas.
Пример 1: Линейный график с данными из DataFrame
Создадим таблицу данных
import pandas as pd
import plotly.express as px
data = {
'Дата': ['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04'],
'Продажи': [100, 80, 210, 150]
}
# Создаем DataFrame
df = pd.DataFrame(data)
# Преобразуем даты в нужный формат
df['Дата'] = pd.to_datetime(df['Дата'])
# Построим график
fig = px.line(df, x='Дата', y='Продажи', title='Продажи по дням')
fig.show()
Результат: Линейный график, показывающий рост продаж по датам.
Пример 2: Гистограмма с группировкой данных
Группировка данных по категориям
data = {
'Категория': ['Продукты', 'Продукты', 'Одежда', 'Одежда'],
'Месяц': ['Январь', 'Февраль', 'Январь', 'Февраль'],
'Продажи': [5000, 7000, 3000, 4000]
}
# Создаем DataFrame
df = pd.DataFrame(data)
# Построим столбчатую диаграмму
fig = px.bar(df, x='Месяц', y='Продажи', color='Категория', title='Продажи по категориям и месяцам')
fig.show()
Результат: Гистограмма, показывающая продажи по категориям и месяцам.
Пример 3: Динамический график с фильтрацией
Динамическая фильтрация данных
import plotly.express as px
import pandas as pd
# Загружаем данные о населении
data = px.data.gapminder()
# Фильтруем данные по году
df = data[data['year'] == 2007]
# Построим интерактивный график
fig = px.scatter(df, x='gdpPercap', y='lifeExp', size='pop', color='continent',
hover_name='country', log_x=True, size_max=60, title='Страны в 2007 году')
fig.show()
Результат: Интерактивный график, где точки можно увеличивать и изучать данные о странах.
Пример 4: Анализ временных рядов
Построение графика с данными по датам
import pandas as pd
import plotly.express as px
# Генерируем данные
df = pd.DataFrame({
'Дата': pd.date_range(start='2024-01-01', periods=10, freq='D'),
'Значение': [10, 15, 12, 18, 20, 22, 25, 23, 28, 30]
})
# Построим график
fig = px.line(df, x='Дата', y='Значение', title='Динамика показателей по дням')
fig.show()
Результат: Линейный график с динамикой показателей по дням.
Задание 4.
- Загрузите данные из CSV-файла в DataFrame.
- Постройте линейный график для анализа изменений данных во времени.
- Создайте гистограмму с группировкой по категориям.
- Добавьте фильтр для динамического отображения данных на графике.
Что такое Dash и для чего он используется
Dash — это фреймворк на языке Python, который помогает создавать интерактивные веб-приложения для визуализации данных.
Почему Dash удобен?
- Простота: Не нужно знать HTML, CSS и JavaScript. Приложения создаются на Python.
- Интерактивность: Можно добавлять кнопки, выпадающие списки и графики, которые меняются в ответ на действия пользователя.
- Интеграция с Plotly: Dash работает с Plotly, поэтому можно легко строить интерактивные графики.
- Подходит для аналитики: Используется для создания дашбордов (информационных панелей) с аналитическими отчетами.
Установка и настройка Dash
Установка Dash
Перед началом работы установите библиотеку Dash:
pip install dash
Проверка установки
import dash
print("Dash version:", dash.__version__)
Результат: Выводится версия установленного Dash.
Структура простого Dash-приложения
Пример кода простого приложения
from dash import Dash, html
# Создаем приложение
app = Dash(__name__)
# Создаем макет (структуру страницы)
app.layout = html.Div([
html.H1("Привет, Dash!"),
html.P("Это ваше первое Dash-приложение.")
])
# Запуск сервера
if __name__ == '__main__':
app.run_server(debug=True)
Разбор примера:
Dash(__name__)
— создает приложение Dash.layout
— определяет внешний вид страницы. В данном случае это заголовок (H1) и абзац (P).run_server(debug=True)
— запускает локальный сервер для отображения приложения.
Результат: После запуска код откроет браузер по адресу http://127.0.0.1:8050/
с текстом:
Привет, Dash!
Это ваше первое Dash-приложение.
Добавление элементов интерфейса
Пример с кнопками и графиками
from dash import Dash, html, dcc
import plotly.express as px
import pandas as pd
# Создаем приложение
app = Dash(__name__)
# Данные
df = pd.DataFrame({
'Фрукты': ['Яблоки', 'Апельсины', 'Бананы', 'Киви'],
'Продажи': [50, 30, 40, 20]
})
# Создаем график
fig = px.bar(df, x='Фрукты', y='Продажи', title='Продажи фруктов')
# Макет приложения
app.layout = html.Div([
html.H1("Продажи в магазине"),
dcc.Graph(figure=fig)
])
# Запуск сервера
if __name__ == '__main__':
app.run_server(debug=True)
Разбор примера:
dcc.Graph
— компонент Dash для отображения графиков.figure=fig
— передает созданный график в компонент для отображения.
Результат: После запуска приложения в браузере откроется столбчатая диаграмма с продажами фруктов.
Задание 5.
- Установите библиотеку Dash, если она еще не установлена.
- Напишите приложение Dash с таблицей данных и добавьте график на основе этой таблицы.
- Добавьте интерактивный элемент — кнопку или выпадающий список.
Пример:
from dash import Dash, html, dcc
import plotly.express as px
app = Dash(__name__)
# Данные для выбора
options = [
{'label': 'Яблоки', 'value': 'Яблоки'},
{'label': 'Апельсины', 'value': 'Апельсины'}
]
app.layout = html.Div([
html.H1("Выберите продукт"),
dcc.Dropdown(options=options, value='Яблоки'),
html.P("График будет добавлен на следующем занятии.")
])
if __name__ == '__main__':
app.run_server(debug=True)
Основные компоненты Dash
Dash позволяет создавать веб-приложения с помощью Python. Главные составляющие Dash-приложения — это Layout (макет) и Callbacks (обратные вызовы).
Layout (Макет)
Макет определяет, как будет выглядеть ваше приложение. В нем указываются элементы, которые появятся на веб-странице: заголовки, кнопки, графики и формы.
Пример простого макета
from dash import Dash, html, dcc
app = Dash(__name__)
app.layout = html.Div([
html.H1("Пример макета Dash"),
html.P("Этот макет содержит заголовок и текстовый абзац."),
dcc.Graph(
id='example-graph',
figure={
'data': [
{'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar', 'name': 'Бар'},
{'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'line', 'name': 'Линия'}
],
'layout': {
'title': 'Пример графика'
}
}
)
])
if __name__ == '__main__':
app.run_server(debug=True)
Результат: На веб-странице появится заголовок, абзац и график с данными.
Callbacks (Обратные вызовы)
Callbacks делают приложение интерактивным. Они позволяют обновлять содержимое элементов на основе действий пользователя.
Пример с интерактивностью
from dash import Dash, html, dcc, Input, Output
app = Dash(__name__)
app.layout = html.Div([
dcc.Input(id='input-text', value='Введите текст', type='text'),
html.Div(id='output-text')
])
@app.callback(
Output('output-text', 'children'),
Input('input-text', 'value')
)
def update_output(input_value):
return f'Вы ввели: {input_value}'
if __name__ == '__main__':
app.run_server(debug=True)
Разбор примера:
- dcc.Input — поле ввода текста.
- html.Div — вывод результата.
- callback — связывает ввод и вывод.
- Input — отслеживает изменения в поле ввода.
- Output — обновляет содержимое другого элемента.
Результат: При вводе текста в поле он автоматически отображается внизу.
Работа с HTML-компонентами через Dash
Dash предоставляет готовые HTML-компоненты, которые легко добавлять в приложение.
Примеры HTML-компонентов
app.layout = html.Div([
html.H1("Заголовок H1"),
html.H2("Подзаголовок H2"),
html.P("Абзац текста."),
html.Button("Кнопка", id='example-button'),
html.Div(id='output-button-clicks')
])
Результат: Появятся заголовки, абзац текста и кнопка.
Введение в Dash Core Components
Dash Core Components (dcc) — это более сложные элементы, такие как выпадающие списки, графики и ползунки.
Пример выпадающего списка
app.layout = html.Div([
dcc.Dropdown(
id='example-dropdown',
options=[
{'label': 'Красный', 'value': 'RED'},
{'label': 'Синий', 'value': 'BLUE'},
{'label': 'Зеленый', 'value': 'GREEN'}
],
value='RED'
),
html.Div(id='output-dropdown')
])
@app.callback(
Output('output-dropdown', 'children'),
Input('example-dropdown', 'value')
)
def update_color(selected_value):
return f'Вы выбрали: {selected_value}'
if __name__ == '__main__':
app.run_server(debug=True)
Разбор примера:
- Dropdown — выпадающий список с тремя вариантами.
- Callback — обновляет текст при выборе значения.
Результат: При выборе цвета в выпадающем списке отображается текст с выбранным значением.
Задание 6.
- Создайте Dash-приложение с двумя элементами:
- Полем ввода (dcc.Input).
- Выпадающим списком (dcc.Dropdown).
- Добавьте обработчик, который будет объединять введенные данные и выбранный элемент в одно сообщение.
Пример вывода:
Вы выбрали: Зеленый, и ввели текст: Пример.
Что такое Callback в Dash?
Callback — это механизм, который связывает действия пользователя с изменениями в интерфейсе. Например, когда пользователь выбирает значение из выпадающего списка, информация в графике автоматически обновляется.
Как это работает?
Callback состоит из двух частей:
- Input — отслеживает изменения в элементах (например, текст в поле ввода или выбор из списка).
- Output — определяет, какой элемент на странице нужно обновить.
Пример 1: Простой Callback с текстовым вводом
Код:
from dash import Dash, html, dcc, Input, Output
app = Dash(__name__)
# Макет приложения
app.layout = html.Div([
dcc.Input(id='input-text', type='text', value='Привет'),
html.Div(id='output-text')
])
# Callback-функция
@app.callback(
Output('output-text', 'children'), # Выход: обновление текста в Div
Input('input-text', 'value') # Вход: отслеживание изменений в Input
)
def update_output(value):
return f'Вы ввели: {value}'
if __name__ == '__main__':
app.run_server(debug=True)
Объяснение кода:
- dcc.Input — поле ввода текста.
- html.Div — вывод результата.
- Callback — связывает ввод и вывод.
- Функция
update_output
вызывается каждый раз, когда меняется значение в поле ввода.
Результат:
Текст, введенный в поле, отображается сразу под ним.
Пример 2: Динамическое обновление графика
Код:
from dash import Dash, html, dcc, Input, Output
import plotly.express as px
import pandas as pd
app = Dash(__name__)
# Данные
data = {
'Категория': ['Продукты', 'Одежда', 'Техника'],
'Январь': [5000, 3000, 2000],
'Февраль': [6000, 4000, 3000]
}
df = pd.DataFrame(data)
# Макет приложения
app.layout = html.Div([
dcc.Dropdown(
id='month-dropdown',
options=[
{'label': 'Январь', 'value': 'Январь'},
{'label': 'Февраль', 'value': 'Февраль'}
],
value='Январь'
),
dcc.Graph(id='bar-chart')
])
# Callback-функция
@app.callback(
Output('bar-chart', 'figure'),
Input('month-dropdown', 'value')
)
def update_chart(selected_month):
fig = px.bar(df, x='Категория', y=selected_month, title=f'Продажи за {selected_month}')
return fig
if __name__ == '__main__':
app.run_server(debug=True)
Объяснение кода:
- Dropdown — выпадающий список для выбора месяца.
- Graph — отображает график.
- Callback — обновляет данные в графике при смене месяца.
- Функция
update_chart
строит новый график в зависимости от выбранного месяца.
Результат:
График обновляется в зависимости от выбранного месяца в выпадающем списке.
Пример 3: Обработка нескольких входов (Inputs)
Код:
from dash import Dash, html, dcc, Input, Output
app = Dash(__name__)
app.layout = html.Div([
dcc.Input(id='input1', type='number', value=0),
dcc.Input(id='input2', type='number', value=0),
html.Div(id='output-sum')
])
@app.callback(
Output('output-sum', 'children'),
Input('input1', 'value'),
Input('input2', 'value')
)
def update_sum(value1, value2):
return f'Сумма: {value1 + value2}'
if __name__ == '__main__':
app.run_server(debug=True)
Объяснение кода:
- Input — отслеживает значения двух полей ввода.
- Output — обновляет текст с результатом.
- Функция
update_sum
вычисляет сумму двух чисел и выводит её.
Результат:
После ввода двух чисел появляется их сумма.
Задание 7.
- Создайте приложение с ползунком (dcc.Slider) и графиком.
- Реализуйте обновление графика при изменении значения ползунка.
Примерный макет:
- Ползунок для выбора диапазона значений.
- График, отображающий данные в выбранном диапазоне.
Хранение состояния приложения
Что такое состояние приложения?
Состояние — это данные, которые сохраняются между взаимодействиями пользователя с приложением. Например, выбранные параметры, фильтры или результаты поиска.
Варианты хранения состояния в Dash:
- Frontend (на стороне клиента): Данные хранятся в браузере пользователя.
- Backend (на стороне сервера): Данные хранятся в памяти сервера или базе данных.
Пример 1: Хранение состояния на клиенте
from dash import Dash, html, dcc, Input, Output, State
app = Dash(__name__)
app.layout = html.Div([
dcc.Input(id='input-text', type='text', value='Введите текст'),
html.Button('Сохранить', id='save-button', n_clicks=0),
html.Div(id='output-text')
])
@app.callback(
Output('output-text', 'children'),
Input('save-button', 'n_clicks'),
State('input-text', 'value')
)
def save_state(n_clicks, value):
return f'Сохранено: {value}'
if __name__ == '__main__':
app.run_server(debug=True)
Объяснение кода:
- State — хранит текущее значение поля ввода, пока кнопка не будет нажата.
- Значение сохраняется при нажатии кнопки и отображается на экране.
Результат: Текст отображается только после нажатия кнопки «Сохранить».
Оптимизация производительности Dash-приложений
1. Кэширование данных
Если приложение работает с большими наборами данных, можно использовать кэш для хранения результатов.
Пример 2: Использование Flask-Caching
from dash import Dash, html, dcc, Input, Output
from flask_caching import Cache
import time
app = Dash(__name__)
cache = Cache(app.server, config={'CACHE_TYPE': 'SimpleCache'})
@cache.memoize(timeout=60) # Кэширование на 60 секунд
def slow_function(n):
time.sleep(2) # Имитация долгой работы
return f'Результат: {n ** 2}'
app.layout = html.Div([
dcc.Input(id='input-number', type='number', value=1),
html.Div(id='output-number')
])
@app.callback(
Output('output-number', 'children'),
Input('input-number', 'value')
)
def update_output(value):
return slow_function(value)
if __name__ == '__main__':
app.run_server(debug=True)
Объяснение кода:
- Flask-Caching — добавляет кэширование данных.
- Функция
slow_function
вызывается только при изменении входных данных. - Если данные уже в кэше, они возвращаются мгновенно.
Результат: Быстрое обновление результатов после первого расчета.
2. Ленивая загрузка компонентов
Если приложение использует много графиков, можно загружать их только по мере необходимости.
from dash import Dash, html, dcc, Input, Output
app = Dash(__name__)
app.layout = html.Div([
dcc.Tabs(id='tabs', value='tab-1', children=[
dcc.Tab(label='График 1', value='tab-1'),
dcc.Tab(label='График 2', value='tab-2')
]),
html.Div(id='tabs-content')
])
@app.callback(
Output('tabs-content', 'children'),
Input('tabs', 'value')
)
def render_content(tab):
if tab == 'tab-1':
return dcc.Graph(figure={'data': [{'x': [1, 2, 3], 'y': [4, 5, 6]}]})
elif tab == 'tab-2':
return dcc.Graph(figure={'data': [{'x': [1, 2, 3], 'y': [10, 20, 30]}]})
if __name__ == '__main__':
app.run_server(debug=True)
Объяснение кода:
Графики загружаются только при переключении вкладок, а не сразу при загрузке приложения.
Использование Dash Extensions
Что такое Dash Extensions?
Dash Extensions — это набор инструментов для расширения возможностей Dash, таких как загрузка файлов, работа с веб-сокетами и улучшенные графики.
Пример 3: Загрузка файлов
from dash import Dash, html, dcc, Input, Output
import os
app = Dash(__name__)
app.layout = html.Div([
html.Button("Скачать файл", id="btn_download"),
dcc.Download(id="download")
])
@app.callback(
Output("download", "data"),
Input("btn_download", "n_clicks"),
prevent_initial_call=True,
)
def download_file(n_clicks):
return dcc.send_file("example_file.csv")
if __name__ == '__main__':
app.run_server(debug=True)
Объяснение кода:
- Dash добавляет функцию загрузки файлов.
- Файл загружается по нажатию кнопки.
Результат: Кнопка позволяет скачать файл с сервера.
Пример: Анимированный график с использованием dash-extensions
Установка библиотеки
pip install dash-extensions
Код:
from dash import Dash, html, dcc, Input, Output
import plotly.express as px
import pandas as pd
from dash_extensions.enrich import DashProxy, MultiplexerTransform
# Создаем приложение с поддержкой нескольких обновлений одного Output
app = DashProxy(__name__, transforms=[MultiplexerTransform()])
# Загружаем данные
df = px.data.gapminder()
# Создаем макет
app.layout = html.Div([
dcc.Dropdown(
id='continent-dropdown',
options=[{'label': c, 'value': c} for c in df['continent'].unique()],
value='Asia'
),
dcc.Graph(id='animated-graph'),
dcc.Slider(
id='year-slider',
min=df['year'].min(),
max=df['year'].max(),
value=df['year'].min(),
marks={str(year): str(year) for year in df['year'].unique()},
step=None
)
])
# Обновляем график при изменении выпадающего списка или слайдера
@app.callback(
Output('animated-graph', 'figure'),
Input('continent-dropdown', 'value'),
Input('year-slider', 'value')
)
def update_graph(selected_continent, selected_year):
filtered_df = df[(df['continent'] == selected_continent) & (df['year'] == selected_year)]
fig = px.scatter(filtered_df, x='gdpPercap', y='lifeExp',
size='pop', color='country', hover_name='country',
log_x=True, size_max=55, title=f'Данные за {selected_year}')
return fig
# Запуск сервера
if __name__ == '__main__':
app.run_server(debug=True)
Разбор примера:
- DashProxy — используется вместо стандартного Dash.
Позволяет включать расширенные возможности, такие как MultiplexerTransform. - MultiplexerTransform — добавляет поддержку множественных обновлений одного и того же Output (например, если график должен обновляться от нескольких Inputs).
- dcc.Dropdown — позволяет выбирать континент для фильтрации данных.
- dcc.Slider — управляет выбором года.
- px.scatter — создает интерактивный график с пузырьками, размер которых зависит от населения.
Результат:
- При выборе континента и года на выпадающем списке и слайдере график автоматически обновляется.
- Показывается распределение стран по ожидаемой продолжительности жизни и ВВП.
Задание 8.
- Добавьте в приложение хранение состояния при переключении вкладок.
- Реализуйте кэширование данных для ускорения работы приложения.
- Добавьте возможность загрузки файла через Dash Extensions.
Обзор архитектуры Flask-приложений
Что такое Flask?
Flask — это фреймворк для создания веб-приложений на языке Python. Он минималистичный, гибкий и часто используется для создания API и серверов приложений.
Основные компоненты Flask:
- Маршруты (Routes): Определяют, какие функции обрабатывают запросы по конкретным адресам URL.
- Контроллеры (View Functions): Логика обработки запросов и возврата ответов пользователю.
- Шаблоны (Templates): HTML-файлы с динамическими элементами, которые формируются на сервере.
- Статика (Static Files): CSS, JavaScript и изображения.
- Расширения (Extensions): Дополнительные библиотеки для авторизации, работы с базами данных и других задач.
Пример простого Flask-приложения:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return 'Привет, Flask!'
if __name__ == '__main__':
app.run(debug=True)
Результат: На странице http://127.0.0.1:5000 появится текст: «Привет, Flask!»
Взаимодействие Flask и Dash: возможности и ограничения
Возможности:
- Интеграция Dash в Flask: Можно добавить интерактивные графики в существующее Flask-приложение.
- Общий сервер: Flask и Dash могут работать на одном сервере, используя общие ресурсы.
- Авторизация и управление пользователями: Flask может обрабатывать авторизацию, а Dash — отображать данные.
- Взаимодействие с базами данных: Flask может запрашивать данные и передавать их в графики Dash.
Ограничения:
- Разделение логики: Flask обрабатывает маршруты и данные, а Dash управляет графическим интерфейсом.
- Производительность: При большом количестве пользователей может потребоваться оптимизация.
- Сложность настройки: Требуется интеграция маршрутов и управление состояниями между двумя фреймворками.
Установка и настройка взаимодействия Flask и Dash
Пример интеграции Dash в Flask
1. Установка библиотек:
pip install flask dash
2. Код приложения Flask и Dash:
from flask import Flask, render_template
from dash import Dash, html, dcc
import plotly.express as px
# Создаем Flask-приложение
server = Flask(__name__)
# Добавляем маршрут для Flask
@server.route('/')
def home():
return '<h1>Главная страница Flask</h1><p><a href="/dashboard">Перейти в Dash</a></p>'
# Создаем Dash-приложение
app = Dash(__name__, server=server, url_base_pathname='/dashboard/')
# Данные для графика
df = px.data.iris()
fig = px.scatter(df, x='sepal_width', y='sepal_length', color='species', title='График цветов')
# Макет Dash
app.layout = html.Div([
html.H1('Dash-приложение'),
dcc.Graph(figure=fig)
])
# Запуск сервера
if __name__ == '__main__':
server.run(debug=True)
Объяснение кода:
- Flask: Создается основное приложение для обработки маршрутов.
- Dash: Добавляется как компонент Flask с собственным URL (
/dashboard/
). - Интерактивный график: Отображается в разделе Dash.
Результат:
- На http://127.0.0.1:5000 отображается текст с кнопкой для перехода к Dash.
- На http://127.0.0.1:5000/dashboard/ открывается интерактивный график.
Задание 9.
- Добавьте в Flask маршрут для страницы «Контакты» с текстом и ссылкой для возврата на главную.
- Добавьте в Dash второй график, доступный по новому URL
/dashboard/second
. Используйте разные данные.- Реализуйте переходы между Flask и Dash через гиперссылки.
Интеграция Dash-приложения в существующий Flask-проект
Что такое интеграция Flask и Dash?
Интеграция позволяет объединить возможности Flask (обработка маршрутов, работа с базами данных) и Dash (интерактивные графики и элементы интерфейса) в одном приложении.
Пример интеграции Dash в Flask
1. Установка библиотек:
pip install flask dash plotly
2. Создание структуры проекта:
project/
├── app.py
├── templates/
│ ├── index.html
│ ├── dashboard.html
3. Код приложения (app.py):
from flask import Flask, render_template
from dash import Dash, html, dcc
import plotly.express as px
# Создаем Flask-приложение
server = Flask(__name__)
# Маршрут для главной страницы Flask
@server.route('/')
def home():
return render_template('index.html')
# Создаем Dash-приложение с Flask в качестве сервера
app = Dash(__name__, server=server, url_base_pathname='/dashboard/')
# Данные для графика
df = px.data.iris()
fig = px.scatter(df, x='sepal_width', y='sepal_length', color='species', title='График цветов')
# Макет Dash-приложения
app.layout = html.Div([
html.H1('Интерактивный график'),
dcc.Graph(figure=fig),
html.A('Вернуться на главную', href='/')
])
# Запуск приложения
if __name__ == '__main__':
server.run(debug=True)
Результат:
- http://127.0.0.1:5000/ — отображает статичную HTML-страницу Flask.
- http://127.0.0.1:5000/dashboard/ — открывает Dash-график с ссылкой на главную страницу.
Маршрутизация и управление URL-адресами
Flask и маршруты
В Flask маршруты обрабатывают запросы на определенные URL-адреса. Пример:
@server.route('/about')
def about():
return '<h1>О проекте</h1>'
Результат: По адресу http://127.0.0.1:5000/about появится текст «О проекте».
Dash и URL-пути
Dash использует параметр url_base_pathname
для привязки своего интерфейса к конкретному маршруту в Flask. Пример:
app = Dash(__name__, server=server, url_base_pathname='/dashboard/')
Результат: Dash доступен по адресу http://127.0.0.1:5000/dashboard/
Обмен данными между Flask и Dash
Пример передачи данных из Flask в Dash
from flask import Flask, render_template
from dash import Dash, html, dcc, Input, Output
import pandas as pd
import plotly.express as px
# Flask-приложение
server = Flask(__name__)
@server.route('/')
def home():
return render_template('index.html')
# Данные для передачи
data = {'Месяц': ['Январь', 'Февраль', 'Март'], 'Продажи': [100, 200, 300]}
df = pd.DataFrame(data)
# Dash-приложение
app = Dash(__name__, server=server, url_base_pathname='/dashboard/')
app.layout = html.Div([
html.H1('Продажи по месяцам'),
dcc.Graph(id='bar-chart'),
dcc.Dropdown(
id='dropdown',
options=[{'label': m, 'value': m} for m in df['Месяц']],
value='Январь'
)
])
@app.callback(
Output('bar-chart', 'figure'),
Input('dropdown', 'value')
)
def update_chart(selected_month):
filtered_df = df[df['Месяц'] == selected_month]
fig = px.bar(filtered_df, x='Месяц', y='Продажи', title=f'Продажи за {selected_month}')
return fig
if __name__ == '__main__':
server.run(debug=True)
Объяснение кода:
- Передача данных из Flask: Данные создаются в Flask и передаются в Dash через переменную
df
. - Dropdown: Пользователь выбирает месяц из списка.
- График: Данные обновляются на основе выбора.
Результат:
- Динамический график обновляется при выборе другого месяца в выпадающем списке.
Задание 10.
- Добавьте страницу «Контакты» в Flask.
- Добавьте второй график в Dash на отдельном маршруте (например,
/dashboard/second/
).- Реализуйте кнопку для скачивания данных в формате CSV из Dash.
Использование SQLAlchemy с Flask
Что такое SQLAlchemy?
SQLAlchemy — это библиотека для работы с базами данных в Python. Она упрощает взаимодействие с базами данных, позволяя работать с таблицами как с обычными объектами Python.
Установка SQLAlchemy
pip install sqlalchemy flask-sqlalchemy
Пример подключения к базе данных SQLite
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
# Создаем Flask-приложение
app = Flask(__name__)
# Настройка базы данных
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# Создаем объект базы данных
db = SQLAlchemy(app)
# Определяем структуру таблицы
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
price = db.Column(db.Float, nullable=False)
# Создаем таблицу
with app.app_context():
db.create_all()
if __name__ == '__main__':
app.run(debug=True)
Результат: Создается база данных example.db
с таблицей Product
.
Передача данных из базы данных в Dash-приложение
Пример кода с подключением Dash и чтением данных из базы
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from dash import Dash, html, dcc, Input, Output
import plotly.express as px
import pandas as pd
# Flask-приложение
server = Flask(__name__)
server.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
server.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# База данных
db = SQLAlchemy(server)
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
price = db.Column(db.Float, nullable=False)
# Dash-приложение
app = Dash(__name__, server=server, url_base_pathname='/dashboard/')
# Получаем данные из базы
with server.app_context():
data = db.session.query(Product.name, Product.price).all()
df = pd.DataFrame(data, columns=['Название', 'Цена'])
# Макет Dash
app.layout = html.Div([
html.H1('График цен продуктов'),
dcc.Graph(
id='bar-chart',
figure=px.bar(df, x='Название', y='Цена', title='Цены продуктов')
)
])
if __name__ == '__main__':
server.run(debug=True)
Объяснение кода:
- Подключение базы данных: Используется SQLAlchemy для работы с SQLite.
- Чтение данных: Выполняется запрос к базе данных, результат преобразуется в DataFrame.
- График: Строится столбчатая диаграмма цен продуктов с помощью Plotly.
Результат: По адресу http://127.0.0.1:5000/dashboard/ отображается график с ценами продуктов.
Обновление графиков на основе данных из базы
Пример с динамическим обновлением данных
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from dash import Dash, html, dcc, Input, Output
import plotly.express as px
import pandas as pd
# Flask-приложение
server = Flask(__name__)
server.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
server.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# База данных
db = SQLAlchemy(server)
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
price = db.Column(db.Float, nullable=False)
# Dash-приложение
app = Dash(__name__, server=server, url_base_pathname='/dashboard/')
app.layout = html.Div([
html.H1('Динамическое обновление данных'),
dcc.Interval(id='interval-component', interval=2000, n_intervals=0),
dcc.Graph(id='live-bar-chart')
])
@app.callback(
Output('live-bar-chart', 'figure'),
Input('interval-component', 'n_intervals')
)
def update_chart(n):
# Читаем обновленные данные из базы
with server.app_context():
data = db.session.query(Product.name, Product.price).all()
df = pd.DataFrame(data, columns=['Название', 'Цена'])
# Строим новый график
fig = px.bar(df, x='Название', y='Цена', title='Обновленные данные')
return fig
# Создание таблицы в базе данных
with server.app_context(): # Используем Flask-контекст вместо Dash
db.create_all()
if __name__ == '__main__':
server.run(debug=True)
Объяснение кода:
- dcc.Interval: Таймер обновляет график каждые 2 секунды.
- Обновление данных: Запрос к базе выполняется в каждом обновлении.
- Динамическое обновление графика: График перерисовывается с новыми данными.
Результат: График автоматически обновляется при изменении данных в базе.
Задание 12.
- Добавьте новый столбец в таблицу, например, «Категория» и отобразите данные с группировкой по категориям.
- Реализуйте фильтр в Dash для выбора конкретной категории.
- Добавьте возможность добавления новых данных в базу через Flask и обновления графика в Dash.
Аутентификация — это проверка личности пользователя (например, по логину и паролю).
Авторизация — это проверка прав доступа к определенным ресурсам (например, страницам или данным).
Реализация системы аутентификации в Flask
Установка необходимых библиотек:
pip install flask flask-login werkzeug
Пример кода с логином и паролем:
from flask import Flask, render_template, redirect, url_for, request, flash
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
app.secret_key = 'supersecretkey'
# Настройка Flask-Login
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
# Фейковые пользователи
users = {
"user1": generate_password_hash("password1"),
"user2": generate_password_hash("password2")
}
# Модель пользователя
class User(UserMixin):
def __init__(self, username):
self.id = username
@login_manager.user_loader
def load_user(user_id):
if user_id in users:
return User(user_id)
return None
# Страница входа
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if username in users and check_password_hash(users[username], password):
user = User(username)
login_user(user)
return redirect(url_for('dashboard'))
flash('Неверный логин или пароль')
return render_template('login.html')
# Страница выхода
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('login'))
# Защищенная страница
@app.route('/dashboard')
@login_required
def dashboard():
return f'Привет, {current_user.id}! Добро пожаловать в панель управления.'
if __name__ == '__main__':
app.run(debug=True)
Объяснение кода:
- Flask-Login: Управляет сессиями пользователей.
- werkzeug.security: Шифрует пароли.
- login_required: Защищает страницы от доступа без входа в систему.
Результат: После ввода правильного логина и пароля открывается защищенная страница.
Ограничение доступа к Dash-приложению
Интеграция с Flask-Login:
from dash import Dash, html, dcc
from flask import Flask
from flask_login import LoginManager, UserMixin, login_required
# Flask-приложение
server = Flask(__name__)
server.secret_key = 'supersecretkey'
# Настройка Flask-Login
login_manager = LoginManager()
login_manager.init_app(server)
login_manager.login_view = '/' # Переход на главную страницу для логина
# Модель пользователя
class User(UserMixin):
def __init__(self, username):
self.id = username
@login_manager.user_loader
def load_user(user_id):
return User(user_id)
# Dash-приложение с защитой
app = Dash(__name__, server=server, url_base_pathname='/dashboard/')
app.layout = html.Div([
html.H1('Добро пожаловать в защищенное Dash-приложение!'),
dcc.Graph(figure={'data': [{'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar'}]})
])
@server.route('/')
def index():
return '<h1>Страница логина (заглушка)</h1>'
@server.route('/dashboard/')
@login_required
def protected_dashboard():
return app.index() # Показываем Dash-приложение только авторизованным пользователям
if __name__ == '__main__':
server.run(debug=True)
Объяснение кода:
- login_required: Защищает маршрут
/dashboard/
. - Пользователи без входа перенаправляются на страницу логина.
- Dash-приложение открывается только для авторизованных пользователей.
Управление правами пользователей
Пример добавления ролей:
roles = {
'user1': 'admin',
'user2': 'viewer'
}
@app.route('/admin')
@login_required
def admin():
if roles[current_user.id] == 'admin':
return 'Добро пожаловать, администратор!'
return 'Доступ запрещен.'
Результат: Доступ на страницу /admin
открыт только для пользователей с ролью ‘admin’.
Задание 13.
- Добавьте формы регистрации и восстановления пароля.
- Реализуйте страницу управления пользователями с ролями (admin/viewer).
- Добавьте защищенные маршруты в Dash с разными уровнями доступа.
На следующем занятии мы разберем развертывание Flask-Dash-приложения на сервере.
Демо-проект: Визуализация туристической инфраструктуры России
Функционал приложения
Главная страница
- Форма авторизации для входа в систему.
- Переходы к дашбордам по регионам и их характеристикам.
Дашборд 1: Карта России с границами регионов и тепловой картой
- Выбор данных для построения тепловой карты:
- Турпоток в регион
- Средняя оценка сегментов туризма
- Оценка инфраструктуры (проживание, питание, транспорт и др.)
- Уровень безопасности
- Среднее количество ночевок
- Климат (комфортность по шкале 1–5)
- Цены (проживание, питание, перелеты)
- Транспортная доступность
- Кликабельные регионы: переход на дашборд региона.
Дашборд 2: Дашборд региона
- Основные характеристики региона:
- Название и фото.
- Комплексная оценка состояния отрасли (5 звезд), места среди всех регионов и в макрорегионе.
- Оценки сегментов туризма:
- Деловой и научный туризм
- Оздоровительный туризм
- Пляжный отдых (кликабельно для перехода на отдельный дашборд)
- Паломнический туризм
- Познавательный туризм
- Семейный и детский туризм
- Спортивный и экстремальный туризм
- Экологический и походный туризм
- Динамика турпотока:
- График по месяцам за последние 3 года.
- Средняя длительность ночевок:
- График по месяцам.
- Инфраструктура:
- Оценки отелей, питания, транспорта и удобств.
- Климат:
- Графики температуры воздуха и воды, осадков.
- Цены:
- Проживание, перелеты, питание.
- Безопасность:
- Оценка уровня и статистика происшествий.
- Доступность:
- Расстояния до крупных городов, количество транспортных объектов, комплексная оценка.
- Достопримечательности:
- Топ городов по численности населения.
- Топ популярных локаций.
Дашборд 3: Пляжная инфраструктура
- Общая оценка инфраструктуры пляжей:
- Средняя оценка.
- Количество пляжей и сравнение с другими регионами.
- Климатические условия:
- Количество месяцев для купания.
- Средняя температура воздуха и воды.
- Рейтинги пляжей:
- Топы по популярности, состоянию, безопасности, экологии и доступности.
Дизайн пользовательского интерфейса
Главная страница:
- Простая форма логина с полями для ввода логина и пароля.
- Панель навигации для перехода на дашборды.
Карта России:
- Интерактивная тепловая карта с возможностью выбора показателей.
- Всплывающие подсказки с данными по регионам при наведении.
- Кликабельные регионы для перехода в детальные отчеты.
Дашборды:
- Графики и диаграммы:
- Линейные графики (динамика по времени).
- Столбчатые диаграммы (сравнения).
- Круговые диаграммы (доли сегментов).
- Таблицы и списки:
- Рейтинги локаций и объектов.
- Карточки с оценками:
- Комплексные оценки в виде звезд.
Данные для визуализации
Источники данных:
- Базы данных: PostgreSQL / SQLite.
- Геоданные: GeoJSON с границами регионов.
- Статистические показатели:
- Турпоток.
- Средние оценки сегментов туризма.
- Инфраструктура (отели, транспорт, питание).
- Цены и доступность.
- Криминальная статистика.
- Климатические данные.
Структура данных в базе:
- Регионы:
- ID региона, название, координаты границ.
- Туризм:
- Турпоток, оценки сегментов.
- Инфраструктура:
- Проживание, транспорт, удобства.
- Безопасность:
- Происшествия, уровень преступности.
- Климат:
- Температуры, осадки.
- Цены:
- Средние стоимости.
Этот проект станет демонстрацией комплексного подхода к анализу и визуализации данных, предлагая удобные и информативные инструменты для оценки туристического потенциала регионов России.
Примерная реализация проекта
Установка необходимых библиотек:
pip install flask flask-login flask-sqlalchemy dash plotly pandas geopandas
Код приложения
from flask import Flask, render_template, redirect, url_for, request
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from dash import Dash, html, dcc, Input, Output, State
import plotly.express as px
import pandas as pd
import geopandas as gpd
# Flask-приложение
server = Flask(__name__)
server.secret_key = 'supersecretkey'
server.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
server.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# Настройка базы данных
db = SQLAlchemy(server)
# Модель данных
class Region(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
population = db.Column(db.Integer, nullable=False)
tourism_score = db.Column(db.Float, nullable=False)
climate_score = db.Column(db.Float, nullable=False)
infrastructure_score = db.Column(db.Float, nullable=False)
safety_score = db.Column(db.Float, nullable=False)
avg_price = db.Column(db.Float, nullable=False)
class Climate(db.Model):
id = db.Column(db.Integer, primary_key=True)
region_id = db.Column(db.Integer, db.ForeignKey('region.id'), nullable=False)
month = db.Column(db.String(20), nullable=False)
temperature = db.Column(db.Float, nullable=False)
rainfall = db.Column(db.Float, nullable=False)
# Flask-Login
login_manager = LoginManager()
login_manager.init_app(server)
login_manager.login_view = 'login'
class User(UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True, nullable=False)
password = db.Column(db.String(50), nullable=False)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# Главная страница с авторизацией
@server.route('/', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if username == 'admin' and password == 'password':
user = User()
user.id = 1
login_user(user)
return redirect('/dashboard')
return render_template('login.html')
@server.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('login'))
# Dash-приложение
app = Dash(__name__, server=server, url_base_pathname='/dashboard/')
# Макет Dash
app.layout = html.Div([
html.H1('Туристическая инфраструктура регионов России'),
dcc.Dropdown(
id='metric-dropdown',
options=[
{'label': 'Турпоток', 'value': 'tourism_score'},
{'label': 'Климат', 'value': 'climate_score'},
{'label': 'Инфраструктура', 'value': 'infrastructure_score'},
{'label': 'Безопасность', 'value': 'safety_score'},
{'label': 'Средняя цена', 'value': 'avg_price'}
],
value='tourism_score'
),
dcc.Graph(id='map'),
html.H2('Динамика турпотока'),
dcc.Graph(id='line-chart'),
html.H2('Оценки сегментов туризма'),
dcc.Graph(id='pie-chart'),
html.H2('Инфраструктура и безопасность'),
dcc.Graph(id='bar-chart'),
dcc.Store(id='selected-region')
])
@app.callback(
[Output('map', 'figure'),
Output('line-chart', 'figure'),
Output('pie-chart', 'figure'),
Output('bar-chart', 'figure')],
[Input('metric-dropdown', 'value'),
State('selected-region', 'data')]
)
def update_charts(selected_metric, region_id):
# Тепловая карта
map_fig = px.choropleth(
pd.read_sql(Region.__table__.select(), db.engine),
locations='id',
color=selected_metric,
hover_name='name',
title='Тепловая карта регионов России'
)
# Линейный график (пример для климата)
if region_id:
climate_data = pd.read_sql(Climate.__table__.select().where(Climate.region_id == region_id), db.engine)
line_fig = px.line(climate_data, x='month', y='temperature', title='Климат региона')
else:
line_fig = px.line()
# Круговая диаграмма
pie_fig = px.pie(map_fig, values=selected_metric, names='name', title='Сегменты туризма')
# Бар-чарт
bar_fig = px.bar(map_fig, x='name', y=['infrastructure_score', 'safety_score'],
barmode='group', title='Инфраструктура и безопасность')
return map_fig, line_fig, pie_fig, bar_fig
if __name__ == '__main__':
db.create_all()
server.run(debug=True)
Дальнейшие шаги:
- Добавить роли пользователей и управление правами доступа.