Python 将第二个轴添加到极坐标图

Python 将第二个轴添加到极坐标图,python,matplotlib,multiple-axes,Python,Matplotlib,Multiple Axes,我尝试在一个图形中绘制两个极坐标图。请参见下面的代码: 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 =

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

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)。蓝色蜘蛛图显示每个扇区的平均值

在所示的图中,每个图的值是相似的,但这是罕见的。我需要将第二个绘图指定给另一个轴,并在另一个方向上显示该轴

编辑:

在得到乔的漂亮回答后,我得到了这个数字的结果。 这几乎是我想要实现的一切。但有几点我没能弄明白

  • 该图是为动态变化的数据库绘制的。因此,我需要一个动态的方法来获得相同的圆的位置。到目前为止,我用以下方法解决它:

    start, end = ax2.get_ylim()
    ax2.yaxis.set_ticks(np.arange(0, end, end / len(ax.yaxis.get_ticklocs())))
    
    方法:对于第二个轴,我改变刻度,以便将刻度线与第一个轴的刻度线相匹配。 在大多数情况下,我会得到一些小数位,但我不想这样,因为这会破坏情节的清晰性。有没有办法更巧妙地解决这个问题

  • ytics(径向圆)的范围从0到下一个到最后一个圆。如何实现从第一个圆到最后一个圆(边界)的值范围?与第一个轴相同


  • 所以,据我所知,你想在同一个极坐标图上显示不同量级的数据。基本上,您要问的是如何对极轴执行类似于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限制(和/或r刻度),以便网格彼此重叠。或者,您可以编写一个自定义定位器来自动执行此操作。让我们继续使用这里的简单方法:

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

    再加上@JoeKington(很棒)的回答,我发现“确保原始轴刻度标签位于绘制在成对轴上的任何东西的顶部的黑客”对我不起作用,因此我使用了以下替代方法:

    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)
    

    请修正你的缩进。看起来您使用的是一组大量定制的类,这使得分类很困难。您能否仅使用标准matplotlib对象演示所需内容?感谢您提供此图像。我的声誉分数太低了,不能自己做。至于你的第二个问题,关于如何显示最后一个半径标签,这只是因为你正在使用
    np.arange
    设置刻度
    arange
    在端点之前停止(例如
    np.arange(0,0.5,0.1)
    生成
    数组([0.0,0.1,0.2,0.3,0.4])
    )。如果您想包括端点,请使用
    end+dx
    (其中
    dx
    是您的时间间隔)。这个答案非常好,我想多投一票,但我不能:(我会尽量让我自己的答案和这个一样好。@GamesBrainiac-谢谢!非常感谢你的详细和易于理解的答案,对我来说效果很好。还有一些问题,在我的第一篇文章中提到过。@fidelitas-谢谢!我会添加一个第二轴刻度自动定位器的示例,但我可能无法获得直到这个周末。(如果其他人想尝试一下,请随意!)