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

Skip to content

Commit 60e67e0

Browse files
committed
Merge pull request #1954 from Westacular/alpha-patch
Supporting different alphas for face and edge colours
2 parents af07100 + ba1f673 commit 60e67e0

27 files changed

+1265
-140
lines changed

doc/api/api_changes.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,27 @@ Changes in 1.3.x
4747
* The :func:`~matplotlib.cbook.check_output` function has been moved to
4848
`~matplotlib.compat.subprocess`.
4949

50+
* :class:`~matplotlib.patches.Patch` now fully supports using RGBA values for
51+
its ``facecolor`` and ``edgecolor`` attributes, which enables faces and
52+
edges to have different alpha values. If the
53+
:class:`~matplotlib.patches.Patch` object's ``alpha`` attribute is set to
54+
anything other than ``None``, that value will override any alpha-channel
55+
value in both the face and edge colors. Previously, if
56+
:class:`~matplotlib.patches.Patch` had ``alpha=None``, the alpha component
57+
of ``edgecolor`` would be applied to both the edge and face.
58+
59+
* The optional ``isRGB`` argument to
60+
:meth:`~matplotlib.backend_bases.GraphicsContextBase.set_foreground` (and
61+
the other GraphicsContext classes that descend from it) has been renamed to
62+
``isRGBA``, and should now only be set to ``True`` if the ``fg`` color
63+
argument is known to be an RGBA tuple.
64+
65+
* For :class:`~matplotlib.patches.Patch`, the ``capstyle`` used is now
66+
``butt``, to be consistent with the default for most other objects, and to
67+
avoid problems with non-solid ``linestyle`` appearing solid when using a
68+
large ``linewidth``. Previously, :class:`~matplotlib.patches.Patch` used
69+
``capstyle='projecting'``.
70+
5071
Changes in 1.2.x
5172
================
5273

doc/users/whats_new.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,16 @@ Wes Campaigne and Phil Elson fixed the Agg backend such that PNGs are now
154154
saved with the correct background color when :meth:`fig.patch.get_alpha` is
155155
not 1.
156156

157+
Independent alpha values for face and edge colors
158+
-------------------------------------------------
159+
Wes Campaigne modified how :class:`~matplotlib.patches.Patch` objects are
160+
drawn such that (for backends supporting transparency) you can set different
161+
alpha values for faces and edges, by specifying their colors in RGBA format.
162+
Note that if you set the alpha attribute for the patch object (e.g. using
163+
:meth:`~matplotlib.patches.Patch.set_alpha` or the ``alpha`` keyword
164+
argument), that value will override the alpha components set in both the
165+
face and edge colors.
166+
157167

158168
.. _whats-new-1-2-2:
159169

lib/matplotlib/backend_bases.py

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,6 @@ def _iter_collection(self, gc, master_transform, all_transforms,
362362
gc0 = self.new_gc()
363363
gc0.copy_properties(gc)
364364

365-
original_alpha = gc.get_alpha()
366-
367365
if Nfacecolors == 0:
368366
rgbFace = None
369367

@@ -387,7 +385,6 @@ def _iter_collection(self, gc, master_transform, all_transforms,
387385
yo = -(yp - yo)
388386
if not (np.isfinite(xo) and np.isfinite(yo)):
389387
continue
390-
gc0.set_alpha(original_alpha)
391388
if Nfacecolors:
392389
rgbFace = facecolors[i % Nfacecolors]
393390
if Nedgecolors:
@@ -400,16 +397,12 @@ def _iter_collection(self, gc, master_transform, all_transforms,
400397
if fg[3] == 0.0:
401398
gc0.set_linewidth(0)
402399
else:
403-
gc0.set_alpha(gc0.get_alpha() * fg[3])
404-
gc0.set_foreground(fg[:3])
400+
gc0.set_foreground(fg)
405401
else:
406402
gc0.set_foreground(fg)
407403
if rgbFace is not None and len(rgbFace) == 4:
408404
if rgbFace[3] == 0:
409405
rgbFace = None
410-
else:
411-
gc0.set_alpha(gc0.get_alpha() * rgbFace[3])
412-
rgbFace = rgbFace[:3]
413406
gc0.set_antialiased(antialiaseds[i % Naa])
414407
if Nurls:
415408
gc0.set_url(urls[i % Nurls])
@@ -562,7 +555,7 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath):
562555

563556
path, transform = self._get_text_path_transform(
564557
x, y, s, prop, angle, ismath)
565-
color = gc.get_rgb()[:3]
558+
color = gc.get_rgb()
566559

567560
gc.set_linewidth(0.0)
568561
self.draw_path(gc, path, transform, rgbFace=color)
@@ -702,7 +695,8 @@ def __init__(self):
702695
self._joinstyle = 'round'
703696
self._linestyle = 'solid'
704697
self._linewidth = 1
705-
self._rgb = (0.0, 0.0, 0.0)
698+
self._rgb = (0.0, 0.0, 0.0, 1.0)
699+
self._orig_color = (0.0, 0.0, 0.0, 1.0)
706700
self._hatch = None
707701
self._url = None
708702
self._gid = None
@@ -711,6 +705,7 @@ def __init__(self):
711705
def copy_properties(self, gc):
712706
'Copy properties from gc to self'
713707
self._alpha = gc._alpha
708+
self._forced_alpha = gc._forced_alpha
714709
self._antialiased = gc._antialiased
715710
self._capstyle = gc._capstyle
716711
self._cliprect = gc._cliprect
@@ -720,6 +715,7 @@ def copy_properties(self, gc):
720715
self._linestyle = gc._linestyle
721716
self._linewidth = gc._linewidth
722717
self._rgb = gc._rgb
718+
self._orig_color = gc._orig_color
723719
self._hatch = gc._hatch
724720
self._url = gc._url
725721
self._gid = gc._gid
@@ -781,6 +777,13 @@ def get_dashes(self):
781777
"""
782778
return self._dashes
783779

780+
def get_forced_alpha(self):
781+
"""
782+
Return whether the value given by get_alpha() should be used to
783+
override any other alpha-channel values.
784+
"""
785+
return self._forced_alpha
786+
784787
def get_joinstyle(self):
785788
"""
786789
Return the line join style as one of ('miter', 'round', 'bevel')
@@ -833,14 +836,19 @@ def get_snap(self):
833836

834837
def set_alpha(self, alpha):
835838
"""
836-
Set the alpha value used for blending - not supported on
837-
all backends
839+
Set the alpha value used for blending - not supported on all backends.
840+
If ``alpha=None`` (the default), the alpha components of the
841+
foreground and fill colors will be used to set their respective
842+
transparencies (where applicable); otherwise, ``alpha`` will override
843+
them.
838844
"""
839845
if alpha is not None:
840846
self._alpha = alpha
841847
self._forced_alpha = True
842848
else:
849+
self._alpha = 1.0
843850
self._forced_alpha = False
851+
self.set_foreground(self._orig_color)
844852

845853
def set_antialiased(self, b):
846854
"""
@@ -890,30 +898,28 @@ def set_dashes(self, dash_offset, dash_list):
890898
"""
891899
self._dashes = dash_offset, dash_list
892900

893-
def set_foreground(self, fg, isRGB=False):
901+
def set_foreground(self, fg, isRGBA=False):
894902
"""
895903
Set the foreground color. fg can be a MATLAB format string, a
896904
html hex color string, an rgb or rgba unit tuple, or a float between 0
897905
and 1. In the latter case, grayscale is used.
898906
899-
If you know fg is rgb or rgba, set ``isRGB=True`` for
900-
efficiency.
907+
If you know fg is rgba, set ``isRGBA=True`` for efficiency.
901908
"""
902-
if isRGB:
909+
self._orig_color = fg
910+
if self._forced_alpha:
911+
self._rgb = colors.colorConverter.to_rgba(fg, self._alpha)
912+
elif isRGBA:
903913
self._rgb = fg
904914
else:
905915
self._rgb = colors.colorConverter.to_rgba(fg)
906-
if len(self._rgb) == 4 and not self._forced_alpha:
907-
self.set_alpha(self._rgb[3])
908-
# Use set_alpha method here so that subclasses will
909-
# be calling their own version, which may set their
910-
# own attributes.
911916

912917
def set_graylevel(self, frac):
913918
"""
914919
Set the foreground color to be a gray level with *frac*
915920
"""
916-
self._rgb = (frac, frac, frac)
921+
self._orig_color = frac
922+
self._rgb = (frac, frac, frac, self._alpha)
917923

918924
def set_joinstyle(self, js):
919925
"""
@@ -942,7 +948,7 @@ def set_linestyle(self, style):
942948
'dotted' : (0, (1.0, 3.0)),
943949
"""
944950

945-
if style in self.dashd.keys():
951+
if style in self.dashd:
946952
offset, dashes = self.dashd[style]
947953
elif isinstance(style, tuple):
948954
offset, dashes = style

lib/matplotlib/backends/backend_cairo.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,13 @@ def set_width_height(self, width, height):
110110
# font transform?
111111

112112

113-
def _fill_and_stroke (self, ctx, fill_c, alpha):
113+
def _fill_and_stroke (self, ctx, fill_c, alpha, alpha_overrides):
114114
if fill_c is not None:
115115
ctx.save()
116-
if len(fill_c) == 3:
116+
if len(fill_c) == 3 or alpha_overrides:
117117
ctx.set_source_rgba (fill_c[0], fill_c[1], fill_c[2], alpha)
118118
else:
119-
ctx.set_source_rgba (fill_c[0], fill_c[1], fill_c[2], alpha*fill_c[3])
119+
ctx.set_source_rgba (fill_c[0], fill_c[1], fill_c[2], fill_c[3])
120120
ctx.fill_preserve()
121121
ctx.restore()
122122
ctx.stroke()
@@ -150,7 +150,7 @@ def draw_path(self, gc, path, transform, rgbFace=None):
150150
ctx.new_path()
151151
self.convert_path(ctx, path, transform)
152152

153-
self._fill_and_stroke(ctx, rgbFace, gc.get_alpha())
153+
self._fill_and_stroke(ctx, rgbFace, gc.get_alpha(), gc.get_forced_alpha())
154154

155155
def draw_image(self, gc, x, y, im):
156156
# bbox - not currently used
@@ -316,7 +316,10 @@ def set_alpha(self, alpha):
316316
GraphicsContextBase.set_alpha(self, alpha)
317317
_alpha = self.get_alpha()
318318
rgb = self._rgb
319-
self.ctx.set_source_rgba (rgb[0], rgb[1], rgb[2], _alpha)
319+
if self.get_forced_alpha():
320+
self.ctx.set_source_rgba (rgb[0], rgb[1], rgb[2], _alpha)
321+
else:
322+
self.ctx.set_source_rgba (rgb[0], rgb[1], rgb[2], rgb[3])
320323

321324

322325
#def set_antialiased(self, b):
@@ -359,8 +362,8 @@ def set_dashes(self, offset, dashes):
359362
self.renderer.points_to_pixels (np.asarray(dashes)), offset)
360363

361364

362-
def set_foreground(self, fg, isRGB=None):
363-
GraphicsContextBase.set_foreground(self, fg, isRGB)
365+
def set_foreground(self, fg, isRGBA=None):
366+
GraphicsContextBase.set_foreground(self, fg, isRGBA)
364367
if len(self._rgb) == 3:
365368
self.ctx.set_source_rgb(*self._rgb)
366369
else:

lib/matplotlib/backends/backend_gdk.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,8 @@ def set_dashes(self, dash_offset, dash_list):
393393
self.gdkGC.line_style = gdk.LINE_ON_OFF_DASH
394394

395395

396-
def set_foreground(self, fg, isRGB=False):
397-
GraphicsContextBase.set_foreground(self, fg, isRGB)
396+
def set_foreground(self, fg, isRGBA=False):
397+
GraphicsContextBase.set_foreground(self, fg, isRGBA)
398398
self.gdkGC.foreground = self.rgb_to_gdk_color(self.get_rgb())
399399

400400

lib/matplotlib/backends/backend_macosx.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ def set_width_height (self, width, height):
5050

5151
def draw_path(self, gc, path, transform, rgbFace=None):
5252
if rgbFace is not None:
53-
rgbFace = tuple(rgbFace[:3])
53+
rgbFace = tuple(rgbFace)
5454
linewidth = gc.get_linewidth()
5555
gc.draw_path(path, transform, linewidth, rgbFace)
5656

5757
def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
5858
if rgbFace is not None:
59-
rgbFace = tuple(rgbFace[:3])
59+
rgbFace = tuple(rgbFace)
6060
linewidth = gc.get_linewidth()
6161
gc.draw_markers(marker_path, marker_trans, path, trans, linewidth, rgbFace)
6262

@@ -183,12 +183,14 @@ def __init__(self):
183183
def set_alpha(self, alpha):
184184
GraphicsContextBase.set_alpha(self, alpha)
185185
_alpha = self.get_alpha()
186-
_macosx.GraphicsContext.set_alpha(self, _alpha)
186+
_macosx.GraphicsContext.set_alpha(self, _alpha, self.get_forced_alpha())
187+
rgb = self.get_rgb()
188+
_macosx.GraphicsContext.set_foreground(self, rgb)
187189

188-
def set_foreground(self, fg, isRGB=False):
189-
GraphicsContextBase.set_foreground(self, fg, isRGB)
190+
def set_foreground(self, fg, isRGBA=False):
191+
GraphicsContextBase.set_foreground(self, fg, isRGBA)
190192
rgb = self.get_rgb()
191-
_macosx.GraphicsContext.set_foreground(self, rgb[:3])
193+
_macosx.GraphicsContext.set_foreground(self, rgb)
192194

193195
def set_graylevel(self, fg):
194196
GraphicsContextBase.set_graylevel(self, fg)

lib/matplotlib/backends/backend_pdf.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,7 +1064,7 @@ def alphaState(self, alpha):
10641064
self.nextAlphaState += 1
10651065
self.alphaStates[alpha] = \
10661066
(name, { 'Type': Name('ExtGState'),
1067-
'CA': alpha, 'ca': alpha })
1067+
'CA': alpha[0], 'ca': alpha[1] })
10681068
return name
10691069

10701070
def hatchPattern(self, hatch_style):
@@ -1443,11 +1443,21 @@ def check_gc(self, gc, fillcolor=None):
14431443
orig_fill = gc._fillcolor
14441444
gc._fillcolor = fillcolor
14451445

1446+
orig_alphas = gc._effective_alphas
1447+
1448+
if gc._forced_alpha:
1449+
gc._effective_alphas = (gc._alpha, gc._alpha)
1450+
elif fillcolor is None or len(fillcolor) < 4:
1451+
gc._effective_alphas = (gc._rgb[3], 1.0)
1452+
else:
1453+
gc._effective_alphas = (gc._rgb[3], fillcolor[3])
1454+
14461455
delta = self.gc.delta(gc)
14471456
if delta: self.file.output(*delta)
14481457

14491458
# Restore gc to avoid unwanted side effects
14501459
gc._fillcolor = orig_fill
1460+
gc._effective_alphas = orig_alphas
14511461

14521462
def tex_font_mapping(self, texfont):
14531463
if self.tex_font_map is None:
@@ -2004,6 +2014,7 @@ class GraphicsContextPdf(GraphicsContextBase):
20042014
def __init__(self, file):
20052015
GraphicsContextBase.__init__(self)
20062016
self._fillcolor = (0.0, 0.0, 0.0)
2017+
self._effective_alphas = (1.0, 1.0)
20072018
self.file = file
20082019
self.parent = None
20092020

@@ -2072,8 +2083,8 @@ def dash_cmd(self, dashes):
20722083
offset = 0
20732084
return [list(dash), offset, Op.setdash]
20742085

2075-
def alpha_cmd(self, alpha):
2076-
name = self.file.alphaState(alpha)
2086+
def alpha_cmd(self, alpha, forced, effective_alphas):
2087+
name = self.file.alphaState(effective_alphas)
20772088
return [name, Op.setgstate]
20782089

20792090
def hatch_cmd(self, hatch):
@@ -2138,7 +2149,7 @@ def clip_cmd(self, cliprect, clippath):
21382149

21392150
commands = (
21402151
(('_cliprect', '_clippath'), clip_cmd), # must come first since may pop
2141-
(('_alpha',), alpha_cmd),
2152+
(('_alpha', '_forced_alpha', '_effective_alphas'), alpha_cmd),
21422153
(('_capstyle',), capstyle_cmd),
21432154
(('_fillcolor',), fillcolor_cmd),
21442155
(('_joinstyle',), joinstyle_cmd),
@@ -2183,6 +2194,7 @@ def copy_properties(self, other):
21832194
"""
21842195
GraphicsContextBase.copy_properties(self, other)
21852196
self._fillcolor = other._fillcolor
2197+
self._effective_alphas = other._effective_alphas
21862198

21872199
def finalize(self):
21882200
"""

0 commit comments

Comments
 (0)