2017-07-30 15 views
8

Trục Matplotlib có ve Lớn và Nhỏ. Làm cách nào để thêm dấu thứ ba dưới mức Nhỏ?Cách thêm mức thứ ba của bọ ve trong trăn matplotlib

Ví dụ

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

t = np.arange(0.0, 100.0, 0.1) 
s = np.sin(0.1*np.pi*t)*np.exp(-t*0.01) 

fig, ax = plt.subplots() 
plt.plot(t, s) 

ax1 = ax.twiny() 
ax1.plot(t, s) 

ax1.xaxis.set_ticks_position('bottom') 

majors = np.linspace(0, 100, 6) 
minors = np.linspace(0, 100, 11) 
thirds = np.linspace(0, 100, 101) 

ax.xaxis.set_major_locator(matplotlib.ticker.FixedLocator(majors)) 
ax.xaxis.set_minor_locator(matplotlib.ticker.FixedLocator(minors)) 
ax1.xaxis.set_major_locator(matplotlib.ticker.FixedLocator([])) 
ax1.xaxis.set_minor_locator(matplotlib.ticker.FixedLocator(thirds)) 
ax1.tick_params(which='minor', length=2) 
ax.tick_params(which='minor', length=4) 
ax.tick_params(which='major', length=6) 
ax.grid(which='both',axis='x',linestyle='--') 

plt.axhline(color='gray') 

plt.show() 

sản xuất hiệu quả tôi muốn sử dụng kết nghĩa x-trục.

Third level ticks

Có cách nào tốt hơn không?

+1

Vì matplotlib chỉ cung cấp bọ ve lớn và nhỏ, giải pháp bạn đã tìm thấy nó thực sự là một dấu hiệu tốt. (Bạn sẽ không cần phải vẽ dữ liệu cho các trục song song mặc dù.) Tôi không nghĩ rằng có "một cách tốt hơn". – ImportanceOfBeingErnest

+0

Bạn có thể viết một lớp trục mới có nguồn gốc từ 'Axis' để tự động hóa những gì bạn muốn, nhưng, nhìn thấy một vài dòng mã mà giải pháp của bạn yêu cầu, nó có thể không đáng giá. –

+0

Tôi không nhận được dấu tick cấp ba nếu tôi không bao gồm 'ax1.plot (t, s)'. Có cách nào khác để phối hợp hai trục không? – pheon

Trả lời

1

Như tôi đã nói rằng bạn có thể đạt được những gì bạn muốn bằng cách bắt nguồn từ một số lớp học chính, tôi quyết định làm như vậy (nhưng như tôi đã nói, nó có lẽ không đáng để thử). Dù sao, đây là những gì tôi đã có:

from matplotlib import pyplot as plt 
from matplotlib import axes as maxes 
from matplotlib import axis as maxis 
import matplotlib.ticker as mticker 
import matplotlib.cbook as cbook 
from matplotlib.projections import register_projection 


from matplotlib import ticker 
import numpy as np 

class SubMinorXAxis(maxis.XAxis): 
    def __init__(self,*args,**kwargs): 
     self.subminor = maxis.Ticker() 
     self.subminorTicks = [] 
     self._subminor_tick_kw = dict() 

     super(SubMinorXAxis,self).__init__(*args,**kwargs) 


    def reset_ticks(self): 
     cbook.popall(self.subminorTicks) 
     ##self.subminorTicks.extend([self._get_tick(major=False)]) 
     self.subminorTicks.extend([maxis.XTick(self.axes, 0, '', major=False, **self._subminor_tick_kw)]) 
     self._lastNumSubminorTicks = 1 
     super(SubMinorXAxis,self).reset_ticks() 


    def set_subminor_locator(self, locator): 
     """ 
     Set the locator of the subminor ticker 

     ACCEPTS: a :class:`~matplotlib.ticker.Locator` instance 
     """ 
     self.isDefault_minloc = False 
     self.subminor.locator = locator 
     locator.set_axis(self) 
     self.stale = True 


    def set_subminor_formatter(self, formatter): 
     """ 
     Set the formatter of the subminor ticker 

     ACCEPTS: A :class:`~matplotlib.ticker.Formatter` instance 
     """ 
     self.isDefault_minfmt = False 
     self.subminor.formatter = formatter 
     formatter.set_axis(self) 
     self.stale = True 


    def get_subminor_ticks(self, numticks=None): 
     'get the subminor tick instances; grow as necessary' 
     if numticks is None: 
      numticks = len(self.get_subminor_locator()()) 

     if len(self.subminorTicks) < numticks: 
      # update the new tick label properties from the old 
      for i in range(numticks - len(self.subminorTicks)): 
       ##tick = self._get_tick(major=False) 
       tick = maxis.XTick(self.axes, 0, '', major=False, **self._subminor_tick_kw) 
       self.subminorTicks.append(tick) 

     if self._lastNumSubminorTicks < numticks: 
      protoTick = self.subminorTicks[0] 
      for i in range(self._lastNumSubminorTicks, len(self.subminorTicks)): 
       tick = self.subminorTicks[i] 
       tick.gridOn = False 
       self._copy_tick_props(protoTick, tick) 

     self._lastNumSubminorTicks = numticks 
     ticks = self.subminorTicks[:numticks] 

     return ticks 

    def set_tick_params(self, which='major', reset=False, **kwargs): 
     if which == 'subminor': 
      kwtrans = self._translate_tick_kw(kwargs, to_init_kw=True) 
      if reset: 
       self.reset_ticks() 
       self._subminor_tick_kw.clear() 
      self._subminor_tick_kw.update(kwtrans) 

      for tick in self.subminorTicks: 
       tick._apply_params(**self._subminor_tick_kw) 
     else: 
      super(SubMinorXAxis, self).set_tick_params(which=which, reset=reset, **kwargs) 

    def cla(self): 
     'clear the current axis' 
     self.set_subminor_locator(mticker.NullLocator()) 
     self.set_subminor_formatter(mticker.NullFormatter()) 

     super(SubMinorXAxis,self).cla() 


    def iter_ticks(self): 
     """ 
     Iterate through all of the major and minor ticks. 
     ...and through the subminors 
     """ 
     majorLocs = self.major.locator() 
     majorTicks = self.get_major_ticks(len(majorLocs)) 
     self.major.formatter.set_locs(majorLocs) 
     majorLabels = [self.major.formatter(val, i) 
         for i, val in enumerate(majorLocs)] 

     minorLocs = self.minor.locator() 
     minorTicks = self.get_minor_ticks(len(minorLocs)) 
     self.minor.formatter.set_locs(minorLocs) 
     minorLabels = [self.minor.formatter(val, i) 
         for i, val in enumerate(minorLocs)] 

     subminorLocs = self.subminor.locator() 
     subminorTicks = self.get_subminor_ticks(len(subminorLocs)) 
     self.subminor.formatter.set_locs(subminorLocs) 
     subminorLabels = [self.subminor.formatter(val, i) 
         for i, val in enumerate(subminorLocs)] 

     major_minor = [ 
      (majorTicks, majorLocs, majorLabels), 
      (minorTicks, minorLocs, minorLabels), 
      (subminorTicks, subminorLocs, subminorLabels), 
     ] 

     for group in major_minor: 
      for tick in zip(*group): 
       yield tick 


class SubMinorAxes(maxes.Axes): 
    name = 'subminor' 

    def _init_axis(self): 
     self.xaxis = SubMinorXAxis(self) 
     self.spines['top'].register_axis(self.xaxis) 
     self.spines['bottom'].register_axis(self.xaxis) 
     self.yaxis = maxis.YAxis(self) 
     self.spines['left'].register_axis(self.yaxis) 
     self.spines['right'].register_axis(self.yaxis) 

register_projection(SubMinorAxes) 




if __name__ == '__main__': 
    fig = plt.figure() 
    ax = fig.add_subplot(111,projection = 'subminor') 

    t = np.arange(0.0, 100.0, 0.1) 
    s = np.sin(0.1*np.pi*t)*np.exp(-t*0.01) 

    majors = np.linspace(0, 100, 6) 
    minors = np.linspace(0, 100, 11) 
    thirds = np.linspace(0, 100, 101) 

    ax.plot(t, s) 

    ax.xaxis.set_ticks_position('bottom') 

    ax.xaxis.set_major_locator(ticker.FixedLocator(majors)) 
    ax.xaxis.set_minor_locator(ticker.FixedLocator(minors)) 
    ax.xaxis.set_subminor_locator(ticker.FixedLocator(thirds)) 

    ##some things in set_tick_params are not being set correctly 
    ##by default. For instance 'top=False' must be stated 
    ##explicitly 
    ax.tick_params(which='subminor', length=2, top=False) 
    ax.tick_params(which='minor', length=4) 
    ax.tick_params(which='major', length=6) 
    ax.grid(which='both',axis='x',linestyle='--') 

    plt.show() 

Nó không hoàn hảo, nhưng đối với trường hợp sử dụng bạn cung cấp nó làm việc tốt. Tôi đã vẽ một số ý tưởng từ this matplotlib example và bằng cách xem trực tiếp mã nguồn. Kết quả như sau:

sub-minor ticks on x-axis

Tôi đã thử nghiệm mã trên cả hai Python 2.7 và Python 3.5.

EDIT:

tôi nhận thấy rằng subminor gridlines sẽ luôn luôn được rút ra nếu lưới được bật (trong khi tôi đã có ý định cho nó không được rút ra ở tất cả). Tôi đã sửa đổi điều này trong mã ở trên, tức là các dấu số subminor sẽ không bao giờ tạo ra các đường lưới. Nếu các đường lưới nên được triển khai đúng cách, cần có thêm một số công việc nữa.

Các vấn đề liên quan