Matplotlib 极坐标图的径向轴偏移

12

我想知道,是否可以偏移径向轴的起始点或将其移动到图形外部。

这是我希望实现的效果:

Goal

而目前我的效果如下:

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)

请发布生成该图表的代码。 - Mike Müller
代码是极坐标绘图的标准,但我仍然编辑了帖子并添加了代码。而数据不是来自公式,而是来自一组数据。 - Renesis
2个回答

10

为了抵消径向轴的起始位置:

注:从Matplotlib 2.2.3版本开始,有一个叫做set_rorigin的新Axes方法可以实现这个功能。您可以使用理论上的径向坐标调用它。如果您调用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

添加一个位于图形外部的刻度尺:

您可以在其他轴的上半部分添加一个额外的轴对象,并使用它的yaxis:

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()

enter image description here


这需要更新为被接受的答案。 - codeAndStuff

8
我不确定极坐标图是否可以像那样进行调整。但是,这里有一个解决方法,基于此处给出的最后一个示例:浮动轴
如果您复制/粘贴代码,我已经在其中包含了解释性注释,应该可以直接运行:
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()  

这将生成以下图表: 伪极地图 您需要微调轴标签以满足您的要求。我进行了数据缩放,否则与您的绘图相同的问题会发生——内部空白圆将被缩放为点。您可以尝试对极坐标图进行缩放,并在径向轴上放置自定义标签以实现类似的效果。

我有一段时间没有活跃了,没想到会有人真的帮忙。这确实有所帮助,我希望我能够修改它以满足需要。 - Renesis
我想我会在周一尝试修改这个,然后我会报告结果。再次感谢您。 - Renesis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接