2013-12-09 5 views
7

matplotlibのsymlogスケールを使用して、正の方向と負の方向の両方に広がる広範囲のパラメータをカバーします。残念なことに、symlogスケールはあまり直感的ではなく、あまり一般的ではないでしょう。したがって、私は、主要なティックの間に小さなダニを配置することによって、使用されるスケーリングをより明白にしたいと思います。スケールのログ部分では、[2,3、...、9] * 10^eにダニを配置したいところです。eは近くのメジャーチックです。さらに、0と0.1の間の範囲は、均等に配置された小さなダニで覆われている必要があります。多くの小目盛りへの道があるsymlogスケールにマイナーチックを配置する方法は?

enter image description here

注こと:

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.ticker import LogLocator, AutoLocator 

x = np.linspace(-5, 5, 100) 
y = x 

plt.plot(x, y) 
plt.yscale('symlog', linthreshy=1e-1) 

yaxis = plt.gca().yaxis 
yaxis.set_minor_locator(LogLocator(subs=np.arange(2, 10))) 

plt.show() 

残念ながら、これは私が欲しいものを生成しません:私は、次のコードを使用して、このようなダニに到着するmatplotlib.ticker APIを使用してみましたおそらくLogLocatorに起因するものと思われます。さらに、負の軸に小さな目盛りはありません。

代わりにAutoLocatorを使用すると小さな目盛りが表示されません。 AutoMinorLocatorでは、スケーリング軸が均等にしかサポートされていません。私の質問は、どのようにして目的のティック配置を達成するのですか?

答えて

8

問題を少し深く掘り下げて、私は一般的な解決策を思いつくのは難しいことに気付きました。幸いなことに、私は私のデータにいくつかの制約を想定することができ、カスタム作られたクラスが十分な問題を解決することであった:

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.ticker import Locator 


class MinorSymLogLocator(Locator): 
    """ 
    Dynamically find minor tick positions based on the positions of 
    major ticks for a symlog scaling. 
    """ 
    def __init__(self, linthresh): 
     """ 
     Ticks will be placed between the major ticks. 
     The placement is linear for x between -linthresh and linthresh, 
     otherwise its logarithmically 
     """ 
     self.linthresh = linthresh 

    def __call__(self): 
     'Return the locations of the ticks' 
     majorlocs = self.axis.get_majorticklocs() 

     # iterate through minor locs 
     minorlocs = [] 

     # handle the lowest part 
     for i in xrange(1, len(majorlocs)): 
      majorstep = majorlocs[i] - majorlocs[i-1] 
      if abs(majorlocs[i-1] + majorstep/2) < self.linthresh: 
       ndivs = 10 
      else: 
       ndivs = 9 
      minorstep = majorstep/ndivs 
      locs = np.arange(majorlocs[i-1], majorlocs[i], minorstep)[1:] 
      minorlocs.extend(locs) 

     return self.raise_if_exceeds(np.array(minorlocs)) 

    def tick_values(self, vmin, vmax): 
     raise NotImplementedError('Cannot get tick locations for a ' 
            '%s type.' % type(self)) 


x = np.linspace(-5, 5, 100) 
y = x 

plt.plot(x, y) 
plt.yscale('symlog', linthreshy=1e-1) 

yaxis = plt.gca().yaxis 
yaxis.set_minor_locator(MinorSymLogLocator(1e-1)) 

plt.show() 

これは、この方法だけの場所が主要な間ティックこと

enter image description here

注意を生成しますダニ。ズームインして画像にパンすると目立つようになります。さらに、軸自体から簡単かつ堅牢に読み取る方法が見つからないため、線形しきい値をクラスに明示的に指定する必要があります。

+0

あなたにこれを追加するために、上流にPRを開くことができます:私は、次を与えるためのOP MinorSymLogLocator()クラス(小目盛りのlocatoinを設定する際に、一時的な大目盛りの場所を追加することにより、エッジを埋める)ハッキングしましたmplコードベース? – tacaswell

0

OPsソリューションはうまく機能しますが、リニアスレッシュホールド値の倍数でない場合、目盛りが軸のエッジで生成されません。

class MinorSymLogLocator(Locator): 
    """ 
    Dynamically find minor tick positions based on the positions of 
    major ticks for a symlog scaling. 
    """ 
    def __init__(self, linthresh, nints=10): 
     """ 
     Ticks will be placed between the major ticks. 
     The placement is linear for x between -linthresh and linthresh, 
     otherwise its logarithmically. nints gives the number of 
     intervals that will be bounded by the minor ticks. 
     """ 
     self.linthresh = linthresh 
     self.nintervals = nints 

    def __call__(self): 
     # Return the locations of the ticks 
     majorlocs = self.axis.get_majorticklocs() 

     if len(majorlocs) == 1: 
      return self.raise_if_exceeds(np.array([])) 

     # add temporary major tick locs at either end of the current range 
     # to fill in minor tick gaps 
     dmlower = majorlocs[1] - majorlocs[0] # major tick difference at lower end 
     dmupper = majorlocs[-1] - majorlocs[-2] # major tick difference at upper end 

     # add temporary major tick location at the upper end 
     if majorlocs[0] != 0. and ((majorlocs[0] != self.linthresh and dmlower > self.linthresh) or (dmlower == self.linthresh and majorlocs[0] < 0)): 
      majorlocs = np.insert(majorlocs, 0, majorlocs[0]*10.) 
     else: 
      majorlocs = np.insert(majorlocs, 0, majorlocs[0]-self.linthresh) 

     # add temporary major tick location at the upper end 
     if majorlocs[-1] != 0. and ((np.abs(majorlocs[-1]) != self.linthresh and dmupper > self.linthresh) or (dmupper == self.linthresh and majorlocs[-1] > 0)): 
      majorlocs = np.append(majorlocs, majorlocs[-1]*10.) 
     else: 
      majorlocs = np.append(majorlocs, majorlocs[-1]+self.linthresh) 

     # iterate through minor locs 
     minorlocs = [] 

     # handle the lowest part 
     for i in xrange(1, len(majorlocs)): 
      majorstep = majorlocs[i] - majorlocs[i-1] 
      if abs(majorlocs[i-1] + majorstep/2) < self.linthresh: 
       ndivs = self.nintervals 
      else: 
       ndivs = self.nintervals - 1. 

      minorstep = majorstep/ndivs 
      locs = np.arange(majorlocs[i-1], majorlocs[i], minorstep)[1:] 
      minorlocs.extend(locs) 

     return self.raise_if_exceeds(np.array(minorlocs)) 

    def tick_values(self, vmin, vmax): 
     raise NotImplementedError('Cannot get tick locations for a ' 
          '%s type.' % type(self)) 
関連する問題