matplotlib  1.4.2
About: matplotlib is a python 2D plotting library which produces publication quality figures in a variety of hardcopy formats and interactive environments across platforms.
  Fossies Dox: matplotlib-1.4.2.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
colorbar.py
Go to the documentation of this file.
1 '''
2 Colorbar toolkit with two classes and a function:
3 
4  :class:`ColorbarBase`
5  the base class with full colorbar drawing functionality.
6  It can be used as-is to make a colorbar for a given colormap;
7  a mappable object (e.g., image) is not needed.
8 
9  :class:`Colorbar`
10  the derived class for use with images or contour plots.
11 
12  :func:`make_axes`
13  a function for resizing an axes and adding a second axes
14  suitable for a colorbar
15 
16 The :meth:`~matplotlib.figure.Figure.colorbar` method uses :func:`make_axes`
17 and :class:`Colorbar`; the :func:`~matplotlib.pyplot.colorbar` function
18 is a thin wrapper over :meth:`~matplotlib.figure.Figure.colorbar`.
19 
20 '''
21 from __future__ import (absolute_import, division, print_function,
22  unicode_literals)
23 
24 import six
25 from six.moves import xrange, zip
26 
27 import warnings
28 
29 import numpy as np
30 
31 import matplotlib as mpl
32 import matplotlib.artist as martist
33 import matplotlib.cbook as cbook
34 import matplotlib.collections as collections
35 import matplotlib.colors as colors
36 import matplotlib.contour as contour
37 import matplotlib.cm as cm
38 import matplotlib.gridspec as gridspec
39 import matplotlib.patches as mpatches
40 import matplotlib.path as mpath
41 import matplotlib.ticker as ticker
42 import matplotlib.transforms as mtrans
43 
44 from matplotlib import docstring
45 
46 make_axes_kw_doc = '''
47 
48  ============= ====================================================
49  Property Description
50  ============= ====================================================
51  *orientation* vertical or horizontal
52  *fraction* 0.15; fraction of original axes to use for colorbar
53  *pad* 0.05 if vertical, 0.15 if horizontal; fraction
54  of original axes between colorbar and new image axes
55  *shrink* 1.0; fraction by which to shrink the colorbar
56  *aspect* 20; ratio of long to short dimensions
57  *anchor* (0.0, 0.5) if vertical; (0.5, 1.0) if horizontal;
58  the anchor point of the colorbar axes
59  *panchor* (1.0, 0.5) if vertical; (0.5, 0.0) if horizontal;
60  the anchor point of the colorbar parent axes. If
61  False, the parent axes' anchor will be unchanged
62  ============= ====================================================
63 
64 '''
65 
66 colormap_kw_doc = '''
67 
68  ============ ====================================================
69  Property Description
70  ============ ====================================================
71  *extend* [ 'neither' | 'both' | 'min' | 'max' ]
72  If not 'neither', make pointed end(s) for out-of-
73  range values. These are set for a given colormap
74  using the colormap set_under and set_over methods.
75  *extendfrac* [ *None* | 'auto' | length | lengths ]
76  If set to *None*, both the minimum and maximum
77  triangular colorbar extensions with have a length of
78  5% of the interior colorbar length (this is the
79  default setting). If set to 'auto', makes the
80  triangular colorbar extensions the same lengths as
81  the interior boxes (when *spacing* is set to
82  'uniform') or the same lengths as the respective
83  adjacent interior boxes (when *spacing* is set to
84  'proportional'). If a scalar, indicates the length
85  of both the minimum and maximum triangular colorbar
86  extensions as a fraction of the interior colorbar
87  length. A two-element sequence of fractions may also
88  be given, indicating the lengths of the minimum and
89  maximum colorbar extensions respectively as a
90  fraction of the interior colorbar length.
91  *extendrect* [ *False* | *True* ]
92  If *False* the minimum and maximum colorbar extensions
93  will be triangular (the default). If *True* the
94  extensions will be rectangular.
95  *spacing* [ 'uniform' | 'proportional' ]
96  Uniform spacing gives each discrete color the same
97  space; proportional makes the space proportional to
98  the data interval.
99  *ticks* [ None | list of ticks | Locator object ]
100  If None, ticks are determined automatically from the
101  input.
102  *format* [ None | format string | Formatter object ]
103  If None, the
104  :class:`~matplotlib.ticker.ScalarFormatter` is used.
105  If a format string is given, e.g., '%.3f', that is
106  used. An alternative
107  :class:`~matplotlib.ticker.Formatter` object may be
108  given instead.
109  *drawedges* [ False | True ] If true, draw lines at color
110  boundaries.
111  ============ ====================================================
112 
113  The following will probably be useful only in the context of
114  indexed colors (that is, when the mappable has norm=NoNorm()),
115  or other unusual circumstances.
116 
117  ============ ===================================================
118  Property Description
119  ============ ===================================================
120  *boundaries* None or a sequence
121  *values* None or a sequence which must be of length 1 less
122  than the sequence of *boundaries*. For each region
123  delimited by adjacent entries in *boundaries*, the
124  color mapped to the corresponding value in values
125  will be used.
126  ============ ===================================================
127 
128 '''
129 
130 colorbar_doc = '''
131 
132 Add a colorbar to a plot.
133 
134 Function signatures for the :mod:`~matplotlib.pyplot` interface; all
135 but the first are also method signatures for the
136 :meth:`~matplotlib.figure.Figure.colorbar` method::
137 
138  colorbar(**kwargs)
139  colorbar(mappable, **kwargs)
140  colorbar(mappable, cax=cax, **kwargs)
141  colorbar(mappable, ax=ax, **kwargs)
142 
143 arguments:
144 
145  *mappable*
146  the :class:`~matplotlib.image.Image`,
147  :class:`~matplotlib.contour.ContourSet`, etc. to
148  which the colorbar applies; this argument is mandatory for the
149  :meth:`~matplotlib.figure.Figure.colorbar` method but optional for the
150  :func:`~matplotlib.pyplot.colorbar` function, which sets the
151  default to the current image.
152 
153 keyword arguments:
154 
155  *cax*
156  None | axes object into which the colorbar will be drawn
157  *ax*
158  None | parent axes object(s) from which space for a new
159  colorbar axes will be stolen. If a list of axes is given
160  they will all be resized to make room for the colorbar axes.
161  *use_gridspec*
162  False | If *cax* is None, a new *cax* is created as an instance of
163  Axes. If *ax* is an instance of Subplot and *use_gridspec* is True,
164  *cax* is created as an instance of Subplot using the
165  grid_spec module.
166 
167 
168 Additional keyword arguments are of two kinds:
169 
170  axes properties:
171 %s
172  colorbar properties:
173 %s
174 
175 If *mappable* is a :class:`~matplotlib.contours.ContourSet`, its *extend*
176 kwarg is included automatically.
177 
178 Note that the *shrink* kwarg provides a simple way to keep a vertical
179 colorbar, for example, from being taller than the axes of the mappable
180 to which the colorbar is attached; but it is a manual method requiring
181 some trial and error. If the colorbar is too tall (or a horizontal
182 colorbar is too wide) use a smaller value of *shrink*.
183 
184 For more precise control, you can manually specify the positions of
185 the axes objects in which the mappable and the colorbar are drawn. In
186 this case, do not use any of the axes properties kwargs.
187 
188 It is known that some vector graphics viewer (svg and pdf) renders white gaps
189 between segments of the colorbar. This is due to bugs in the viewers not
190 matplotlib. As a workaround the colorbar can be rendered with overlapping
191 segments::
192 
193  cbar = colorbar()
194  cbar.solids.set_edgecolor("face")
195  draw()
196 
197 However this has negative consequences in other circumstances. Particularly
198 with semi transparent images (alpha < 1) and colorbar extensions and is not
199 enabled by default see (issue #1188).
200 
201 returns:
202  :class:`~matplotlib.colorbar.Colorbar` instance; see also its base class,
203  :class:`~matplotlib.colorbar.ColorbarBase`. Call the
204  :meth:`~matplotlib.colorbar.ColorbarBase.set_label` method
205  to label the colorbar.
206 
207 ''' % (make_axes_kw_doc, colormap_kw_doc)
208 
209 docstring.interpd.update(colorbar_doc=colorbar_doc)
210 
211 
212 def _set_ticks_on_axis_warn(*args, **kw):
213  # a top level function which gets put in at the axes'
214  # set_xticks set_yticks by _patch_ax
215  warnings.warn("Use the colorbar set_ticks() method instead.")
216 
217 
219  '''
220  Draw a colorbar in an existing axes.
221 
222  This is a base class for the :class:`Colorbar` class, which is the
223  basis for the :func:`~matplotlib.pyplot.colorbar` function and the
224  :meth:`~matplotlib.figure.Figure.colorbar` method, which are the
225  usual ways of creating a colorbar.
226 
227  It is also useful by itself for showing a colormap. If the *cmap*
228  kwarg is given but *boundaries* and *values* are left as None,
229  then the colormap will be displayed on a 0-1 scale. To show the
230  under- and over-value colors, specify the *norm* as::
231 
232  colors.Normalize(clip=False)
233 
234  To show the colors versus index instead of on the 0-1 scale,
235  use::
236 
237  norm=colors.NoNorm.
238 
239  Useful attributes:
240 
241  :attr:`ax`
242  the Axes instance in which the colorbar is drawn
243 
244  :attr:`lines`
245  a list of LineCollection if lines were drawn, otherwise
246  an empty list
247 
248  :attr:`dividers`
249  a LineCollection if *drawedges* is True, otherwise None
250 
251  Useful public methods are :meth:`set_label` and :meth:`add_lines`.
252 
253  '''
254  _slice_dict = {'neither': slice(0, None),
255  'both': slice(1, -1),
256  'min': slice(1, None),
257  'max': slice(0, -1)}
258 
259  def __init__(self, ax, cmap=None,
260  norm=None,
261  alpha=None,
262  values=None,
263  boundaries=None,
264  orientation='vertical',
265  ticklocation='auto',
266  extend='neither',
267  spacing='uniform', # uniform or proportional
268  ticks=None,
269  format=None,
270  drawedges=False,
271  filled=True,
272  extendfrac=None,
273  extendrect=False,
274  label='',
275  ):
276  #: The axes that this colorbar lives in.
277  self.ax = ax
278  self._patch_ax()
279  if cmap is None:
280  cmap = cm.get_cmap()
281  if norm is None:
282  norm = colors.Normalize()
283  self.alpha = alpha
284  cm.ScalarMappable.__init__(self, cmap=cmap, norm=norm)
285  self.values = values
286  self.boundaries = boundaries
287  self.extend = extend
288  self._inside = self._slice_dict[extend]
289  self.spacing = spacing
290  self.orientation = orientation
291  self.drawedges = drawedges
292  self.filled = filled
293  self.extendfrac = extendfrac
294  self.extendrect = extendrect
295  self.solids = None
296  self.lines = list()
297  self.outline = None
298  self.patch = None
299  self.dividers = None
300 
301  if ticklocation == 'auto':
302  ticklocation = 'bottom' if orientation == 'horizontal' else 'right'
303  self.ticklocation = ticklocation
304 
305  self.set_label(label)
306  if cbook.iterable(ticks):
307  self.locator = ticker.FixedLocator(ticks, nbins=len(ticks))
308  else:
309  self.locator = ticks # Handle default in _ticker()
310  if format is None:
311  if isinstance(self.norm, colors.LogNorm):
313  else:
315  elif cbook.is_string_like(format):
316  self.formatter = ticker.FormatStrFormatter(format)
317  else:
318  self.formatter = format # Assume it is a Formatter
319  # The rest is in a method so we can recalculate when clim changes.
320  self.config_axis()
321  self.draw_all()
322 
323  def _extend_lower(self):
324  """Returns whether the lower limit is open ended."""
325  return self.extend in ('both', 'min')
326 
327  def _extend_upper(self):
328  """Returns whether the uper limit is open ended."""
329  return self.extend in ('both', 'max')
330 
331  def _patch_ax(self):
332  # bind some methods to the axes to warn users
333  # against using those methods.
334  self.ax.set_xticks = _set_ticks_on_axis_warn
335  self.ax.set_yticks = _set_ticks_on_axis_warn
336 
337  def draw_all(self):
338  '''
339  Calculate any free parameters based on the current cmap and norm,
340  and do all the drawing.
341  '''
342  self._process_values()
343  self._find_range()
344  X, Y = self._mesh()
345  C = self._values[:, np.newaxis]
346  self._config_axes(X, Y)
347  if self.filled:
348  self._add_solids(X, Y, C)
349 
350  def config_axis(self):
351  ax = self.ax
352  if self.orientation == 'vertical':
353  ax.xaxis.set_ticks([])
354  # location is either one of 'bottom' or 'top'
355  ax.yaxis.set_label_position(self.ticklocation)
356  ax.yaxis.set_ticks_position(self.ticklocation)
357  else:
358  ax.yaxis.set_ticks([])
359  # location is either one of 'left' or 'right'
360  ax.xaxis.set_label_position(self.ticklocation)
361  ax.xaxis.set_ticks_position(self.ticklocation)
362 
363  self._set_label()
364 
365  def update_ticks(self):
366  """
367  Force the update of the ticks and ticklabels. This must be
368  called whenever the tick locator and/or tick formatter changes.
369  """
370  ax = self.ax
371  ticks, ticklabels, offset_string = self._ticker()
372  if self.orientation == 'vertical':
373  ax.yaxis.set_ticks(ticks)
374  ax.set_yticklabels(ticklabels)
375  ax.yaxis.get_major_formatter().set_offset_string(offset_string)
376 
377  else:
378  ax.xaxis.set_ticks(ticks)
379  ax.set_xticklabels(ticklabels)
380  ax.xaxis.get_major_formatter().set_offset_string(offset_string)
381 
382  def set_ticks(self, ticks, update_ticks=True):
383  """
384  set tick locations. Tick locations are updated immediately unless
385  update_ticks is *False*. To manually update the ticks, call
386  *update_ticks* method explicitly.
387  """
388  if cbook.iterable(ticks):
389  self.locator = ticker.FixedLocator(ticks, nbins=len(ticks))
390  else:
391  self.locator = ticks
392 
393  if update_ticks:
394  self.update_ticks()
395 
396  def set_ticklabels(self, ticklabels, update_ticks=True):
397  """
398  set tick labels. Tick labels are updated immediately unless
399  update_ticks is *False*. To manually update the ticks, call
400  *update_ticks* method explicitly.
401  """
402  if isinstance(self.locator, ticker.FixedLocator):
403  self.formatter = ticker.FixedFormatter(ticklabels)
404  if update_ticks:
405  self.update_ticks()
406  else:
407  warnings.warn("set_ticks() must have been called.")
408 
409  def _config_axes(self, X, Y):
410  '''
411  Make an axes patch and outline.
412  '''
413  ax = self.ax
414  ax.set_frame_on(False)
415  ax.set_navigate(False)
416  xy = self._outline(X, Y)
417  ax.update_datalim(xy)
418  ax.set_xlim(*ax.dataLim.intervalx)
419  ax.set_ylim(*ax.dataLim.intervaly)
420  if self.outline is not None:
421  self.outline.remove()
422  self.outline = mpatches.Polygon(
423  xy, edgecolor=mpl.rcParams['axes.edgecolor'],
424  facecolor='none',
425  linewidth=mpl.rcParams['axes.linewidth'],
426  closed=True,
427  zorder=2)
428  ax.add_artist(self.outline)
429  self.outline.set_clip_box(None)
430  self.outline.set_clip_path(None)
431  c = mpl.rcParams['axes.facecolor']
432  if self.patch is not None:
433  self.patch.remove()
434  self.patch = mpatches.Polygon(xy, edgecolor=c,
435  facecolor=c,
436  linewidth=0.01,
437  zorder=-1)
438  ax.add_artist(self.patch)
439 
440  self.update_ticks()
441 
442  def _set_label(self):
443  if self.orientation == 'vertical':
444  self.ax.set_ylabel(self._label, **self._labelkw)
445  else:
446  self.ax.set_xlabel(self._label, **self._labelkw)
447 
448  def set_label(self, label, **kw):
449  '''
450  Label the long axis of the colorbar
451  '''
452  self._label = '%s' % (label, )
453  self._labelkw = kw
454  self._set_label()
455 
456  def _outline(self, X, Y):
457  '''
458  Return *x*, *y* arrays of colorbar bounding polygon,
459  taking orientation into account.
460  '''
461  N = X.shape[0]
462  ii = [0, 1, N - 2, N - 1, 2 * N - 1, 2 * N - 2, N + 1, N, 0]
463  x = np.take(np.ravel(np.transpose(X)), ii)
464  y = np.take(np.ravel(np.transpose(Y)), ii)
465  x = x.reshape((len(x), 1))
466  y = y.reshape((len(y), 1))
467  if self.orientation == 'horizontal':
468  return np.hstack((y, x))
469  return np.hstack((x, y))
470 
471  def _edges(self, X, Y):
472  '''
473  Return the separator line segments; helper for _add_solids.
474  '''
475  N = X.shape[0]
476  # Using the non-array form of these line segments is much
477  # simpler than making them into arrays.
478  if self.orientation == 'vertical':
479  return [list(zip(X[i], Y[i])) for i in xrange(1, N - 1)]
480  else:
481  return [list(zip(Y[i], X[i])) for i in xrange(1, N - 1)]
482 
483  def _add_solids(self, X, Y, C):
484  '''
485  Draw the colors using :meth:`~matplotlib.axes.Axes.pcolormesh`;
486  optionally add separators.
487  '''
488  if self.orientation == 'vertical':
489  args = (X, Y, C)
490  else:
491  args = (np.transpose(Y), np.transpose(X), np.transpose(C))
492  kw = dict(cmap=self.cmap,
493  norm=self.norm,
494  alpha=self.alpha,
495  edgecolors='None')
496  # Save, set, and restore hold state to keep pcolor from
497  # clearing the axes. Ordinarily this will not be needed,
498  # since the axes object should already have hold set.
499  _hold = self.ax.ishold()
500  self.ax.hold(True)
501  col = self.ax.pcolormesh(*args, **kw)
502  self.ax.hold(_hold)
503  #self.add_observer(col) # We should observe, not be observed...
504 
505  if self.solids is not None:
506  self.solids.remove()
507  self.solids = col
508  if self.dividers is not None:
509  self.dividers.remove()
510  self.dividers = None
511  if self.drawedges:
512  linewidths = (0.5 * mpl.rcParams['axes.linewidth'],)
513  self.dividers = collections.LineCollection(self._edges(X, Y),
514  colors=(mpl.rcParams['axes.edgecolor'],),
515  linewidths=linewidths)
516  self.ax.add_collection(self.dividers)
517 
518  def add_lines(self, levels, colors, linewidths, erase=True):
519  '''
520  Draw lines on the colorbar.
521 
522  *colors* and *linewidths* must be scalars or
523  sequences the same length as *levels*.
524 
525  Set *erase* to False to add lines without first
526  removing any previously added lines.
527  '''
528  y = self._locate(levels)
529  igood = (y < 1.001) & (y > -0.001)
530  y = y[igood]
531  if cbook.iterable(colors):
532  colors = np.asarray(colors)[igood]
533  if cbook.iterable(linewidths):
534  linewidths = np.asarray(linewidths)[igood]
535  N = len(y)
536  x = np.array([0.0, 1.0])
537  X, Y = np.meshgrid(x, y)
538  if self.orientation == 'vertical':
539  xy = [list(zip(X[i], Y[i])) for i in xrange(N)]
540  else:
541  xy = [list(zip(Y[i], X[i])) for i in xrange(N)]
542  col = collections.LineCollection(xy, linewidths=linewidths)
543 
544  if erase and self.lines:
545  for lc in self.lines:
546  lc.remove()
547  self.lines = []
548  self.lines.append(col)
549  col.set_color(colors)
550  self.ax.add_collection(col)
551 
552  def _ticker(self):
553  '''
554  Return the sequence of ticks (colorbar data locations),
555  ticklabels (strings), and the corresponding offset string.
556  '''
557  locator = self.locator
558  formatter = self.formatter
559  if locator is None:
560  if self.boundaries is None:
561  if isinstance(self.norm, colors.NoNorm):
562  nv = len(self._values)
563  base = 1 + int(nv / 10)
564  locator = ticker.IndexLocator(base=base, offset=0)
565  elif isinstance(self.norm, colors.BoundaryNorm):
566  b = self.norm.boundaries
567  locator = ticker.FixedLocator(b, nbins=10)
568  elif isinstance(self.norm, colors.LogNorm):
569  locator = ticker.LogLocator()
570  else:
571  locator = ticker.MaxNLocator()
572  else:
573  b = self._boundaries[self._inside]
574  locator = ticker.FixedLocator(b, nbins=10)
575  if isinstance(self.norm, colors.NoNorm):
576  intv = self._values[0], self._values[-1]
577  else:
578  intv = self.vmin, self.vmax
579  locator.create_dummy_axis(minpos=intv[0])
580  formatter.create_dummy_axis(minpos=intv[0])
581  locator.set_view_interval(*intv)
582  locator.set_data_interval(*intv)
583  formatter.set_view_interval(*intv)
584  formatter.set_data_interval(*intv)
585 
586  b = np.array(locator())
587  ticks = self._locate(b)
588  inrange = (ticks > -0.001) & (ticks < 1.001)
589  ticks = ticks[inrange]
590  b = b[inrange]
591  formatter.set_locs(b)
592  ticklabels = [formatter(t, i) for i, t in enumerate(b)]
593  offset_string = formatter.get_offset()
594  return ticks, ticklabels, offset_string
595 
596  def _process_values(self, b=None):
597  '''
598  Set the :attr:`_boundaries` and :attr:`_values` attributes
599  based on the input boundaries and values. Input boundaries
600  can be *self.boundaries* or the argument *b*.
601  '''
602  if b is None:
603  b = self.boundaries
604  if b is not None:
605  self._boundaries = np.asarray(b, dtype=float)
606  if self.values is None:
607  self._values = 0.5 * (self._boundaries[:-1]
608  + self._boundaries[1:])
609  if isinstance(self.norm, colors.NoNorm):
610  self._values = (self._values + 0.00001).astype(np.int16)
611  return
612  self._values = np.array(self.values)
613  return
614  if self.values is not None:
615  self._values = np.array(self.values)
616  if self.boundaries is None:
617  b = np.zeros(len(self.values) + 1, 'd')
618  b[1:-1] = 0.5 * (self._values[:-1] - self._values[1:])
619  b[0] = 2.0 * b[1] - b[2]
620  b[-1] = 2.0 * b[-2] - b[-3]
621  self._boundaries = b
622  return
623  self._boundaries = np.array(self.boundaries)
624  return
625  # Neither boundaries nor values are specified;
626  # make reasonable ones based on cmap and norm.
627  if isinstance(self.norm, colors.NoNorm):
628  b = self._uniform_y(self.cmap.N + 1) * self.cmap.N - 0.5
629  v = np.zeros((len(b) - 1,), dtype=np.int16)
630  v[self._inside] = np.arange(self.cmap.N, dtype=np.int16)
631  if self._extend_lower():
632  v[0] = -1
633  if self._extend_upper():
634  v[-1] = self.cmap.N
635  self._boundaries = b
636  self._values = v
637  return
638  elif isinstance(self.norm, colors.BoundaryNorm):
639  b = list(self.norm.boundaries)
640  if self._extend_lower():
641  b = [b[0] - 1] + b
642  if self._extend_upper():
643  b = b + [b[-1] + 1]
644  b = np.array(b)
645  v = np.zeros((len(b) - 1,), dtype=float)
646  bi = self.norm.boundaries
647  v[self._inside] = 0.5 * (bi[:-1] + bi[1:])
648  if self._extend_lower():
649  v[0] = b[0] - 1
650  if self._extend_upper():
651  v[-1] = b[-1] + 1
652  self._boundaries = b
653  self._values = v
654  return
655  else:
656  self.norm.vmin, self.norm.vmax = mtrans.nonsingular(self.norm.vmin,
657  self.norm.vmax,
658  expander=0.1)
659  if not self.norm.scaled():
660  self.norm.vmin = 0
661  self.norm.vmax = 1
662  b = self.norm.inverse(self._uniform_y(self.cmap.N + 1))
663  if self._extend_lower():
664  b[0] = b[0] - 1
665  if self._extend_upper():
666  b[-1] = b[-1] + 1
667  self._process_values(b)
668 
669  def _find_range(self):
670  '''
671  Set :attr:`vmin` and :attr:`vmax` attributes to the first and
672  last boundary excluding extended end boundaries.
673  '''
674  b = self._boundaries[self._inside]
675  self.vmin = b[0]
676  self.vmax = b[-1]
677 
678  def _central_N(self):
679  '''number of boundaries **before** extension of ends'''
680  nb = len(self._boundaries)
681  if self.extend == 'both':
682  nb -= 2
683  elif self.extend in ('min', 'max'):
684  nb -= 1
685  return nb
686 
687  def _extended_N(self):
688  '''
689  Based on the colormap and extend variable, return the
690  number of boundaries.
691  '''
692  N = self.cmap.N + 1
693  if self.extend == 'both':
694  N += 2
695  elif self.extend in ('min', 'max'):
696  N += 1
697  return N
698 
699  def _get_extension_lengths(self, frac, automin, automax, default=0.05):
700  '''
701  Get the lengths of colorbar extensions.
702 
703  A helper method for _uniform_y and _proportional_y.
704  '''
705  # Set the default value.
706  extendlength = np.array([default, default])
707  if isinstance(frac, six.string_types):
708  if frac.lower() == 'auto':
709  # Use the provided values when 'auto' is required.
710  extendlength[0] = automin
711  extendlength[1] = automax
712  else:
713  # Any other string is invalid.
714  raise ValueError('invalid value for extendfrac')
715  elif frac is not None:
716  try:
717  # Try to set min and max extension fractions directly.
718  extendlength[:] = frac
719  # If frac is a sequence contaning None then NaN may
720  # be encountered. This is an error.
721  if np.isnan(extendlength).any():
722  raise ValueError()
723  except (TypeError, ValueError):
724  # Raise an error on encountering an invalid value for frac.
725  raise ValueError('invalid value for extendfrac')
726  return extendlength
727 
728  def _uniform_y(self, N):
729  '''
730  Return colorbar data coordinates for *N* uniformly
731  spaced boundaries, plus ends if required.
732  '''
733  if self.extend == 'neither':
734  y = np.linspace(0, 1, N)
735  else:
736  automin = automax = 1. / (N - 1.)
737  extendlength = self._get_extension_lengths(self.extendfrac,
738  automin, automax,
739  default=0.05)
740  if self.extend == 'both':
741  y = np.zeros(N + 2, 'd')
742  y[0] = 0. - extendlength[0]
743  y[-1] = 1. + extendlength[1]
744  elif self.extend == 'min':
745  y = np.zeros(N + 1, 'd')
746  y[0] = 0. - extendlength[0]
747  else:
748  y = np.zeros(N + 1, 'd')
749  y[-1] = 1. + extendlength[1]
750  y[self._inside] = np.linspace(0, 1, N)
751  return y
752 
753  def _proportional_y(self):
754  '''
755  Return colorbar data coordinates for the boundaries of
756  a proportional colorbar.
757  '''
758  if isinstance(self.norm, colors.BoundaryNorm):
759  y = (self._boundaries - self._boundaries[0])
760  y = y / (self._boundaries[-1] - self._boundaries[0])
761  else:
762  y = self.norm(self._boundaries.copy())
763  if self.extend == 'min':
764  # Exclude leftmost interval of y.
765  clen = y[-1] - y[1]
766  automin = (y[2] - y[1]) / clen
767  automax = (y[-1] - y[-2]) / clen
768  elif self.extend == 'max':
769  # Exclude rightmost interval in y.
770  clen = y[-2] - y[0]
771  automin = (y[1] - y[0]) / clen
772  automax = (y[-2] - y[-3]) / clen
773  else:
774  # Exclude leftmost and rightmost intervals in y.
775  clen = y[-2] - y[1]
776  automin = (y[2] - y[1]) / clen
777  automax = (y[-2] - y[-3]) / clen
778  extendlength = self._get_extension_lengths(self.extendfrac,
779  automin, automax,
780  default=0.05)
781  if self.extend in ('both', 'min'):
782  y[0] = 0. - extendlength[0]
783  if self.extend in ('both', 'max'):
784  y[-1] = 1. + extendlength[1]
785  yi = y[self._inside]
786  norm = colors.Normalize(yi[0], yi[-1])
787  y[self._inside] = norm(yi)
788  return y
789 
790  def _mesh(self):
791  '''
792  Return X,Y, the coordinate arrays for the colorbar pcolormesh.
793  These are suitable for a vertical colorbar; swapping and
794  transposition for a horizontal colorbar are done outside
795  this function.
796  '''
797  x = np.array([0.0, 1.0])
798  if self.spacing == 'uniform':
799  y = self._uniform_y(self._central_N())
800  else:
801  y = self._proportional_y()
802  self._y = y
803  X, Y = np.meshgrid(x, y)
804  if self._extend_lower() and not self.extendrect:
805  X[0, :] = 0.5
806  if self._extend_upper() and not self.extendrect:
807  X[-1, :] = 0.5
808  return X, Y
809 
810  def _locate(self, x):
811  '''
812  Given a set of color data values, return their
813  corresponding colorbar data coordinates.
814  '''
815  if isinstance(self.norm, (colors.NoNorm, colors.BoundaryNorm)):
816  b = self._boundaries
817  xn = x
818  else:
819  # Do calculations using normalized coordinates so
820  # as to make the interpolation more accurate.
821  b = self.norm(self._boundaries, clip=False).filled()
822  xn = self.norm(x, clip=False).filled()
823 
824  # The rest is linear interpolation with extrapolation at ends.
825  ii = np.searchsorted(b, xn)
826  i0 = ii - 1
827  itop = (ii == len(b))
828  ibot = (ii == 0)
829  i0[itop] -= 1
830  ii[itop] -= 1
831  i0[ibot] += 1
832  ii[ibot] += 1
833 
834  db = np.take(b, ii) - np.take(b, i0)
835  y = self._y
836  dy = np.take(y, ii) - np.take(y, i0)
837  z = np.take(y, i0) + (xn - np.take(b, i0)) * dy / db
838  return z
839 
840  def set_alpha(self, alpha):
841  self.alpha = alpha
842 
843  def remove(self):
844  """
845  Remove this colorbar from the figure
846  """
847 
848  fig = self.ax.figure
849  fig.delaxes(self.ax)
850 
851 
853  """
854  This class connects a :class:`ColorbarBase` to a
855  :class:`~matplotlib.cm.ScalarMappable` such as a
856  :class:`~matplotlib.image.AxesImage` generated via
857  :meth:`~matplotlib.axes.Axes.imshow`.
858 
859  It is not intended to be instantiated directly; instead,
860  use :meth:`~matplotlib.figure.Figure.colorbar` or
861  :func:`~matplotlib.pyplot.colorbar` to make your colorbar.
862 
863  """
864  def __init__(self, ax, mappable, **kw):
865  # Ensure the given mappable's norm has appropriate vmin and vmax set
866  # even if mappable.draw has not yet been called.
867  mappable.autoscale_None()
868 
869  self.mappable = mappable
870  kw['cmap'] = cmap = mappable.cmap
871  kw['norm'] = norm = mappable.norm
872 
873  if isinstance(mappable, contour.ContourSet):
874  CS = mappable
875  kw['alpha'] = mappable.get_alpha()
876  kw['boundaries'] = CS._levels
877  kw['values'] = CS.cvalues
878  kw['extend'] = CS.extend
879  #kw['ticks'] = CS._levels
880  kw.setdefault('ticks', ticker.FixedLocator(CS.levels, nbins=10))
881  kw['filled'] = CS.filled
882  ColorbarBase.__init__(self, ax, **kw)
883  if not CS.filled:
884  self.add_lines(CS)
885  else:
886  if getattr(cmap, 'colorbar_extend', False) is not False:
887  kw.setdefault('extend', cmap.colorbar_extend)
888 
889  if isinstance(mappable, martist.Artist):
890  kw['alpha'] = mappable.get_alpha()
891 
892  ColorbarBase.__init__(self, ax, **kw)
893 
894  def on_mappable_changed(self, mappable):
895  """
896  Updates this colorbar to match the mappable's properties.
897 
898  Typically this is automatically registered as an event handler
899  by :func:`colorbar_factory` and should not be called manually.
900 
901  """
902  self.set_cmap(mappable.get_cmap())
903  self.set_clim(mappable.get_clim())
904  self.update_normal(mappable)
905 
906  def add_lines(self, CS, erase=True):
907  '''
908  Add the lines from a non-filled
909  :class:`~matplotlib.contour.ContourSet` to the colorbar.
910 
911  Set *erase* to False if these lines should be added to
912  any pre-existing lines.
913  '''
914  if not isinstance(CS, contour.ContourSet) or CS.filled:
915  raise ValueError('add_lines is only for a ContourSet of lines')
916  tcolors = [c[0] for c in CS.tcolors]
917  tlinewidths = [t[0] for t in CS.tlinewidths]
918  # The following was an attempt to get the colorbar lines
919  # to follow subsequent changes in the contour lines,
920  # but more work is needed: specifically, a careful
921  # look at event sequences, and at how
922  # to make one object track another automatically.
923  #tcolors = [col.get_colors()[0] for col in CS.collections]
924  #tlinewidths = [col.get_linewidth()[0] for lw in CS.collections]
925  #print 'tlinewidths:', tlinewidths
926  ColorbarBase.add_lines(self, CS.levels, tcolors, tlinewidths,
927  erase=erase)
928 
929  def update_normal(self, mappable):
930  '''
931  update solid, lines, etc. Unlike update_bruteforce, it does
932  not clear the axes. This is meant to be called when the image
933  or contour plot to which this colorbar belongs is changed.
934  '''
935  self.draw_all()
936  if isinstance(self.mappable, contour.ContourSet):
937  CS = self.mappable
938  if not CS.filled:
939  self.add_lines(CS)
940 
941  def update_bruteforce(self, mappable):
942  '''
943  Destroy and rebuild the colorbar. This is
944  intended to become obsolete, and will probably be
945  deprecated and then removed. It is not called when
946  the pyplot.colorbar function or the Figure.colorbar
947  method are used to create the colorbar.
948 
949  '''
950  # We are using an ugly brute-force method: clearing and
951  # redrawing the whole thing. The problem is that if any
952  # properties have been changed by methods other than the
953  # colorbar methods, those changes will be lost.
954  self.ax.cla()
955  # clearing the axes will delete outline, patch, solids, and lines:
956  self.outline = None
957  self.patch = None
958  self.solids = None
959  self.lines = list()
960  self.dividers = None
961  self.set_alpha(mappable.get_alpha())
962  self.cmap = mappable.cmap
963  self.norm = mappable.norm
964  self.config_axis()
965  self.draw_all()
966  if isinstance(self.mappable, contour.ContourSet):
967  CS = self.mappable
968  if not CS.filled:
969  self.add_lines(CS)
970  #if self.lines is not None:
971  # tcolors = [c[0] for c in CS.tcolors]
972  # self.lines.set_color(tcolors)
973  #Fixme? Recalculate boundaries, ticks if vmin, vmax have changed.
974  #Fixme: Some refactoring may be needed; we should not
975  # be recalculating everything if there was a simple alpha
976  # change.
977 
978  def remove(self):
979  """
980  Remove this colorbar from the figure. If the colorbar was created with
981  ``use_gridspec=True`` then restore the gridspec to its previous value.
982  """
983 
984  ColorbarBase.remove(self)
985  self.mappable.callbacksSM.disconnect(self.mappable.colorbar_cid)
986  self.mappable.colorbar = None
987  self.mappable.colorbar_cid = None
988 
989  try:
990  ax = self.mappable.axes
991  except AttributeError:
992  return
993 
994  try:
995  gs = ax.get_subplotspec().get_gridspec()
996  subplotspec = gs.get_topmost_subplotspec()
997  except AttributeError:
998  # use_gridspec was False
999  pos = ax.get_position(original=True)
1000  ax.set_position(pos)
1001  else:
1002  # use_gridspec was True
1003  ax.set_subplotspec(subplotspec)
1004 
1005 
1006 @docstring.Substitution(make_axes_kw_doc)
1007 def make_axes(parents, location=None, orientation=None, fraction=0.15,
1008  shrink=1.0, aspect=20, **kw):
1009  '''
1010  Resize and reposition parent axes, and return a child
1011  axes suitable for a colorbar::
1012 
1013  cax, kw = make_axes(parent, **kw)
1014 
1015  Keyword arguments may include the following (with defaults):
1016 
1017  location : [None|'left'|'right'|'top'|'bottom']
1018  The position, relative to **parents**, where the colorbar axes
1019  should be created. If None, the value will either come from the
1020  given ``orientation``, else it will default to 'right'.
1021 
1022  orientation : [None|'vertical'|'horizontal']
1023  The orientation of the colorbar. Typically, this keyword shouldn't
1024  be used, as it can be derived from the ``location`` keyword.
1025 
1026  %s
1027 
1028  Returns (cax, kw), the child axes and the reduced kw dictionary to be
1029  passed when creating the colorbar instance.
1030  '''
1031  locations = ["left", "right", "top", "bottom"]
1032  if orientation is not None and location is not None:
1033  msg = ('position and orientation are mutually exclusive. '
1034  'Consider setting the position to any of '
1035  '{0}'.format(', '.join(locations)))
1036  raise TypeError(msg)
1037 
1038  # provide a default location
1039  if location is None and orientation is None:
1040  location = 'right'
1041 
1042  # allow the user to not specify the location by specifying the
1043  # orientation instead
1044  if location is None:
1045  location = 'right' if orientation == 'vertical' else 'bottom'
1046 
1047  if location not in locations:
1048  raise ValueError('Invalid colorbar location. Must be one '
1049  'of %s' % ', '.join(locations))
1050 
1051  default_location_settings = {'left': {'anchor': (1.0, 0.5),
1052  'panchor': (0.0, 0.5),
1053  'pad': 0.10,
1054  'orientation': 'vertical'},
1055  'right': {'anchor': (0.0, 0.5),
1056  'panchor': (1.0, 0.5),
1057  'pad': 0.05,
1058  'orientation': 'vertical'},
1059  'top': {'anchor': (0.5, 0.0),
1060  'panchor': (0.5, 1.0),
1061  'pad': 0.05,
1062  'orientation': 'horizontal'},
1063  'bottom': {'anchor': (0.5, 1.0),
1064  'panchor': (0.5, 0.0),
1065  'pad': 0.15, # backwards compat
1066  'orientation': 'horizontal'},
1067  }
1068 
1069  loc_settings = default_location_settings[location]
1070 
1071  # put appropriate values into the kw dict for passing back to
1072  # the Colorbar class
1073  kw['orientation'] = loc_settings['orientation']
1074  kw['ticklocation'] = location
1075 
1076  anchor = kw.pop('anchor', loc_settings['anchor'])
1077  parent_anchor = kw.pop('panchor', loc_settings['panchor'])
1078  pad = kw.pop('pad', loc_settings['pad'])
1079 
1080  # turn parents into a list if it is not already
1081  if not isinstance(parents, (list, tuple)):
1082  parents = [parents]
1083 
1084  fig = parents[0].get_figure()
1085  if not all(fig is ax.get_figure() for ax in parents):
1086  raise ValueError('Unable to create a colorbar axes as not all '
1087  'parents share the same figure.')
1088 
1089  # take a bounding box around all of the given axes
1090  parents_bbox = mtrans.Bbox.union([ax.get_position(original=True).frozen()
1091  for ax in parents])
1092 
1093  pb = parents_bbox
1094  if location in ('left', 'right'):
1095  if location == 'left':
1096  pbcb, _, pb1 = pb.splitx(fraction, fraction + pad)
1097  else:
1098  pb1, _, pbcb = pb.splitx(1 - fraction - pad, 1 - fraction)
1099  pbcb = pbcb.shrunk(1.0, shrink).anchored(anchor, pbcb)
1100  else:
1101  if location == 'bottom':
1102  pbcb, _, pb1 = pb.splity(fraction, fraction + pad)
1103  else:
1104  pb1, _, pbcb = pb.splity(1 - fraction - pad, 1 - fraction)
1105  pbcb = pbcb.shrunk(shrink, 1.0).anchored(anchor, pbcb)
1106 
1107  # define the aspect ratio in terms of y's per x rather than x's per y
1108  aspect = 1.0 / aspect
1109 
1110  # define a transform which takes us from old axes coordinates to
1111  # new axes coordinates
1112  shrinking_trans = mtrans.BboxTransform(parents_bbox, pb1)
1113 
1114  # transform each of the axes in parents using the new transform
1115  for ax in parents:
1116  new_posn = shrinking_trans.transform(ax.get_position())
1117  new_posn = mtrans.Bbox(new_posn)
1118  ax.set_position(new_posn)
1119  if parent_anchor is not False:
1120  ax.set_anchor(parent_anchor)
1121 
1122  cax = fig.add_axes(pbcb)
1123  cax.set_aspect(aspect, anchor=anchor, adjustable='box')
1124  return cax, kw
1125 
1126 
1127 @docstring.Substitution(make_axes_kw_doc)
1128 def make_axes_gridspec(parent, **kw):
1129  '''
1130  Resize and reposition a parent axes, and return a child axes
1131  suitable for a colorbar. This function is similar to
1132  make_axes. Prmary differences are
1133 
1134  * *make_axes_gridspec* only handles the *orientation* keyword
1135  and cannot handle the "location" keyword.
1136 
1137  * *make_axes_gridspec* should only be used with a subplot parent.
1138 
1139  * *make_axes* creates an instance of Axes. *make_axes_gridspec*
1140  creates an instance of Subplot.
1141 
1142  * *make_axes* updates the position of the
1143  parent. *make_axes_gridspec* replaces the grid_spec attribute
1144  of the parent with a new one.
1145 
1146  While this function is meant to be compatible with *make_axes*,
1147  there could be some minor differences.::
1148 
1149  cax, kw = make_axes_gridspec(parent, **kw)
1150 
1151  Keyword arguments may include the following (with defaults):
1152 
1153  *orientation*
1154  'vertical' or 'horizontal'
1155 
1156  %s
1157 
1158  All but the first of these are stripped from the input kw set.
1159 
1160  Returns (cax, kw), the child axes and the reduced kw dictionary to be
1161  passed when creating the colorbar instance.
1162  '''
1163 
1164  orientation = kw.setdefault('orientation', 'vertical')
1165  kw['ticklocation'] = 'auto'
1166 
1167  fraction = kw.pop('fraction', 0.15)
1168  shrink = kw.pop('shrink', 1.0)
1169  aspect = kw.pop('aspect', 20)
1170 
1171  x1 = 1.0 - fraction
1172 
1173  # for shrinking
1174  pad_s = (1. - shrink) * 0.5
1175  wh_ratios = [pad_s, shrink, pad_s]
1176 
1177  gs_from_subplotspec = gridspec.GridSpecFromSubplotSpec
1178  if orientation == 'vertical':
1179  pad = kw.pop('pad', 0.05)
1180  wh_space = 2 * pad / (1 - pad)
1181 
1182  gs = gs_from_subplotspec(1, 2,
1183  subplot_spec=parent.get_subplotspec(),
1184  wspace=wh_space,
1185  width_ratios=[x1 - pad, fraction]
1186  )
1187 
1188  gs2 = gs_from_subplotspec(3, 1,
1189  subplot_spec=gs[1],
1190  hspace=0.,
1191  height_ratios=wh_ratios,
1192  )
1193 
1194  anchor = (0.0, 0.5)
1195  panchor = (1.0, 0.5)
1196  else:
1197  pad = kw.pop('pad', 0.15)
1198  wh_space = 2 * pad / (1 - pad)
1199 
1200  gs = gs_from_subplotspec(2, 1,
1201  subplot_spec=parent.get_subplotspec(),
1202  hspace=wh_space,
1203  height_ratios=[x1 - pad, fraction]
1204  )
1205 
1206  gs2 = gs_from_subplotspec(1, 3,
1207  subplot_spec=gs[1],
1208  wspace=0.,
1209  width_ratios=wh_ratios,
1210  )
1211 
1212  aspect = 1.0 / aspect
1213  anchor = (0.5, 1.0)
1214  panchor = (0.5, 0.0)
1215 
1216  parent.set_subplotspec(gs[0])
1217  parent.update_params()
1218  parent.set_position(parent.figbox)
1219  parent.set_anchor(panchor)
1220 
1221  fig = parent.get_figure()
1222  cax = fig.add_subplot(gs2[1])
1223  cax.set_aspect(aspect, anchor=anchor, adjustable='box')
1224  return cax, kw
1225 
1226 
1228  """
1229  A Colorbar which is created using :class:`~matplotlib.patches.Patch`
1230  rather than the default :func:`~matplotlib.axes.pcolor`.
1231 
1232  It uses a list of Patch instances instead of a
1233  :class:`~matplotlib.collections.PatchCollection` because the
1234  latter does not allow the hatch pattern to vary among the
1235  members of the collection.
1236  """
1237  def __init__(self, ax, mappable, **kw):
1238  # we do not want to override the behaviour of solids
1239  # so add a new attribute which will be a list of the
1240  # colored patches in the colorbar
1241  self.solids_patches = []
1242  Colorbar.__init__(self, ax, mappable, **kw)
1243 
1244  def _add_solids(self, X, Y, C):
1245  """
1246  Draw the colors using :class:`~matplotlib.patches.Patch`;
1247  optionally add separators.
1248  """
1249  # Save, set, and restore hold state to keep pcolor from
1250  # clearing the axes. Ordinarily this will not be needed,
1251  # since the axes object should already have hold set.
1252  _hold = self.ax.ishold()
1253  self.ax.hold(True)
1254 
1255  kw = {'alpha': self.alpha, }
1256 
1257  n_segments = len(C)
1258 
1259  # ensure there are sufficent hatches
1260  hatches = self.mappable.hatches * n_segments
1261 
1262  patches = []
1263  for i in xrange(len(X) - 1):
1264  val = C[i][0]
1265  hatch = hatches[i]
1266 
1267  xy = np.array([[X[i][0], Y[i][0]],
1268  [X[i][1], Y[i][0]],
1269  [X[i + 1][1], Y[i + 1][0]],
1270  [X[i + 1][0], Y[i + 1][1]]])
1271 
1272  if self.orientation == 'horizontal':
1273  # if horizontal swap the xs and ys
1274  xy = xy[..., ::-1]
1275 
1276  patch = mpatches.PathPatch(mpath.Path(xy),
1277  facecolor=self.cmap(self.norm(val)),
1278  hatch=hatch, linewidth=0,
1279  antialiased=False, **kw)
1280  self.ax.add_patch(patch)
1281  patches.append(patch)
1282 
1283  if self.solids_patches:
1284  for solid in self.solids_patches:
1285  solid.remove()
1286 
1287  self.solids_patches = patches
1288 
1289  if self.dividers is not None:
1290  self.dividers.remove()
1291  self.dividers = None
1292 
1293  if self.drawedges:
1294  self.dividers = collections.LineCollection(self._edges(X, Y),
1295  colors=(mpl.rcParams['axes.edgecolor'],),
1296  linewidths=(0.5 * mpl.rcParams['axes.linewidth'],))
1297  self.ax.add_collection(self.dividers)
1298 
1299  self.ax.hold(_hold)
1300 
1301 
1302 def colorbar_factory(cax, mappable, **kwargs):
1303  """
1304  Creates a colorbar on the given axes for the given mappable.
1305 
1306  Typically, for automatic colorbar placement given only a mappable use
1307  :meth:`~matplotlib.figure.Figure.colorbar`.
1308 
1309  """
1310  # if the given mappable is a contourset with any hatching, use
1311  # ColorbarPatch else use Colorbar
1312  if (isinstance(mappable, contour.ContourSet)
1313  and any([hatch is not None for hatch in mappable.hatches])):
1314  cb = ColorbarPatch(cax, mappable, **kwargs)
1315  else:
1316  cb = Colorbar(cax, mappable, **kwargs)
1317 
1318  cid = mappable.callbacksSM.connect('changed', cb.on_mappable_changed)
1319  mappable.colorbar = cb
1320  mappable.colorbar_cid = cid
1321 
1322  return cb