@@ -1338,7 +1338,7 @@ def format_data_short(self, value):
1338
1338
return f"1-{ 1 - value :e} "
1339
1339
1340
1340
1341
- class EngFormatter (Formatter ):
1341
+ class EngFormatter (ScalarFormatter ):
1342
1342
"""
1343
1343
Format axis values using engineering prefixes to represent powers
1344
1344
of 1000, plus a specified unit, e.g., 10 MHz instead of 1e7.
@@ -1370,7 +1370,7 @@ class EngFormatter(Formatter):
1370
1370
}
1371
1371
1372
1372
def __init__ (self , unit = "" , places = None , sep = " " , * , usetex = None ,
1373
- useMathText = None ):
1373
+ useMathText = None , useOffset = None ):
1374
1374
r"""
1375
1375
Parameters
1376
1376
----------
@@ -1404,55 +1404,93 @@ def __init__(self, unit="", places=None, sep=" ", *, usetex=None,
1404
1404
useMathText : bool, default: :rc:`axes.formatter.use_mathtext`
1405
1405
To enable/disable the use mathtext for rendering the numbers in
1406
1406
the formatter.
1407
+ useOffset : bool or float, default: :rc:`axes.formatter.useoffset`
1408
+ Whether to use offset notation. See `.set_useOffset`.
1407
1409
"""
1408
1410
self .unit = unit
1409
1411
self .places = places
1410
1412
self .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
+ )
1427
1419
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 ))
1431
1428
else :
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 )
1433
1433
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 ()
1435
1451
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 ''
1442
1476
1443
1477
def format_eng (self , num ):
1478
+ """Alias to EngFormatter.format_data"""
1479
+ return self .format_data (num )
1480
+
1481
+ def format_data (self , value ):
1444
1482
"""
1445
1483
Format a number in engineering notation, appending a letter
1446
1484
representing the power of 1000 of the original number.
1447
1485
Some examples:
1448
1486
1449
- >>> format_eng (0) # for self.places = 0
1487
+ >>> format_data (0) # for self.places = 0
1450
1488
'0'
1451
1489
1452
- >>> format_eng (1000000) # for self.places = 1
1490
+ >>> format_data (1000000) # for self.places = 1
1453
1491
'1.0 M'
1454
1492
1455
- >>> format_eng (-1e-6) # for self.places = 2
1493
+ >>> format_data (-1e-6) # for self.places = 2
1456
1494
'-1.00 \N{MICRO SIGN} '
1457
1495
"""
1458
1496
sign = 1
@@ -1482,13 +1520,15 @@ def format_eng(self, num):
1482
1520
mant /= 1000
1483
1521
pow10 += 3
1484
1522
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 = ""
1486
1528
if self ._usetex or self ._useMathText :
1487
- formatted = f "${ mant :{fmt }} ${ self . sep } { prefix } "
1529
+ return rf "${ mant :{fmt }} ${ suffix } "
1488
1530
else :
1489
- formatted = f"{ mant :{fmt }} { self .sep } { prefix } "
1490
-
1491
- return formatted
1531
+ return rf"{ mant :{fmt }} { suffix } "
1492
1532
1493
1533
1494
1534
class PercentFormatter (Formatter ):
0 commit comments