Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ def __init__(self):
self._raster_depth = 0
self._rasterizing = False

self._use_blend_group_for_contourf = False
self._use_blend_group_for_pcolor = False

def open_group(self, s, gid=None):
"""
Open a grouping element with label *s* and *gid* (if set) as id.
Expand Down
3 changes: 3 additions & 0 deletions lib/matplotlib/backends/backend_agg.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ def __init__(self, width, height, dpi):

self._override_blend_mode_to_knockout = False

self._use_blend_group_for_contourf = True
self._use_blend_group_for_pcolor = True

self._update_methods()
self.mathtext_parser = MathTextParser('path')

Expand Down
3 changes: 3 additions & 0 deletions lib/matplotlib/backends/backend_cairo.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ def __init__(self, dpi):

self._override_blend_mode_to_knockout = False

self._use_blend_group_for_contourf = True
self._use_blend_group_for_pcolor = True

def set_context(self, ctx):
surface = ctx.get_target()
if hasattr(surface, "get_width") and hasattr(surface, "get_height"):
Expand Down
26 changes: 26 additions & 0 deletions lib/matplotlib/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -2546,6 +2546,7 @@ def draw(self, renderer):
if not self.get_visible():
return
renderer.open_group(self.__class__.__name__, self.get_gid())

transform = self.get_transform()
offset_trf = self.get_offset_transform()
offsets = self.get_offsets()
Expand Down Expand Up @@ -2580,14 +2581,24 @@ def draw(self, renderer):
renderer.draw_gouraud_triangles(
gc, triangles, colors, transform.frozen())
else:
isolate = (renderer._use_blend_group_for_pcolor and self._antialiased
and (self._edgecolors.size == 0 or self._edgecolors[0][3] == 0))
if isolate:
gc.set_blend_mode("plus")
renderer.open_blend_group(self.get_blend_mode())

renderer.draw_quad_mesh(
gc, transform.frozen(),
coordinates.shape[1] - 1, coordinates.shape[0] - 1,
coordinates, offsets, offset_trf,
# Backends expect flattened rgba arrays (n*m, 4) for fc and ec
self.get_facecolor().reshape((-1, 4)),
self._antialiased, self.get_edgecolors().reshape((-1, 4)))

if isolate:
renderer.close_blend_group()
gc.restore()

renderer.close_group(self.__class__.__name__)
self.stale = False

Expand Down Expand Up @@ -2688,6 +2699,21 @@ def get_edgecolor(self):
return ec
return ec[unmasked_polys, :]

@artist.allow_rasterization
def draw(self, renderer):
isolate = (renderer._use_blend_group_for_pcolor and np.all(self._antialiaseds)
and (self._edgecolors.size == 0 or self._edgecolors[0][3] == 0))
if isolate:
blend_mode = self.get_blend_mode()
self.set_blend_mode("plus")
renderer.open_blend_group(blend_mode)

super().draw(renderer)

if isolate:
renderer.close_blend_group()
self.set_blend_mode(blend_mode)

def get_facecolor(self):
# docstring inherited
# We only want to return the facecolors of the polygons
Expand Down
16 changes: 15 additions & 1 deletion lib/matplotlib/contour.py
Original file line number Diff line number Diff line change
Expand Up @@ -1285,11 +1285,25 @@ def find_nearest_contour(self, x, y, indices=None, pixel=True):
def draw(self, renderer):
paths = self._paths
n_paths = len(paths)
edgecolors = self.get_edgecolors()
if not self.filled or all(hatch is None for hatch in self.hatches):
isolate = (renderer._use_blend_group_for_contourf and
self.filled and self.get_antialiased() and
(edgecolors.size == 0 or edgecolors[0][3] == 0))

if isolate:
blend_mode = self.get_blend_mode()
self.set_blend_mode("plus")
renderer.open_blend_group(blend_mode)

super().draw(renderer)

if isolate:
renderer.close_blend_group()
self.set_blend_mode(blend_mode)

return
# In presence of hatching, draw contours one at a time.
edgecolors = self.get_edgecolors()
if edgecolors.size == 0:
edgecolors = ("none",)
for idx in range(n_paths):
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,32 @@ def test_pcolormesh_alpha():
ax4.pcolormesh(Qx, Qy, Z, cmap=cmap, shading='gouraud', zorder=1)


@image_comparison(['pcolormesh_antialiasing.png'], style='mpl20')
def test_pcolormesh_antialiasing():
N = 5
data = np.arange(N**2, dtype=float).reshape((N, N))
data[2, 2] = np.nan

x, y = np.meshgrid(np.arange(N + 1), np.arange(N + 1))

rotation = mtransforms.Affine2D().rotate(1)

fig, axs = plt.subplots(2, 3, figsize=(5, 3.5), layout="constrained")

for i, antialiased in enumerate([None, False, True]):
kwargs = {'cmap': 'jet', 'alpha': 0.5}
if antialiased is not None:
kwargs['antialiased'] = antialiased

axs[0, i].pcolormesh(x, y, data, transform=rotation + axs[0, i].transData,
**kwargs)
axs[1, i].pcolor(x, y, data, transform=rotation + axs[1, i].transData, **kwargs)

for j in range(2):
axs[j, i].set_aspect("equal")
axs[j, i].set_axis_off()


@pytest.mark.parametrize("dims,alpha", [(3, 1), (4, 0.5)])
@check_figures_equal()
def test_pcolormesh_rgba(fig_test, fig_ref, dims, alpha):
Expand Down
20 changes: 20 additions & 0 deletions lib/matplotlib/tests/test_contour.py
Original file line number Diff line number Diff line change
Expand Up @@ -896,3 +896,23 @@ def test_clabel_manual_subset():
cs = ax.contour([[1, 2], [3, 4]], levels=[1.5, 2.5, 3.5])
# Attempt to label only one specific level manually
ax.clabel(cs, levels=[2.5], manual=[(0.5, 0.5)])


@image_comparison(['contourf_antialiasing.png'], style='mpl20')
def test_contourf_antialiasing():
x = np.arange(1, 6)
y = x.reshape(-1, 1)
data = (x * y).astype(float)
data[2, 2] = np.nan

fig, axs = plt.subplots(1, 3, figsize=(5, 2), layout="constrained")

for i, antialiased in enumerate([None, False, True]):
kwargs = {'cmap': 'jet', 'alpha': 0.5}
if antialiased is not None:
kwargs['antialiased'] = antialiased

axs[i].contourf(data, levels=np.arange(1, 25, 1), extend="both", **kwargs)

axs[i].set_aspect("equal")
axs[i].set_axis_off()
Loading