1414import logging
1515
1616import numpy as np
17+ from collections .abc import Sequence
1718
1819import matplotlib as mpl
1920from matplotlib import _api , cbook , collections , colors , contour , ticker
@@ -1675,6 +1676,73 @@ def _cbar_cla(self):
16751676 self .ax .cla ()
16761677
16771678
1679+ class MultivarColorbar (Sequence ):
1680+ def __init__ (self , axes , mappable = None , ** kwargs ):
1681+ if isinstance (mappable , mpl .colorizer .Colorizer ):
1682+ mappable = mcolorizer .ColorizingArtist (mappable )
1683+
1684+ self .mappable = mappable
1685+ self .colorizer = mappable .colorizer
1686+ cmap = self .colorizer .cmap
1687+ norm = self .colorizer .norm
1688+ n = cmap .n_variates
1689+
1690+ self ._colorbars = [Colorbar (axes [i ],
1691+ norm = norm .norms [i ],
1692+ cmap = cmap [i ],
1693+ ** kwargs ,
1694+ ) for i in range (n )]
1695+
1696+ mappable .colorbar = self
1697+ mappable .colorbar_cid = mappable .callbacks .connect (
1698+ 'changed' , self .update_normals )
1699+
1700+ self .axes = axes
1701+
1702+ def _set_colorbar_info (self , colorbar_info ):
1703+ if colorbar_info is not None :
1704+ parents = colorbar_info ['parents' ]
1705+ for a in parents :
1706+ a ._colorbars .append (self )
1707+
1708+ def update_normals (self , mappable = None ):
1709+ [c .update_normal () for c in self ._colorbars ]
1710+
1711+ def remove (self ):
1712+ if hasattr (self , '_colorbar_info' ):
1713+ parents = self ._colorbar_info ['parents' ]
1714+ for a in parents :
1715+ if self in a ._colorbars :
1716+ a ._colorbars .remove (self )
1717+
1718+ for ax in self .axes :
1719+ ax .remove ()
1720+
1721+ self .mappable .callbacks .disconnect (self .mappable .colorbar_cid )
1722+ self .mappable .colorbar = None
1723+ self .mappable .colorbar_cid = None
1724+
1725+ try :
1726+ ax = self .mappable .axes
1727+ if ax is None :
1728+ return
1729+ except AttributeError :
1730+ return
1731+ try :
1732+ subplotspec = self .ax .get_subplotspec ().get_gridspec ()._subplot_spec
1733+ except AttributeError : # use_gridspec was False
1734+ pos = ax .get_position (original = True )
1735+ ax ._set_position (pos )
1736+ else : # use_gridspec was True
1737+ ax .set_subplotspec (subplotspec )
1738+
1739+ def __getitem__ (self , index ):
1740+ return self ._colorbars [index ]
1741+
1742+ def __len__ (self ):
1743+ return len (self ._colorbars )
1744+
1745+
16781746def _normalize_location_orientation (location , orientation ):
16791747 if location is None :
16801748 location = _get_ticklocation_from_orientation (orientation )
@@ -1777,19 +1845,8 @@ def _get_bbox_shrink_parents(parents, location, fraction,
17771845 return pbcb
17781846
17791847
1780- def _make_axes_helper (loc_settings , fraction , shrink , aspect , kwargs , parents ):
1781- """
1782- Help function for `make_axes` and `make_bivar_axes`.
1783-
1784- `make_axes` and `make_bivar_axes` are identical
1785- except for the fact that `make_axes` also deals with:
1786- 1. the aspect
1787- 2. orientation.
1848+ def _make_axes_get_pbcb (loc_settings , fraction , shrink , aspect , kwargs , parents ):
17881849
1789- `make_bivar_axes` on the other hand has no concept of orientation
1790- and the aspect is handled by the `BivarColormap` instance, not during
1791- creation of the axes.
1792- """
17931850 location = loc_settings ['location' ]
17941851 kwargs ['location' ] = location
17951852
@@ -1803,11 +1860,7 @@ def _make_axes_helper(loc_settings, fraction, shrink, aspect, kwargs, parents):
18031860 # shrink the parents and get the bbox for the colorbar
18041861 pbcb = _get_bbox_shrink_parents (parents , location , fraction ,
18051862 pad , shrink , anchor , panchor )
1806- cax = fig .add_axes (pbcb , label = "<colorbar>" )
1807- for a in parents :
1808- a ._colorbars .append (cax ) # tell the parent it has a colorbar
1809-
1810- cax ._colorbar_info = dict (
1863+ colorbar_info = dict (
18111864 parents = parents ,
18121865 location = location ,
18131866 shrink = shrink ,
@@ -1817,7 +1870,30 @@ def _make_axes_helper(loc_settings, fraction, shrink, aspect, kwargs, parents):
18171870 aspect = aspect ,
18181871 pad = pad )
18191872
1820- cax .set_anchor (anchor )
1873+ return fig , pbcb , colorbar_info
1874+
1875+
1876+ def _make_axes_helper (loc_settings , fraction , shrink , aspect , kwargs , parents ):
1877+ """
1878+ Help function for `make_axes` and `make_bivar_axes`.
1879+
1880+ `make_axes` and `make_bivar_axes` are identical
1881+ except for the fact that `make_axes` also deals with:
1882+ 1. the aspect
1883+ 2. orientation.
1884+
1885+ `make_bivar_axes` on the other hand has no concept of orientation
1886+ and the aspect is handled by the `BivarColormap` instance, not during
1887+ creation of the axes.
1888+ """
1889+ fig , pbcb , colorbar_info = _make_axes_get_pbcb (loc_settings , fraction , shrink ,
1890+ aspect , kwargs , parents )
1891+ cax = fig .add_axes (pbcb , label = "<colorbar>" )
1892+ for a in colorbar_info ["parents" ]:
1893+ a ._colorbars .append (cax ) # tell the parent it has a colorbar
1894+
1895+ cax ._colorbar_info = colorbar_info
1896+ cax .set_anchor (colorbar_info ["anchor" ])
18211897 return cax
18221898
18231899
@@ -1892,6 +1968,103 @@ def make_bivar_axes(parents, location=None, fraction=0.15,
18921968 return cax , kwargs
18931969
18941970
1971+ @_docstring .interpd
1972+ def make_multivar_axes (parents , n_variates , n_major , location = None , orientation = None ,
1973+ fraction = 0.15 , shrink = 1.0 , aspect = 20 , ** kwargs ):
1974+ """
1975+ Create an `~.axes.Axes` suitable for a mulitvariate colorbar.
1976+
1977+ The Axes is placed in the figure of the *parents* Axes, by resizing and
1978+ repositioning *parents*.
1979+
1980+ Parameters
1981+ ----------
1982+ parents : `~matplotlib.axes.Axes` or iterable or `numpy.ndarray` of `~.axes.Axes`
1983+ The Axes to use as parents for placing the colorbar.
1984+ %(_make_axes_kw_doc)s
1985+
1986+ Returns
1987+ -------
1988+ cax : `~matplotlib.axes.Axes`
1989+ The child Axes.
1990+ kwargs : dict
1991+ The reduced keyword dictionary to be passed when creating the colorbar
1992+ instance.
1993+ """
1994+ loc_settings = _normalize_location_orientation (location , orientation )
1995+ # put appropriate values into the kwargs dict for passing back to
1996+ # the Colorbar class
1997+ orientation = loc_settings ['orientation' ]
1998+ kwargs ['orientation' ] = orientation
1999+ kwargs ['ticklocation' ] = loc_settings ['location' ]
2000+ fig , pbcb , colorbar_info = _make_axes_get_pbcb (loc_settings , fraction , shrink ,
2001+ aspect , kwargs , parents )
2002+ major_pad = 0.1
2003+ minor_pad = 0.6
2004+
2005+ # get the shape of the grid of new colorbars
2006+ if n_major == - 1 :
2007+ n_major = n_variates
2008+ n_minor = 1
2009+ else :
2010+ n_minor = n_variates // n_major
2011+ if n_major * n_minor < n_variates :
2012+ n_minor += 1
2013+
2014+ # adjust aspect
2015+ aspect = aspect / n_major
2016+ if loc_settings ["location" ] in ('top' , 'bottom' ):
2017+ aspect = 1.0 / aspect
2018+
2019+ # define how the bbox needs to be split
2020+ major_width = (1 - major_pad ) / n_major
2021+ if n_major > 1 :
2022+ major_space = major_pad / (n_major - 1 )
2023+ else :
2024+ major_space = 0
2025+ major_split = np .empty (2 * (n_major - 1 ))
2026+ major_split [0 ::2 ] = major_width
2027+ major_split [1 ::2 ] = major_space
2028+ major_split = np .cumsum (major_split )
2029+
2030+ minor_width = (1 - minor_pad ) / n_minor
2031+ if n_minor > 1 :
2032+ minor_space = minor_pad / (n_minor - 1 )
2033+ else :
2034+ minor_space = 0
2035+ minor_split = np .empty (2 * (n_minor - 1 ))
2036+ minor_split [0 ::2 ] = minor_width
2037+ minor_split [1 ::2 ] = minor_space
2038+ minor_split = np .cumsum (minor_split )
2039+
2040+ # make the colorbar axes
2041+ caxes = []
2042+ v = orientation == "vertical"
2043+ pbcbs = pbcb .splitx (* minor_split ) if v else pbcb .splity (* minor_split )[::- 1 ]
2044+ for i , mpcbc in enumerate (pbcbs ):
2045+ if i % 2 == 1 :
2046+ continue
2047+ fbcbs = mpcbc .splity (* major_split )[::- 1 ] if v else mpcbc .splitx (* major_split )
2048+ for j , bbox in enumerate (fbcbs ):
2049+ if j % 2 == 1 :
2050+ continue
2051+ if len (caxes ) < n_variates :
2052+ cax = fig .add_axes (bbox , label = "<colorbar>" )
2053+ caxes .append (cax )
2054+
2055+ for cax in caxes :
2056+ for a in colorbar_info ["parents" ]:
2057+ a ._colorbars .append (cax ) # tell the parent it has a colorbar
2058+
2059+ cax .set_anchor (colorbar_info ["anchor" ])
2060+
2061+ cax .set_box_aspect (aspect )
2062+ cax .set_aspect ('auto' )
2063+ cax ._colorbar_info = colorbar_info
2064+
2065+ return caxes , kwargs , colorbar_info
2066+
2067+
18952068def _make_axes_gridspec_helper (loc_settings , fraction , shrink , aspect , kwargs , parent ):
18962069 """
18972070 Help function for `make_axes_gridspec` and `make_bivar_axes_gridspec`.
0 commit comments