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
956
dnum = decimal .Decimal (str (num ))
945
957
946
958
sign = 1
@@ -973,6 +985,90 @@ 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
+ `xmax` parameter. `xmax` is the data value that corresponds to 100%.
994
+ Percentages are computed as ``x / xmax * 100``. So if the data is
995
+ already scaled to be percentages, `xmax` will be 100. Another common
996
+ situation is where `xmax` is 1.0.
997
+
998
+ `symbol` is a string which will be appended to the label. It may be
999
+ `None` or empty to indicate that no symbol should be used.
1000
+
1001
+ `decimals` is the number of decimal places to place after the point.
1002
+ If it is set to `None` (the default), the number will be computed
1003
+ automatically.
1004
+ """
1005
+ def __init__ (self , xmax = 100 , decimals = None , symbol = '%' ):
1006
+ self .xmax = xmax + 0.0
1007
+ self .decimals = decimals
1008
+ self .symbol = symbol
1009
+
1010
+ def __call__ (self , x , pos = None ):
1011
+ """
1012
+ Formats the tick as a percentage with the appropriate scaling.
1013
+ """
1014
+ ax_min , ax_max = self .axis .get_view_interval ()
1015
+ display_range = abs (ax_max - ax_min )
1016
+
1017
+ return self .fix_minus (self .format_pct (x , display_range ))
1018
+
1019
+ def format_pct (self , x , display_range ):
1020
+ """
1021
+ Formats the number as a percentage number with the correct
1022
+ number of decimals and adds the percent symbol, if any.
1023
+
1024
+ If `self.decimals` is `None`, the number of digits after the
1025
+ decimal point is set based on the `display_range` of the axis
1026
+ as follows:
1027
+
1028
+ +---------------+----------+------------------------+
1029
+ | display_range | decimals | sample |
1030
+ +---------------+----------+------------------------+
1031
+ | >50 | 0 | ``x = 34.5`` => 35% |
1032
+ +---------------+----------+------------------------+
1033
+ | >5 | 1 | ``x = 34.5`` => 34.5% |
1034
+ +---------------+----------+------------------------+
1035
+ | >0.5 | 2 | ``x = 34.5`` => 34.50% |
1036
+ +---------------+----------+------------------------+
1037
+ | ... | ... | ... |
1038
+ +---------------+----------+------------------------+
1039
+
1040
+ This method will not be very good for tiny axis ranges or
1041
+ extremely large ones. It assumes that the values on the chart
1042
+ are percentages displayed on a reasonable scale.
1043
+ """
1044
+ x = self .convert_to_pct (x )
1045
+ if self .decimals is None :
1046
+ # conversion works because display_range is a difference
1047
+ scaled_range = self .convert_to_pct (display_range )
1048
+ if scaled_range <= 0 :
1049
+ decimals = 0
1050
+ else :
1051
+ # Luckily Python's built-in ceil rounds to +inf, not away from
1052
+ # zero. This is very important since the equation for decimals
1053
+ # starts out as `scaled_range > 0.5 * 10**(2 - decimals)`
1054
+ # and ends up with `decimals > 2 - log10(2 * scaled_range)`.
1055
+ decimals = math .ceil (2.0 - math .log10 (2.0 * scaled_range ))
1056
+ if decimals > 5 :
1057
+ decimals = 5
1058
+ elif decimals < 0 :
1059
+ decimals = 0
1060
+ else :
1061
+ decimals = self .decimals
1062
+ s = '{x:0.{decimals}f}' .format (x = x , decimals = int (decimals ))
1063
+
1064
+ if self .symbol :
1065
+ return s + self .symbol
1066
+ return s
1067
+
1068
+ def convert_to_pct (self , x ):
1069
+ return 100.0 * (x / self .xmax )
1070
+
1071
+
976
1072
class Locator (TickHelper ):
977
1073
"""
978
1074
Determine the tick locations;
@@ -2055,13 +2151,3 @@ def get_locator(self, d):
2055
2151
locator = MultipleLocator (ticksize )
2056
2152
2057
2153
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