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