Inner colorbar & Outer colorbar #691

Closed
wants to merge 3 commits into
from
View
48 examples/axes_grid/demo_colorbar.py
@@ -0,0 +1,48 @@
+import numpy as np
+import matplotlib.gridspec as gridspec
+import matplotlib.pyplot as plt
+
+from mpl_toolkits.axes_grid1.colorbar import outer_colorbar, inner_colorbar
+
+
+plt.figure(figsize=[6,6])
+gs = gridspec.GridSpec(3,3, hspace=0.7, wspace=0.7)
+
+locs = [1, 2, 3, 4, 6, 7, 8, 9, 10]
+arr = np.arange(100).reshape((10,10))
+for i, ss in zip(locs, gs):
+ ax = plt.subplot(ss)
+ ax.axison = False
+ im = ax.imshow(arr, interpolation="none")
+ cb = outer_colorbar(ax, mappable=im, loc=i,
+ orientation=None,
+ ticks=[0, 50],
+ length="50%", thickness="7%",
+ pad=0.2,
+ )
+
+
+
+
+plt.figure(figsize=[6,6])
+gs = gridspec.GridSpec(3,3)
+
+from matplotlib.patheffects import withStroke
+pe = [withStroke(foreground="w", linewidth=3)]
+
+locs = [1, 2, 3, 4, 6, 7, 8, 9, 10]
+arr = np.arange(100).reshape((10,10))
+for i, ss in zip(locs, gs):
+ ax = plt.subplot(ss)
+ ax.axison = False
+ im = ax.imshow(arr, interpolation="none")
+ cb = inner_colorbar(ax, mappable=im, loc=i,
+ orientation=None,
+ ticks=[0, 50],
+ length="50%", thickness="5%",
+ pad=0.2,
+ )
+ cb.ax.axis[:].major_ticklabels.set_path_effects(pe)
+
+
+plt.show()
View
16 lib/matplotlib/offsetbox.py
@@ -1045,13 +1045,20 @@ def _update_offset_func(self, renderer, fontsize=None):
def _offset(w, h, xd, yd, renderer, fontsize=fontsize, self=self):
bbox = Bbox.from_bounds(0, 0, w, h)
- borderpad = self.borderpad*fontsize
+ try:
+ borderpadx, borderpady = self.borderpad
+ except TypeError:
+ borderpadx = self.borderpad
+ borderpady = self.borderpad
+ borderpadx = borderpadx*fontsize
+ borderpady = borderpady*fontsize
+
bbox_to_anchor = self.get_bbox_to_anchor()
x0, y0 = self._get_anchored_bbox(self.loc,
bbox,
bbox_to_anchor,
- borderpad)
+ borderpadx, borderpady)
@pelson
Matplotlib Developers member
pelson added a line comment Jun 13, 2012

Again, I have readability issues with this. xborderpad is better, x_border_pad is best (but most inconsistent with the rest of the code).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
return x0+xd, y0+yd
self.set_offset(_offset)
@@ -1088,7 +1095,8 @@ def draw(self, renderer):
- def _get_anchored_bbox(self, loc, bbox, parentbbox, borderpad):
+ def _get_anchored_bbox(self, loc, bbox, parentbbox,
+ borderpadx, borderpady):
"""
return the position of the bbox anchored at the parentbbox
with the loc code, with the borderpad.
@@ -1110,7 +1118,7 @@ def _get_anchored_bbox(self, loc, bbox, parentbbox, borderpad):
c = anchor_coefs[loc]
- container = parentbbox.padded(-borderpad)
+ container = parentbbox.padded(-borderpadx, -borderpady)
anchored_box = bbox.anchored(c, container=container)
return anchored_box.x0, anchored_box.y0
View
6 lib/matplotlib/transforms.py
@@ -631,13 +631,15 @@ def expanded(self, sw, sh):
a = np.array([[-deltaw, -deltah], [deltaw, deltah]])
return Bbox(self._points + a)
- def padded(self, p):
+ def padded(self, p, pady=None):
@pelson
Matplotlib Developers member
pelson added a line comment Jun 13, 2012

I can't help but see one word with this variable name, I think the variable name ypadding would probably make things clearer (I would personally go for y_padding, but that is probably a bit inconsistent with other variable names in matplotlib).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
"""
Return a new :class:`Bbox` that is padded on all four sides by
the given value.
"""
+ if pady is None:
+ pady = p
points = self.get_points()
- return Bbox(points + [[-p, -p], [p, p]])
+ return Bbox(points + [[-p, -pady], [p, pady]])
def translated(self, tx, ty):
"""
View
331 lib/mpl_toolkits/axes_grid1/colorbar.py
@@ -791,14 +791,15 @@ def make_axes(parent, **kw):
return cax, kw
-def colorbar(mappable, cax=None, ax=None, **kw):
@WeatherGod
Matplotlib Developers member
WeatherGod added a line comment Feb 22, 2012

I am really not a big fan of this renaming of these functions. I would rather see a new keyword added to colorbar that would specify whether it is inner or outer (and default to outer).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+def axesgrid1_colorbar(mappable, cax=None, ax=None, **kw):
"""
Create a colorbar for a ScalarMappable instance.
Documentation for the pylab thin wrapper:
%(colorbar_doc)s
"""
import matplotlib.pyplot as plt
+ from matplotlib.colorbar import Colorbar
if ax is None:
ax = plt.gca()
if cax is None:
@@ -815,3 +816,331 @@ def on_changed(m):
mappable.set_colorbar(cb, cax)
ax.figure.sca(ax)
return cb
+
+
+def mpl_colorbar(mappable, cax=None, ax=None, **kw):
+ """
+ Create a colorbar for a ScalarMappable instance.
+
+ Documentation for the pylab thin wrapper:
+ %(colorbar_doc)s
+ """
+ import matplotlib.pyplot as plt
+ from matplotlib.colorbar import Colorbar
+ if ax is None:
+ ax = plt.gca()
+ if cax is None:
+ cax, kw = make_axes(ax, **kw)
+ cax.hold(True)
+ cb = Colorbar(cax, mappable, **kw)
+
+ def on_changed(m):
+ cb.set_cmap(m.get_cmap())
+ cb.set_clim(m.get_clim())
+ cb.update_bruteforce(m)
+
+ cbid = mappable.callbacksSM.connect('changed', on_changed)
+ mappable.set_colorbar(cb, cax)
+ ax.figure.sca(ax)
+ return cb
+
+
+colorbar = mpl_colorbar
+
+from mpl_toolkits.axes_grid1.inset_locator import inset_axes
+
+
+def _get_colorbar_params(loc, orientation, length, thickness):
+ if orientation is None:
+ if loc in [8, 9]:
+ orientation="horizontal"
+ else:
+ orientation="vertical"
+
+
+ if orientation == "vertical":
+ height = length
+ width = thickness
+ elif orientation == "horizontal":
+ height = thickness
+ width = length
+ else:
+ raise ValueError("Unknown orientation value : %s" % orientation)
+
+ if orientation == "vertical":
+ if loc in [1, 4, 5, 7]:
+ tickdir = "left"
+ elif loc in [2, 3, 6, 8, 9, 10]:
+ tickdir = "right"
+
+ elif orientation == "horizontal":
+ if loc in [3, 4, 8]:
+ tickdir = "top"
+ elif loc in [1, 2, 5, 6, 7, 9, 10]:
+ tickdir = "bottom"
+
+ return loc, orientation, height, width, tickdir
+
+
+@docstring.Substitution(colormap_kw_doc)
+def inner_colorbar(ax, mappable, loc,
+ orientation=None,
+ length="45%", thickness="5%",
+ pad=None,
+ **kw):
+ """
+ Create a colorbar at the inner side of the Axes of the given
+ location. The size and location of the original axes is not
+ changed. For example::
+
+ inner_colorbar(ax, mappable, loc=2, **kwargs)
+
+ required arguments are:
+
+ *ax*
+ parent axes object a new
+ colorbar axes will be attached
+
+ *mappable*
+ the :class:`~matplotlib.image.Image`,
+ :class:`~matplotlib.contour.ContourSet`, etc. to
+ which the colorbar applies; this argument is mandatory for the
+ :meth:`~matplotlib.figure.Figure.colorbar` method but optional for the
+ :func:`~matplotlib.pyplot.colorbar` function, which sets the
+ default to the current image.
+
+ *loc*
+ location code as in Legend
+
+ Keyword arguments are:
+
+ ============= ====================================================
+ Property Description
+ ============= ====================================================
+ *orientation* None, vertical or horizontal
+ *length* length of the colorbar.
+ *thickness* thickness of the colorbar.
+ *pad* pad bewtween original axes and colorbar in inches
+ ============= ====================================================
+
+ For *thickness* and *length*, if a float is given, it is
+ considered as a size in inches. If a string in the form of
+ '50%%' is given, the value is considered as a fraction of the
+ original axes.
+
+ Additional keyword arguments are:
+
+ %s
+
+ returns:
+ :class:`~matplotlib.colorbar.Colorbar` instance; see also its base class,
+ :class:`~matplotlib.colorbar.ColorbarBase`. Call the
+ :meth:`~matplotlib.colorbar.ColorbarBase.set_label` method
+ to label the colorbar.
+
+ """
+
+ if pad is None:
+ pad = mpl.rcParams['legend.borderaxespad']
+
+ loc, orientation, height, width, tickdir = \
+ _get_colorbar_params(loc, orientation, length, thickness)
+
+ cax = inset_axes(ax,
+ width=width,
+ height=height,
+ loc=loc,
+ bbox_to_anchor=(0, 0, 1, 1),
+ bbox_transform=ax.transAxes,
+ borderpad=pad)
+
+ cb = colorbar(mappable, cax=cax, ax=ax,
+ orientation=orientation, **kw)
+
+ if tickdir == "left":
+ cax.yaxis.tick_left()
+ elif tickdir == "right":
+ cax.yaxis.tick_right()
+ elif tickdir == "top":
+ cax.xaxis.tick_top()
+ else:
+ cax.xaxis.tick_bottom()
+
+ return cb
+
+
+@docstring.Substitution(colormap_kw_doc)
+def outer_colorbar(ax, mappable, loc,
+ orientation=None,
+ length="100%", thickness="5%",
+ pad=None,
+ **kw):
+
+ """
+ Create a colorbar at the outer side of the Axes of the given
+ location. The size and location of the original axes is not
+ changed. For example::
+
+ outer_colorbar(ax, mappable, loc=2, **kwargs)
+
+ required arguments are:
+
+ *ax*
+ parent axes object a new
+ colorbar axes will be attached
+
+ *mappable*
+ the :class:`~matplotlib.image.Image`,
+ :class:`~matplotlib.contour.ContourSet`, etc. to
+ which the colorbar applies; this argument is mandatory for the
+ :meth:`~matplotlib.figure.Figure.colorbar` method but optional for the
+ :func:`~matplotlib.pyplot.colorbar` function, which sets the
+ default to the current image.
+
+ *loc*
+ location code as in Legend
@efiring
Matplotlib Developers member
efiring added a line comment Feb 19, 2012

Requiring a numeric code is rather unfriendly and harms readability of user code. It would be nice to have location specifications and codes factored out, and encourage use of names. Even in mpl code, names would be better where possible. One concise naming method for such location is map-oriented: e.g. NE is upper right, CE is center right, C is center, etc. Or one could use T for top, B for bottom, L for left, R for right, and C for center.

@WeatherGod
Matplotlib Developers member
WeatherGod added a line comment Feb 22, 2012

My vote would be to be consistent with how legends are done (but without "best"). So, map names would be best.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ Keyword arguments are:
+
+ ============= ====================================================
+ Property Description
+ ============= ====================================================
+ *orientation* None, vertical or horizontal
+ *length* length of the colorbar.
+ *thickness* thickness of the colorbar.
+ *pad* pad bewtween original axes and colorbar in inches
+ ============= ====================================================
+
+ For *thickness* and *length*, if a float is given, it is
+ considered as a size in inches. If a string in the form of
+ '50%%' is given, the value is considered as a fraction of the
+ original axes.
+
+ Additional keyword arguments are:
+
+ %s
+
+ returns:
+ :class:`~matplotlib.colorbar.Colorbar` instance; see also its base class,
+ :class:`~matplotlib.colorbar.ColorbarBase`. Call the
+ :meth:`~matplotlib.colorbar.ColorbarBase.set_label` method
+ to label the colorbar.
+
+ """
+
+ if pad is None:
+ pad = mpl.rcParams['legend.borderaxespad']
+
+ loc, orientation, height, width, tickdir = \
+ _get_colorbar_params(loc, orientation, length, thickness)
+
+ if loc in [5, 7]:
+ bbox_to_anchor = [1, 0, 1, 1]
+ elif loc in [6]:
+ bbox_to_anchor = [-1, 0, 1, 1]
+ elif loc in [8]:
+ bbox_to_anchor = [0, -1, 1, 1]
+ elif loc in [9]:
+ bbox_to_anchor = [0, 1, 1, 1]
+ elif loc in [1, 2, 3, 4]:
+ if orientation == "vertical":
+ if loc in [1, 4]:
+ bbox_to_anchor = [1, 0, 1, 1]
+ elif loc in [2, 3]:
+ bbox_to_anchor = [-1, 0, 1, 1]
+ else: # horizontal
+ if loc in [1, 2]:
+ bbox_to_anchor = [0, 1, 1, 1]
+ elif loc in [3, 4]:
+ bbox_to_anchor = [0, -1, 1, 1]
+ else:
+ bbox_to_anchor = [0, 0, 1, 1]
+
+ try:
+ padx, pady = pad
+ except TypeError:
+ if orientation == "vertical":
+ if loc in [8, 9]:
+ padx, pady = pad, pad
+ else:
+ padx, pady = pad, 0
+ else:
+ if loc in [5, 6, 7]:
+ padx, pady = pad, pad
+ else:
+ padx, pady = 0, pad
+
+ loc_map_h = {1:4,
+ 2:3,
+ 3:2,
+ 4:1,
+ 5:6,
+ 6:7,
+ 7:6,
+ 8:9,
+ 9:8,
+ 10:10}
+ loc_map_v = {1:2,
+ 2:1,
+ 3:4,
+ 4:3,
+ 5:6,
+ 6:7,
+ 7:6,
+ 8:9,
+ 9:8,
+ 10:10}
+
+ if orientation == "horizontal":
+ loc = loc_map_h[loc]
+ else:
+ loc = loc_map_v[loc]
+ tickdir_map = {"left":"right",
+ "right":"left",
+ "top":"bottom",
+ "bottom":"top"}
+ tickdir = tickdir_map[tickdir]
+ cax = inset_axes(ax,
+ width=width,
+ height=height,
+ loc=loc,
+ bbox_to_anchor=bbox_to_anchor,
+ bbox_transform=ax.transAxes,
+ borderpad=(padx, pady))
+
+ cb = colorbar(mappable, cax=cax, ax=ax,
+ orientation=orientation, **kw)
+
+ if tickdir == "left":
+ cax.yaxis.tick_left()
+ elif tickdir == "right":
+ cax.yaxis.tick_right()
+ elif tickdir == "top":
+ cax.xaxis.tick_top()
+ else:
+ cax.xaxis.tick_bottom()
+
+ return cb
+
+
+if __name__ == '__main__':
+ import matplotlib.gridspec as gridspec
+ gs = gridspec.GridSpec(3,3)
+
+ locs = [1, 2, 3, 4, 6, 7, 8, 9, 10][:]
+ arr = np.arange(100).reshape((10,10))
+ for i, ss in zip(locs, gs):
+ ax = subplot(ss)
+ im = ax.imshow(arr, interpolation="none")
+ cb = outer_colorbar(ax, mappable=im, loc=i,
+ orientation=None,
+ #orientation="vertical",
+ #orientation="horizontal",
+ length="100%", thickness="5%",
+ #pad=0.1,
+ )
+
+
+# ax.inner_colorbar(mappable=im, loc=4,
+# orientation='vertical',
+# lenght="45%", thickness="8%")