@@ -548,33 +548,50 @@ 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 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
+ lmin , lmax = locs .min (), locs .max ()
565
+ # min, max comparing absolute values (we want division to round towards
566
+ # zero so we work on absolute values).
567
+ abs_min , abs_max = sorted (map (abs , [lmin , lmax ]))
568
+ # Only use offset if there are at least two ticks, every tick has the
569
+ # same sign, and if the span is small compared to the absolute values.
570
+ if (lmin == lmax or lmin <= 0 <= lmax or
571
+ (abs_max - abs_min ) / abs_max >= 1e-2 ):
572
+ self .offset = 0
573
+ return
574
+ sign = math .copysign (1 , lmin )
575
+ # What is the smallest power of ten such that abs_min and abs_max are
576
+ # equal up to that precision?
577
+ oom = 10 ** int (math .log10 (abs_max ) + 1 )
578
+ while True :
579
+ if abs_min // oom != abs_max // oom :
580
+ oom *= 10
581
+ break
582
+ oom /= 10
583
+ if (abs_max - abs_min ) / oom <= 1e-2 :
584
+ # Handle the case of straddling a multiple of a large power of ten
585
+ # (relative to the span).
586
+ # What is the smallest power of ten such that abs_min and abs_max
587
+ # at most 1 apart?
588
+ oom = 10 ** int (math .log10 (abs_max ) + 1 )
589
+ while True :
590
+ if abs_max // oom - abs_min // oom > 1 :
591
+ oom *= 10
592
+ break
593
+ oom /= 10
594
+ self .offset = sign * (abs_max // oom ) * oom
578
595
579
596
def _set_orderOfMagnitude (self , range ):
580
597
# if scientific notation is to be used, find the appropriate exponent
0 commit comments