@@ -1564,7 +1564,9 @@ def __init__(self, *args, **kwargs):
15641564 e.g., [1, 2, 4, 5, 10]
15651565
15661566 *integer*
1567- If True, ticks will take only integer values.
1567+ If True, ticks will take only integer values, provided
1568+ at least `min_n_ticks` integers are found within the
1569+ view limits.
15681570
15691571 *symmetric*
15701572 If True, autoscaling will result in a range symmetric
@@ -1574,16 +1576,16 @@ def __init__(self, *args, **kwargs):
15741576 ['lower' | 'upper' | 'both' | None]
15751577 Remove edge ticks -- useful for stacked or ganged plots
15761578 where the upper tick of one axes overlaps with the lower
1577- tick of the axes above it.
1578- If prune=='lower', the smallest tick will
1579- be removed. If prune=='upper', the largest tick will be
1580- removed. If prune=='both', the largest and smallest ticks
1581- will be removed. If prune==None, no ticks will be removed.
1579+ tick of the axes above it, primarily when
1580+ `rcParams['axes.autolimit_mode']` is `'round_numbers'`.
1581+ If `prune=='lower'`, the smallest tick will
1582+ be removed. If `prune=='upper'`, the largest tick will be
1583+ removed. If `prune=='both'`, the largest and smallest ticks
1584+ will be removed. If `prune==None`, no ticks will be removed.
15821585
15831586 *min_n_ticks*
1584- While the estimated number of ticks is less than the minimum,
1585- the target value *nbins* is incremented and the ticks are
1586- recalculated.
1587+ Relax `nbins` and `integer` constraints if necessary to
1588+ obtain this minimum number of ticks.
15871589
15881590 """
15891591 if args :
@@ -1604,8 +1606,6 @@ def set_params(self, **kwargs):
16041606 warnings .warn (
16051607 "The 'trim' keyword has no effect since version 2.0." ,
16061608 mplDeprecation )
1607- if 'integer' in kwargs :
1608- self ._integer = kwargs ['integer' ]
16091609 if 'symmetric' in kwargs :
16101610 self ._symmetric = kwargs ['symmetric' ]
16111611 if 'prune' in kwargs :
@@ -1623,6 +1623,13 @@ def set_params(self, **kwargs):
16231623 steps = list (steps )
16241624 steps .append (10 )
16251625 self ._steps = steps
1626+ # Make an extended staircase within which the needed
1627+ # step will be found. This is probably much larger
1628+ # than necessary.
1629+ flights = (0.1 * np .array (self ._steps [:- 1 ]),
1630+ self ._steps ,
1631+ [10 * self ._steps [1 ]])
1632+ self ._extended_steps = np .hstack (flights )
16261633 if 'integer' in kwargs :
16271634 self ._integer = kwargs ['integer' ]
16281635 if self ._integer :
@@ -1637,42 +1644,38 @@ def _raw_ticks(self, vmin, vmax):
16371644 else :
16381645 nbins = self ._nbins
16391646
1640- while True :
1641- ticks = self ._try_raw_ticks (vmin , vmax , nbins )
1647+ scale , offset = scale_range (vmin , vmax , nbins )
1648+ _vmin = vmin - offset
1649+ _vmax = vmax - offset
1650+ raw_step = (vmax - vmin ) / nbins
1651+ steps = self ._extended_steps * scale
1652+ istep = np .nonzero (steps >= raw_step )[0 ][0 ]
1653+
1654+ # Classic round_numbers mode may require a larger step.
1655+ if rcParams ['axes.autolimit_mode' ] == 'round_numbers' :
1656+ for istep in range (istep , len (steps )):
1657+ step = steps [istep ]
1658+ best_vmin = (_vmin // step ) * step
1659+ best_vmax = best_vmin + step * nbins
1660+ if (best_vmax >= _vmax ):
1661+ break
1662+
1663+ # This is an upper limit; move to smaller steps if necessary.
1664+ for i in range (istep ):
1665+ step = steps [istep - i ]
1666+ if (self ._integer and
1667+ np .floor (_vmax ) - np .ceil (_vmin ) >= self ._min_n_ticks - 1 ):
1668+ step = max (1 , step )
1669+ best_vmin = (_vmin // step ) * step
1670+
1671+ low = round (Base (step ).le (_vmin - best_vmin ) / step )
1672+ high = round (Base (step ).ge (_vmax - best_vmin ) / step )
1673+ ticks = np .arange (low , high + 1 ) * step + best_vmin + offset
16421674 nticks = ((ticks <= vmax ) & (ticks >= vmin )).sum ()
16431675 if nticks >= self ._min_n_ticks :
16441676 break
1645- nbins += 1
1646-
1647- self ._nbins_used = nbins # Maybe useful for troubleshooting.
16481677 return ticks
16491678
1650- def _try_raw_ticks (self , vmin , vmax , nbins ):
1651- scale , offset = scale_range (vmin , vmax , nbins )
1652- if self ._integer :
1653- scale = max (1 , scale )
1654- vmin = vmin - offset
1655- vmax = vmax - offset
1656- raw_step = (vmax - vmin ) / nbins
1657- scaled_raw_step = raw_step / scale
1658- best_vmax = vmax
1659- best_vmin = vmin
1660-
1661- steps = (x for x in self ._steps if x >= scaled_raw_step )
1662- for step in steps :
1663- step *= scale
1664- best_vmin = vmin // step * step
1665- best_vmax = best_vmin + step * nbins
1666- if best_vmax >= vmax :
1667- break
1668-
1669- # More than nbins may be required, e.g. vmin, vmax = -4.1, 4.1 gives
1670- # nbins=9 but 10 bins are actually required after rounding. So we just
1671- # create the bins that span the range we need instead.
1672- low = round (Base (step ).le (vmin - best_vmin ) / step )
1673- high = round (Base (step ).ge (vmax - best_vmin ) / step )
1674- return np .arange (low , high + 1 ) * step + best_vmin + offset
1675-
16761679 @cbook .deprecated ("2.0" )
16771680 def bin_boundaries (self , vmin , vmax ):
16781681 return self ._raw_ticks (vmin , vmax )
0 commit comments