Полярный график matplotlib смещение радиальной оси

Мне было интересно, можно ли сместить начало радиальной оси или переместить ее за пределы графика.

Вот чего я надеюсь достичь:

Цель

И это то, что у меня есть на данный момент.

CurRes

Я прочитал документацию и разные темы по SO, но не нашел ничего полезного. Означает ли это, что это невозможно, если об этом нигде не упоминается.

Заранее спасибо.

РЕДАКТИРОВАТЬ (добавлен фрагмент кода, используемого для создания сюжета):

ax = fig.add_subplot(111, projection='polar')
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)      
ax.plot(X,lines[li]*yScalingFactor,label=linelabels[li],color=color,linestyle=ls)

person Renesis    schedule 17.05.2013    source источник
comment
Пожалуйста, опубликуйте свой код, который создал диаграмму.   -  person Mike Müller    schedule 03.06.2013
comment
Код стандартный для полярного построения, но тем не менее я отредактировал сообщение и добавил код. И данные не из формулы, а из набора данных.   -  person Renesis    schedule 07.06.2013


Ответы (2)


Чтобы сместить начало радиальной оси:

РЕДАКТИРОВАТЬ: Начиная с Matplotlib 2.2.3 существует новый метод Axes под названием set_rorigin, который делает именно это. Вы называете это теоретической радиальной координатой начала координат. Итак, если вы вызовете ax.set_ylim(0, 2) и ax.set_rorigin(-1), радиус центрального круга будет составлять треть радиуса графика.

Быстрый и грязный обходной путь для Matplotlib ‹2.2.3 - установить нижний предел радиальной оси на отрицательное значение и скрыть внутреннюю часть графика за кругом:

import numpy as np
import matplotlib.pyplot as plt

CIRCLE_RES = 36 # resolution of circle inside
def offset_radial_axis(ax):
    x_circle = np.linspace(0, 2*np.pi, CIRCLE_RES)
    y_circle = np.zeros_like(x_circle)
    ax.fill(x_circle, y_circle, fc='white', ec='black', zorder=2) # circle
    ax.set_rmin(-1) # needs to be after ax.fill. No idea why.
    ax.set_rticks([tick for tick in ax.get_yticks() if tick >= 0])
    # or set the ticks manually (simple)
    # or define a custom TickLocator (very flexible)
    # or leave out this line if the ticks are fully behind the circle

Чтобы добавить масштаб вне графика:

Вы можете добавить объект дополнительных осей в верхнюю половину других осей и использовать его оси y:

X_OFFSET = 0 # to control how far the scale is from the plot (axes coordinates)
def add_scale(ax):
    # add extra axes for the scale
    rect = ax.get_position()
    rect = (rect.xmin-X_OFFSET, rect.ymin+rect.height/2, # x, y
            rect.width, rect.height/2) # width, height
    scale_ax = ax.figure.add_axes(rect)
    # hide most elements of the new axes
    for loc in ['right', 'top', 'bottom']:
        scale_ax.spines[loc].set_visible(False)
    scale_ax.tick_params(bottom=False, labelbottom=False)
    scale_ax.patch.set_visible(False) # hide white background
    # adjust the scale
    scale_ax.spines['left'].set_bounds(*ax.get_ylim())
    # scale_ax.spines['left'].set_bounds(0, ax.get_rmax()) # mpl < 2.2.3
    scale_ax.set_yticks(ax.get_yticks())
    scale_ax.set_ylim(ax.get_rorigin(), ax.get_rmax())
    # scale_ax.set_ylim(ax.get_ylim()) # Matplotlib < 2.2.3

Собираем все вместе:

(Пример взят из демонстрации полярного графика Matplotlib)

r = np.arange(0, 2, 0.01)
theta = 2 * np.pi * r

ax = plt.subplot(111, projection='polar')
ax.plot(theta, r)
ax.grid(True)

ax.set_rorigin(-1)
# offset_radial_axis(ax) # Matplotlib < 2.2.3
add_scale(ax)

ax.set_title("A line plot on an offset polar axis", va='bottom')
plt.show()

введите описание изображения здесь

person Joooeey    schedule 14.09.2018
comment
это необходимо обновить до принятого ответа. - person codeAndStuff; 26.01.2021

Я не уверен, можно ли так настроить polar plot. Но вот обходной путь, основанный на последнем примере, приведенном здесь: Плавающие оси.

Я включил в код пояснительные комментарии, если вы скопируете / вставите его, он должен работать как есть:

import mpl_toolkits.axisartist.floating_axes as floating_axes
from matplotlib.projections import PolarAxes
from mpl_toolkits.axisartist.grid_finder import FixedLocator, \
     MaxNLocator, DictFormatter
import numpy as np
import matplotlib.pyplot as plt

# generate 100 random data points
# order the theta coordinates

# theta between 0 and 2*pi
theta = np.random.rand(100)*2.*np.pi
theta = np.sort(theta)

# "radius" between 0 and a max value of 40,000
# as roughly in your example
# normalize the r coordinates and offset by 1 (will be clear later)
MAX_R = 40000.
radius = np.random.rand(100)*MAX_R
radius = radius/np.max(radius) + 1.

# initialize figure:
fig = plt.figure()

# set up polar axis
tr = PolarAxes.PolarTransform()

# define angle ticks around the circumference:
angle_ticks = [(0, r"$0$"),
               (.25*np.pi, r"$\frac{1}{4}\pi$"),
               (.5*np.pi, r"$\frac{1}{2}\pi$"), 
               (.75*np.pi, r"$\frac{3}{4}\pi$"),
               (1.*np.pi, r"$\pi$"),
               (1.25*np.pi, r"$\frac{5}{4}\pi$"),
               (1.5*np.pi, r"$\frac{3}{2}\pi$"),
               (1.75*np.pi, r"$\frac{7}{4}\pi$")]

# set up ticks and spacing around the circle
grid_locator1 = FixedLocator([v for v, s in angle_ticks])
tick_formatter1 = DictFormatter(dict(angle_ticks))

# set up grid spacing along the 'radius'
radius_ticks = [(1., '0.0'),
                (1.5, '%i' % (MAX_R/2.)),
                (2.0, '%i' % (MAX_R))]

grid_locator2 = FixedLocator([v for v, s in radius_ticks])
tick_formatter2 = DictFormatter(dict(radius_ticks))

# set up axis:
# tr: the polar axis setup
# extremes: theta max, theta min, r max, r min
# the grid for the theta axis
# the grid for the r axis
# the tick formatting for the theta axis
# the tick formatting for the r axis
grid_helper = floating_axes.GridHelperCurveLinear(tr,
                                                  extremes=(2.*np.pi, 0, 2, 1),
                                                  grid_locator1=grid_locator1,
                                                  grid_locator2=grid_locator2,
                                                  tick_formatter1=tick_formatter1,
                                                  tick_formatter2=tick_formatter2)

ax1 = floating_axes.FloatingSubplot(fig, 111, grid_helper=grid_helper)
fig.add_subplot(ax1)

# create a parasite axes whose transData in RA, cz
aux_ax = ax1.get_aux_axes(tr)

aux_ax.patch = ax1.patch # for aux_ax to have a clip path as in ax
ax1.patch.zorder=0.9 # but this has a side effect that the patch is
                     # drawn twice, and possibly over some other
                     # artists. So, we decrease the zorder a bit to
                     # prevent this.

# plot your data:
aux_ax.plot(theta, radius)
plt.show()  

Это сгенерирует следующий сюжет:

псевдополярный сюжет

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

person Schorsch    schedule 03.06.2013
comment
Я давно не был активен и не ожидал, что кто-то действительно поможет. Это в некоторой степени помогает, и я надеюсь, что смогу изменить его так, чтобы оно было необходимо. - person Renesis; 07.06.2013
comment
Думаю, в понедельник постараюсь это исправить, потом сообщу о результатах. Еще раз спасибо. - person Renesis; 08.06.2013