How to add third level ticks in python matplotlib

Matplotlib axes have majors and minor tics. How to add a third tick level below Minor?

for example

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

creates the effect I want to use with double x axes.

Third tick level

Is there a better way?

+8
python matplotlib
source share
1 answer

As I said, you can achieve what you want based on some key classes, I decided to do it (but, as I said, this is probably not worth the effort). Anyway, here is what I got:

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

This is not ideal, but for the use case, you gave him the opportunity to work normally. I drew some ideas from this matplotlib example and directly going through the source code. The result is as follows:

x minor ticks

I tested the code in both Python 2.7 and Python 3.5.

EDIT

I noticed that the subminor grid subminor always be drawn if the grid is on (although I assumed that it would not be drawn at all). I fixed this in the code above, i.e. subminor should never create grid lines. If the meshes have to be done correctly, another job will be required.

+1
source share

All Articles