10

1 つの図に 2 つの極座標プロットをプロットしようとしています。以下のコードを参照してください。

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) の頻度を示します。青いスパイダー プロットは、各セクターの平均値を示しています。

示されている図では、各プロットの値は類似していますが、これはまれです。2 番目のプロットを別の軸に割り当て、この軸を別の方向に表示する必要があります。

編集:

ジョーの素敵な答えの後、私は数字の結果を得る. 暫定結果 それが私が達成したかったほとんどすべてです。しかし、私が理解できなかったいくつかの点があります。

  1. プロットは、動的に変化するデータベース用に作成されています。したがって、円の同じ位置を取得する動的な方法が必要です。今まで私はそれを解決します:

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

    手段: 2 番目の軸については、ticklocs を最初の軸の 1 つに合わせるために目盛りを変更します。ほとんどの場合、小数点以下の桁数を取得しますが、プロットの明確さが損なわれるため、それは望ましくありません。この問題をよりスマートに解決する方法はありますか?

  2. ytics (放射状のもの) の範囲は、0 から最後から 2 番目の円までです。値が最初の円から最後の円 (境界線) までの範囲になるようにするにはどうすればよいですか? 最初の軸も同様です。

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

ここに画像の説明を入力

これは私たちが望んでいることですが、最初はかなり悪いように見えます。改善点の 1 つは、目盛りラベルをプロット対象に対応させることです。

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

ここに画像の説明を入力

ただし、まだダブル グリッドがあり、かなり混乱しています。これを回避する簡単な方法の 1 つは、グリッドが互いに重なるように r-limits (および/または r-ticks) を手動で設定することです。または、これを自動的に行うカスタム ロケーターを作成することもできます。ここでは単純なアプローチに固執しましょう。

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

ここに画像の説明を入力

警告:共有軸は極座標プロットでは機能しないため、上記の実装では、元の軸の位置を変更すると問題が発生します。たとえば、Figure にカラーバーを追加すると、さまざまな問題が発生します。これを回避することは可能ですが、私はその部分を省略しました。必要な場合はお知らせください。例を追加します。

いずれにせよ、最終的な図を生成するための完全なスタンドアロン コードは次のとおりです。

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の(素晴らしい)回答に追加するだけで、「元の軸の目盛りラベルが双子の軸にプロットされているものの上にあることを確認するためのハック」がうまくいかないことがわかったので、代わりに私は使用した:

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 に答える