|
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,7 +936,8 @@ 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 |
| 939 | + """ |
| 940 | + Formats a number in engineering notation, appending a letter |
926 | 941 | representing the power of 1000 of the original number. Some examples:
|
927 | 942 |
|
928 | 943 | >>> format_eng(0) # for self.places = 0
|
@@ -973,6 +988,89 @@ def format_eng(self, num):
|
973 | 988 | return formatted.strip()
|
974 | 989 |
|
975 | 990 |
|
| 991 | +class PercentFormatter(Formatter): |
| 992 | + """ |
| 993 | + Format numbers as a percentage. |
| 994 | +
|
| 995 | + How the number is converted into a percentage is determined by the |
| 996 | + `max` parameter. `max` is the data value that corresponds to 100%. |
| 997 | + Percentages are computed as ``x / max * 100``. So if the data is |
| 998 | + already scaled to be percentages, `max` will be 100. Another common |
| 999 | + situation is where `max` is 1.0. |
| 1000 | + """ |
| 1001 | + def __init__(self, max=100, decimals=None, symbol='%'): |
| 1002 | + """ |
| 1003 | + Initializes the formatter. |
| 1004 | +
|
| 1005 | + `max` is the data value that corresponds to 100%. `symbol` is |
| 1006 | + a string which will be appended to the label. It may be `None` |
| 1007 | + or empty to indicate that no symbol should be used. `decimals` |
| 1008 | + is the number of decimal places to place after the point. If |
| 1009 | + it is set to `None` (the default), the number will be computed |
| 1010 | + automatically. |
| 1011 | + """ |
| 1012 | + self.max = max + 0.0 |
| 1013 | + self.decimals = decimals |
| 1014 | + self.symbol = symbol |
| 1015 | + |
| 1016 | + def __call__(self, x, pos=None): |
| 1017 | + """ |
| 1018 | + Formats the tick as a percentage with the appropriate scaling. |
| 1019 | + """ |
| 1020 | + xmin, xmax = self.axis.get_view_interval() |
| 1021 | + d = abs(xmax - xmin) |
| 1022 | + |
| 1023 | + return self.fix_minus(format_pct(x, d)) |
| 1024 | + |
| 1025 | + def format_pct(self, x, d): |
| 1026 | + """ |
| 1027 | + Formats the number as a percentage number with the correct |
| 1028 | + number of decimals and adds the percent symbol, if any. |
| 1029 | +
|
| 1030 | + If `self.decimals` is `None`, the number of digits after the |
| 1031 | + decimal point is set based on the width of the domain `d` as |
| 1032 | + follows: |
| 1033 | +
|
| 1034 | + +-------+----------+------------------------+ |
| 1035 | + | d | decimals | sample | |
| 1036 | + +-------+----------+------------------------+ |
| 1037 | + + >50 | 0 | ``x = 34.5`` => 34% | |
| 1038 | + +-------+----------+------------------------+ |
| 1039 | + | >5 | 1 | ``x = 34.5`` => 34.5% | |
| 1040 | + +-------+----------+------------------------+ |
| 1041 | + | >0.5 | 2 | ``x = 34.5`` => 34.50% | |
| 1042 | + +-------+----------+------------------------+ |
| 1043 | + | ... | ... | ... | |
| 1044 | + +-------+----------+------------------------+ |
| 1045 | +
|
| 1046 | + This method will not be very good for tiny ranges or extremely |
| 1047 | + large ranges. It assumes that the values on the chart are |
| 1048 | + percentages displayed on a reasonable scale. |
| 1049 | + """ |
| 1050 | + x = self.convert_to_pct(x) |
| 1051 | + if self.decimals is None: |
| 1052 | + # Luckily Python's built-in `ceil` rounds to +inf, not away |
| 1053 | + # from zero. This is very important since the equation for |
| 1054 | + # `decimals` starts out as `d > 0.5 * 10**(2 - decimals)` |
| 1055 | + # and ends up with `decimals > 2 - log10(2 * d)`. |
| 1056 | + d = self.convert_to_pct(d) # d is a difference, so this works |
| 1057 | + decimals = math.ceil(2.0 - math.log10(2.0 * d)) |
| 1058 | + if decimals > 5: |
| 1059 | + decimals = 5 |
| 1060 | + elif decimals < 0: |
| 1061 | + decimals = 0 |
| 1062 | + else: |
| 1063 | + decimals = self.decimals |
| 1064 | + s = '{x:0.{decimals}f}'.format(x=x, decimals=int(decimals)) |
| 1065 | + |
| 1066 | + if self.symbol: |
| 1067 | + return s + self.symbol |
| 1068 | + return s |
| 1069 | + |
| 1070 | + def convert_to_pct(self, x): |
| 1071 | + return 100.0 * (x / self.max) |
| 1072 | + |
| 1073 | + |
976 | 1074 | class Locator(TickHelper):
|
977 | 1075 | """
|
978 | 1076 | Determine the tick locations;
|
@@ -2055,13 +2153,3 @@ def get_locator(self, d):
|
2055 | 2153 | locator = MultipleLocator(ticksize)
|
2056 | 2154 |
|
2057 | 2155 | 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