9
9
10
10
import numpy as np
11
11
12
+ import matplotlib .colors as mcolors
12
13
import matplotlib .cbook as cbook
13
- import matplotlib .units as units
14
- import matplotlib .ticker as ticker
15
-
14
+ import matplotlib .units as munits
15
+ import matplotlib .ticker as mticker
16
16
17
17
# pure hack for numpy 1.6 support
18
18
from distutils .version import LooseVersion
@@ -33,11 +33,22 @@ def to_array(data, maxlen=100):
33
33
return vals
34
34
35
35
36
- class StrCategoryConverter (units .ConversionInterface ):
36
+ class StrCategoryConverter (munits .ConversionInterface ):
37
+ """Converts categorical (or string) data to numerical values
38
+
39
+ Conversion typically happens in the following order:
40
+ 1. default_units:
41
+ creates unit_data category-integer mapping and binds to axis
42
+ 2. axis_info:
43
+ sets ticks/locator and label/formatter
44
+ 3. convert:
45
+ maps input category data to integers using unit_data
46
+
47
+ """
37
48
@staticmethod
38
49
def convert (value , unit , axis ):
39
- """Uses axis.unit_data map to encode
40
- data as floats
50
+ """
51
+ Encode value as floats using axis.unit_data
41
52
"""
42
53
vmap = dict (zip (axis .unit_data .seq , axis .unit_data .locs ))
43
54
@@ -52,33 +63,107 @@ def convert(value, unit, axis):
52
63
53
64
@staticmethod
54
65
def axisinfo (unit , axis ):
66
+ """
67
+ Return the :class:`~matplotlib.units.AxisInfo` for *unit*.
68
+
69
+ *unit* is None
70
+ *axis.unit_data* is used to set ticks and labels
71
+ """
55
72
majloc = StrCategoryLocator (axis .unit_data .locs )
56
73
majfmt = StrCategoryFormatter (axis .unit_data .seq )
57
- return units .AxisInfo (majloc = majloc , majfmt = majfmt )
74
+ return munits .AxisInfo (majloc = majloc , majfmt = majfmt )
58
75
59
76
@staticmethod
60
77
def default_units (data , axis ):
61
- # the conversion call stack is:
62
- # default_units->axis_info->convert
78
+ """
79
+ Create mapping between string categories in *data*
80
+ and integers, then store in *axis.unit_data*
81
+ """
63
82
if axis .unit_data is None :
64
83
axis .unit_data = UnitData (data )
65
84
else :
66
85
axis .unit_data .update (data )
67
86
return None
68
87
69
88
70
- class StrCategoryLocator (ticker .FixedLocator ):
89
+ class StrCategoryLocator (mticker .FixedLocator ):
90
+ """
91
+ Ensures that every category has a tick by subclassing
92
+ :class:`~matplotlib.ticker.FixedLocator`
93
+ """
71
94
def __init__ (self , locs ):
72
95
self .locs = locs
73
96
self .nbins = None
74
97
75
98
76
- class StrCategoryFormatter (ticker .FixedFormatter ):
99
+ class StrCategoryFormatter (mticker .FixedFormatter ):
100
+ """
101
+ Labels every category by subclassing
102
+ :class:`~matplotlib.ticker.FixedFormatter`
103
+ """
77
104
def __init__ (self , seq ):
78
105
self .seq = seq
79
106
self .offset_string = ''
80
107
81
108
109
+ class CategoryNorm (mcolors .Normalize ):
110
+ """
111
+ Preserves ordering of discrete values
112
+ """
113
+ def __init__ (self , categories ):
114
+ """
115
+ *categories*
116
+ distinct values for mapping
117
+
118
+ Out-of-range values are mapped to a value not in categories;
119
+ these are then converted to valid indices by :meth:`Colormap.__call__`.
120
+ """
121
+ self .categories = categories
122
+ self .N = len (self .categories )
123
+ self .vmin = 0
124
+ self .vmax = self .N
125
+ self ._interp = False
126
+
127
+ def __call__ (self , value , clip = None ):
128
+ if not cbook .iterable (value ):
129
+ value = [value ]
130
+
131
+ value = np .asarray (value )
132
+ ret = np .ones (value .shape ) * np .nan
133
+
134
+ for i , c in enumerate (self .categories ):
135
+ ret [value == c ] = i / (self .N * 1.0 )
136
+
137
+ return np .ma .array (ret , mask = np .isnan (ret ))
138
+
139
+ def inverse (self , value ):
140
+ # not quite sure what invertible means in this context
141
+ return ValueError ("CategoryNorm is not invertible" )
142
+
143
+
144
+ def colors_from_categories (codings ):
145
+ """
146
+ Helper routine to generate a cmap and a norm from a list
147
+ of (color, value) pairs
148
+
149
+ Parameters
150
+ ----------
151
+ codings : sequence of (key, value) pairs
152
+
153
+ Returns
154
+ -------
155
+ (cmap, norm) : tuple containing a :class:`Colormap` and a \
156
+ :class:`Normalize` instance
157
+ """
158
+ if isinstance (codings , dict ):
159
+ codings = codings .items ()
160
+
161
+ values , colors = zip (* codings )
162
+ cmap = mcolors .ListedColormap (list (colors ))
163
+ norm = CategoryNorm (list (values ))
164
+ return cmap , norm
165
+
166
+
82
167
def convert_to_string (value ):
83
168
"""Helper function for numpy 1.6, can be replaced with
84
169
np.array(...,dtype=unicode) for all later versions of numpy"""
@@ -132,6 +217,6 @@ def _set_seq_locs(self, data, value):
132
217
value += 1
133
218
134
219
# Connects the convertor to matplotlib
135
- units .registry [str ] = StrCategoryConverter ()
136
- units .registry [bytes ] = StrCategoryConverter ()
137
- units .registry [six .text_type ] = StrCategoryConverter ()
220
+ munits .registry [str ] = StrCategoryConverter ()
221
+ munits .registry [bytes ] = StrCategoryConverter ()
222
+ munits .registry [six .text_type ] = StrCategoryConverter ()
0 commit comments