Фреймворки Plotly и Dash

Содержание

Введение в визуализацию данных

Что такое визуализация данных?

Визуализация данных — это процесс преобразования чисел и текстовой информации в графики, диаграммы и другие наглядные изображения. Она помогает быстро понять, какие закономерности или тенденции скрываются в данных.

Почему это важно?

  1. Понятность: Графики проще анализировать, чем таблицы с числами.
  2. Принятие решений: Руководителям легче принимать решения на основе наглядных диаграмм.
  3. Презентации: Визуализация делает доклады более интересными и убедительными.
  4. Поиск ошибок: Графики помогают обнаружить аномалии в данных.

Пример

Представьте, что у вас есть таблица с данными о продажах за год. Если вы построите линейный график, вы сразу увидите, в какие месяцы продажи были самыми высокими.


Популярные библиотеки для визуализации в Python

1. Matplotlib

  • Самая старая и гибкая библиотека.
  • Подходит для простых графиков.
  • Пример кода:
import matplotlib.pyplot as plt

x = [1, 2, 3, 4]
y = [10, 20, 25, 30]

plt.plot(x, y)
plt.show()

График matplotlib

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

График seaborn

3. Plotly

  • Создает интерактивные графики (можно увеличивать, перемещать и настраивать).
  • Подходит для работы в веб-приложениях.
  • Прост в использовании и поддерживает 3D-графику.
  • Пример кода (будет разобран ниже).

Введение в Plotly

Plotly — это библиотека для создания интерактивных графиков в Python. Она особенно удобна для работы с данными в веб-приложениях.

Преимущества Plotly

  1. Интерактивность: Можно увеличивать графики, перемещать их и выделять области.
  2. Простота интеграции с веб-приложениями: Работает с Flask и другими фреймворками.
  3. Поддержка множества типов графиков: Линейные, гистограммы, 3D-графики, тепловые карты и диаграммы на карте мира.
  4. Удобная работа с большими данными.

Установка 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

Разбор примера:

  1. Импорт библиотеки: Используем plotly.express для простоты кода.
  2. Данные: Создаем словарь с данными о месяцах и продажах.
  3. График: Функция px.line() строит линейный график. Мы передаем данные и указываем, какие столбцы использовать для осей X и Y.
  4. Сохранение графика: fig.write_html('graph.html') сохраняет график в файл html.

Задание1

  1. Установите библиотеку Plotly, если она еще не установлена.
  2. Постройте диаграмму (гистограмму) с произвольными данными о расходах по категориям за месяц (например, продукты, транспорт, развлечения).
  3. Экспериментируйте с изменением цветов и подписей осей в графике.

Пример для старта:

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.

Линейный график plotly

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

Scatter Plot — Точечный график

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

Scatter 3D — Трехмерный точечный график

3. Scatter Polar — Полярный точечный график

fig = px.scatter_polar(df, r='sepal_length', theta='sepal_width', color='species', title='Полярный график (Scatter Polar)')
fig.show()

Scatter Polar — Полярный точечный график

4. Scatter Ternary — Тернарный точечный график

fig = px.scatter_ternary(df, a='sepal_length', b='sepal_width', c='petal_length', color='species', title='Тернарный график (Scatter Ternary)')
fig.show()

Scatter Ternary — Тернарный точечный график

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

Scatter Geo — Географический точечный график

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

Scatter Geo — Географический точечный график

7. Line Plot — Линейный график

df = px.data.gapminder()
fig = px.line(df, x='year', y='gdpPercap', color='continent', title='Линейный график (Line Plot)')
fig.show()

Line Plot — Линейный график

8. Line 3D — Трехмерный линейный график

fig = px.line_3d(df, x='year', y='gdpPercap', z='pop', color='continent', title='3D Линейный график (Line 3D)')
fig.show()

Line 3D — Трехмерный линейный график

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

Line Polar — Полярный линейный график

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

Line Ternary — Тернарный линейный график

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

Line Ternary — Тернарный линейный график

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

Area Plot — График областей

14. Bar Plot — Столбчатый график

fig = px.bar(df, x='continent', y='pop', color='continent', title='Столбчатый график (Bar Plot)')
fig.show()

Bar Plot — Столбчатый график

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

Timeline Plot — Временная шкала

16. Polar Bar Plot — Полярный столбчатый график

fig = px.bar_polar(df, r='pop', theta='continent', color='continent', title='Полярный столбчатый график (Polar Bar Plot)')
fig.show()

Polar Bar Plot — Полярный столбчатый график

17. Violin Plot — Виолончельный график

fig = px.violin(df, x='continent', y='lifeExp', color='continent', title='Виолончельный график (Violin Plot)')
fig.show()

Violin Plot — Виолончельный график

18. Box Plot — Коробчатый график

fig = px.box(df, x='continent', y='lifeExp', color='continent', title='Коробчатый график (Box Plot)')
fig.show()

Box Plot — Коробчатый график

19. Histogram — Гистограмма

fig = px.histogram(df, x='lifeExp', color='continent', title='Гистограмма (Histogram)')
fig.show()

Histogram — Гистограмма

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

Pie Plot — Круговая диаграмма

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

Treemap — Иерархическое дерево

22. Sunburst — Круговая иерархия

fig = px.sunburst(df, path=['continent', 'country'], values='pop', title='Круговая иерархия (Sunburst)')
fig.show()

Sunburst — Круговая иерархия

23. Icicle — Ледяная диаграмма

fig = px.icicle(df, path=['continent', 'country'], values='pop', title='Ледяная диаграмма (Icicle)')
fig.show()

Icicle — Ледяная диаграмма

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

Funnel Plot — Воронка

25. Funnel Area Plot — Площадь воронки

fig = px.funnel_area(names=['A', 'B', 'C'], values=[10, 20, 30], title='Площадь воронки (Funnel Area)')
fig.show()

Funnel Area Plot — Площадь воронки

26. Scatter Matrix — Матрица диаграмм рассеяния

fig = px.scatter_matrix(df, dimensions=['sepal_length', 'sepal_width', 'petal_length'], color='species', title='Матрица диаграмм рассеяния (Scatter Matrix)')
fig.show()

Scatter Matrix — Матрица диаграмм рассеяния

27. Parallel Coordinates — Параллельные координаты

df = px.data.iris()
fig = px.parallel_coordinates(df, color='species_id', title='Параллельные координаты (Parallel Coordinates)')
fig.show()

Parallel Coordinates — Параллельные координаты

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

 Parallel Categories — Параллельные категории

29. Choropleth — Картограмма

df = px.data.gapminder()
fig = px.choropleth(df, locations='iso_alpha', color='lifeExp', hover_name='country', title='Картограмма (Choropleth)')
fig.show()

Choropleth — Картограмма

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

Choropleth Mapbox — Картограмма на Mapbox

31. Density Contour — Контур плотности

fig = px.density_contour(df, x='sepal_length', y='sepal_width', title='Контур плотности (Density Contour)')
fig.show()

Density Contour — Контур плотности

32. Density Heatmap — Тепловая карта плотности

fig = px.density_heatmap(df, x='sepal_length', y='sepal_width', title='Тепловая карта плотности (Density Heatmap)')
fig.show()

Density Heatmap — Тепловая карта плотности

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

Density Mapbox — Карта плотности на Mapbox

34. Imshow — Изображение

import numpy as np
img = np.random.rand(10, 10)
fig = px.imshow(img, title='Изображение (Imshow)')
fig.show()

Imshow — Изображение

Настройка внешнего вида графиков

Изменение цвета графиков

Можно задать цвета вручную:

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.

  1. Создайте свой график для анализа расходов или доходов за неделю. Используйте разные типы графиков (линейный, столбчатый или круговой).
  2. Добавьте цвета, подписи и легенды.
  3. Сохраните график в 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()

Результат: Два графика (линейный и столбчатый) в одном окне, расположенные в ряд.

Работа с подграфиками (subplots)


Анимации и интерактивность в графиках

Анимации

Анимации помогают показать, как данные изменяются со временем. Рассмотрим пример графика, который анимируется по кадрам:

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.

  1. Создайте подграфик из двух графиков: линейного и круговой диаграммы.
  2. Постройте анимированный график, показывающий изменения температуры в вашем городе по месяцам.
  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()

Результат: Линейный график, показывающий рост продаж по датам.

Линейный график с данными из DataFrame


Пример 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.

  1. Загрузите данные из CSV-файла в DataFrame.
  2. Постройте линейный график для анализа изменений данных во времени.
  3. Создайте гистограмму с группировкой по категориям.
  4. Добавьте фильтр для динамического отображения данных на графике.

Что такое Dash и для чего он используется

Dash — это фреймворк на языке Python, который помогает создавать интерактивные веб-приложения для визуализации данных.

Почему Dash удобен?

  1. Простота: Не нужно знать HTML, CSS и JavaScript. Приложения создаются на Python.
  2. Интерактивность: Можно добавлять кнопки, выпадающие списки и графики, которые меняются в ответ на действия пользователя.
  3. Интеграция с Plotly: Dash работает с Plotly, поэтому можно легко строить интерактивные графики.
  4. Подходит для аналитики: Используется для создания дашбордов (информационных панелей) с аналитическими отчетами.

Установка и настройка 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)

Разбор примера:

  1. Dash(__name__) — создает приложение Dash.
  2. layout — определяет внешний вид страницы. В данном случае это заголовок (H1) и абзац (P).
  3. 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)

Разбор примера:

  1. dcc.Graph — компонент Dash для отображения графиков.
  2. figure=fig — передает созданный график в компонент для отображения.

Результат: После запуска приложения в браузере откроется столбчатая диаграмма с продажами фруктов.

Интеграция plotly и dash


Задание 5.

  1. Установите библиотеку Dash, если она еще не установлена.
  2. Напишите приложение Dash с таблицей данных и добавьте график на основе этой таблицы.
  3. Добавьте интерактивный элемент — кнопку или выпадающий список.

Пример:

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)

Результат: На веб-странице появится заголовок, абзац и график с данными.

Пример простого макета Dash


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)

Разбор примера:

  1. dcc.Input — поле ввода текста.
  2. html.Div — вывод результата.
  3. callback — связывает ввод и вывод.
  4. Input — отслеживает изменения в поле ввода.
  5. 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')
])

Результат: Появятся заголовки, абзац текста и кнопка.

Примеры HTML-компонентов


Введение в 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)

Разбор примера:

  1. Dropdown — выпадающий список с тремя вариантами.
  2. Callback — обновляет текст при выборе значения.

Результат: При выборе цвета в выпадающем списке отображается текст с выбранным значением.

Dash Core Components Dash Core Components


Задание 6.

  1. Создайте Dash-приложение с двумя элементами:
    • Полем ввода (dcc.Input).
    • Выпадающим списком (dcc.Dropdown).
  2. Добавьте обработчик, который будет объединять введенные данные и выбранный элемент в одно сообщение.

Пример вывода:

Вы выбрали: Зеленый, и ввели текст: Пример.

Что такое Callback в Dash?

Callback — это механизм, который связывает действия пользователя с изменениями в интерфейсе. Например, когда пользователь выбирает значение из выпадающего списка, информация в графике автоматически обновляется.

Как это работает?

Callback состоит из двух частей:

  1. Input — отслеживает изменения в элементах (например, текст в поле ввода или выбор из списка).
  2. 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)

Объяснение кода:

  1. dcc.Input — поле ввода текста.
  2. html.Div — вывод результата.
  3. Callback — связывает ввод и вывод.
  4. Функция update_output вызывается каждый раз, когда меняется значение в поле ввода.

Результат:

Текст, введенный в поле, отображается сразу под ним.

Простой Callback с текстовым вводом


Пример 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)

Объяснение кода:

  1. Dropdown — выпадающий список для выбора месяца.
  2. Graph — отображает график.
  3. Callback — обновляет данные в графике при смене месяца.
  4. Функция 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)

Объяснение кода:

  1. Input — отслеживает значения двух полей ввода.
  2. Output — обновляет текст с результатом.
  3. Функция update_sum вычисляет сумму двух чисел и выводит её.

Результат:

После ввода двух чисел появляется их сумма.

Обработка нескольких входов (Inputs)

Задание 7.

  1. Создайте приложение с ползунком (dcc.Slider) и графиком.
  2. Реализуйте обновление графика при изменении значения ползунка.

 

Примерный макет:

  • Ползунок для выбора диапазона значений.
  • График, отображающий данные в выбранном диапазоне.

Хранение состояния приложения

Что такое состояние приложения?

Состояние — это данные, которые сохраняются между взаимодействиями пользователя с приложением. Например, выбранные параметры, фильтры или результаты поиска.

Варианты хранения состояния в Dash:

  1. Frontend (на стороне клиента): Данные хранятся в браузере пользователя.
  2. 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)

Объяснение кода:

  1. State — хранит текущее значение поля ввода, пока кнопка не будет нажата.
  2. Значение сохраняется при нажатии кнопки и отображается на экране.

Результат: Текст отображается только после нажатия кнопки «Сохранить».


Оптимизация производительности 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)

Объяснение кода:

  1. Flask-Caching — добавляет кэширование данных.
  2. Функция slow_function вызывается только при изменении входных данных.
  3. Если данные уже в кэше, они возвращаются мгновенно.

Результат: Быстрое обновление результатов после первого расчета.


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)

Объяснение кода:

  1. Dash добавляет функцию загрузки файлов.
  2. Файл загружается по нажатию кнопки.

Результат: Кнопка позволяет скачать файл с сервера.

Загрузка файлов

Пример: Анимированный график с использованием 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)

Разбор примера:

  1. DashProxy — используется вместо стандартного Dash.
    Позволяет включать расширенные возможности, такие как MultiplexerTransform.
  2. MultiplexerTransform — добавляет поддержку множественных обновлений одного и того же Output (например, если график должен обновляться от нескольких Inputs).
  3. dcc.Dropdown — позволяет выбирать континент для фильтрации данных.
  4. dcc.Slider — управляет выбором года.
  5. px.scatter — создает интерактивный график с пузырьками, размер которых зависит от населения.

Результат:

  • При выборе континента и года на выпадающем списке и слайдере график автоматически обновляется.
  • Показывается распределение стран по ожидаемой продолжительности жизни и ВВП.

Анимированный график с использованием dash-extensions


Задание 8.

  1. Добавьте в приложение хранение состояния при переключении вкладок.
  2. Реализуйте кэширование данных для ускорения работы приложения.
  3. Добавьте возможность загрузки файла через Dash Extensions.

Обзор архитектуры Flask-приложений

Что такое Flask?

Flask — это фреймворк для создания веб-приложений на языке Python. Он минималистичный, гибкий и часто используется для создания API и серверов приложений.

Основные компоненты Flask:

  1. Маршруты (Routes): Определяют, какие функции обрабатывают запросы по конкретным адресам URL.
  2. Контроллеры (View Functions): Логика обработки запросов и возврата ответов пользователю.
  3. Шаблоны (Templates): HTML-файлы с динамическими элементами, которые формируются на сервере.
  4. Статика (Static Files): CSS, JavaScript и изображения.
  5. Расширения (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: возможности и ограничения

Возможности:

  1. Интеграция Dash в Flask: Можно добавить интерактивные графики в существующее Flask-приложение.
  2. Общий сервер: Flask и Dash могут работать на одном сервере, используя общие ресурсы.
  3. Авторизация и управление пользователями: Flask может обрабатывать авторизацию, а Dash — отображать данные.
  4. Взаимодействие с базами данных: Flask может запрашивать данные и передавать их в графики Dash.

Ограничения:

  1. Разделение логики: Flask обрабатывает маршруты и данные, а Dash управляет графическим интерфейсом.
  2. Производительность: При большом количестве пользователей может потребоваться оптимизация.
  3. Сложность настройки: Требуется интеграция маршрутов и управление состояниями между двумя фреймворками.

Установка и настройка взаимодействия 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)

Объяснение кода:

  1. Flask: Создается основное приложение для обработки маршрутов.
  2. Dash: Добавляется как компонент Flask с собственным URL (/dashboard/).
  3. Интерактивный график: Отображается в разделе Dash.

Результат:


Задание 9.

  1. Добавьте в Flask маршрут для страницы «Контакты» с текстом и ссылкой для возврата на главную.
  2. Добавьте в Dash второй график, доступный по новому URL /dashboard/second. Используйте разные данные.
  3. Реализуйте переходы между 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)

Результат:


Маршрутизация и управление 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)

Объяснение кода:

  1. Передача данных из Flask: Данные создаются в Flask и передаются в Dash через переменную df.
  2. Dropdown: Пользователь выбирает месяц из списка.
  3. График: Данные обновляются на основе выбора.

Результат:

  • Динамический график обновляется при выборе другого месяца в выпадающем списке.

Задание 10.

  1. Добавьте страницу «Контакты» в Flask.
  2. Добавьте второй график в Dash на отдельном маршруте (например, /dashboard/second/).
  3. Реализуйте кнопку для скачивания данных в формате 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)

Объяснение кода:

  1. Подключение базы данных: Используется SQLAlchemy для работы с SQLite.
  2. Чтение данных: Выполняется запрос к базе данных, результат преобразуется в DataFrame.
  3. График: Строится столбчатая диаграмма цен продуктов с помощью 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)

Объяснение кода:

  1. dcc.Interval: Таймер обновляет график каждые 2 секунды.
  2. Обновление данных: Запрос к базе выполняется в каждом обновлении.
  3. Динамическое обновление графика: График перерисовывается с новыми данными.

Результат: График автоматически обновляется при изменении данных в базе.

Обновление графиков на основе данных из базыОбновление графиков на основе данных из базыОбновление графиков на основе данных из базыОбновление графиков на основе данных из базы


Задание 12.

  1. Добавьте новый столбец в таблицу, например, «Категория» и отобразите данные с группировкой по категориям.
  2. Реализуйте фильтр в Dash для выбора конкретной категории.
  3. Добавьте возможность добавления новых данных в базу через 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)

Объяснение кода:

  1. Flask-Login: Управляет сессиями пользователей.
  2. werkzeug.security: Шифрует пароли.
  3. 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)

Объяснение кода:

  1. login_required: Защищает маршрут /dashboard/.
  2. Пользователи без входа перенаправляются на страницу логина.
  3. Dash-приложение открывается только для авторизованных пользователей.

Управление правами пользователей

Пример добавления ролей:

roles = {
    'user1': 'admin',
    'user2': 'viewer'
}

@app.route('/admin')
@login_required
def admin():
    if roles[current_user.id] == 'admin':
        return 'Добро пожаловать, администратор!'
    return 'Доступ запрещен.'

Результат: Доступ на страницу /admin открыт только для пользователей с ролью ‘admin’.


Задание 13.

  1. Добавьте формы регистрации и восстановления пароля.
  2. Реализуйте страницу управления пользователями с ролями (admin/viewer).
  3. Добавьте защищенные маршруты в Dash с разными уровнями доступа.

На следующем занятии мы разберем развертывание Flask-Dash-приложения на сервере.

Демо-проект: Визуализация туристической инфраструктуры России

Функционал приложения

Главная страница

  • Форма авторизации для входа в систему.
  • Переходы к дашбордам по регионам и их характеристикам.

Дашборд 1: Карта России с границами регионов и тепловой картой

  • Выбор данных для построения тепловой карты:
    1. Турпоток в регион
    2. Средняя оценка сегментов туризма
    3. Оценка инфраструктуры (проживание, питание, транспорт и др.)
    4. Уровень безопасности
    5. Среднее количество ночевок
    6. Климат (комфортность по шкале 1–5)
    7. Цены (проживание, питание, перелеты)
    8. Транспортная доступность
  • Кликабельные регионы: переход на дашборд региона.

Дашборд 2: Дашборд региона

  • Основные характеристики региона:
    • Название и фото.
    • Комплексная оценка состояния отрасли (5 звезд), места среди всех регионов и в макрорегионе.
  • Оценки сегментов туризма:
    • Деловой и научный туризм
    • Оздоровительный туризм
    • Пляжный отдых (кликабельно для перехода на отдельный дашборд)
    • Паломнический туризм
    • Познавательный туризм
    • Семейный и детский туризм
    • Спортивный и экстремальный туризм
    • Экологический и походный туризм
  • Динамика турпотока:
    • График по месяцам за последние 3 года.
  • Средняя длительность ночевок:
    • График по месяцам.
  • Инфраструктура:
    • Оценки отелей, питания, транспорта и удобств.
  • Климат:
    • Графики температуры воздуха и воды, осадков.
  • Цены:
    • Проживание, перелеты, питание.
  • Безопасность:
    • Оценка уровня и статистика происшествий.
  • Доступность:
    • Расстояния до крупных городов, количество транспортных объектов, комплексная оценка.
  • Достопримечательности:
    • Топ городов по численности населения.
    • Топ популярных локаций.

Дашборд 3: Пляжная инфраструктура

  • Общая оценка инфраструктуры пляжей:
    • Средняя оценка.
    • Количество пляжей и сравнение с другими регионами.
  • Климатические условия:
    • Количество месяцев для купания.
    • Средняя температура воздуха и воды.
  • Рейтинги пляжей:
    • Топы по популярности, состоянию, безопасности, экологии и доступности.

Дизайн пользовательского интерфейса

Главная страница:

  • Простая форма логина с полями для ввода логина и пароля.
  • Панель навигации для перехода на дашборды.

Карта России:

  • Интерактивная тепловая карта с возможностью выбора показателей.
  • Всплывающие подсказки с данными по регионам при наведении.
  • Кликабельные регионы для перехода в детальные отчеты.

Дашборды:

  • Графики и диаграммы:
    • Линейные графики (динамика по времени).
    • Столбчатые диаграммы (сравнения).
    • Круговые диаграммы (доли сегментов).
  • Таблицы и списки:
    • Рейтинги локаций и объектов.
  • Карточки с оценками:
    • Комплексные оценки в виде звезд.

Данные для визуализации

Источники данных:

  • Базы данных: PostgreSQL / SQLite.
  • Геоданные: GeoJSON с границами регионов.
  • Статистические показатели:
    1. Турпоток.
    2. Средние оценки сегментов туризма.
    3. Инфраструктура (отели, транспорт, питание).
    4. Цены и доступность.
    5. Криминальная статистика.
    6. Климатические данные.

Структура данных в базе:

  1. Регионы:
    • ID региона, название, координаты границ.
  2. Туризм:
    • Турпоток, оценки сегментов.
  3. Инфраструктура:
    • Проживание, транспорт, удобства.
  4. Безопасность:
    • Происшествия, уровень преступности.
  5. Климат:
    • Температуры, осадки.
  6. Цены:
    • Средние стоимости.

Этот проект станет демонстрацией комплексного подхода к анализу и визуализации данных, предлагая удобные и информативные инструменты для оценки туристического потенциала регионов России.

Примерная реализация проекта

Установка необходимых библиотек:

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)

Дальнейшие шаги:

  1. Добавить роли пользователей и управление правами доступа.
Понравилась статья? Поделиться с друзьями:
Школа Виктора Комлева
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.