131
131
:class:`LogFormatter`
132
132
formatter for log axes
133
133
134
+ :class:`PercentFormatter`
135
+ Format labels as a percentage
134
136
135
137
You can derive your own formatter from the Formatter base class by
136
138
simply overriding the ``__call__`` method. The formatter class has access
165
167
166
168
import warnings
167
169
170
+
171
+ __all__ = ('TickHelper' , 'Formatter' , 'FixedFormatter' ,
172
+ 'NullFormatter' , 'FuncFormatter' , 'FormatStrFormatter' ,
173
+ 'StrMethodFormatter' , 'ScalarFormatter' , 'LogFormatter' ,
174
+ 'LogFormatterExponent' , 'LogFormatterMathtext' ,
175
+ 'LogitFormatter' , 'EngFormatter' , 'PercentFormatter' ,
176
+ 'Locator' , 'IndexLocator' , 'FixedLocator' , 'NullLocator' ,
177
+ 'LinearLocator' , 'LogLocator' , 'AutoLocator' ,
178
+ 'MultipleLocator' , 'MaxNLocator' , 'AutoMinorLocator' ,
179
+ 'SymmetricalLogLocator' )
180
+
181
+
168
182
if six .PY3 :
169
183
long = int
170
184
@@ -922,8 +936,10 @@ def __call__(self, x, pos=None):
922
936
return self .fix_minus (s )
923
937
924
938
def format_eng (self , num ):
925
- """ Formats a number in engineering notation, appending a letter
926
- representing the power of 1000 of the original number. Some examples:
939
+ """
940
+ Formats a number in engineering notation, appending a letter
941
+ representing the power of 1000 of the original number.
942
+ Some examples:
927
943
928
944
>>> format_eng(0) # for self.places = 0
929
945
'0'
@@ -934,13 +950,9 @@ def format_eng(self, num):
934
950
>>> format_eng("-1e-6") # for self.places = 2
935
951
u'-1.00 \u03bc '
936
952
937
- @param num: the value to represent
938
- @type num: either a numeric value or a string that can be converted to
939
- a numeric value (as per decimal.Decimal constructor)
940
-
941
- @return: engineering formatted string
953
+ `num` may be a numeric value or a string that can be converted
954
+ to a numeric value with the `decimal.Decimal` constructor.
942
955
"""
943
-
944
9
F438
56
dnum = decimal .Decimal (str (num ))
945
957
946
958
sign = 1
@@ -973,6 +985,89 @@ def format_eng(self, num):
973
985
return formatted .strip ()
974
986
975
987
988
+ class PercentFormatter (Formatter ):
989
+ """
990
+ Format numbers as a percentage.
991
+
992
+ How the number is converted into a percentage is determined by the
993
+ `max` parameter. `max` is the data value that corresponds to 100%.
994
+ Percentages are computed as ``x / max * 100``. So if the data is
995
+ already scaled to be percentages, `max` will be 100. Another common
996
+ situation is where `max` is 1.0.
997
+ """
998
+ def __init__ (self , max = 100 , decimals = None , symbol = '%' ):
999
+ """
1000
+ Initializes the formatter.
1001
+
1002
+ `max` is the data value that corresponds to 100%. `symbol` is
1003
+ a string which will be appended to the label. It may be `None`
1004
+ or empty to indicate that no symbol should be used. `decimals`
1005
+ is the number of decimal places to place after the point. If
1006
+ it is set to `None` (the default), the number will be computed
1007
+ automatically.
1008
+ """
1009
+ self .max = max + 0.0
1010
+ self .decimals = decimals
1011
+ self .symbol = symbol
1012
+
1013
+ def __call__ (self , x , pos = None ):
1014
+ """
1015
+ Formats the tick as a percentage with the appropriate scaling.
1016
+ """
1017
+ xmin , xmax = self .axis .get_view_interval ()
1018
+ d = abs (xmax - xmin )
1019
+
1020
+ return self .fix_minus (format_pct (x , d ))
1021
+
1022
+ def format_pct (self , x , d ):
1023
+ """
1024
+ Formats the number as a percentage number with the correct
1025
+ number of decimals and adds the percent symbol, if any.
1026
+
1027
+ If `self.decimals` is `None`, the number of digits after the
1028
+ decimal point is set based on the width of the domain `d` as
1029
+ follows:
1030
+
1031
+ +-------+----------+------------------------+
1032
+ | d | decimals | sample |
1033
+ +-------+----------+------------------------+
1034
+ + >50 | 0 | ``x = 34.5`` => 34% |
1035
+ +-------+----------+------------------------+
1036
+ | >5 | 1 | ``x = 34.5`` => 34.5% |
1037
+ +-------+----------+------------------------+
1038
+ | >0.5 | 2 | ``x = 34.5`` => 34.50% |
1039
+ +-------+----------+------------------------+
1040
+ | ... | ... | ... |
1041
+ +-------+----------+------------------------+
1042
+
1043
+ This method will not be very good for tiny ranges or extremely
1044
+ large ranges. It assumes that the values on the chart are
1045
+ percentages displayed on a reasonable scale.
1046
+ """
1047
+ x = self .convert_to_pct (x )
1048
+ if self .decimals is None :
1049
+ # Luckily Python's built-in `ceil` rounds to +inf, not away
1050
+ # from zero. This is very important since the equation for
1051
+ # `decimals` starts out as `d > 0.5 * 10**(2 - decimals)`
1052
+ # and ends up with `decimals > 2 - log10(2 * d)`.
1053
+ d = self .convert_to_pct (d ) # d is a difference, so this works
1054
+ decimals = math .ceil (2.0 - math .log10 (2.0 * d ))
1055
+ if decimals > 5 :
1056
+ decimals = 5
1057
+ elif decimals < 0 :
1058
+ decimals = 0
1059
+ else :
1060
+ decimals = self .decimals
1061
+ s = '{x:0.{decimals}f}' .format (x = x , decimals = int (decimals ))
1062
+
1063
+ if self .symbol :
1064
+ return s + self .symbol
1065
+ return s
1066
+
1067
+ def convert_to_pct (self , x ):
1068
+ return 100.0 * (x / self .max )
1069
+
1070
+
976
1071
class Locator (TickHelper ):
977
1072
"""
978
1073
Determine the tick locations;
@@ -2055,13 +2150,3 @@ def get_locator(self, d):
2055
2150
locator = MultipleLocator (ticksize )
2056
2151
2057
2152
return locator
2058
-
2059
-
2060
- __all__ = ('TickHelper' , 'Formatter' , 'FixedFormatter' ,
2061
- 'NullFormatter' , 'FuncFormatter' , 'FormatStrFormatter' ,
2062
- 'StrMethodFormatter' , 'ScalarFormatter' , 'LogFormatter' ,
2063
- 'LogFormatterExponent' , 'LogFormatterMathtext' , 'Locator' ,
2064
- 'IndexLocator' , 'FixedLocator' , 'NullLocator' ,
2065
- 'LinearLocator' , 'LogLocator' , 'AutoLocator' ,
2066
- 'MultipleLocator' , 'MaxNLocator' , 'AutoMinorLocator' ,
2067
- 'SymmetricalLogLocator' )
0 commit comments