Для финального проекта по курсу «Программирование для креативных индустрий» я выбрала данные по водоемам с общественными пространствами с официального портала мэра Москвы, потому что наличие подобных мест благотворно влияет на жизнь людей, и я решила проанализировать ситуацию в своем городе.
Процесс работы и ее результат я решила презентовать в формате некой истории, сопровождаемой рядом изображений, сгенерированных в Midjourney
История

В семье проживающей в Челябинске повысили на работе отца, вследствие чего его переводят в Москву и вся семья переезжает с ним.
Семья решила, что для них принципиально наличие водоема поблизости с их будущим домом. Поэтому отец составил диаграмму, показывающую количество водоемов на административный округ.
Первый график
Он использовал следующий код: import matplotlib.pyplot as plt
Данные из таблицы
административные_округа = [ "Центральный", "Северный", "Восточный", "Западный", "Южный", "Юго-Восточный", "Юго-Западный", "Северо-Западный", "Северо-Восточный", "Зеленоградский", "Троицкий", "Новомосковский" ]
количество_водоемов = [10, 7, 13, 13, 14, 6, 15, 22, 11, 7, 3, 2]
Настройка размера графика
plt.figure(figsize=(12, 6))
Создание гистограммы
plt.bar(административные_округа, количество_водоемов, color='skyblue', edgecolor='black')
Настройка заголовка и меток
plt.title('Количество водоёмов по административным округам', fontsize=16, fontweight='bold') plt.xlabel('Административный округ', fontsize=12) plt.ylabel('Количество водоёмов', fontsize=12)
Поворот подписей по оси X для удобства чтения
plt.xticks(rotation=45, ha='right', fontsize=10)
Автоматическая подгонка макета
plt.tight_layout()
Отображение графика
plt.show()
Второй график
Семья подумала и решила, что им предпочтительно жить в не густонаселённом округе, так как там спокойней. Отец составил диаграмму корреляции населения и водоемов.
import matplotlib.pyplot as plt import numpy as np from scipy import stats
Данные из таблицы
округа = [ "Центральный", "Северный", "Западный", "Южный", "Юго-Восточный", "Юго-Западный", "Северо-Западный", "Северо-Восточный", "Зеленоградский", "Троицкий", "Новомосковский", "Восточный" ]
количество_водоемов = [10, 7, 13, 14, 6, 15, 22, 11, 7, 3, 2, 13] население = [779352, 1186128, 1395986, 1791187, 1431746, 1446432, 1011387, 1432571, 250173, 130315, 275508, 1524265]
Рассчитываем коэффициент корреляции
correlation = np.corrcoef(население, количество_водоемов)[0, 1]
Настройка размера графика
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))
Левая панель: scatter plot с подписями
for i, округ in enumerate(округа): ax1.scatter(население[i], количество_водоемов[i], s=100, alpha=0.7, edgecolors='black') ax1.annotate(округ, (население[i], количество_водоемов[i]), xytext=(5, 5), textcoords='offset points', fontsize=9)
Линия регрессии
if len(население) > 1: slope, intercept, r_value, p_value, std_err = stats.linregress(население, количество_водоемов) x_line = np.array([min(население), max(население)]) y_line = intercept + slope * x_line ax1.plot(x_line, y_line, color='red', linewidth=2, linestyle='--') ax1.set_xlabel('Население округа', fontsize=12) ax1.set_ylabel('Количество водоёмов', fontsize=12) ax1.set_title(f'Диаграмма рассеяния\nКорреляция: {correlation:.3f}', fontsize=14) ax1.grid(True, alpha=0.3)
Правая панель: таблица с данными для справки
table_data = [] for i in range(len(округа)): table_data.append([округа[i], f"{население[i]:,}", количество_водоемов[i]])
Создаем таблицу
ax2.axis('tight') ax2.axis('off') table = ax2.table(cellText=table_data, colLabels=['Округ', 'Население', 'Водоёмы'], cellLoc='center', loc='center', colWidths=[0.3, 0.3, 0.2])
Стилизация таблицы
table.auto_set_font_size(False) table.set_fontsize(9) table.scale(1.2, 1.5)
Заголовок для таблицы
ax2.set_title('Данные по округам', fontsize=14, pad=20)
plt.suptitle('Анализ зависимости количества водоёмов от населения административных округов', fontsize=16, fontweight='bold', y=1.02) plt.tight_layout() plt.show()
Вывод статистики
print(f"Коэффициент корреляции между населением и количеством водоёмов: {correlation:.3f}") if correlation > 0: print("Положительная корреляция: чем больше населения, тем больше водоёмов.") elif correlation < 0: print("Отрицательная корреляция: чем больше населения, тем меньше водоёмов.") else: print("Корреляция отсутствует.")
Третий график
Сын хочет купаться летом, поэтому папа вывел график, на котором отмечены места для купания.
import matplotlib.pyplot as plt
Данные из таблицы
округа = [ "Центральный", "Северный", "Восточный", "Западный", "Южный", "Юго-Восточный", "Юго-Западный", "Северо-Западный", "Северо-Восточный", "Зеленоградский", "Троицкий", "Новомосковский" ]
общее_количество = [10, 7, 13, 13, 14, 6, 15, 22, 11, 7, 3, 2] с_зоной_купания = [0, 3, 1, 1, 0, 0, 1, 2, 0, 3, 0, 0]
Настройка размера графика
fig, ax = plt.subplots(figsize=(14, 7))
Создание двух наборов столбцов с наложением
x_pos = range(len(округа))
Первый набор столбцов (все водоёмы) - прозрачный и шире
bars1 = ax.bar(x_pos, общее_количество, width=0.8, alpha=0.6, label='Все водоёмы', color='lightblue', edgecolor='black')
Второй набор столбцов (с зоной купания) - непрозрачный и уже
bars2 = ax.bar(x_pos, с_зоной_купания, width=0.5, label='С зоной для купания', color='salmon', edgecolor='black')
Настройка осей и заголовка
ax.set_xlabel('Административный округ', fontsize=12) ax.set_ylabel('Количество водоёмов', fontsize=12) ax.set_title('Количество водоёмов по административным округам', fontsize=16, fontweight='bold') ax.set_xticks(x_pos) ax.set_xticklabels(округа, rotation=45, ha='right', fontsize=10) ax.legend()
Добавление значений на столбцы
for i, (total, with_swim) in enumerate(zip(общее_количество, с_зоной_купания)): if total > 0: ax.text(i, total + 0.1, f'{total}', ha='center', va='bottom', fontsize=9) if with_swim > 0: ax.text(i, with_swim + 0.1, f'{with_swim}', ha='center', va='bottom', fontsize=9, fontweight='bold', color='darkred')
Автоматическая подгонка макета
plt.tight_layout() plt.show()
Четвертый график
Мама хочет, чтобы рядом с водоемом также были места для культурного отдыха. Папа составил следующий код:
import matplotlib.pyplot as plt import numpy as np
Данные из таблицы (исключаем строку "всего")
округа = [ "Центральный", "Северный", "Западный", "Южный", "Юго-Восточный", "Юго-Западный", "Северо-Западный", "Северо-Восточный", "Зеленоградский", "Троицкий", "Новомосковский", "Восточный" ]
всего_водоемов = [10, 7, 13, 14, 6, 15, 22, 11, 7, 3, 2, 13] с_купанием = [0, 3, 1, 0, 0, 1, 2, 0, 3, 0, 0, 1] без_купания = [9, 4, 2, 1, 4, 2, 3, 7, 4, 1, 0, 9] массовый_отдых = [1, 0, 10, 13, 2, 14, 17, 4, 0, 2, 2, 3] # Исправлено название переменной
Проверка: с_купанием + без_купания + массовый_отдых = всего_водоемов
for i in range(len(округа)): if с_купанием[i] + без_купания[i] + массовый_отдых[i] != всего_водоемов[i]: print(f"Несоответствие в {округа[i]}: {с_купанием[i]}+{без_купания[i]}+{массовый_отдых[i]} ≠ {всего_водоемов[i]}")
Настройка размера графика
fig, ax = plt.subplots(figsize=(16, 8))
Позиции для столбцов
x = np.arange(len(округа)) ширина = 0.6
Создание stacked bar chart
p1 = ax.bar(x, с_купанием, ширина, label='С купанием', color='#FF6B6B', edgecolor='black') p2 = ax.bar(x, без_купания, ширина, bottom=с_купанием, label='Без купания', color='#4ECDC4', edgecolor='black') p3 = ax.bar(x, массовый_отдых, ширина, bottom=np.array(с_купанием) + np.array(без_купания), # Исправлено название переменной label='Места массового отдыха', color='#45B7D1', edgecolor='black')
Настройка осей и заголовка
ax.set_xlabel('Административный округ', fontsize=12, fontweight='bold') ax.set_ylabel('Количество объектов', fontsize=12, fontweight='bold') ax.set_title('Распределение водоёмов по категориям по административным округам', fontsize=16, fontweight='bold', pad=20) ax.set_xticks(x) ax.set_xticklabels(округа, rotation=45, ha='right', fontsize=10) ax.legend(loc='upper right')
Добавление подписей для каждого сегмента
def add_labels(bars, bottoms=None): for i, bar in enumerate(bars): height = bar.get_height() if height > 0: # Добавляем только ненулевые значения if bottoms is not None: y = bottoms[i] + height/2 else: y = height/2 ax.text(bar.get_x() + bar.get_width()/2, y, f'{int(height)}', ha='center', va='center', fontsize=8, color='white' if height > max(всего_водоемов)/4 else 'black', fontweight='bold')
Добавление подписей для каждого сегмента
add_labels(p1) add_labels(p2, с_купанием) add_labels(p3, np.array(с_купанием) + np.array(без_купания))
Добавление общего количества над столбцами
for i, total in enumerate(всего_водоемов): ax.text(i, total + 0.5, f'{total}', ha='center', va='bottom', fontsize=10, fontweight='bold', color='#2C3E50')
Добавление сетки
ax.yaxis.grid(True, alpha=0.3, linestyle='--')
Автоматическая подгонка макета
plt.tight_layout() plt.show()
У семьи получилось найти дом мечты, как же хорошо, что папа программист. Сын хорошо закончил школу и поступил в хороший вуз в Москве.
Таблицы, используемые в работе




