Skip to content

Shared axes colorbars & finer location control #956

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 14, 2013
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Shared colorbar axes working.
  • Loading branch information
pelson committed May 14, 2013
commit be049b26cfa73e7c69baa73d681ea2a7f44b61b6
99 changes: 86 additions & 13 deletions lib/matplotlib/colorbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import matplotlib.patches as mpatches
import matplotlib.path as mpath
import matplotlib.ticker as ticker
import matplotlib.transforms as mtrans

from matplotlib import docstring

Expand All @@ -52,7 +53,8 @@
*anchor* (0.0, 0.5) if vertical; (0.5, 1.0) if horizontal;
the anchor point of the colorbar axes
*panchor* (1.0, 0.5) if vertical; (0.5, 0.0) if horizontal;
the anchor point of the colorbar parent axes
the anchor point of the colorbar parent axes. If
False, the parent axes' anchor will be unchanged
============= ====================================================

'''
Expand Down Expand Up @@ -149,8 +151,9 @@
*cax*
None | axes object into which the colorbar will be drawn
*ax*
None | parent axes object from which space for a new
colorbar axes will be stolen
None | parent axes object(s) from which space for a new
colorbar axes will be stolen. If a list of axes is given
they will be resized to make room for the colorbar axes.
*use_gridspec*
False | If *cax* is None, a new *cax* is created as an instance of
Axes. If *ax* is an instance of Subplot and *use_gridspec* is True,
Expand Down Expand Up @@ -255,6 +258,7 @@ def __init__(self, ax, cmap=None,
values=None,
boundaries=None,
orientation='vertical',
location='right',
extend='neither',
spacing='uniform', # uniform or proportional
ticks=None,
Expand All @@ -278,6 +282,7 @@ def __init__(self, ax, cmap=None,
self._inside = self._slice_dict[extend]
self.spacing = spacing
self.orientation = orientation
self.location = location
self.drawedges = drawedges
self.filled = filled
self.extendfrac = extendfrac
Expand Down Expand Up @@ -336,11 +341,15 @@ def config_axis(self):
ax = self.ax
if self.orientation == 'vertical':
ax.xaxis.set_ticks([])
ax.yaxis.set_label_position('right')
ax.yaxis.set_ticks_position('right')
# location is either one of 'bottom' or 'top'
ax.yaxis.set_label_position(self.location)
ax.yaxis.set_ticks_position(self.location)
else:
ax.yaxis.set_ticks([])
ax.xaxis.set_label_position('bottom')
# location is either one of 'left' or 'right'
ax.xaxis.set_label_position(self.location)
# XXX This wasn't enabled before...
ax.xaxis.set_ticks_position(self.location)

self._set_label()

Expand Down Expand Up @@ -835,11 +844,10 @@ class Colorbar(ColorbarBase):

"""
def __init__(self, ax, mappable, **kw):
mappable.autoscale_None() # Ensure mappable.norm.vmin, vmax
# are set when colorbar is called,
# even if mappable.draw has not yet
# been called. This will not change
# vmin, vmax if they are already set.
# Ensure the given mappable's norm has appropriate vmin and vmax set
# even if mappable.draw has not yet been called.
mappable.autoscale_None()

self.mappable = mappable
kw['cmap'] = mappable.cmap
kw['norm'] = mappable.norm
Expand Down Expand Up @@ -948,7 +956,7 @@ def update_bruteforce(self, mappable):


@docstring.Substitution(make_axes_kw_doc)
def make_axes(parent, **kw):
def make_axes_orig(parent, **kw):
'''
Resize and reposition a parent axes, and return a child
axes suitable for a colorbar::
Expand Down Expand Up @@ -994,6 +1002,71 @@ def make_axes(parent, **kw):
return cax, kw


@docstring.Substitution(make_axes_kw_doc)
def make_axes(parent, location=None, orientation=None, fraction=0.15, shrink=1.0, aspect=20, **kw):
locations = ["left", "right", "top", "bottom"]
if orientation is not None and location is not None:
raise TypeError('position and orientation are mutually exclusive. Consider ' \
'setting the position to any of %s' % ','.join(locations))

# must pump out an orientation for colorbar creation
if location in ['left', 'right']:
kw['orientation'] = 'vertical'
kw['location'] = location
anchor = kw.pop('anchor', (0.0, 0.5))
# define the parent's anchor to be next to the new colorbar axes
panchor = kw.pop('panchor', (1.0, 0.5))
else:
kw['orientation'] = 'horizontal'
kw['location'] = location
anchor = kw.pop('anchor', (0.5, 1.0))
# define the parent's anchor to be next to the new colorbar axes
panchor = kw.pop('panchor', (0.5, 0.0))

# define padding between colorbar axes and parent axes in axes coordinates.
# For best outcomes, pad is best at 0.15 when location is "bottom"
if location == 'bottom':
pad = kw.pop('pad', 0.0)
else:
pad = kw.pop('pad', 0.00)

if isinstance(parent, list):
parents_bbox = mtrans.Bbox.union([ax.get_position(original=True).frozen() \
for ax in parent])

pb = parents_bbox
if location in ('left', 'right'):
if location == 'left':
pbcb, _, pb1 = pb.splitx(1 - fraction, fraction + pad)
else:
pb1, _, pbcb = pb.splitx(1 - fraction - pad, 1 - fraction)
pbcb = pbcb.shrunk(1.0, shrink).anchored('C', pbcb)

else:
if location == 'top':
pb1, _, pbcb = pb.splity(1 - fraction - pad, fraction)
else:
pbcb, _, pb1 = pb.splity(fraction, fraction + pad)
pbcb = pbcb.shrunk(shrink, 1.0).anchored('C', pbcb)
# define the aspect ratio in terms of y's per x rather than x's per y
aspect = 1.0/aspect

shrinking_trans = mtrans.BboxTransform(parents_bbox, pb1)

for ax in parent:
new_posn = shrinking_trans.transform(ax.get_position())
new_posn = mtrans.Bbox(new_posn)
ax.set_position(new_posn)
if panchor is not False:
ax.set_anchor(panchor)

# XXX test all axes must be on the same figure...
fig = parent[0].get_figure()
cax = fig.add_axes(pbcb)
cax.set_aspect(aspect, anchor=anchor, adjustable='box')
return cax, kw


@docstring.Substitution(make_axes_kw_doc)
def make_axes_gridspec(parent, **kw):
'''
Expand All @@ -1018,7 +1091,7 @@ def make_axes_gridspec(parent, **kw):
Keyword arguments may include the following (with defaults):

*orientation*
'vertical' or 'horizontal'
'vertical' or 'horizontal'

%s

Expand Down
4 changes: 2 additions & 2 deletions lib/matplotlib/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1418,7 +1418,7 @@ def savefig(self, *args, **kwargs):
ax.patch.set_edgecolor(cc[1])

@docstring.dedent_interpd
def colorbar(self, mappable, cax=None, ax=None, **kw):
def colorbar(self, mappable, cax=None, ax=None, use_gridspec=False, **kw):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched the use_gridspec default to True in #774; I don't know of any disadvantages. You might take this into account if/when you rebase.

"""
Create a colorbar for a ScalarMappable instance, *mappable*.

Expand All @@ -1427,7 +1427,7 @@ def colorbar(self, mappable, cax=None, ax=None, **kw):
"""
if ax is None:
ax = self.gca()
use_gridspec = kw.pop("use_gridspec", True)

if cax is None:
if use_gridspec and isinstance(ax, SubplotBase):
cax, kw = cbar.make_axes_gridspec(ax, **kw)
Expand Down
12 changes: 5 additions & 7 deletions lib/matplotlib/pyplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
import warnings

import matplotlib
import matplotlib.colorbar
from matplotlib import _pylab_helpers, interactive
from matplotlib.cbook import dedent, silent_list, is_string_like, is_numlike
from matplotlib import docstring
from matplotlib.figure import Figure, figaspect
from matplotlib.backend_bases import FigureCanvasBase
from matplotlib.figure import Figure, figaspect
from matplotlib.gridspec import GridSpec
from matplotlib.image import imread as _imread
from matplotlib.image import imsave as _imsave
from matplotlib import rcParams, rcParamsDefault, get_backend
Expand Down Expand Up @@ -207,16 +209,16 @@ def rc_context(rc=None, fname=None):
return matplotlib.rc_context(rc, fname)



@docstring.copy_dedent(matplotlib.rcdefaults)
def rcdefaults():
matplotlib.rcdefaults()
draw_if_interactive()


# The current "image" (ScalarMappable) is retrieved or set
# only via the pyplot interface using the following two
# functions:


def gci():
"""
Get the current colorable artist. Specifically, returns the
Expand Down Expand Up @@ -246,9 +248,7 @@ def sci(im):


## Any Artist ##

# (getp is simply imported)

@docstring.copy(_setp)
def setp(*args, **kwargs):
ret = _setp(*args, **kwargs)
Expand Down Expand Up @@ -1099,7 +1099,6 @@ def subplots(nrows=1, ncols=1, sharex=False, sharey=False, squeeze=True,
return ret


from gridspec import GridSpec
def subplot2grid(shape, loc, rowspan=1, colspan=1, **kwargs):
"""
Create a subplot in a grid. The grid is specified by *shape*, at
Expand Down Expand Up @@ -2091,7 +2090,6 @@ def pad(s, l):

## Plotting part 1: manually generated functions and wrappers ##

import matplotlib.colorbar
def colorbar(mappable=None, cax=None, ax=None, **kw):
if mappable is None:
mappable = gci()
Expand Down