10

我尝试在一个图中绘制两个极坐标图。请参见下面的代码:

fig = super(PlotWindPowerDensity, self).get_figure()
    rect = [0.1, 0.1, 0.8, 0.8]
    ax = WindSpeedDirectionAxes(fig, rect)

    self.values_dict = collections.OrderedDict(sorted(self.values_dict.items()))
    values = self.values_dict.items()
    di, wpd = zip(*values)
    wpd = np.array(wpd).astype(np.double)
    wpdmask = np.isfinite(wpd)
    theta = self.radar_factory(int(len(wpd)))

    # spider plot
    ax.plot(theta[wpdmask], wpd[wpdmask], color = 'b', alpha = 0.5)
    ax.fill(theta[wpdmask], wpd[wpdmask], facecolor = 'b', alpha = 0.5)

    # bar plot
    ax.plot_bar(table=self.table, sectors=self.sectors, speedbins=self.wpdbins, option='wind_power_density', colorfn=get_sequential_colors)

    fig.add_axes(ax)
    return fig

结果到现在

条的长度是数据库(该扇区有多少个采样点)。条形的颜色显示相应扇区中某些值箱的频率(例如 2.5-5 m/s)(蓝色:低,红色:高)。蓝色蜘蛛图显示了每个扇区的平均值。

在所示图中,每个图的值都相似,但这种情况很少见。我需要将第二个图分配给另一个轴并在另一个方向显示该轴。

编辑:

在乔的好回答之后,我得到了这个数字的结果。 暂定结果 这几乎就是我想要实现的一切。但是有些地方我无法弄清楚。

  1. 该图是为动态变化的数据库制作的。因此,我需要一种动态的方式来获得圆圈的相同位置。直到现在我解决它:

    start, end = ax2.get_ylim()
    ax2.yaxis.set_ticks(np.arange(0, end, end / len(ax.yaxis.get_ticklocs())))
    

    意思是:对于第二个轴,我更改刻度以使刻度块适合第一个轴的刻度。在大多数情况下,我会得到一些小数位,但我不希望这样,因为它破坏了情节的清晰度。有没有办法更聪明地解决这个问题?

  2. ytics(径向的)范围从 0 到倒数第二个圆。我怎样才能实现从第一个圆圈到最后一个圆圈(边界)的值范围?与第一个轴相同。

4

2 回答 2

11

因此,据我了解,您希望在同一个极坐标图上显示具有非常不同幅度的数据。基本上你在问如何做类似于twinx极轴的事情。

作为说明问题的示例,最好在下图中以与蓝色系列不同的比例显示绿色系列,同时将它们保持在相同的极轴上以便于比较:

import numpy as np
import matplotlib.pyplot as plt

numpoints = 30
theta = np.linspace(0, 2*np.pi, numpoints)
r1 = np.random.random(numpoints)
r2 = 5 * np.random.random(numpoints)

params = dict(projection='polar', theta_direction=-1, theta_offset=np.pi/2)
fig, ax = plt.subplots(subplot_kw=params)

ax.fill_between(theta, r2, color='blue', alpha=0.5)
ax.fill_between(theta, r1, color='green', alpha=0.5)

plt.show()

在此处输入图像描述

但是,ax.twinx()不适用于极坐标图。

可以解决这个问题,但这不是很简单。这是一个例子:

import numpy as np
import matplotlib.pyplot as plt

def main():
    numpoints = 30
    theta = np.linspace(0, 2*np.pi, numpoints)
    r1 = np.random.random(numpoints)
    r2 = 5 * np.random.random(numpoints)

    params = dict(projection='polar', theta_direction=-1, theta_offset=np.pi/2)
    fig, ax = plt.subplots(subplot_kw=params)
    ax2 = polar_twin(ax)

    ax.fill_between(theta, r2, color='blue', alpha=0.5)
    ax2.fill_between(theta, r1, color='green', alpha=0.5)
    plt.show()

def polar_twin(ax):
    ax2 = ax.figure.add_axes(ax.get_position(), projection='polar', 
                             label='twin', frameon=False,
                             theta_direction=ax.get_theta_direction(),
                             theta_offset=ax.get_theta_offset())
    ax2.xaxis.set_visible(False)
    # There should be a method for this, but there isn't... Pull request?
    ax2._r_label_position._t = (22.5 + 180, 0.0)
    ax2._r_label_position.invalidate()
    # Ensure that original axes tick labels are on top of plots in twinned axes
    for label in ax.get_yticklabels():
        ax.figure.texts.append(label)
    return ax2

main()

在此处输入图像描述

这可以满足我们的要求,但起初看起来相当糟糕。一项改进是刻度标签与我们正在绘制的内容相对应:

plt.setp(ax2.get_yticklabels(), color='darkgreen')
plt.setp(ax.get_yticklabels(), color='darkblue')

在此处输入图像描述

然而,我们仍然有双网格,这是相当混乱的。解决此问题的一种简单方法是手动设置 r-limits(和/或 r-ticks),以使网格彼此重叠。或者,您可以编写一个自定义定位器来自动执行此操作。让我们在这里坚持简单的方法:

ax.set_rlim([0, 5])
ax2.set_rlim([0, 1])

在此处输入图像描述

警告:因为共享轴不适用于极坐标图,所以我上面的实现会遇到任何改变原始轴位置的问题。例如,在图中添加颜色条会导致各种问题。有可能解决这个问题,但我已经把这部分排除在外了。如果您需要它,请告诉我,我将添加一个示例。

无论如何,这是生成最终图形的完整独立代码:

import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1977)

def main():
    numpoints = 30
    theta = np.linspace(0, 2*np.pi, numpoints)
    r1 = np.random.random(numpoints)
    r2 = 5 * np.random.random(numpoints)

    params = dict(projection='polar', theta_direction=-1, theta_offset=np.pi/2)
    fig, ax = plt.subplots(subplot_kw=params)
    ax2 = polar_twin(ax)

    ax.fill_between(theta, r2, color='blue', alpha=0.5)
    ax2.fill_between(theta, r1, color='green', alpha=0.5)

    plt.setp(ax2.get_yticklabels(), color='darkgreen')
    plt.setp(ax.get_yticklabels(), color='darkblue')
    ax.set_ylim([0, 5])
    ax2.set_ylim([0, 1])

    plt.show()

def polar_twin(ax):
    ax2 = ax.figure.add_axes(ax.get_position(), projection='polar', 
                             label='twin', frameon=False,
                             theta_direction=ax.get_theta_direction(),
                             theta_offset=ax.get_theta_offset())
    ax2.xaxis.set_visible(False)

    # There should be a method for this, but there isn't... Pull request?
    ax2._r_label_position._t = (22.5 + 180, 0.0)
    ax2._r_label_position.invalidate()

    # Bit of a hack to ensure that the original axes tick labels are on top of
    # whatever is plotted in the twinned axes. Tick labels will be drawn twice.
    for label in ax.get_yticklabels():
        ax.figure.texts.append(label)

    return ax2

if __name__ == '__main__':
    main()
于 2013-10-27T17:09:03.543 回答
2

只是为了添加到@JoeKington 的(很棒的)答案,我发现“确保原始轴刻度标签位于双轴中绘制的任何内容之上的hack”对我不起作用,因此作为替代我用过:

from matplotlib.ticker import MaxNLocator

#Match the tick point locations by setting the same number of ticks in the 
# 2nd axis as the first    
ax2.yaxis.set_major_locator(MaxNLocator(nbins=len(ax1.get_yticks())))

#Set the last tick as the plot limit
ax2.set_ylim(0, ax2.get_yticks()[-1])

#Remove the tick label at zero
ax2.yaxis.get_major_ticks()[0].label1.set_visible(False)
于 2015-03-08T17:21:50.513 回答