131131:class:`LogFormatter`
132132 formatter for log axes
133133
134+ :class:`PercentFormatter`
135+ Format labels as a percentage
134136
135137You can derive your own formatter from the Formatter base class by
136138simply overriding the ``__call__`` method. The formatter class has access
165167
166168import warnings
167169
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+
168182if six .PY3 :
169183 long = int
170184
@@ -922,8 +936,10 @@ def __call__(self, x, pos=None):
922936 return self .fix_minus (s )
923937
924938 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:
927943
928944 >>> format_eng(0) # for self.places = 0
929945 '0'
@@ -934,13 +950,9 @@ def format_eng(self, num):
934950 >>> format_eng("-1e-6") # for self.places = 2
935951 u'-1.00 \u03bc '
936952
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.
942955 """
943-
944956 dnum = decimal .Decimal (str (num ))
945957
946958 sign = 1
@@ -973,6 +985,90 @@ def format_eng(self, num):
973985 return formatted .strip ()
974986
975987
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+
9761072class Locator (TickHelper ):
9771073 """
9781074 Determine the tick locations;
@@ -2055,13 +2151,3 @@ def get_locator(self, d):
20552151 locator = MultipleLocator (ticksize )
20562152
20572153 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