Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d2cf66d

Browse files
authored
Merge pull request #18527 from anntzer/cbarunpatch
Fold ColorbarPatch into Colorbar, deprecate colorbar_factory.
2 parents fcb6296 + 51b55fa commit d2cf66d

File tree

8 files changed

+65
-112
lines changed

8 files changed

+65
-112
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
``ColorbarPatch`` and ``colorbar_factory`` are deprecated
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
All the relevant functionality has been moved to the
4+
`~matplotlib.colorbar.Colorbar` class.

lib/matplotlib/colorbar.py

Lines changed: 53 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
On top of `.ColorbarBase` this connects the colorbar with a
2020
`.ScalarMappable` such as an image or contour plot.
2121
22-
:class:`ColorbarPatch`
23-
A specialized `.Colorbar` to support hatched contour plots.
24-
2522
:func:`make_axes`
2623
Create an `~.axes.Axes` suitable for a colorbar. This functions can be
2724
used with figures containing a single axes or with freely placed axes.
@@ -472,6 +469,7 @@ def __init__(self, ax, cmap=None,
472469
self.extendfrac = extendfrac
473470
self.extendrect = extendrect
474471
self.solids = None
472+
self.solids_patches = []
475473
self.lines = []
476474

477475
for spine in ax.spines.values():
@@ -531,14 +529,13 @@ def draw_all(self):
531529
# Set self.vmin and self.vmax to first and last boundary, excluding
532530
# extensions.
533531
self.vmin, self.vmax = self._boundaries[self._inside][[0, -1]]
534-
# Compute the X/Y mesh, assuming vertical orientation.
532+
# Compute the X/Y mesh.
535533
X, Y = self._mesh()
536534
# Extract bounding polygon (the last entry's value (X[0, 1]) doesn't
537535
# matter, it just matches the CLOSEPOLY code).
538536
x = np.concatenate([X[[0, 1, -2, -1], 0], X[[-1, -2, 1, 0, 0], 1]])
539537
y = np.concatenate([Y[[0, 1, -2, -1], 0], Y[[-1, -2, 1, 0, 0], 1]])
540-
xy = (np.column_stack([x, y]) if self.orientation == 'vertical' else
541-
np.column_stack([y, x])) # Apply orientation.
538+
xy = np.column_stack([x, y])
542539
# Configure axes limits, patch, and outline.
543540
xmin, ymin = xy.min(axis=0)
544541
xmax, ymax = xy.max(axis=0)
@@ -798,42 +795,52 @@ def set_label(self, label, *, loc=None, **kwargs):
798795

799796
def _edges(self, X, Y):
800797
"""Return the separator line segments; helper for _add_solids."""
801-
N = X.shape[0]
802798
# Using the non-array form of these line segments is much
803799
# simpler than making them into arrays.
804-
if self.orientation == 'vertical':
805-
return [list(zip(X[i], Y[i])) for i in range(1, N - 1)]
806-
else:
807-
return [list(zip(Y[i], X[i])) for i in range(1, N - 1)]
800+
return [list(zip(X[i], Y[i])) for i in range(1, len(X) - 1)]
808801

809802
def _add_solids(self, X, Y, C):
810-
"""
811-
Draw the colors using `~.axes.Axes.pcolormesh`;
812-
optionally add separators.
813-
"""
814-
if self.orientation == 'vertical':
815-
args = (X, Y, C)
816-
else:
817-
args = (np.transpose(Y), np.transpose(X), np.transpose(C))
818-
kw = dict(cmap=self.cmap,
819-
norm=self.norm,
820-
alpha=self.alpha,
821-
edgecolors='None')
822-
_log.debug('Setting pcolormesh')
823-
col = self.ax.pcolormesh(*args, **kw, shading='flat')
824-
# self.add_observer(col) # We should observe, not be observed...
825-
803+
"""Draw the colors; optionally add separators."""
804+
# Cleanup previously set artists.
826805
if self.solids is not None:
827806
self.solids.remove()
828-
self.solids = col
829-
830-
if self.drawedges:
831-
self.dividers.set_segments(self._edges(X, Y))
807+
for solid in self.solids_patches:
808+
solid.remove()
809+
# Add new artist(s), based on mappable type. Use individual patches if
810+
# hatching is needed, pcolormesh otherwise.
811+
mappable = getattr(self, 'mappable', None)
812+
if (isinstance(mappable, contour.ContourSet)
813+
and any(hatch is not None for hatch in mappable.hatches)):
814+
self._add_solids_patches(X, Y, C, mappable)
832815
else:
833-
self.dividers.set_segments([])
816+
self._add_solids_pcolormesh(X, Y, C)
817+
self.dividers.set_segments(self._edges(X, Y) if self.drawedges else [])
818+
819+
def _add_solids_pcolormesh(self, X, Y, C):
820+
_log.debug('Setting pcolormesh')
821+
self.solids = self.ax.pcolormesh(
822+
X, Y, C, cmap=self.cmap, norm=self.norm, alpha=self.alpha,
823+
edgecolors='none', shading='flat')
824+
if not self.drawedges:
834825
if len(self._y) >= self.n_rasterize:
835826
self.solids.set_rasterized(True)
836827

828+
def _add_solids_patches(self, X, Y, C, mappable):
829+
hatches = mappable.hatches * len(C) # Have enough hatches.
830+
patches = []
831+
for i in range(len(X) - 1):
832+
xy = np.array([[X[i, 0], Y[i, 0]],
833+
[X[i, 1], Y[i, 0]],
834+
[X[i + 1, 1], Y[i + 1, 0]],
835+
[X[i + 1, 0], Y[i + 1, 1]]])
836+
patch = mpatches.PathPatch(mpath.Path(xy),
837+
facecolor=self.cmap(self.norm(C[i][0])),
838+
hatch=hatches[i], linewidth=0,
839+
antialiased=False, alpha=self.alpha)
840+
self.ax.add_patch(patch)
841+
patches.append(patch)
842+
self.solids_patches = patches
843+
837844
def add_lines(self, levels, colors, linewidths, erase=True):
838845
"""
839846
Draw lines on the colorbar.
@@ -1082,11 +1089,10 @@ def _proportional_y(self):
10821089

10831090
def _mesh(self):
10841091
"""
1085-
Return ``(X, Y)``, the coordinate arrays for the colorbar pcolormesh.
1086-
These are suitable for a vertical colorbar; swapping and transposition
1087-
for a horizontal colorbar are done outside this function.
1092+
Return the coordinate arrays for the colorbar pcolormesh/patches.
10881093
1089-
These are scaled between vmin and vmax.
1094+
These are scaled between vmin and vmax, and already handle colorbar
1095+
orientation.
10901096
"""
10911097
# copy the norm and change the vmin and vmax to the vmin and
10921098
# vmax of the colorbar, not the norm. This allows the situation
@@ -1119,7 +1125,7 @@ def _mesh(self):
11191125
X[0, :] = xmid
11201126
if self._extend_upper() and not self.extendrect:
11211127
X[-1, :] = xmid
1122-
return X, Y
1128+
return (X, Y) if self.orientation == 'vertical' else (Y, X)
11231129

11241130
def _locate(self, x):
11251131
"""
@@ -1213,6 +1219,10 @@ def __init__(self, ax, mappable, **kwargs):
12131219
_add_disjoint_kwargs(kwargs, alpha=mappable.get_alpha())
12141220
super().__init__(ax, **kwargs)
12151221

1222+
mappable.colorbar = self
1223+
mappable.colorbar_cid = mappable.callbacksSM.connect(
1224+
'changed', self.update_normal)
1225+
12161226
@cbook.deprecated("3.3", alternative="update_normal")
12171227
def on_mappable_changed(self, mappable):
12181228
"""
@@ -1548,61 +1558,12 @@ def make_axes_gridspec(parent, *, location=None, orientation=None,
15481558
return cax, kw
15491559

15501560

1561+
@cbook.deprecated("3.4", alternative="Colorbar")
15511562
class ColorbarPatch(Colorbar):
1552-
"""
1553-
A Colorbar that uses a list of `~.patches.Patch` instances rather than the
1554-
default `~.collections.PatchCollection` created by `~.axes.Axes.pcolor`,
1555-
because the latter does not allow the hatch pattern to vary among the
1556-
members of the collection.
1557-
"""
1558-
1559-
def __init__(self, ax, mappable, **kw):
1560-
# we do not want to override the behaviour of solids
1561-
# so add a new attribute which will be a list of the
1562-
# colored patches in the colorbar
1563-
self.solids_patches = []
1564-
super().__init__(ax, mappable, **kw)
1565-
1566-
def _add_solids(self, X, Y, C):
1567-
"""
1568-
Draw the colors using `~matplotlib.patches.Patch`;
1569-
optionally add separators.
1570-
"""
1571-
n_segments = len(C)
1572-
1573-
# ensure there are sufficient hatches
1574-
hatches = self.mappable.hatches * n_segments
1575-
1576-
patches = []
1577-
for i in range(len(X) - 1):
1578-
val = C[i][0]
1579-
hatch = hatches[i]
1580-
1581-
xy = np.array([[X[i][0], Y[i][0]],
1582-
[X[i][1], Y[i][0]],
1583-
[X[i + 1][1], Y[i + 1][0]],
1584-
[X[i + 1][0], Y[i + 1][1]]])
1585-
1586-
if self.orientation == 'horizontal':
1587-
# if horizontal swap the xs and ys
1588-
xy = xy[..., ::-1]
1589-
1590-
patch = mpatches.PathPatch(mpath.Path(xy),
1591-
facecolor=self.cmap(self.norm(val)),
1592-
hatch=hatch, linewidth=0,
1593-
antialiased=False, alpha=self.alpha)
1594-
self.ax.add_patch(patch)
1595-
patches.append(patch)
1596-
1597-
if self.solids_patches:
1598-
for solid in self.solids_patches:
1599-
solid.remove()
1600-
1601-
self.solids_patches = patches
1602-
1603-
self.dividers.set_segments(self._edges(X, Y) if self.drawedges else [])
1563+
pass
16041564

16051565

1566+
@cbook.deprecated("3.4", alternative="Colorbar")
16061567
def colorbar_factory(cax, mappable, **kwargs):
16071568
"""
16081569
Create a colorbar on the given axes for the given mappable.
@@ -1624,20 +1585,7 @@ def colorbar_factory(cax, mappable, **kwargs):
16241585
16251586
Returns
16261587
-------
1627-
`.Colorbar` or `.ColorbarPatch`
1628-
The created colorbar instance. `.ColorbarPatch` is only used if
1629-
*mappable* is a `.ContourSet` with hatches.
1588+
`.Colorbar`
1589+
The created colorbar instance.
16301590
"""
1631-
# if the given mappable is a contourset with any hatching, use
1632-
# ColorbarPatch else use Colorbar
1633-
if (isinstance(mappable, contour.ContourSet)
1634-
and any(hatch is not None for hatch in mappable.hatches)):
1635-
cb = ColorbarPatch(cax, mappable, **kwargs)
1636-
else:
1637-
cb = Colorbar(cax, mappable, **kwargs)
1638-
1639-
cid = mappable.callbacksSM.connect('changed', cb.update_normal)
1640-
mappable.colorbar = cb
1641-
mappable.colorbar_cid = cid
1642-
1643-
return cb
1591+
return Colorbar(cax, mappable, **kwargs)

lib/matplotlib/figure.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2394,7 +2394,7 @@ def colorbar(self, mappable, cax=None, ax=None, use_gridspec=True, **kw):
23942394
NON_COLORBAR_KEYS = ['fraction', 'pad', 'shrink', 'aspect', 'anchor',
23952395
'panchor']
23962396
cb_kw = {k: v for k, v in kw.items() if k not in NON_COLORBAR_KEYS}
2397-
cb = cbar.colorbar_factory(cax, mappable, **cb_kw)
2397+
cb = cbar.Colorbar(cax, mappable, **cb_kw)
23982398

23992399
self.sca(current_ax)
24002400
self.stale = True

lib/matplotlib/tests/test_colorbar.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ def test_colorbar_extension_shape():
110110

111111

112112
@image_comparison(['colorbar_extensions_uniform.png',
113-
'colorbar_extensions_proportional.png'])
113+
'colorbar_extensions_proportional.png'],
114+
tol=1.0)
114115
def test_colorbar_extension_length():
115116
"""Test variable length colorbar extensions."""
116117
# Remove this line when this test image is regenerated.

lib/matplotlib/tests/test_colors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ def test_cmap_and_norm_from_levels_and_colors():
665665

666666

667667
@image_comparison(baseline_images=['boundarynorm_and_colorbar'],
668-
extensions=['png'])
668+
extensions=['png'], tol=1.0)
669669
def test_boundarynorm_and_colorbarbase():
670670
# Remove this line when this test image is regenerated.
671671
plt.rcParams['pcolormesh.snap'] = False

lib/matplotlib/tests/test_constrainedlayout.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def test_constrained_layout4():
7676
fig.colorbar(pcm, ax=axs, pad=0.01, shrink=0.6)
7777

7878

79-
@image_comparison(['constrained_layout5.png'])
79+
@image_comparison(['constrained_layout5.png'], tol=0.002)
8080
def test_constrained_layout5():
8181
"""
8282
Test constrained_layout for a single colorbar with subplots,
@@ -93,7 +93,7 @@ def test_constrained_layout5():
9393
location='bottom')
9494

9595

96-
@image_comparison(['constrained_layout6.png'])
96+
@image_comparison(['constrained_layout6.png'], tol=0.002)
9797
def test_constrained_layout6():
9898
"""Test constrained_layout for nested gridspecs"""
9999
# Remove this line when this test image is regenerated.

lib/matplotlib/tests/test_image.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ def test_image_preserve_size2():
786786
np.identity(n, bool)[::-1])
787787

788788

789-
@image_comparison(['mask_image_over_under.png'], remove_text=True)
789+
@image_comparison(['mask_image_over_under.png'], remove_text=True, tol=1.0)
790790
def test_mask_image_over_under():
791791
# Remove this line when this test image is regenerated.
792792
plt.rcParams['pcolormesh.snap'] = False

lib/mpl_toolkits/axes_grid1/axes_grid.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def colorbar(self, mappable, *, ticks=None, **kwargs):
5050
mappable.colorbar = cb
5151
self._locator = cb.cbar_axis.get_major_locator()
5252
else:
53-
cb = mpl.colorbar.colorbar_factory(
53+
cb = mpl.colorbar.Colorbar(
5454
self, mappable, orientation=orientation, ticks=ticks, **kwargs)
5555
self._cbid = mappable.colorbar_cid # deprecated.
5656
self._locator = cb.locator # deprecated.

0 commit comments

Comments
 (0)