Использование библиотеки Matplotlib. Как рисовать графики в разных окнах | jenyay.net

Использование библиотеки Matplotlib. Как рисовать графики в разных окнах

Дата публикации: 14.02.2010
Дата последней правки: 22.10.2023

Оглавление

Последовательное создание окон

В статье Как нарисовать несколько графиков в одном окне описывалось, как можно рисовать несколько графиков в одном окне. На этот раз мы разберемся, как можно рисовать графики в разных окнах. Для создания нового окна или выбора уже существующего (о чем будет сказано далее), предназначена функция figure() из модуля matplotlib.pyplot. В терминах Matplotlib окно с графиком называется фигурой и описывается классом Figure. В дальнейшем в этой статье термины "фигура" и "окно" будут использоваться как синонимы. Функция figure() в зависимости от значения первого именованного параметра num может вести себя по-разному.

  • Если параметр num не указан или равен None, то будет создано новое окно.
  • Если в качестве параметра num передан экземпляр класса Figure, то указанная фигура будет установлена как активная фигура (Matplotlib будет использовать эту фигуру для создания новых графиков).
  • Если в качестве num будет передан целочисленный идентификатор, то активной фигурой будет назначена фигура с указанным идентификатором, а если такой фигуры нет, то будет создана новая фигура с заданным значением идентификатора.
  • Если в качестве num будет передана строка, то Matplotlib будет вести себя аналогично предыдущему случаю, но искать фигуру не по целочисленному идентификатору, а по строковой метке (label).

В качестве результата работы функция figure() возвращает экземпляр уже упомянутого класса Figure.

Начнем с примера, в котором последовательно создаются два окна и выводятся две кривые.

# coding: utf-8

import matplotlib.pyplot as plt
import numpy as np


if __name__ == '__main__':
    # Интервал изменения переменной по оси X и количество точек на этом интервале
    xmin = -20.0
    xmax = 20.0
    count = 200

    # Создадим список координат по оси X на отрезке [xmin; xmax], включая концы
    x = np.linspace(xmin, xmax, count)

    # Вычислим значение функции в заданных точках
    y1 = np.sinc(x / np.pi)
    y2 = np.sinc(x / np.pi * 0.2)

    # !!! Создадим первое окно и нарисуем в нем график
    plt.figure()
    plt.plot(x, y1, label="f(x)")

    # !!! Создадим второе окно и нарисуем график в нем
    plt.figure()
    plt.plot(x, y2, label="f(x * 0.2)")
    plt.legend()

    # Покажем окна с нарисованными графиками
    plt.show()

Здесь последовательно вызываются функции figure() без параметров, и поэтому будут созданы новые окна (фигуры), а затем в только что созданном окне создается график.

В результате у нас будет два окна со следующим содержимым:

А что если нам после отображения второго графика нужно вернуться в первое окно и что-то дорисовать там, например, добавить еще одну кривую? Рассмотрим разные способы переключения между окнами.

Переключение между окнами по экземпляру класса Figure

Воспользуемся тем фактом, что функция figure() возвращает экземпляр класса Figure, имея который мы можем снова переключаться на окно, соответствующее данному экземпляру класса.

# coding: utf-8

import matplotlib.pyplot as plt
import numpy as np


if __name__ == '__main__':
    # Интервал изменения переменной по оси X и количество точек на этом интервале
    xmin = -20.0
    xmax = 20.0
    count = 200

    # Создадим список координат по оси X на отрезке [xmin; xmax], включая концы
    x = np.linspace(xmin, xmax, count)

    # Вычислим значение функции в заданных точках
    y1 = np.sinc(x / np.pi)
    y2 = np.sinc(x / np.pi * 0.2)
    y3 = np.sinc(x / np.pi * 2.0)

    # !!! Создадим первое окно и нарисуем в нем график
    fig1 = plt.figure()
    plt.plot(x, y1, label="f(x)")

    # !!! Создадим второе окно и нарисуем график в нем
    fig2 = plt.figure()
    plt.plot(x, y2, label="f(x * 0.2)")
    plt.legend()

    # !!! Переключимся снова на первое окно и нарисуем там еще один график
    plt.figure(fig1)
    plt.plot(x, y3, label="f(x * 2)")
    plt.legend()

    # Покажем окна с нарисованными графиками
    plt.show()

В этом случае график во первом окне будет выглядеть следующим образом (внешний вид графика во втором окне не изменится):

Если нам нужно получить экземпляр класса Figure, который является активным в данный момент, можно воспользоваться функцией gcf() (Get the Current Figure) из модуля matplotlib.pyplot.

Переключение между окнами по числовому идентификатору

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

Узнать идентификатор фигуры можно через свойство Figure.number.

Изменим предыдущий пример таким образом, чтобы использовать идентификаторы.

# coding: utf-8

import matplotlib.pyplot as plt
import numpy as np


if __name__ == '__main__':
    # Интервал изменения переменной по оси X и количество точек на этом интервале
    xmin = -20.0
    xmax = 20.0
    count = 200

    # Создадим список координат по оси X на отрезке [xmin; xmax], включая концы
    x = np.linspace(xmin, xmax, count)

    # Вычислим значение функции в заданных точках
    y1 = np.sinc(x / np.pi)
    y2 = np.sinc(x / np.pi * 0.2)
    y3 = np.sinc(x / np.pi * 2.0)

    # !!! Идентификаторы окон (фигур)
    fig1_id = 1
    fig2_id = 2

    # !!! Создадим первое окно и нарисуем в нем график
    fig1 = plt.figure(fig1_id)
    print(f"fig1.number = {fig1.number}")

    plt.plot(x, y1, label="f(x)")

    # !!! Создадим второе окно и нарисуем график в нем
    fig2 = plt.figure(fig2_id)
    print(f"fig2.number = {fig2.number}")

    plt.plot(x, y2, label="f(x * 0.2)")
    plt.legend()

    # Переключимся снова на первое окно и нарисуем там еще один график
    plt.figure(fig1_id)
    plt.plot(x, y3, label="f(x * 2)")
    plt.legend()

    # Покажем окна с нарисованными графиками
    plt.show()

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

В результате выполнения этого скрипта помимо отображения графиков в окнах, в консоли будут выведены следующие строки:

fig1.number = 1
fig2.number = 2

Переключение между окнами по заголовку окна

При вызове функции figure() в качестве параметра num вместо числа можно передать строку. В этом случае библиотека Matplotlib сначала попытается найти имеющийся экземпляр класса Figure с меткой (label), совпадающей с указанной строкой, а если такого экземпляра класса нет, то он будет создан. Указанная метка фигуры отображается в заголовке окна и может быть получена с помощью метода get_label() из класса Figure.

Следующий пример создает два таких же окна, как и в предыдущих примерах, но при этом в качестве параметра функции figure() используются строки.

# coding: utf-8

import matplotlib.pyplot as plt
import numpy as np


if __name__ == '__main__':
    # Интервал изменения переменной по оси X и количество точек на этом интервале
    xmin = -20.0
    xmax = 20.0
    count = 200

    # Создадим список координат по оси X на отрезке [xmin; xmax], включая концы
    x = np.linspace(xmin, xmax, count)

    # Вычислим значение функции в заданных точках
    y1 = np.sinc(x / np.pi)
    y2 = np.sinc(x / np.pi * 0.2)
    y3 = np.sinc(x / np.pi * 2.0)

    # !!! Метки окон (фигур)
    fig1_label = "Фигура 1"
    fig2_label = "Фигура 2"

    # !!! Создадим первое окно и нарисуем в нем график
    fig1 = plt.figure(fig1_label)
    print(f"fig1.number = {fig1.number}")
    print(f"fig1 label = {fig1.get_label()}")

    plt.plot(x, y1, label="f(x)")

    # !!! Создадим второе окно и нарисуем график в нем
    fig2 = plt.figure(fig2_label)
    print(f"fig2.number = {fig2.number}")
    print(f"fig2 label = {fig2.get_label()}")

    plt.plot(x, y2, label="f(x * 0.2)")
    plt.legend()

    # !!! Переключимся снова на первое окно и нарисуем там еще один график
    plt.figure(fig1_label)
    plt.plot(x, y3, label="f(x * 2)")
    plt.legend()

    # Покажем окна с нарисованными графиками
    plt.show()
 

В результате будут созданы два окна с заголовками, переданными в функцию figure().

Свойства number экземпляров класса Figure по-прежнему будут представлять собой последовательность целых чисел.

fig1.number = 1
fig1 label = Фигура 1
fig2.number = 2
fig2 label = Фигура 2

Здесь надо сделать оговорку, что метка (label) фигуры не всегда совпадает с заголовком окна. Метку фигуры можно изменить с помощью метода set_label() класса Figure, но при этом заголовок окна не изменится. Если нужно изменить именно заголовок окна, то можно воспользоваться следующей командой:

fig.canvas.manager.set_window_title('Новый заголовок окна')

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

# coding: utf-8

import matplotlib.pyplot as plt
import numpy as np


if __name__ == '__main__':
    # Интервал изменения переменной по оси X и количество точек на этом интервале
    xmin = -20.0
    xmax = 20.0
    count = 200

    # Создадим список координат по оси X на отрезке [xmin; xmax], включая концы
    x = np.linspace(xmin, xmax, count)

    # Вычислим значение функции в заданных точках
    y1 = np.sinc(x / np.pi)
    y2 = np.sinc(x / np.pi * 0.2)
    y3 = np.sinc(x / np.pi * 2.0)

    # Метки окон (фигур)
    fig1_label = "Фигура 1"
    fig2_label = "Фигура 2"

    # Создадим первое окно и нарисуем в нем график
    fig1 = plt.figure(fig1_label)
    print(f"fig1.number = {fig1.number}")
    print(f"fig1 label = {fig1.get_label()}")

    plt.plot(x, y1, label="f(x)")

    # !!! Создадим второе окно и нарисуем график в нем
    fig2 = plt.figure(fig2_label)
    print(f"fig2.number = {fig2.number}")
    print(f"fig2 label = {fig2.get_label()}")

    plt.plot(x, y2, label="f(x * 0.2)")
    plt.legend()

    # Переключимся снова на первое окно и нарисуем там еще один график
    plt.figure(fig1_label)
    plt.plot(x, y3, label="f(x * 2)")
    plt.legend()

    # !!! Изменим метку и заголовок окна
    fig1.set_label("Фигура 1-1")
    fig1.canvas.manager.set_window_title('Новый заголовок окна')
    print(f"fig1 label = {fig1.get_label()}")

    # Покажем окна с нарисованными графиками
    plt.show()

В результате в первом окне изменится заголовок, как показано на предыдущем рисунке, а в консоль будут выведены следующие строки:

fig1.number = 1
fig1 label = Фигура 1
fig2.number = 2
fig2 label = Фигура 2
fig1 label = Фигура 1-1

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

Рисование графиков в разных окнах с использованием объектно-ориентированного подхода

Все, что было описано выше, полезно, если вы пользуетесь высокоуровневыми функциями из модуля matplotlib.pyplot наподобие plot(), xlabel() / ylabel(), xlim() / ylim(), legend() и т.п. Однако при использовании объектно-ориентированного стиля создания графиков (см. статью Применение объектно-ориентированного стиля) как правило нет необходимости в переключении между фигурами, поскольку у вас имеются объекты осей, привязанных к фигуре, и вы можете рисовать графики в этих осях независимо от того, какая фигура в данный момент считается активной.

Чтобы получить экземпляры класса осей, мы можем пойти разными путями. Первый из них заключается в том, чтобы воспользоваться методом subplots() из класса Figure(). Этот метод предназначен для создания осей в фигуре. За один раз можно создать несколько осей, как это делается с помощью функции matplotlib.pyplot.subplot() (см. статью Как нарисовать несколько графиков в одном окне). Если в метод subplots() не передавать никакие параметры или указать, что количество ячеек в условной таблице для графиков по вертикали и горизонтали равны 1, то метод subplots() вернет один экземпляр класса Axes. Если с помощью этой функции создается несколько осей, то она вернет массив экземпляров класса Axes.

То есть создать оси можно примерно так:

fig1 = plt.figure()
axes1 = fig1.subplots()

А затем можно использовать метод axes1.plot(...) для создания графика в нужных осях.

Этот подход показан в следующем скрипте:

# coding: utf-8

import matplotlib.pyplot as plt
import numpy as np


if __name__ == '__main__':
    # Интервал изменения переменной по оси X и количество точек на этом интервале
    xmin = -20.0
    xmax = 20.0
    count = 200

    # Создадим список координат по оси X на отрезке [xmin; xmax], включая концы
    x = np.linspace(xmin, xmax, count)

    # Вычислим значение функции в заданных точках
    y1 = np.sinc(x / np.pi)
    y2 = np.sinc(x / np.pi * 0.2)
    y3 = np.sinc(x / np.pi * 2.0)

    # !!! Создадим первое окно и нарисуем в нем график
    fig1 = plt.figure()
    axes1 = fig1.subplots()
    axes1.plot(x, y1, label="f(x)")

    # !!! Создадим второе окно и нарисуем график в нем
    fig2 = plt.figure()
    axes2 = fig2.subplots()
    axes2.plot(x, y2, label="f(x * 0.2)")
    plt.legend()

    # !!! Нарисуем еще один график в первом окне
    axes1.plot(x, y3, label="f(x * 2)")
    axes1.legend()

    # Покажем окна с нарисованными графиками
    plt.show()

Здесь функция figure() вызывается только для создания окон, и явного переключения между окнами не происходит.

Однако этот код мы можем немного сократить, объединив в одном вызове создание фигуры и осей с помощью функции subplots() из модуля matplotlib.pyplot. Эта функция аналогична одноименному методу из класса Figure, но при этом она создает одновременно и фигуру, и оси. Функция subplots() возвращает кортеж, состоящий из экземпляра класса Figure и экземпляра (или экземпляров) класса Axes.

То есть с использованием функции subplots() создание окна и осей будет выглядеть примерно так: fig, axes = plt.subplots(). Следующий код демонстрирует использование такого способа создания окон.

# coding: utf-8

import matplotlib.pyplot as plt
import numpy as np


if __name__ == '__main__':
    # Интервал изменения переменной по оси X и количество точек на этом интервале
    xmin = -20.0
    xmax = 20.0
    count = 200

    # Создадим список координат по оси X на отрезке [xmin; xmax], включая концы
    x = np.linspace(xmin, xmax, count)

    # Вычислим значение функции в заданных точках
    y1 = np.sinc(x / np.pi)
    y2 = np.sinc(x / np.pi * 0.2)
    y3 = np.sinc(x / np.pi * 2.0)

    # !!! Создадим первое окно и нарисуем в нем график
    fig1, axes1 = plt.subplots()
    axes1.plot(x, y1, label="f(x)")

    # !!! Создадим второе окно и нарисуем график в нем
    fig2, axes2 = plt.subplots()
    axes2.plot(x, y2, label="f(x * 0.2)")
    plt.legend()

    # Нарисуем еще один график в первом окне
    axes1.plot(x, y3, label="f(x * 2)")
    axes1.legend()

    # Покажем окна с нарисованными графиками
    plt.show()

Внешне результат работы этого скрипта выглядит так же, как и результат выполнения предыдущих скриптов - будет создано два окна с разными графиками.

Заключение

В этой статье мы рассмотрели несколько способов для работы с графиками, нарисованными в разных окнах (в разных фигурах). При использовании высокоуровневых функций из модуля matplotlib.pyplot для переключения между фигурами используется функция figure(), которая может принимать в качестве первого параметра целочисленный идентификатор фигуры, строковую метку (label) или сам экземпляр класса Figure, который отвечает за фигуру, которая должна стать активной.

Активную в данный момент фигуру можно получить с помощью функции gcf() из модуля matplotlib.pyplot.

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

Похожие статьи

Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.
4.5 stars

Рейтинг 4.3/5. Всего 12 голос(а, ов)



автор 25.05.2022 - 21:10

тема

happy smiley


Подписаться на комментарии
Автор:
Тема:
 Ваш комментарий
 
 
Введите код 118