@@ -1338,7 +1338,7 @@ def format_data_short(self, value):
13381338return f"1-{ 1 - value :e} "
13391339
13401340
1341- class EngFormatter (Formatter ):
1341+ class EngFormatter (ScalarFormatter ):
13421342"""
13431343 Format axis values using engineering prefixes to represent powers
13441344 of 1000, plus a specified unit, e.g., 10 MHz instead of 1e7.
@@ -1370,7 +1370,7 @@ class EngFormatter(Formatter):
13701370 }
13711371
13721372def __init__ (self ,unit = "" ,places = None ,sep = " " ,* ,usetex = None ,
1373- useMathText = None ):
1373+ useMathText = None , useOffset = None ):
13741374r"""
13751375 Parameters
13761376 ----------
@@ -1404,55 +1404,93 @@ def __init__(self, unit="", places=None, sep=" ", *, usetex=None,
14041404 useMathText : bool, default: :rc:`axes.formatter.use_mathtext`
14051405 To enable/disable the use mathtext for rendering the numbers in
14061406 the formatter.
1407+ useOffset : bool or float, default: :rc:`axes.formatter.useoffset`
1408+ Whether to use offset notation. See `.set_useOffset`.
14071409 """
14081410self .unit = unit
14091411self .places = places
14101412self .sep = sep
1411- self .set_usetex (usetex )
1412- self .set_useMathText (useMathText )
1413-
1414- def get_usetex (self ):
1415- return self ._usetex
1416-
1417- def set_usetex (self ,val ):
1418- if val is None :
1419- self ._usetex = mpl .rcParams ['text.usetex' ]
1420- else :
1421- self ._usetex = val
1422-
1423- usetex = property (fget = get_usetex ,fset = set_usetex )
1424-
1425- def get_useMathText (self ):
1426- return self ._useMathText
1413+ super ().__init__ (
1414+ useOffset = useOffset ,
1415+ useMathText = useMathText ,
1416+ useLocale = False ,
1417+ usetex = usetex ,
1418+ )
14271419
1428- def set_useMathText (self ,val ):
1429- if val is None :
1430- self ._useMathText = mpl .rcParams ['axes.formatter.use_mathtext' ]
1420+ def __call__ (self ,x ,pos = None ):
1421+ """
1422+ Return the format for tick value *x* at position *pos*. If there is no
1423+ currently offset in the data, it returns the best engineering formatting
1424+ that fits the given argument, independently.
1425+ """
1426+ if len (self .locs )== 0 or self .offset == 0 :
1427+ return self .fix_minus (self .format_data (x ))
14311428else :
1432- self ._useMathText = val
1429+ xp = (x - self .offset )/ (10. ** self .orderOfMagnitude )
1430+ if abs (xp )< 1e-8 :
1431+ xp = 0
1432+ return self ._format_maybe_minus_and_locale (self .format ,xp )
14331433
1434- useMathText = property (fget = get_useMathText ,fset = set_useMathText )
1434+ def set_locs (self ,locs ):
1435+ # docstring inherited
1436+ self .locs = locs
1437+ if len (self .locs )> 0 :
1438+ if self ._useOffset :
1439+ self ._compute_offset ()
1440+ self ._set_order_of_magnitude ()
1441+ # This is what's different from ScalarFormatter: We search among
1442+ # the engineers' standard orders of magnitudes (0, -3, 3, -6, 6,
1443+ # -9, 9 etc) the oom closest to our self.orderOfMagnitude. Then we
1444+ # set our self.orderOfMagnitude to it.
1445+ c = abs (self .orderOfMagnitude )
1446+ for sciOom in itertools .count (0 ,3 ):
1447+ if c <= sciOom :
1448+ self .orderOfMagnitude = math .copysign (sciOom ,self .orderOfMagnitude )
1449+ break
1450+ self ._set_format ()
14351451
1436- def __call__ (self ,x ,pos = None ):
1437- s = f"{ self .format_eng (x )} { self .unit } "
1438- # Remove the trailing separator when there is neither prefix nor unit
1439- if self .sep and s .endswith (self .sep ):
1440- s = s [:- len (self .sep )]
1441- return self .fix_minus (s )
1452+ # Simplify a bit ScalarFormatter.get_offset: We always want to use
1453+ # self.format_data. We insert here the surrounding $...$ here, if tex /
1454+ # mathtext is set.
1455+ def get_offset (self ):
1456+ # docstring inherited
1457+ if len (self .locs )== 0 :
1458+ return ''
1459+ if self .orderOfMagnitude or self .offset :
1460+ offsetStr = ''
1461+ sciNotStr = ''
1462+ if self .offset :
1463+ offsetStr = self .format_data (self .offset )
1464+ if self .offset > 0 :
1465+ offsetStr = '+' + offsetStr
1466+ if self .orderOfMagnitude :
1467+ sciNotStr = self .format_data (10 ** self .orderOfMagnitude )
1468+ if self ._useMathText or self ._usetex :
1469+ if sciNotStr != '' :
1470+ sciNotStr = r'\times%s' % sciNotStr
1471+ s = fr'${ sciNotStr } { offsetStr } $'
1472+ else :
1473+ s = '' .join ((sciNotStr ,offsetStr ))
1474+ return self .fix_minus (s )
1475+ return ''
14421476
14431477def format_eng (self ,num ):
1478+ """Alias to EngFormatter.format_data"""
1479+ return self .format_data (num )
1480+
1481+ def format_data (self ,num ):
14441482"""
14451483 Format a number in engineering notation, appending a letter
14461484 representing the power of 1000 of the original number.
14471485 Some examples:
14481486
1449- >>>format_eng (0) # for self.places = 0
1487+ >>>format_data (0) # for self.places = 0
14501488 '0'
14511489
1452- >>>format_eng (1000000) # for self.places = 1
1490+ >>>format_data (1000000) # for self.places = 1
14531491 '1.0 M'
14541492
1455- >>>format_eng (-1e-6) # for self.places = 2
1493+ >>>format_data (-1e-6) # for self.places = 2
14561494 '-1.00\N{MICRO SIGN} '
14571495 """
14581496sign = 1
@@ -1482,13 +1520,15 @@ def format_eng(self, num):
14821520mant /= 1000
14831521pow10 += 3
14841522
1485- prefix = self .ENG_PREFIXES [int (pow10 )]
1523+ unitPrefix = self .ENG_PREFIXES [int (pow10 )]
1524+ if self .unit or unitPrefix :
1525+ suffix = f"{ self .sep } { unitPrefix } { self .unit } "
1526+ else :
1527+ suffix = ""
14861528if self ._usetex or self ._useMathText :
1487- formatted = f "${ mant :{fmt }} ${ self . sep } { prefix } "
1529+ return rf "${ mant :{fmt }} ${ suffix } "
14881530else :
1489- formatted = f"{ mant :{fmt }} { self .sep } { prefix } "
1490-
1491- return formatted
1531+ return rf"{ mant :{fmt }} { suffix } "
14921532
14931533
14941534class PercentFormatter (Formatter ):