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