2011-04-13 21 views
55

私は不連続なx軸を持つpyplotを使ってプロットを作成しようとしています。これが描かれている通常の方法は、軸はこのようなものがありますということです。Python/Matplotlib - 不連続な軸を作る方法はありますか?

(値)---- // //あなたがしていることを示している----(後の値)

(値)と(後の値)の間をすべてスキップします。

私はこれの例を見つけることができませんでしたので、可能かどうかは疑問です。私はあなたが財務データなどの不連続性を介してデータを結合できることを知っていますが、軸のジャンプをより明示的にしたいと思います。現時点では、私はサブプロットを使用していますが、最終的にはすべて同じグラフになるようにしたいと思っています。

答えて

56

パウロの答えは、これを行うための完全に罰金方法です。

ただし、カスタムトランスフォームを作成したくない場合は、2つのサブプロットを使用して同じ効果を作成できます。

例をゼロから作成するのではなく、matplotlibの例にはan excellent example of this written by Paul Ivanovがあります(これは現行のgitのヒントの中にあります。数ヶ月前にコミットされているので、まだWebページにはありません)。

これは、y軸の代わりに不連続なx軸を持つこの例の単純な変更です。

import matplotlib.pylab as plt 
import numpy as np 

# If you're not familiar with np.r_, don't worry too much about this. It's just 
# a series with points from 0 to 1 spaced at 0.1, and 9 to 10 with the same spacing. 
x = np.r_[0:1:0.1, 9:10:0.1] 
y = np.sin(x) 

fig,(ax,ax2) = plt.subplots(1, 2, sharey=True) 

# plot the same data on both axes 
ax.plot(x, y, 'bo') 
ax2.plot(x, y, 'bo') 

# zoom-in/limit the view to different portions of the data 
ax.set_xlim(0,1) # most of the data 
ax2.set_xlim(9,10) # outliers only 

# hide the spines between ax and ax2 
ax.spines['right'].set_visible(False) 
ax2.spines['left'].set_visible(False) 
ax.yaxis.tick_left() 
ax.tick_params(labeltop='off') # don't put tick labels at the top 
ax2.yaxis.tick_right() 

# Make the spacing between the two axes a bit smaller 
plt.subplots_adjust(wspace=0.15) 

plt.show() 

enter image description here

壊れ軸ラインに//効果を追加するには、我々が行うことができます:基本的に

、あなたはこのような何かを(どの私はこの記事CWを作ってるんだ理由です)この(再び、ポール・イワノフの例から変更):

import matplotlib.pylab as plt 
import numpy as np 

# If you're not familiar with np.r_, don't worry too much about this. It's just 
# a series with points from 0 to 1 spaced at 0.1, and 9 to 10 with the same spacing. 
x = np.r_[0:1:0.1, 9:10:0.1] 
y = np.sin(x) 

fig,(ax,ax2) = plt.subplots(1, 2, sharey=True) 

# plot the same data on both axes 
ax.plot(x, y, 'bo') 
ax2.plot(x, y, 'bo') 

# zoom-in/limit the view to different portions of the data 
ax.set_xlim(0,1) # most of the data 
ax2.set_xlim(9,10) # outliers only 

# hide the spines between ax and ax2 
ax.spines['right'].set_visible(False) 
ax2.spines['left'].set_visible(False) 
ax.yaxis.tick_left() 
ax.tick_params(labeltop='off') # don't put tick labels at the top 
ax2.yaxis.tick_right() 

# Make the spacing between the two axes a bit smaller 
plt.subplots_adjust(wspace=0.15) 

# This looks pretty good, and was fairly painless, but you can get that 
# cut-out diagonal lines look with just a bit more work. The important 
# thing to know here is that in axes coordinates, which are always 
# between 0-1, spine endpoints are at these locations (0,0), (0,1), 
# (1,0), and (1,1). Thus, we just need to put the diagonals in the 
# appropriate corners of each of our axes, and so long as we use the 
# right transform and disable clipping. 

d = .015 # how big to make the diagonal lines in axes coordinates 
# arguments to pass plot, just so we don't keep repeating them 
kwargs = dict(transform=ax.transAxes, color='k', clip_on=False) 
ax.plot((1-d,1+d),(-d,+d), **kwargs) # top-left diagonal 
ax.plot((1-d,1+d),(1-d,1+d), **kwargs) # bottom-left diagonal 

kwargs.update(transform=ax2.transAxes) # switch to the bottom axes 
ax2.plot((-d,d),(-d,+d), **kwargs) # top-right diagonal 
ax2.plot((-d,d),(1-d,1+d), **kwargs) # bottom-right diagonal 

# What's cool about this is that now if we vary the distance between 
# ax and ax2 via f.subplots_adjust(hspace=...) or plt.subplot_tool(), 
# the diagonal lines will move accordingly, and stay right at the tips 
# of the spines they are 'breaking' 

plt.show() 

enter image description here

+5

私はそれをもっと良く言ったわけではありませんでした;) –

+1

サブフィギュアの比率が1:1の場合、 '//'効果を作る方法はうまくいくようです。どのような比率で導入するかを知っていますか? 'GridSpec(width_ratio = [n、m])'? –

23

この機能には多くの提案がありますが、実装されているという示唆はありません。時間を置いて実行可能なソリューションです。これは、ステップ関数変換をx軸に適用します。コードはたくさんありますが、ほとんどは定型的なカスタムスケールのものなので、かなりシンプルです。私はスタイルの問題であるため、ブレークの位置を示すグラフィックを追加していません。仕事を終えることを幸運。

from matplotlib import pyplot as plt 
from matplotlib import scale as mscale 
from matplotlib import transforms as mtransforms 
import numpy as np 

def CustomScaleFactory(l, u): 
    class CustomScale(mscale.ScaleBase): 
     name = 'custom' 

     def __init__(self, axis, **kwargs): 
      mscale.ScaleBase.__init__(self) 
      self.thresh = None #thresh 

     def get_transform(self): 
      return self.CustomTransform(self.thresh) 

     def set_default_locators_and_formatters(self, axis): 
      pass 

     class CustomTransform(mtransforms.Transform): 
      input_dims = 1 
      output_dims = 1 
      is_separable = True 
      lower = l 
      upper = u 
      def __init__(self, thresh): 
       mtransforms.Transform.__init__(self) 
       self.thresh = thresh 

      def transform(self, a): 
       aa = a.copy() 
       aa[a>self.lower] = a[a>self.lower]-(self.upper-self.lower) 
       aa[(a>self.lower)&(a<self.upper)] = self.lower 
       return aa 

      def inverted(self): 
       return CustomScale.InvertedCustomTransform(self.thresh) 

     class InvertedCustomTransform(mtransforms.Transform): 
      input_dims = 1 
      output_dims = 1 
      is_separable = True 
      lower = l 
      upper = u 

      def __init__(self, thresh): 
       mtransforms.Transform.__init__(self) 
       self.thresh = thresh 

      def transform(self, a): 
       aa = a.copy() 
       aa[a>self.lower] = a[a>self.lower]+(self.upper-self.lower) 
       return aa 

      def inverted(self): 
       return CustomScale.CustomTransform(self.thresh) 

    return CustomScale 

mscale.register_scale(CustomScaleFactory(1.12, 8.88)) 

x = np.concatenate((np.linspace(0,1,10), np.linspace(9,10,10))) 
xticks = np.concatenate((np.linspace(0,1,6), np.linspace(9,10,6))) 
y = np.sin(x) 
plt.plot(x, y, '.') 
ax = plt.gca() 
ax.set_xscale('custom') 
ax.set_xticks(xticks) 
plt.show() 

enter image description here

+0

を。これは私の初めてのカスタム軸をめちゃくちゃにするので、どうやってそれがどうなるか見る必要があります。 –

+0

'InvertedCustomTransform'の' def transform'に小さなタイプミスがあります。ここで、 'upper'の代わりに' self.upper'を読むべきです。しかし、素晴らしい例をありがとう! –

+0

クラスを使用する方法を示すためにいくつかの行を追加できますか? –

0

フレデリック・ノールの質問によれば、比が1:1でないグリッド・スペックを使用するとき、斜めの「折れ線」の平行な方向付けを可能にする方法は、Paul IvanovとJoe Kingtonsの提案に基づいて以下の変更が役立ちます。幅比は、変数nおよびmを使用して変更できます。

import matplotlib.pylab as plt 
import numpy as np 
import matplotlib.gridspec as gridspec 

x = np.r_[0:1:0.1, 9:10:0.1] 
y = np.sin(x) 

n = 5; m = 1; 
gs = gridspec.GridSpec(1,2, width_ratios = [n,m]) 

plt.figure(figsize=(10,8)) 

ax = plt.subplot(gs[0,0]) 
ax2 = plt.subplot(gs[0,1], sharey = ax) 
plt.setp(ax2.get_yticklabels(), visible=False) 
plt.subplots_adjust(wspace = 0.1) 

ax.plot(x, y, 'bo') 
ax2.plot(x, y, 'bo') 

ax.set_xlim(0,1) 
ax2.set_xlim(10,8) 

# hide the spines between ax and ax2 
ax.spines['right'].set_visible(False) 
ax2.spines['left'].set_visible(False) 
ax.yaxis.tick_left() 
ax.tick_params(labeltop='off') # don't put tick labels at the top 
ax2.yaxis.tick_right() 

d = .015 # how big to make the diagonal lines in axes coordinates 
# arguments to pass plot, just so we don't keep repeating them 
kwargs = dict(transform=ax.transAxes, color='k', clip_on=False) 

on = (n+m)/n; om = (n+m)/m; 
ax.plot((1-d*on,1+d*on),(-d,d), **kwargs) # bottom-left diagonal 
ax.plot((1-d*on,1+d*on),(1-d,1+d), **kwargs) # top-left diagonal 
kwargs.update(transform=ax2.transAxes) # switch to the bottom axes 
ax2.plot((-d*om,d*om),(-d,d), **kwargs) # bottom-right diagonal 
ax2.plot((-d*om,d*om),(1-d,1+d), **kwargs) # top-right diagonal 

plt.show() 
6

brokenaxesパッケージチェック:私はちょうど今のために行う必要があります推測

import matplotlib.pyplot as plt 
from brokenaxes import brokenaxes 
import numpy as np 

fig = plt.figure(figsize=(5,2)) 
bax = brokenaxes(xlims=((0, .1), (.4, .7)), ylims=((-1, .7), (.79, 1)), hspace=.05) 
x = np.linspace(0, 1, 100) 
bax.plot(x, np.sin(10 * x), label='sin') 
bax.plot(x, np.cos(10 * x), label='cos') 
bax.legend(loc=3) 
bax.set_xlabel('time') 
bax.set_ylabel('value') 

example from brokenaxes

+0

Pycharm Community 2016.3.2のインストール後に '' brokenaxes import brokenaxes''を実行できません。 @ ben.dichter –

+0

バグがありました。それを私が直した。固定バージョンのコードをインストールするには 'pip install brokenaxes == 0.2'を実行してください。 –

+0

ax.grid(True)とのやりとりが悪いようです – innisfree

関連する問題