@@ -1603,7 +1603,9 @@ def __init__(self, *args, **kwargs):
16031603 e.g., [1, 2, 4, 5, 10]
16041604
16051605 *integer*
1606- If True, ticks will take only integer values.
1606+ If True, ticks will take only integer values, provided
1607+ at least `min_n_ticks` integers are found within the
1608+ view limits.
16071609
16081610 *symmetric*
16091611 If True, autoscaling will result in a range symmetric
@@ -1613,16 +1615,16 @@ def __init__(self, *args, **kwargs):
16131615 ['lower' | 'upper' | 'both' | None]
16141616 Remove edge ticks -- useful for stacked or ganged plots
16151617 where the upper tick of one axes overlaps with the lower
1616- tick of the axes above it.
1617- If prune=='lower', the smallest tick will
1618- be removed. If prune=='upper', the largest tick will be
1619- removed. If prune=='both', the largest and smallest ticks
1620- will be removed. If prune==None, no ticks will be removed.
1618+ tick of the axes above it, primarily when
1619+ `rcParams['axes.autolimit_mode']` is `'round_numbers'`.
1620+ If `prune=='lower'`, the smallest tick will
1621+ be removed. If `prune=='upper'`, the largest tick will be
1622+ removed. If `prune=='both'`, the largest and smallest ticks
1623+ will be removed. If `prune==None`, no ticks will be removed.
16211624
16221625 *min_n_ticks*
1623- While the estimated number of ticks is less than the minimum,
1624- the target value *nbins* is incremented and the ticks are
1625- recalculated.
1626+ Relax `nbins` and `integer` constraints if necessary to
1627+ obtain this minimum number of ticks.
16261628
16271629 """
16281630 if args :
@@ -1643,8 +1645,6 @@ def set_params(self, **kwargs):
16431645 warnings .warn (
16441646 "The 'trim' keyword has no effect since version 2.0." ,
16451647 mplDeprecation )
1646- if 'integer' in kwargs :
1647- self ._integer = kwargs ['integer' ]
16481648 if 'symmetric' in kwargs :
16491649 self ._symmetric = kwargs ['symmetric' ]
16501650 if 'prune' in kwargs :
@@ -1662,6 +1662,13 @@ def set_params(self, **kwargs):
16621662 steps = list (steps )
16631663 steps .append (10 )
16641664 self ._steps = steps
1665+ # Make an extended staircase within which the needed
1666+ # step will be found. This is probably much larger
1667+ # than necessary.
1668+ flights = (0.1 * np .array (self ._steps [:- 1 ]),
1669+ self ._steps ,
1670+ [10 * self ._steps [1 ]])
1671+ self ._extended_steps = np .hstack (flights )
16651672 if 'integer' in kwargs :
16661673 self ._integer = kwargs ['integer' ]
16671674 if self ._integer :
@@ -1676,42 +1683,38 @@ def _raw_ticks(self, vmin, vmax):
16761683 else :
16771684 nbins = self ._nbins
16781685
1679- while True :
1680- ticks = self ._try_raw_ticks (vmin , vmax , nbins )
1686+ scale , offset = scale_range (vmin , vmax , nbins )
1687+ _vmin = vmin - offset
1688+ _vmax = vmax - offset
1689+ raw_step = (vmax - vmin ) / nbins
1690+ steps = self ._extended_steps * scale
1691+ istep = np .nonzero (steps >= raw_step )[0 ][0 ]
1692+
1693+ # Classic round_numbers mode may require a larger step.
1694+ if rcParams ['axes.autolimit_mode' ] == 'round_numbers' :
1695+ for istep in range (istep , len (steps )):
1696+ step = steps [istep ]
1697+ best_vmin = (_vmin // step ) * step
1698+ best_vmax = best_vmin + step * nbins
1699+ if (best_vmax >= _vmax ):
1700+ break
1701+
1702+ # This is an upper limit; move to smaller steps if necessary.
1703+ for i in range (istep ):
1704+ step = steps [istep - i ]
1705+ if (self ._integer and
1706+ np .floor (_vmax ) - np .ceil (_vmin ) > self ._min_n_ticks - 1 ):
1707+ step = max (1 , step )
1708+ best_vmin = (_vmin // step ) * step
1709+
1710+ low = round (Base (step ).le (_vmin - best_vmin ) / step )
1711+ high = round (Base (step ).ge (_vmax - best_vmin ) / step )
1712+ ticks = np .arange (low , high + 1 ) * step + best_vmin + offset
16811713 nticks = ((ticks <= vmax ) & (ticks >= vmin )).sum ()
16821714 if nticks >= self ._min_n_ticks :
16831715 break
1684- nbins += 1
1685-
1686- self ._nbins_used = nbins # Maybe useful for troubleshooting.
16871716 return ticks
16881717
1689- def _try_raw_ticks (self , vmin , vmax , nbins ):
1690- scale , offset = scale_range (vmin , vmax , nbins )
1691- if self ._integer :
1692- scale = max (1 , scale )
1693- vmin = vmin - offset
1694- vmax = vmax - offset
1695- raw_step = (vmax - vmin ) / nbins
1696- scaled_raw_step = raw_step / scale
1697- best_vmax = vmax
1698- best_vmin = vmin
1699-
1700- steps = (x for x in self ._steps if x >= scaled_raw_step )
1701- for step in steps :
1702- step *= scale
1703- best_vmin = vmin // step * step
1704- best_vmax = best_vmin + step * nbins
1705- if best_vmax >= vmax :
1706- break
1707-
1708- # More than nbins may be required, e.g. vmin, vmax = -4.1, 4.1 gives
1709- # nbins=9 but 10 bins are actually required after rounding. So we just
1710- # create the bins that span the range we need instead.
1711- low = round (Base (step ).le (vmin - best_vmin ) / step )
1712- high = round (Base (step ).ge (vmax - best_vmin ) / step )
1713- return np .arange (low , high + 1 ) * step + best_vmin + offset
1714-
17151718 @cbook .deprecated ("2.0" )
17161719 def bin_boundaries (self , vmin , vmax ):
17171720 return self ._raw_ticks (vmin , vmax )
0 commit comments