35
35
import matplotlib .patches as mpatches
36
36
import matplotlib .path as mpath
37
37
import matplotlib .ticker as ticker
38
+ import matplotlib .transforms as mtrans
38
39
39
40
from matplotlib import docstring
40
41
52
53
*anchor* (0.0, 0.5) if vertical; (0.5, 1.0) if horizontal;
53
54
the anchor point of the colorbar axes
54
55
*panchor* (1.0, 0.5) if vertical; (0.5, 0.0) if horizontal;
55
- the anchor point of the colorbar parent axes
56
+ the anchor point of the colorbar parent axes. If
57
+ False, the parent axes' anchor will be unchanged
56
58
============= ====================================================
57
59
58
60
'''
149
151
*cax*
150
152
None | axes object into which the colorbar will be drawn
151
153
*ax*
152
- None | parent axes object from which space for a new
153
- colorbar axes will be stolen
154
+ None | parent axes object(s) from which space for a new
155
+ colorbar axes will be stolen. If a list of axes is given
156
+ they will all be resized to make room for the colorbar axes.
154
157
*use_gridspec*
155
158
False | If *cax* is None, a new *cax* is created as an instance of
156
159
Axes. If *ax* is an instance of Subplot and *use_gridspec* is True,
@@ -255,6 +258,7 @@ def __init__(self, ax, cmap=None,
255
258
values = None ,
256
259
boundaries = None ,
257
260
orientation = 'vertical' ,
261
+ ticklocation = 'auto' ,
258
262
extend = 'neither' ,
259
263
spacing = 'uniform' , # uniform or proportional
260
264
ticks = None ,
@@ -263,6 +267,7 @@ def __init__(self, ax, cmap=None,
263
267
filled = True ,
264
268
extendfrac = None ,
265
269
extendrect = False ,
270
+ label = '' ,
266
271
):
267
272
self .ax = ax
268
273
self ._patch_ax ()
@@ -287,7 +292,12 @@ def __init__(self, ax, cmap=None,
287
292
self .outline = None
288
293
self .patch = None
289
294
self .dividers = None
290
- self .set_label ('' )
295
+
296
+ if ticklocation == 'auto' :
297
+ ticklocation = 'bottom' if orientation == 'horizontal' else 'right'
298
+ self .ticklocation = ticklocation
299
+
300
+ self .set_label (label )
291
301
if cbook .iterable (ticks ):
292
302
self .locator = ticker .FixedLocator (ticks , nbins = len (ticks ))
293
303
else :
@@ -336,11 +346,14 @@ def config_axis(self):
336
346
ax = self .ax
337
347
if self .orientation == 'vertical' :
338
348
ax .xaxis .set_ticks ([])
339
- ax .yaxis .set_label_position ('right' )
340
- ax .yaxis .set_ticks_position ('right' )
349
+ # location is either one of 'bottom' or 'top'
350
+ ax .yaxis .set_label_position (self .ticklocation )
351
+ ax .yaxis .set_ticks_position (self .ticklocation )
341
352
else :
342
353
ax .yaxis .set_ticks ([])
343
- ax .xaxis .set_label_position ('bottom' )
354
+ # location is either one of 'left' or 'right'
355
+ ax .xaxis .set_label_position (self .ticklocation )
356
+ ax .xaxis .set_ticks_position (self .ticklocation )
344
357
345
358
self ._set_label ()
346
359
@@ -835,11 +848,10 @@ class Colorbar(ColorbarBase):
835
848
836
849
"""
837
850
def __init__ (self , ax , mappable , ** kw ):
838
- mappable .autoscale_None () # Ensure mappable.norm.vmin, vmax
839
- # are set when colorbar is called,
840
- # even if mappable.draw has not yet
841
- # been called. This will not change
842
- # vmin, vmax if they are already set.
851
+ # Ensure the given mappable's norm has appropriate vmin and vmax set
852
+ # even if mappable.draw has not yet been called.
853
+ mappable .autoscale_None ()
854
+
843
855
self .mappable = mappable
844
856
kw ['cmap' ] = mappable .cmap
845
857
kw ['norm' ] = mappable .norm
@@ -948,47 +960,118 @@ def update_bruteforce(self, mappable):
948
960
949
961
950
962
@docstring .Substitution (make_axes_kw_doc )
951
- def make_axes (parent , ** kw ):
963
+ def make_axes (parents , location = None , orientation = None , fraction = 0.15 ,
964
+ shrink = 1.0 , aspect = 20 , ** kw ):
952
965
'''
953
- Resize and reposition a parent axes, and return a child
966
+ Resize and reposition parent axes, and return a child
954
967
axes suitable for a colorbar::
955
968
956
969
cax, kw = make_axes(parent, **kw)
957
970
958
971
Keyword arguments may include the following (with defaults):
959
972
960
- *orientation*
961
- 'vertical' or 'horizontal'
973
+ *location*: [**None**|'left'|'right'|'top'|'bottom']
974
+ The position, relative to **parents**, where the colorbar axes
975
+ should be created. If None, the value will either come from the
976
+ given **orientation**, else it will default to 'right'.
962
977
963
- %s
978
+ *orientation*: [**None**|'vertical'
10000
;|'horizontal']
979
+ The orientation of the colorbar. Typically, this keyword shouldn't
980
+ be used, as it can be derived from the **location** keyword.
964
981
965
- All but the first of these are stripped from the input kw set.
982
+ %s
966
983
967
- Returns (cax, kw), the child axes and the reduced kw dictionary.
984
+ Returns (cax, kw), the child axes and the reduced kw dictionary to be
985
+ passed when creating the colorbar instance.
968
986
'''
969
- orientation = kw .setdefault ('orientation' , 'vertical' )
970
- fraction = kw .pop ('fraction' , 0.15 )
971
- shrink = kw .pop ('shrink' , 1.0 )
972
- aspect = kw .pop ('aspect' , 20 )
973
- #pb = transforms.PBox(parent.get_position())
974
- pb = parent .get_position (original = True ).frozen ()
975
- if orientation == 'vertical' :
976
- pad = kw .pop ('pad' , 0.05 )
977
- x1 = 1.0 - fraction
978
- pb1 , pbx , pbcb = pb .splitx (x1 - pad , x1 )
979
- pbcb = pbcb .shrunk (1.0 , shrink ).anchored ('C' , pbcb )
980
- anchor = kw .pop ('anchor' , (0.0 , 0.5 ))
981
- panchor = kw .pop ('panchor' , (1.0 , 0.5 ))
987
+ locations = ["left" , "right" , "top" , "bottom" ]
988
+ if orientation is not None and location is not None :
989
+ raise TypeError ('position and orientation are mutually exclusive. Consider ' \
990
+ 'setting the position to any of %s' % ', ' .join (locations ))
991
+
992
+ # provide a default location
993
+ if location is None and orientation is None :
994
+ location = 'right'
995
+
996
+ # allow the user to not specify the location by specifying the orientation instead
997
+ if location is None :
998
+ location = 'right' if orientation == 'vertical' else 'bottom'
999
+
1000
+ if location not in locations :
1001
+ raise ValueError ('Invalid colorbar location. Must be one of %s' % ', ' .join (locations ))
1002
+
1003
+ default_location_settings = {'left' : {'anchor' : (1.0 , 0.5 ),
1004
+ 'panchor' : (0.0 , 0.5 ),
1005
+ 'pad' : 0.10 ,
1006
+ 'orientation' : 'vertical' },
1007
+ 'right' : {'anchor' : (0.0 , 0.5 ),
1008
+ 'panchor' : (1.0 , 0.5 ),
1009
+ 'pad' : 0.05 ,
1010
+ 'orientation' : 'vertical' },
1011
+ 'top' : {'anchor' : (0.5 , 0.0 ),
1012
+ 'panchor' : (0.5 , 1.0 ),
1013
+ 'pad' : 0.05 ,
1014
+ 'orientation' : 'horizontal' },
1015
+ 'bottom' : {'anchor' : (0.5 , 1.0 ),
1016
+ 'panchor' : (0.5 , 0.0 ),
1017
+ 'pad' : 0.15 , # backwards compat
1018
+ 'orientation' : 'horizontal' },
1019
+ }
1020
+
1021
+ loc_settings = default_location_settings [location ]
1022
+
1023
+ # put appropriate values into the kw dict for passing back to
1024
+ # the Colorbar class
1025
+ kw ['orientation' ] = loc_settings ['orientation' ]
1026
+ kw ['ticklocation' ] = location
1027
+
1028
+ anchor = kw .pop ('anchor' , loc_settings ['anchor' ])
1029
+ parent_anchor = kw .pop ('panchor' , loc_settings ['panchor' ])
1030
+ pad = kw .pop ('pad' , loc_settings ['pad' ])
1031
+
1032
+
1033
+ # turn parents into a list if it is not already
1034
+ if not isinstance (parents , (list , tuple )):
1035
+ parents = [parents ]
1036
+
1037
+ fig = parents [0 ].get_figure ()
1038
+ if not all (fig is ax .get_figure () for ax in parents ):
1039
+ raise ValueError ('Unable to create a colorbar axes as not all ' + \
1040
+ 'parents share the same figure.' )
1041
+
1042
+ # take a bounding box around all of the given axes
1043
+ parents_bbox = mtrans .Bbox .union ([ax .get_position (original = True ).frozen () \
1044
+ for ax in parents ])
1045
+
1046
+ pb = parents_bbox
1047
+ <
179B
span class=pl-k>if location in ('left' , 'right' ):
1048
+ if location == 'left' :
1049
+ pbcb , _ , pb1 = pb .splitx (fraction , fraction + pad )
1050
+ else :
1051
+ pb1 , _ , pbcb = pb .splitx (1 - fraction - pad , 1 - fraction )
1052
+ pbcb = pbcb .shrunk (1.0 , shrink ).anchored (anchor , pbcb )
982
1053
else :
983
- pad = kw .pop ('pad' , 0.15 )
984
- pbcb , pbx , pb1 = pb .splity (fraction , fraction + pad )
985
- pbcb = pbcb .shrunk (shrink , 1.0 ).anchored ('C' , pbcb )
986
- aspect = 1.0 / aspect
987
- anchor = kw .pop ('anchor' , (0.5 , 1.0 ))
988
- panchor = kw .pop ('panchor' , (0.5 , 0.0 ))
989
- parent .set_position (pb1 )
990
- parent .set_anchor (panchor )
991
- fig = parent .get_figure ()
1054
+ if location == 'bottom' :
1055
+ pbcb , _ , pb1 = pb .splity (fraction , fraction + pad )
1056
+ else :
1057
+ pb1 , _ , pbcb = pb .splity (1 - fraction - pad , 1 - fraction )
1058
+ pbcb = pbcb .shrunk (shrink , 1.0 ).anchored (anchor , pbcb )
1059
+
1060
+ # define the aspect ratio in terms of y's per x rather than x's per y
1061
+ aspect = 1.0 / aspect
1062
+
1063
+ # define a transform which takes us from old axes coordinates to
1064
+ # new axes coordinates
1065
+ shrinking_trans = mtrans .BboxTransform (parents_bbox , pb1 )
1066
+
1067
+ # transform each of the axes in parents using the new transform
1068
+ for ax in parents :
1069
+ new_posn = shrinking_trans .transform (ax .get_position ())
1070
+ new_posn = mtrans .Bbox (new_posn )
1071
+ ax .set_position (new_posn )
1072
+ if parent_anchor is not False :
1073
+ ax .set_anchor (parent_anchor )
1074
+
992
1075
cax = fig .add_axes (pbcb )
993
1076
cax .set_aspect (aspect , anchor = anchor , adjustable = 'box' )
994
1077
return cax , kw
@@ -1001,6 +1084,9 @@ def make_axes_gridspec(parent, **kw):
1001
1084
suitable for a colorbar. This function is similar to
1002
1085
make_axes. Prmary differences are
1003
1086
1087
+ * *make_axes_gridspec* only handles the *orientation* keyword
1088
+ and cannot handle the "location" keyword.
1089
+
1004
1090
* *make_axes_gridspec* should only be used with a subplot parent.
1005
1091
1006
1092
* *make_axes* creates an instance of Axes. *make_axes_gridspec*
@@ -1018,16 +1104,19 @@ def make_axes_gridspec(parent, **kw):
1018
1104
Keyword arguments may include the following (with defaults):
1019
1105
1020
1106
*orientation*
1021
- 'vertical' or 'horizontal'
1107
+ 'vertical' or 'horizontal'
1022
1108
1023
1109
%s
1024
1110
1025
1111
All but the first of these are stripped from the input kw set.
1026
1112
1027
- Returns (cax, kw), the child axes and the reduced kw dictionary.
1113
+ Returns (cax, kw), the child axes and the reduced kw dictionary to be
1114
+ passed when creating the colorbar instance.
1028
1115
'''
1029
1116
1030
1117
orientation = kw .setdefault ('orientation' , 'vertical' )
1118
+ kw ['ticklocation' ] = 'auto'
1119
+
1031
1120
fraction = kw .pop ('fraction' , 0.15 )
1032
1121
shrink = kw .pop ('shrink' , 1.0 )
1033
1122
aspect = kw .pop ('aspect' , 20 )
@@ -1139,11 +1228,8 @@ def _add_solids(self, X, Y, C):
1139
1228
1140
1229
patch = mpatches .PathPatch (mpath .Path (xy ),
1141
1230
facecolor = self .cmap (self .norm (val )),
1142
- hatch = hatch ,
1143
- edgecolor = 'none' , linewidth = 0 ,
1144
- antialiased = False , ** kw
1145
- )
1146
-
1231
+ hatch = hatch , linewidth = 0 ,
1232
+ antialiased = False , ** kw )
1147
1233
self .ax .add_patch (patch )
1148
1234
patches .append (patch )
1149
1235
@@ -1158,12 +1244,9 @@ def _add_solids(self, X, Y, C):
1158
1244
self .dividers = None
1159
1245
1160
1246
if self .drawedges :
1161
- self .dividers = collections .LineCollection (
1162
- self ._edges (X , Y ),
1163
- colors = (mpl .rcParams ['axes.edgecolor' ],),
1164
- linewidths = (
1165
- 0.5 * mpl .rcParams ['axes.linewidth' ],)
1166
- )
1247
+ self .dividers = collections .LineCollection (self ._edges (X , Y ),
1248
+ colors = (mpl .rcParams ['axes.edgecolor' ],),
1249
+ linewidths = (0.5 * mpl .rcParams ['axes.linewidth' ],))
1167
1250
self .ax .add_collection (self .dividers )
1168
1251
1169
1252
self .ax .hold (_hold )
0 commit comments