@@ -548,33 +548,53 @@ def set_locs(self, locs):
548
548
vmin , vmax = self .axis .get_view_interval ()
549
549
d = abs (vmax - vmin )
550
550
if self ._useOffset :
551
- self ._set_offset ( d )
551
+ self ._compute_offset ( )
552
552
self ._set_orderOfMagnitude (d )
553
553
self ._set_format (vmin , vmax )
554
554
555
- def _set_offset (self , range ):
556
- # offset of 20,001 is 20,000, for example
555
+ def _compute_offset (self ):
557
556
locs = self .locs
558
-
559
- if locs is None or not len (locs ) or range == 0 :
557
+ if locs is None or not len (locs ):
560
558
self .offset = 0
561
559
return
560
+ # Restrict to visible ticks.
562
561
vmin , vmax = sorted (self .axis .get_view_interval ())
563
562
locs = np .asarray (locs )
564
563
locs = locs [(vmin <= locs ) & (locs <= vmax )]
565
- ave_loc = np .mean (locs )
566
- if len (locs ) and ave_loc : # dont want to take log10(0)
567
- ave_oom = math .floor (math .log10 (np .mean (np .absolute (locs ))))
568
- range_oom = math .floor (math .log10 (range ))
569
-
570
- if np .absolute (ave_oom - range_oom ) >= 3 : # four sig-figs
571
- p10 = 10 ** range_oom
572
- if ave_loc < 0 :
573
- self .offset = (math .ceil (np .max (locs ) / p10 ) * p10 )
574
- else :
575
- self .offset = (math .floor (np .min (locs ) / p10 ) * p10 )
576
- else :
577
- self .offset = 0
564
+ if not len (locs ):
565
+ self .offset = 0
566
+ return
567
+ lmin , lmax = locs .min (), locs .max ()
568
+ # min, max comparing absolute values (we want division to round towards
569
+ # zero so we work on absolute values).
570
+ abs_min , abs_max = sorted (map (abs , [lmin , lmax ]))
571
+ # Only use offset if there are at least two ticks, every tick has the
572
+ # same sign, and if the span is small compared to the absolute values.
573
+ if (lmin == lmax or lmin <= 0 <= lmax or
574
+ (abs_max - abs_min ) / abs_max >= 1e-2 ):
575
+ self .offset = 0
576
+ return
577
+ sign = math .copysign (1 , lmin )
578
+ # What is the smallest power of ten such that abs_min and abs_max are
579
+ # equal up to that precision?
580
+ oom = 10 ** int (math .log10 (abs_max ) + 1 )
581
+ while True :
582
+ if abs_min // oom != abs_max // oom :
583
+ oom *= 10
584
+ break
585
+ oom /= 10
586
+ if (abs_max - abs_min ) / oom <= 1e-2 :
587
+ # Handle the case of straddling a multiple of a large power of ten
588
+ # (relative to the span).
589
+ # What is the smallest power of ten such that abs_min and abs_max
590
+ # at most 1 apart?
591
+ oom = 10 ** int (math .log10 (abs_max ) + 1 )
592
+ while True :
593
+ if abs_max // oom - abs_min // oom > 1 :
594
+ oom *= 10
595
+ break
596
+ oom /= 10
597
+ self .offset = sign * (abs_max // oom ) * oom
578
598
579
599
def _set_orderOfMagnitude (self , range ):
580
600
# if scientific notation is to be used, find the appropriate exponent
0 commit comments