具有“浮动”径向轴的极坐标图

时间:2014-06-27 17:18:49

标签: python matplotlib polar-coordinates

我正在处理一个由网格中的大量极坐标图组成的图,所有这些图都在径向轴上共享一个共同的比例。为了适应图形,每个图需要非常小,但是当我缩小轴的尺寸时,径向轴的刻度标签看起来很拥挤且难以辨认,并且模糊了我试图绘制的数据。

例如:

import numpy as np
from matplotlib import pyplot as plt

fig, axes = plt.subplots(1, 4, figsize=(9, 2), subplot_kw=dict(polar=True))

theta = np.r_[np.linspace(0, 2*np.pi, 12), 0]
for aa in axes.flat:
    x = np.random.rand(12)
    aa.plot(theta, np.r_[x, x[0]], '-sb')
    aa.set_rlim(0, 1)

fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9, wspace=0.5)

enter image description here

我意识到通过减小字体大小和径向刻度的数量可以部分地减轻问题,但我更愿意避免刻度标签与我的数据完全重叠。相反,我希望有一个漂浮的'位于图之外的径向轴,如下所示:

enter image description here

使用正常的笛卡尔图我会使用ax.spine['left'].set_position(...),但PolarAxesSubplot只有一个u'polar'脊椎无法抵消。有一个很好的'为极坐标图创建浮动径向轴的方法,理想情况是更新其比例和限制以匹配极坐标图径向轴的任何变化?

3 个答案:

答案 0 :(得分:3)

这不完全是你想要的,但它可能会给你一个关于如何准确定位极轴的标签的提示:

import numpy as np
from matplotlib import pyplot as plt

fig, axes = plt.subplots(1, 4, figsize=(9, 2), subplot_kw=dict(polar=True))

theta = np.r_[np.linspace(0, 2*np.pi, 12), 0]
for aa in axes.flat:
    x = np.random.rand(12)
    aa.plot(theta, np.r_[x, x[0]], '-sb')
    aa.set_rlim(0, 1)

plt.draw()
ax = axes[-1]
for r, t in zip(ax.yaxis.get_ticklocs(), ax.yaxis.get_ticklabels()):
    ax.text(np.pi/2, r, '$\cdot$'*20 + t.get_text(), ha='left', va='center',
            fontsize=10, color='0.25')
for ax in axes:
    ax.yaxis.set_ticklabels([])

fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9, wspace=0.5)
fig.savefig('test.png', bbox_inches='tight')

enter image description here

答案 1 :(得分:2)

也许我们可以在上面叠加另一个情节:

fig, axes = plt.subplots(1, 4, figsize=(9, 2), subplot_kw=dict(polar=True))

for aa in axes.flat:
    aa.plot(theta, r, '-sb')
    aa.set_rlim(0, 1)
    aa.set_yticklabels([])

box=axes[0].get_position()
axl=fig.add_axes([box.xmin/2, #put it half way between the edge of the 1st subplot and the left edge of the figure
                  0.5*(box.ymin+box.ymax), #put the origin at the same height of the origin of the polar plots
                  box.width/40, #Doesn't really matter, we will set everything invisible, except the y axis
                  box.height*0.4], #fig.subplots_adjust will not adjust this axis, so we will need to manually set the height to 0.4 (half of 0.9-0.1)
                 axisbg=None) #transparent background.
axl.spines['top'].set_visible(False)
axl.spines['right'].set_visible(False)
axl.spines['bottom'].set_visible(False)
axl.yaxis.set_ticks_position('both')
axl.xaxis.set_ticks_position('none')
axl.set_xticklabels([])
axl.set_ylim(0,1)
axl.set_ylabel('$R$\t', rotation=0)

fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9, wspace=0.5)

enter image description here

修改

事实证明subplots_adjust也会影响叠加轴。如果我们检查fig内的轴列表,叠加轴就在那里(如果有疑问,请检查 site-packages \ matplotlib \ figure.py ):

In [27]:

fig.axes
Out[27]:
[<matplotlib.axes.PolarAxesSubplot at 0x9714650>,
 <matplotlib.axes.PolarAxesSubplot at 0x9152730>,
 <matplotlib.axes.PolarAxesSubplot at 0x9195b90>,
 <matplotlib.axes.PolarAxesSubplot at 0x91878b0>,
 <matplotlib.axes.Axes at 0x9705a90>]

真正的问题是wspace=0.5不仅会影响极坐标图的宽度,还会影响高度(因此方面保持不变)。但对于非极性叠加轴,它只影响宽度。因此,需要额外的宽度修改,解决方案是:

fig, axes = plt.subplots(1, 4, figsize=(10, 2), subplot_kw=dict(polar=True))

for aa in axes.flat:
    aa.plot(theta, r, '-sb')
    aa.set_rlim(0, 1)
    aa.set_yticklabels([])

#fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9, wspace=0.5)

box=axes[0].get_position()
axl=fig.add_axes([box.xmin/2, 
                  0.5*(box.ymin+box.ymax),
                  box.width/40,
                  box.height*0.5],
                 axisbg=None)
#fig.add_axes([box.xmin, box.ymin, box.width, box.height])
axl.spines['top'].set_visible(False)
axl.spines['right'].set_visible(False)
axl.spines['bottom'].set_visible(False)
axl.yaxis.set_ticks_position('both')
axl.xaxis.set_ticks_position('none')
axl.set_xticklabels([])
axl.set_ylim(0,1)
axl.set_ylabel('$R$\t', rotation=0)

w_pre_scl=box.width

fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9, wspace=0.5)
ratio=axes[0].get_position().width/w_pre_scl

axlb=axl.get_position()
axl.set_position([axlb.xmin, axlb.ymin, axlb.width, axlb.height*ratio])

enter image description here

如果没有wspace=0.5,则最后几行没有净影响:

fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)
#ratio=axes[0].get_position().width/w_pre_scl

#axlb=axl.get_position()
#axl.set_position([axlb.xmin, axlb.ymin, axlb.width, axlb.height*ratio])

enter image description here

答案 2 :(得分:2)

根据Saullo的回答,这里有一个看起来稍微好看的黑客,包括在数据坐标中绘制刻度,然后在x中应用固定的翻译:

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import transforms

theta = np.linspace(0, 2 * np.pi, 13, endpoint=True)
fig, axes = plt.subplots(1, 4, figsize=(5, 2), subplot_kw=dict(polar=True))

for aa in axes.flat:
    aa.hold(True)
    r = np.random.rand(12)
    r = np.r_[r, r[0]]
    aa.plot(theta, r, '-sb')
    aa.set_rlim(0, 1)
    aa.set_yticklabels([])

factor = 1.1
d = axes[0].get_yticks()[-1] * factor
r_tick_labels = [0] + axes[0].get_yticks()
r_ticks = (np.array(r_tick_labels) ** 2 + d ** 2) ** 0.5
theta_ticks = np.arcsin(d / r_ticks) + np.pi / 2
r_axlabel = (np.mean(r_tick_labels) ** 2 + d ** 2) ** 0.5
theta_axlabel = np.arcsin(d / r_axlabel) + np.pi / 2

# fixed offsets in x
offset_spine = transforms.ScaledTranslation(-100, 0, axes[0].transScale)
offset_ticklabels = transforms.ScaledTranslation(-10, 0, axes[0].transScale)
offset_axlabel = transforms.ScaledTranslation(-40, 0, axes[0].transScale)

# apply these to the data coordinates of the line/ticks
trans_spine = axes[0].transData + offset_spine
trans_ticklabels = trans_spine + offset_ticklabels
trans_axlabel = trans_spine + offset_axlabel

# plot the 'spine'
axes[0].plot(theta_ticks, r_ticks, '-_k', transform=trans_spine,
             clip_on=False)

# plot the 'tick labels'
for ii in xrange(len(r_ticks)):
    axes[0].text(theta_ticks[ii], r_ticks[ii], "%.1f" % r_tick_labels[ii],
                 ha="right", va="center", clip_on=False,
                 transform=trans_ticklabels)

# plot the 'axis label'
axes[0].text(theta_axlabel, r_axlabel, '$r$', fontsize='xx-large',
             ha='right', va='center', clip_on=False, transform=trans_axlabel)

fig.savefig('test.png', bbox_inches='tight')

enter image description here

同样,这具有以下优点:当图形尺寸改变时,刻度线的y位置将相对于极坐标图的径向轴保持正确。但是(在从@SaulloCastro更新之前),由于x-offset是以点为单位指定的,并且是固定的,当图形大小改变时浮动轴将无法正确定位,并且最终可能与极坐标图重叠:

enter image description here