Использование библиотеки Matplotlib. Как строить графики в полярной системе координат
Дата публикации: 28.11.2025
Дата последней правки: 28.11.2025
Оглавление
- Создание осей для полярной системы координат
- Настройки осей для полярной системы координат
- Похожие статьи
- Комментарии
Создание осей для полярной системы координат
Графики, которые должны показывать зависимость значения какой-то величины от направления на плоскости, принято рисовать в полярной системе координат. Например, в такой системе координат отображают диаграммы направленности антенн, эффективную площадь рассеяния объектов и другие величины.
Полярная система координат позволяет отображать зависимость некоторой величины или функции f(θ) от угла θ. Чем большее значение принимает функция f(θ), тем дальше от центра отмечается точка для соответствующего угла.
Для дальнейших примеров мы будем строить график функции, которая описывается следующим выражением:

С использованием библиотеки Matplotlib у нас имеется несколько способов создать график в полярной системе координат:
- воспользоваться функцией
polar()из модуляmatplotlib.pyplot; - создать оси в полярной системе координат с помощью метода
Figure.add_subplot()и передать ему параметрpolar=True; - создать оси в полярной системе координат с помощью функции
subplots()из модуляmatplotlib.pyplot, передав туда параметрsubplot_kw={'projection': 'polar'}.
Приведем примеры для каждого из этого способа. Начнем с функции polar().
Использование функции polar()
Применение функции polar() напоминает применение функции plot() для рисования графиков в декартовой системе координат. На самом деле polar() и вызывает plot(), предварительно создав оси в полярной системе координат.
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(0, 2 * np.pi, 361)
r = np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
# !!!
plt.polar(theta, r)
plt.show()
В этом примере мы создаем массив theta, который содержит 361 значение в радианах в интервале от 0 до 2π, а затем на этом интервале значения приведенной выше функции, результат помещаем в переменную r. Именно эти два массива передаются как параметры в функцию polar().
В результате выполнения этого скрипта будет создан график следующего вида:

Обратите внимание, что в функцию polar() мы передаем значения углов в радианах, но на графике они отображаются в градусах.
Аналогично функции plot(), с помощью функции polar() можно рисовать одновременно несколько кривых, а также задавать для них стили.
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(0, 2 * np.pi, 361)
r1 = np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
r2 = np.abs((np.cos(2 * np.pi * np.cos(theta)) - np.cos(2 * np.pi)) / np.sin(theta))
plt.polar(theta, r1, "--b", theta, r2, "-k")
plt.show()
В результате мы получим две кривые: первая будет показана штриховой голубой линией, а вторая - сплошной черной линией.

Функция polar(), как и функция plot(), возвращает список экземпляров класса Line2D, отвечающих за каждую созданную кривую.
При необходимости в предыдущем примере мы могли бы разбить вызов функции plot() на два вызова:
plt.polar(theta, r1, "--b")
plt.polar(theta, r2, "-k")
Предварительное создание осей для полярной системы координат
Аналогичных результатов можно добиться, если предварительно создать оси для отображения графика в полярной системе координат, а затем для полученного экземпляра класса осей вызвать метод plot(). Создать оси мы можем с помощью метода add_subplot() экземпляра класса Figure, который нужно предварительно создать с помощью функции figure(). Про этот подход более подробно написано в статье Применение объектно-ориентированного стиля.
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(0, 2 * np.pi, 361)
r = np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
# Поулчаем экземпляр класса Figure
fig = plt.figure()
# !!! ---------------v
ax = fig.add_subplot(polar=True)
print(f"{type(ax)=}")
# !!!
ax.plot(theta, r)
plt.show()
Здесь важно отметить, что в метод add_subplot() передается дополнительный параметр polar=True, благодаря чему создаются оси именно для полярной системы координат, а не для декартовой, как это было бы по умолчанию.
В результате мы получим такую же картинку, как и для первого скрипта в этой статье. Помимо графика в консоль еще будет выведен тип переменной ax, отвечающей за оси. Для полярных осей этот тип будет matplotlib.projections.polar.PolarAxes.
Также мы можем совместить создание фигуры и осей в одном вызове, воспользовавшись функцией subplots() из модуля matplotlib.pyplot:
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(0, 2 * np.pi, 361)
r = np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
# !!! -----------------------------v
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
# !!!
ax.plot(theta, r)
plt.show()
В этом случае для создания полярной системы координат мы воспользовались дополнительным параметром subplot_kw, который принимает в качестве значения словарь. В этом словаре мы указываем ключ "projection" и значение "polar". Результат выполнения этого скрипта отличаться от предыдущих примеров не будет.
Настройки осей для полярной системы координат
Теперь, когда мы умеем создавать график с настройками по умолчанию, рассмотрим методы класса PolarAxes, которые позволяют настраивать внешний вид графика.
Положение нуля градусов
Из картинок в предыдущем разделе видно, что по умолчанию нулевой угол расположен справа. Чтобы изменить его положение, например, поместить его сверху, как часто делают, предназначен метод set_theta_zero_location(), который описывается следующим образом:
set_theta_zero_location(loc, offset=0.0)
Параметр loc описывает расположение нуля в формате, как это принято на картах йо-хо-хо и бутылка рома. Этот строковый параметр может принимать следующие значения:
- "N" - ноль будет расположен сверху;
- "NW" - ноль будет расположен слева сверху;
- "W" - ноль будет расположен слева;
- "SW" - ноль будет расположен слева внизу;
- "S" - ноль будет расположен снизу;
- "SE" - ноль будет расположен справа внизу;
- "E" - ноль будет расположен справа;
- "NE" - ноль будет расположен справа сверху;
Если нужно сместить ноль на дополнительный угол от этих направлений, нужно воспользоваться необязательным параметром offset, который указывает дополнительное смещение в градусах против часовой стрелки.
Изменим последний пример, переместив ноль угловых отсчетов вверх:
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(0, 2 * np.pi, 361)
r = np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
# !!!
ax.set_theta_zero_location("N")
ax.plot(theta, r)
plt.show()
Теперь график будет выглядеть следующим образом:

Такого же результата можно было бы достичь с использованием другого метода для поворота оси углов - set_theta_offset(). Он принимает в качестве параметра угол в радианах, на который нужно повернуть систему координат против часовой стрелки. Поэтому если в предыдущем примере вызов метода set_theta_zero_location() заменить на строку
ax.set_theta_offset(np.pi / 2)
то результат не изменится.
Направление отсчета углов
Если в случае, когда ноль был расположен справа, направление увеличения углов против часовой стрелки выглядело логично, то теперь нужно сделать, чтобы углы откладывались по часовой стрелке. Сделать это можно с помощью метода set_theta_direction(). Этот метод принимает единственный параметр: если он равен 1, то углы будут нарастать против часовой стрелки (настройка по умолчанию), а если он будет равен -1, то по часовой стрелке.
Дополним предыдущий пример вызовом этого метода.
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(0, 2 * np.pi, 361)
r = np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.set_theta_zero_location("N")
# !!!
ax.set_theta_direction(-1)
ax.plot(theta, r)
plt.show()
Теперь график выглядит более привычно:

Ограничение значений по углу
Предположим, что перед нами стоит задача, для которой не требуется отображать значения во всем секторе углов от 0 до 360 градусов, и нам нагляднее было бы изобразить график на интервале углов от -90 до 90 градусов. Если мы только ограничим данные этим интервалом, то у нас будет не экономно расходоваться место - половина графика будет пустой. Покажем это на примере:
import numpy as np
import matplotlib.pyplot as plt
# !!!
theta = np.linspace(-np.pi / 2, np.pi / 2, 181)
r = np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
ax.plot(theta, r)
plt.show()
В качестве результата выполнения этого скрипта будет показан следующий график:

Чтобы место расходовалось более экономно, мы можем оставить только интересующую нас часть сектора углов (в нашем случае только верхнюю половину). Для этого в классе PolarAxes имеется несколько методов: set_thetamin() и set_thetamax(), а также set_thetalim(). В нашем примере нам подойдут первые два метода. Ограничим с помощью них интервал по оси углов:
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(-np.pi / 2, np.pi / 2, 181)
r = np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
ax.set_thetamin(-90)
ax.set_thetamax(90)
ax.plot(theta, r)
plt.show()
В результате нижняя часть графика будет отброшена:

Того же самого результата мы бы добились, если бы заменили вызовы методов set_thetamin() и set_thetamax() на один вызов метода set_thetalim():
ax.set_thetalim(thetamin=-90, thetamax=90)
При этом метод set_thetalim() является более универсальным, чем может показаться. В том виде, как мы его вызвали, мы обязаны были использовать именно именованные переменные, чтобы указать пределы в градусах. Однако мы можем воспользоваться версией метода set_thetalim(), передавая ему в качестве предела не именованные параметры, чтобы задать интервал по оси углов в радианах:
ax.set_thetalim(-np.pi / 2, np.pi / 2)
Внешний вид графика при этом не изменится. Но и это еще не все особенности этого метода. Ко всему прочему он еще умеет пересчитывать углы, вычитая иди добавляя к ним 360 градусов (или 2π). Вернемся к одному из наших предыдущих примеров, в котором мы считали функцию на интервале от 0 до 360 градусов. Что если бы именно эти (с избытком) данные нужно было бы отобразить на интервале от -90 до 90 градусов? Можно было бы добавить еще несколько строк программы и переформатировать исходные данные, приведя их к интересующему нас диапазону. Однако, с помощью метода set_thetalim() мы можем указать нужный интервал, и интервал углов будет пересчитан за нас:
import numpy as np
import matplotlib.pyplot as plt
# !!!
theta = np.linspace(0, 2 * np.pi, 361)
r = np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
# !!! Оба варианта дадут один и тот же результат
ax.set_thetalim(thetamin=-90, thetamax=90)
# ax.set_thetalim(-np.pi / 2, np.pi / 2)
ax.plot(theta, r)
plt.show()
Полученный график будет точно такой же, как и на предыдущей картинке.
Изменение интервала значений по радиусу
Чтобы следующие примеры были более наглядны, изменим нашу рассчитываемую функцию, добавив в нее десятичный логарифм:

Также в примере добавим больше промежуточных точек, чтобы на графике образовались более глубокие провалы к нулю. Для экономии места будем рисовать только график на интервале от -90 до 90 градусов. Таким образом наш исходный скрипт, с которым мы будем далее работать, будет выглядеть следующим образом:
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(-np.pi / 2, np.pi / 2, 721)
# !!!
r = np.log10(
np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
)
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
ax.set_thetalim(thetamin=-90, thetamax=90)
ax.plot(theta, r)
plt.show()
Внешний вид графика новой функции теперь выглядит так:

Если нам нужно более подробно рассмотреть график в пределах максимумов лепестков, и нас не интересует глубина провалов, то мы можем ограничить интервал по радиусу значениями, например, от -2 до 1. Для этого класс PolarAxes предоставляет метод set_rlim().
Изменим предыдущий пример, воспользовавшись этим методом, чтобы установить интервал по радиусу [-2, 1]:
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(-np.pi / 2, np.pi / 2, 721)
r = np.log10(
np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
)
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
ax.set_thetalim(thetamin=-90, thetamax=90)
# !!!
ax.set_rlim(-2, 1)
ax.plot(theta, r)
plt.show()
Новый график будет выглядеть следующим образом:

Теперь центр системы координат соответствует значению -2.
Если в процессе выполнения программы нужно сбросить значения интервала к значениям по умолчанию, можно воспользоваться следующим вызовом метода set_rlim():
ax.set_rlim(auto=True)
Изменение параметров сетки по углам
В последних наших примерах по умолчанию риски с углами по окружности расставлены с шагом 30 градусов, однако мы можем расставлять риски на произвольных углах с помощью метода set_thetagrids(), в которой можно передать список (или другой итерируемый объект) с числовыми значениями отсчетов по углу. Изменим предыдущий пример таким образом, чтобы шаг сетки по углу составлял 15 градусов:
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(-np.pi / 2, np.pi / 2, 721)
r = np.log10(
np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
)
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
ax.set_thetalim(thetamin=-90, thetamax=90)
ax.set_rlim(-2, 1)
# !!!
grid_angles = range(-90, 105, 15)
ax.set_thetagrids(grid_angles)
ax.plot(theta, r)
plt.show()
Теперь наш график будет выглядеть следующим образом:

Кроме того метод set_thetagrids() позволяет менять отображаемый текст для каждого угла. Для этого надо передать дополнительный параметр labels, который должен содержать список строк для каждой отображаемой метки. Например, сделаем так, чтобы градусы отображались в формате с двумя цифрами после запятой.
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(-np.pi / 2, np.pi / 2, 721)
r = np.log10(
np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
)
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
ax.set_thetalim(thetamin=-90, thetamax=90)
ax.set_rlim(-2, 1)
# !!!
grid_angles = list(range(-90, 105, 15))
labels = [f"{val:.2f}\u00b0" for val in grid_angles]
ax.set_thetagrids(grid_angles, labels=labels)
ax.plot(theta, r)
plt.show()
После этого график примет вид

Но у метода set_thetagrids есть еще один странный параметр. Если посмотреть документацию к этому методу, то там упоминается параметр fmt как раз для форматирования чисел. Казалось бы, если мы хотим всего лишь поменять формат отображения чисел, то не нужно создавать список строк, а достаточно было бы указать параметр fmt="%.2f". Однако здесь есть одно существенное "но". Если мы так сделаем, то градусы внезапно превратятся в радианы (в документации об этом написано, но все равно странно). Вот, что получится, если мы попытаемся использовать параметр fmt:
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(-np.pi / 2, np.pi / 2, 721)
r = np.log10(
np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
)
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
ax.set_thetalim(thetamin=-90, thetamax=90)
ax.set_rlim(-2, 1)
# !!!
grid_angles = range(-90, 105, 15)
ax.set_thetagrids(grid_angles, fmt="%.2f")
ax.plot(theta, r)
plt.show()
Надписи по окружности теперь будут выглядеть следующим образом:

Изменение параметров сетки по радиусу
Аналогично изменению параметров сетки по углу можно менять и параметры сетки по радиусу. Для этого используется метод set_rgrids() класса PolarAxes. По своему использованию он напоминает метод set_thetagrids(), описанный в предыдущем разделе.
Для начала изменим шаг по оси радиуса, чтобы он был равен 1:
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(-np.pi / 2, np.pi / 2, 721)
r = np.log10(
np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
)
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
ax.set_thetalim(thetamin=-90, thetamax=90)
ax.set_rlim(-2, 1)
ax.set_thetagrids(range(-90, 105, 15))
# !!!
r_ticks = range(-2, 2)
ax.set_rgrids(r_ticks)
ax.plot(theta, r)
plt.show()
Теперь наш график примет вид:

С помощью дополнительного параметра labels можно менять надписи, соответствующие каждой метке. Поменяем формат чисел, чтобы отображались две цифры после запятой:
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(-np.pi / 2, np.pi / 2, 721)
r = np.log10(
np.abs((np.cos(6 * np.pi * np.cos(theta)) - np.cos(6 * np.pi)) / np.sin(theta))
)
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
ax.set_thetalim(thetamin=-90, thetamax=90)
ax.set_rlim(-2, 1)
ax.set_thetagrids(range(-90, 105, 15))
# !!!
r_ticks = list(range(-2, 2))
labels = [f"{val:.2f}" for val in r_ticks]
ax.set_rgrids(r_ticks, labels=labels)
ax.plot(theta, r)
plt.show()
Теперь наш график будет выглядеть следующим образом:

Однако такого же результата можно было бы достичь, если использовать параметр fmt, который описывает способ форматирования чисел для меток:
r_ticks = range(-2, 2)
ax.set_rgrids(r_ticks, fmt="%.2f")
На этом мы закончим обзор основных возможностей для построения графиков в полярных системах координат. Если есть какие-то вопросы и пожелания относительно того, о чем еще стоило бы написать, пишите в комментариях, может быть это будет темой для будущих статей.
Похожие статьи
- Другие статьи про Matplotlib
- Как рисовать графики вида y = f(x)
- Как менять стиль линий на одномерном графике
- Применение объектно-ориентированного стиля
Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.