Skip to content

8. Разделение экрана: Мультиграфики (Subplots) и матрицы осей ​

Построение сеток графиков side-by-side ​

Концепция многопанельного холста ​

В реальной практике ИИ-инженерии часто требуется сопоставить поведение нескольких процессов одновременно на одном холсте. Например, при обучении классической нейросети стандартным интерфейсом мониторинга является вывод двух окон side-by-side: слева отображается сходимость функции потерь (Loss), а справа — рост метрики точности (Accuracy). Создание отдельных файлов для каждого графика неудобно и мешает быстрому анализу.

Для разделения экрана на несколько независимых координатных зон в функции-фабрике matplotlib.pyplot.subplots(nrows, ncols) настраиваются параметры геометрии сетки:

  • nrows — количество строк графиков на холсте.
  • ncols — количество столбцов графиков в одной строке холста.

Индексация и правила обхода матрицы осей axes ​

Когда мы создаем сетку графиков (например, nrows=2, ncols=2), переменная axes (или ax), возвращаемая фабрикой, становится не одиночным объектом координатной сетки, а двумерной матрицей (массивом numpy.ndarray) ссылок на эти сетки. Чтобы обратиться к конкретному окну для отрисовки, необходимо применить стандартную двумерную индексацию: axes[row_index, column_index].

Если окон много и вы хотите обойти их все в последовательном цикле (например, построить графики для 4 разных гиперпараметров), двумерную матрицу осей перед циклом рекомендуется развернуть в плоский одномерный вектор с помощью унаследованного метода .flatten().

python
import matplotlib.pyplot

# Creating a 2x2 grid of separate plotting windows
fig, axes = matplotlib.pyplot.subplots(nrows=2, ncols=2, figsize=(10, 10))

# Accessing individual windows using multi-dimensional array coordinates
axes[0, 0].plot(, [1.5, 0.8, 0.4])  # Top-left window
axes[0, 1].plot(, [0.5, 0.7, 0.9])  # Top-right window
axes[1, 0].plot(, [10, 20, 30])    # Bottom-left window
axes[1, 1].plot(, [5, 4, 2])       # Bottom-right window

Синхронизация масштабов и выравнивание ​

Зачем нужны параметры sharex и sharey ​

Когда вы сравниваете скорость сходимости нескольких моделей (например, одной архитектуры, обученной с разными значениями Learning Rate), по умолчанию Matplotlib автоматически масштабирует оси каждого окна под его локальный диапазон чисел.

Ловушка автоматического масштабирования

Если на первом графике шкала Y автоматически установится в диапазоне от 0 до 10, а на втором — от 0 до 1, то визуально кривые могут выглядеть одинаково крутыми. Это приведет к ложным выводам, и инженер не заметит, что одна из моделей сходится в 10 раз хуже.

Для обеспечения абсолютно честного визуального сравнения используются параметры сквозной синхронизации:

  • sharex=True — принудительно выстраивает единый масштаб оси X для всех окон сетки.
  • sharey=True — фиксирует единый масштаб оси Y для всех окон сетки, ориентируясь на глобальный экстремум среди всех переданных векторов.

Автоматическое выравнивание отступов через tight_layout ​

При создании плотных сеток графиков подписи осей нижних окон часто накладываются на заголовки верхних окон, превращая холст в нечитаемый хаос. Чтобы дерево объектов автоматически пересчитало координаты, выровняло все отступы и устранило пересечения элементов, в самом конце сборки перед сохранением обязательно вызывается метод холста fig.tight_layout().

python
import matplotlib.pyplot

# Instantiating a fair, synchronized 1x2 charts row layout
fig, axes = matplotlib.pyplot.subplots(nrows=1, ncols=2, sharey=True, figsize=(10, 4))

axes[0].plot(, [0.9, 0.4], label="Model A")
axes[1].plot(, [0.9, 0.1], label="Model B")

# Automatically adjusting spacing boundaries node values
fig.tight_layout()

Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию) ​

1. Создание горизонтальной строки из двух окон ​

Задача: Напишите код, который с помощью matplotlib.pyplot.subplots() создает холст, разделенный на 1 строку и 2 столбца графиков side-by-side. Выведите форму (shape) возвращаемого массива осей, чтобы подтвердить его структуру.

Посмотреть решение
python
import matplotlib.pyplot

# Initializing a 1x2 horizontal plots layout array
fig, axes = matplotlib.pyplot.subplots(nrows=1, ncols=2)
print("Axes array geometric configuration shape:", axes.shape)  # Outputs: (2,)

2. Адресация в квадратной сетке 2x2 ​

Задача: Создайте сетку графиков размером 2 строки на 2 столбца. С помощью точечной двумерной индексации массива осей обратитесь к правому нижнему окну (строка индекс 1, столбец индекс 1) и включите в нем отображение координатной сетки .grid(True).

Посмотреть решение
python
import matplotlib.pyplot

fig, axes = matplotlib.pyplot.subplots(nrows=2, ncols=2)

# Pinpointing the exact bottom-right sub-coordinate zone node
axes[1, 1].grid(True)

3. Циклический обход осей через .flatten() ​

Задача: Создайте сетку графиков 2x2. Разверните матрицу осей в плоский вектор через метод .flatten(). Напишите цикл for ax in axes_flat:, который автоматически включает координатную сетку и добавляет заголовок "Sub-window" во все 4 окна одновременно.

Посмотреть решение
python
import matplotlib.pyplot

fig, axes = matplotlib.pyplot.subplots(nrows=2, ncols=2)

# Collapsing 2D coordinates array down to a flat linear 1D vector stream
axes_flat = axes.flatten()

for ax in axes_flat:
    ax.grid(True)
    ax.set_title("Sub-window")

4. Жесткая синхронизация вертикальной шкалы ​

Задача: Напишите команду инициализации сетки из 1 строки и 3 столбцов графиков, добавив параметр, который заставит все 3 окна иметь строго одинаковый масштаб по вертикальной оси цен или вероятностей Y.

Посмотреть решение
python
import matplotlib.pyplot

# Forcing unified y-axis bounding scale coordinates across all row items
fig, axes = matplotlib.pyplot.subplots(nrows=1, ncols=3, sharey=True)

5. Применение tight_layout для предотвращения наложений ​

Задача: Напишите шаблон бэкенд-скрипта, который создает плотную сетку графиков 3x1 (3 строки, 1 столбец). Добавьте в код строку вызова метода холста, который автоматически пересчитает геометрию отступов, чтобы подписи шкал не пересекались.

Посмотреть решение
python
import matplotlib.pyplot

fig, axes = matplotlib.pyplot.subplots(nrows=3, ncols=1)

# Enforcing strict boundaries recalculation before exporting
fig.tight_layout()

Упражнения смешанные (5 шт) (включают материал прошлых уроков) ​

6. Мониторинг Loss и Accuracy на двух панелях side-by-side из логов Pandas ​

Задача: Загрузите лог обучения нейросети из таблицы df_metrics = pandas.DataFrame({"loss": [0.95, 0.42, 0.15], "accuracy": [0.45, 0.78, 0.94], "epoch":}) (Урок 5 модуля Pandas). Настройте Matplotlib для работы без вывода графического интерфейса (Урок 3 модуля Matplotlib). Создайте холст, разделенный на 1 строку и 2 столбца графиков (Урок 8 модуля Matplotlib). В первом окне (axes[0]) постройте график линии "loss" от "epoch" синего цвета (Урок 4). Во втором окне (axes[1]) постройте график линии "accuracy" от "epoch" зеленого цвета. Подпишите индивидуальные оси и заголовки окон (Урок 4). Вызовите команду автоматического выравнивания отступов (Урок 8) и сохраните итоговую панель мониторинга в файл "training_dashboard.png" (Урок 3).

Посмотреть решение
python
import matplotlib
# Locking non-interactive backend configurations first (Lesson 3)
matplotlib.use('Agg')
import matplotlib.pyplot
import pandas

df_metrics = pandas.DataFrame({"loss": [0.95, 0.42, 0.15], "accuracy": [0.45, 0.78, 0.94], "epoch":})

# Instantiating a 1x2 layout dashboard mesh (Lesson 8)
fig, axes = matplotlib.pyplot.subplots(nrows=1, ncols=2, figsize=(12, 5))

# Plotting into the left Loss panel (Lesson 2 & Lesson 4)
axes[0].plot(df_metrics["epoch"], df_metrics["loss"], color="blue", marker="o", label="Train Loss")
axes[0].set_title("Loss Convergence Curve")
axes[0].set_xlabel("Epochs")
axes[0].set_ylabel("Loss Magnitude")
axes[0].grid(True)

# Plotting into the right Accuracy panel (Lesson 2 & Lesson 4)
axes[1].plot(df_metrics["epoch"], df_metrics["accuracy"], color="green", marker="s", label="Train Accuracy")
axes[1].set_title("Accuracy Performance Curve")
axes[1].set_xlabel("Epochs")
axes[1].set_ylabel("Accuracy Score")
axes[1].grid(True)

# Resolving sub-plots spacing overlaps (Lesson 8)
fig.tight_layout()

# Save final asset block straight to disk paths (Lesson 3)
fig.savefig("training_dashboard.png")

7. Сетка 2x2 для сравнения распределений случайных весов NumPy с общей шкалой Y ​

Задача: С помощью генератора случайных чисел rng = numpy.random.default_rng(seed=10) сгенерируйте четыре независимых вектора по 500 элементов каждый, моделирующих распределения весов четырех разных слоев модели (Урок 17 модуля NumPy). Настройте Matplotlib для работы на сервере в headless-режиме (Урок 3). Создайте сетку графиков размером 2x2, принудительно зафиксировав единый масштаб по вертикали для всех четырех окон через параметр sharey=True (Урок 8). Разверните матрицу осей в плоский вектор (Урок 8). Используя цикл for i, ax in enumerate(axes_flat):, постройте в каждом окне частотную гистограмму соответствующего вектора весов на 30 корзин, покрасив их в фиолетовый цвет (Урок 5). Примените метод fig.tight_layout() и выгрузите результат в "weights_comparison.png".

Посмотреть решение
python
import numpy
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot

# Generating 4 independent stochastic tensors (NumPy Lesson 17)
rng = numpy.random.default_rng(seed=10)
layers_data = [rng.normal(loc=0.0, scale=0.5, size=500) for _ in range(4)]

# Creating a synchronized 2x2 grid layout mesh (Matplotlib Lesson 8)
fig, axes = matplotlib.pyplot.subplots(nrows=2, ncols=2, sharey=True, figsize=(10, 10))
axes_flat = axes.flatten()

# Iterating through collapsed 1D array stream mapping histogram charts (Matplotlib Lesson 5 & 8)
for i, ax in enumerate(axes_flat):
    ax.hist(layers_data[i], bins=30, color="purple", alpha=0.7)
    ax.set_title(f"Layer {i+1} Weights")
    ax.set_xlabel("Weight Value")
    ax.set_ylabel("Frequency")
    ax.grid(True)

fig.tight_layout()
fig.savefig("weights_comparison.png")

8. Сравнение признаков датасета на сетке скаттерплотов после очистки дубликатов ​

Задача: Загрузите данные из файла "sensor_telemetry.parquet" (Урок 8 модуля Pandas). Очистите таблицу от дубликатов строк на месте (Урок 9 модуля Pandas). Создайте сетку графиков из 1 строки и 2 столбцов в headless-режиме (Урок 3 / Урок 8 модуля Matplotlib). В первом окне постройте диаграмму рассеяния признака "param_Y" от "param_X" (Урок 6). Во втором окне постройте скаттерплот признака "param_Z" от "param_X". Задайте точкам синий цвет, уменьшите размер до s=8 и выставьте полупрозрачность alpha=0.4 для борьбы с перекрытием (Урок 6). Подпишите оси и сохраните в файл "telemetry_subplots.png".

Посмотреть решение
python
import pandas
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot

# Parsing parquet databases files (Pandas Lesson 8)
telemetry_df = pandas.read_parquet(path="sensor_telemetry.parquet")

# Discarding duplicate samples entities in place (Pandas Lesson 9)
telemetry_df.drop_duplicates(inplace=True)

# Allocation of a 1x2 plotting space layout (Matplotlib Lesson 8)
fig, axes = matplotlib.pyplot.subplots(nrows=1, ncols=2, figsize=(12, 5))

# Plotting scatter mapping into the first window channel node (Matplotlib Lesson 6)
axes[0].scatter(telemetry_df["param_X"], telemetry_df["param_Y"], color="blue", s=8, alpha=0.4)
axes[0].set_title("Param Y vs Param X")
axes[0].set_xlabel("Param X")
axes[0].set_ylabel("Param Y")
axes[0].grid(True)

# Plotting scatter mapping into the second window channel node
axes[1].scatter(telemetry_df["param_X"], telemetry_df["param_Z"], color="blue", s=8, alpha=0.4)
axes[1].set_title("Param Z vs Param X")
axes[1].set_xlabel("Param X")
axes[1].set_ylabel("Param Z")
axes[1].grid(True)

fig.tight_layout()
fig.savefig("telemetry_subplots.png")

9. Сравнение важности фичей ТОП-3 и распределения классов на мультипанельном холсте ​

Задача: Дан готовый датасет важности признаков df_imp = pandas.DataFrame({"name": ["f_age", "f_income", "f_days"], "score": [0.15, 0.65, 0.20]}) и Series распределения классов class_series = pandas.Series([120, 450], index=["Class 0", "Class 1"]) (Урок 2 / Урок 5 модуля Pandas). Настройте неинтерактивный режим работы (Урок 3). Создайте сетку графиков из 1 строки и 2 столбцов (Урок 8). В первом окне постройте горизонтальную диаграмму важности фичей ax.barh() на основе столбцов таблицы df_imp (Урок 7). Во втором окне постройте вертикальный бар-чарт ax.bar() распределения классов на основе индексов и значений class_series (Урок 7). Примените метод выравнивания отступов и выведите холст в файл "features_classes_summary.png".

Посмотреть решение
python
import pandas
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot

df_imp = pandas.DataFrame({"name": ["f_age", "f_income", "f_days"], "score": [0.15, 0.65, 0.20]})
class_series = pandas.Series([120, 450], index=["Class 0", "Class 1"])

# Setting up a 1x2 split panels grid canvas (Matplotlib Lesson 8)
fig, axes = matplotlib.pyplot.subplots(nrows=1, ncols=2, figsize=(12, 5))

# Panel 0: Horizontal bar chart analysis layout (Matplotlib Lesson 7)
axes[0].barh(df_imp["name"], df_imp["score"], color="darkblue")
axes[0].set_title("Model Feature Importance Weights")
axes[0].invert_yaxis()
axes[0].grid(True)

# Panel 1: Vertical discrete classes frequency column blocks (Matplotlib Lesson 7)
axes[1].bar(class_series.index, class_series.values, color="seagreen")
axes[1].set_title("Target Labels Counts Balance")
axes[1].grid(True)

fig.tight_layout()
fig.savefig("features_classes_summary.png")

10. Поиск и раскрытие спецификаций фабричного метода plt.subplots в Jupyter ​

Задача: Напишите строку кода для выполнения в ячейке Jupyter Notebook, которая открывает интерактивную Docstring-инструкцию по главному фабричному ООП-методу построения сеток графиков matplotlib.pyplot.subplots с помощью символа интроспекции (Урок 1 модуля NumPy / Урок 1 модуля Pandas).

Посмотреть решение
python
import matplotlib.pyplot

# Running this cell evaluation line pulls up the comprehensive subplots architecture guide
?matplotlib.pyplot.subplots