Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 36f1353

Browse filesBrowse files
authored
Merge pull request #6904 from efiring/scatter_edgecolor
MNT: Use edgecolor rather than linewidth to control edge display.
2 parents b2a25b2 + 69af0e7 commit 36f1353
Copy full SHA for 36f1353

File tree

6 files changed

+118
-113
lines changed
Filter options

6 files changed

+118
-113
lines changed

‎lib/matplotlib/collections.py

Copy file name to clipboardExpand all lines: lib/matplotlib/collections.py
+51-52Lines changed: 51 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,10 @@ def __init__(self,
128128
# list of unbroadcast/scaled linewidths
129129
self._us_lw = [0]
130130
self._linewidths = [0]
131+
self._is_filled = True # May be modified by set_facecolor().
131132

132-
self.set_edgecolor(edgecolors)
133133
self.set_facecolor(facecolors)
134+
self.set_edgecolor(edgecolors)
134135
self.set_linewidth(linewidths)
135136
self.set_linestyle(linestyles)
136137
self.set_antialiased(antialiaseds)
@@ -492,14 +493,9 @@ def set_linewidth(self, lw):
492493
ACCEPTS: float or sequence of floats
493494
"""
494495
if lw is None:
495-
if (self._edge_default or
496-
mpl.rcParams['_internal.classic_mode'] or
497-
not self._is_filled):
498-
lw = mpl.rcParams['patch.linewidth']
499-
if lw is None:
500-
lw = mpl.rcParams['lines.linewidth']
501-
else:
502-
lw = 0
496+
lw = mpl.rcParams['patch.linewidth']
497+
if lw is None:
498+
lw = mpl.rcParams['lines.linewidth']
503499
# get the un-scaled/broadcast lw
504500
self._us_lw = self._get_value(lw)
505501

@@ -644,6 +640,20 @@ def set_color(self, c):
644640
self.set_facecolor(c)
645641
self.set_edgecolor(c)
646642

643+
def _set_facecolor(self, c):
644+
if c is None:
645+
c = mpl.rcParams['patch.facecolor']
646+
647+
self._is_filled = True
648+
try:
649+
if c.lower() == 'none':
650+
self._is_filled = False
651+
except AttributeError:
652+
pass
653+
self._facecolors = mcolors.to_rgba_array(c, self._alpha)
654+
self.stale = True
655+
656+
647657
def set_facecolor(self, c):
648658
"""
649659
Set the facecolor(s) of the collection. *c* can be a
@@ -655,17 +665,9 @@ def set_facecolor(self, c):
655665
656666
ACCEPTS: matplotlib color spec or sequence of specs
657667
"""
658-
self._is_filled = True
659-
try:
660-
if c.lower() == 'none':
661-
self._is_filled = False
662-
except AttributeError:
663-
pass
664-
if c is None:
665-
c = mpl.rcParams['patch.facecolor']
666-
self._facecolors_original = c
667-
self._facecolors = mcolors.to_rgba_array(c, self._alpha)
668-
self.stale = True
668+
self._original_facecolor = c
669+
self._set_facecolor(c)
670+
669671

670672
def set_facecolors(self, c):
671673
"""alias for set_facecolor"""
@@ -683,38 +685,45 @@ def get_edgecolor(self):
683685
return self._edgecolors
684686
get_edgecolors = get_edgecolor
685687

686-
def set_edgecolor(self, c):
687-
"""
688-
Set the edgecolor(s) of the collection. *c* can be a
689-
matplotlib color spec (all patches have same color), or a
690-
sequence of specs; if it is a sequence the patches will
691-
cycle through the sequence.
692-
693-
If *c* is 'face', the edge color will always be the same as
694-
the face color. If it is 'none', the patch boundary will not
695-
be drawn.
696-
697-
ACCEPTS: matplotlib color spec or sequence of specs
698-
"""
688+
def _set_edgecolor(self, c):
689+
if c is None:
690+
if (mpl.rcParams['patch.force_edgecolor'] or
691+
not self._is_filled or self._edge_default):
692+
c = mpl.rcParams['patch.edgecolor']
693+
else:
694+
c = 'none'
699695
self._is_stroked = True
700696
try:
701697
if c.lower() == 'none':
702698
self._is_stroked = False
703699
except AttributeError:
704700
pass
701+
705702
try:
706-
if c.lower() == 'face':
703+
if c.lower() == 'face': # Special case: lookup in "get" method.
707704
self._edgecolors = 'face'
708-
self._edgecolors_original = 'face'
709705
return
710706
except AttributeError:
711707
pass
712-
if c is None:
713-
c = mpl.rcParams['patch.edgecolor']
714-
self._edgecolors_original = c
715708
self._edgecolors = mcolors.to_rgba_array(c, self._alpha)
716709
self.stale = True
717710

711+
def set_edgecolor(self, c):
712+
"""
713+
Set the edgecolor(s) of the collection. *c* can be a
714+
matplotlib color spec (all patches have same color), or a
715+
sequence of specs; if it is a sequence the patches will
716+
cycle through the sequence.
717+
718+
If *c* is 'face', the edge color will always be the same as
719+
the face color. If it is 'none', the patch boundary will not
720+
be drawn.
721+
722+
ACCEPTS: matplotlib color spec or sequence of specs
723+
"""
724+
self._original_edgecolor = c
725+
self._set_edgecolor(c)
726+
718727
def set_edgecolors(self, c):
719728
"""alias for set_edgecolor"""
720729
return self.set_edgecolor(c)
@@ -732,18 +741,8 @@ def set_alpha(self, alpha):
732741
except TypeError:
733742
raise TypeError('alpha must be a float or None')
734743
artist.Artist.set_alpha(self, alpha)
735-
try:
736-
self._facecolors = mcolors.to_rgba_array(
737-
self._facecolors_original, self._alpha)
738-
except (AttributeError, TypeError, IndexError):
739-
pass
740-
try:
741-
if (not isinstance(self._edgecolors_original, six.string_types)
742-
or self._edgecolors_original != str('face')):
743-
self._edgecolors = mcolors.to_rgba_array(
744-
self._edgecolors_original, self._alpha)
745-
except (AttributeError, TypeError, IndexError):
746-
pass
744+
self._set_facecolor(self._original_facecolor)
745+
self._set_edgecolor(self._original_edgecolor)
747746

748747
def get_linewidths(self):
749748
return self._linewidths
@@ -779,9 +778,9 @@ def update_from(self, other):
779778

780779
artist.Artist.update_from(self, other)
781780
self._antialiaseds = other._antialiaseds
782-
self._edgecolors_original = other._edgecolors_original
781+
self._original_edgecolor = other._original_edgecolor
783782
self._edgecolors = other._edgecolors
784-
self._facecolors_original = other._facecolors_original
783+
self._original_facecolor = other._original_facecolor
785784
self._facecolors = other._facecolors
786785
self._linewidths = other._linewidths
787786
self._linestyles = other._linestyles

‎lib/matplotlib/mpl-data/stylelib/classic.mplstyle

Copy file name to clipboardExpand all lines: lib/matplotlib/mpl-data/stylelib/classic.mplstyle
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ markers.fillstyle: full
2929
# information on patch properties
3030
patch.linewidth : 1.0 # edge width in points
3131
patch.facecolor : b
32+
patch.force_edgecolor : True
3233
patch.edgecolor : k
3334
patch.antialiased : True # render patches in antialiased (no jaggies)
3435

‎lib/matplotlib/patches.py

Copy file name to clipboardExpand all lines: lib/matplotlib/patches.py
+42-36Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -154,18 +154,26 @@ def get_verts(self):
154154
return polygons[0]
155155
return []
156156

157+
def _process_radius(self, radius):
158+
if radius is not None:
159+
return radius
160+
if cbook.is_numlike(self._picker):
161+
_radius = self._picker
162+
else:
163+
if self.get_edgecolor()[3] == 0:
164+
_radius = 0
165+
else:
166+
_radius = self.get_linewidth()
167+
return _radius
168+
157169
def contains(self, mouseevent, radius=None):
158170
"""Test whether the mouse event occurred in the patch.
159171
160172
Returns T/F, {}
161173
"""
162174
if six.callable(self._contains):
163175
return self._contains(self, mouseevent)
164-
if radius is None:
165-
if cbook.is_numlike(self._picker):
166-
radius = self._picker
167-
else:
168-
radius = self.get_linewidth()
176+
radius = self._process_radius(radius)
169177
inside = self.get_path().contains_point(
170178
(mouseevent.x, mouseevent.y), self.get_transform(), radius)
171179
return inside, {}
@@ -175,11 +183,7 @@ def contains_point(self, point, radius=None):
175183
Returns *True* if the given point is inside the path
176184
(transformed with its transform attribute).
177185
"""
178-
if radius is None:
179-
if cbook.is_numlike(self._picker):
180-
radius = self._picker
181-
else:
182-
radius = self.get_linewidth()
186+
radius = self._process_radius(radius)
183187
return self.get_path().contains_point(point,
184188
self.get_transform(),
185189
radius)
@@ -281,37 +285,44 @@ def set_aa(self, aa):
281285
"""alias for set_antialiased"""
282286
return self.set_antialiased(aa)
283287

288+
def _set_edgecolor(self, color):
289+
if color is None:
290+
if (mpl.rcParams['patch.force_edgecolor'] or
291+
not self._fill or self._edge_default):
292+
color = mpl.rcParams['patch.edgecolor']
293+
else:
294+
color = 'none'
295+
self._edgecolor = colors.to_rgba(color, self._alpha)
296+
self.stale = True
297+
284298
def set_edgecolor(self, color):
285299
"""
286300
Set the patch edge color
287301
288-
ACCEPTS: mpl color spec, or None for default, or 'none' for no color
302+
ACCEPTS: mpl color spec, None, 'none', or 'auto'
289303
"""
290-
if color is None:
291-
color = mpl.rcParams['patch.edgecolor']
292304
self._original_edgecolor = color
293-
self._edgecolor = colors.to_rgba(color, self._alpha)
294-
self.stale = True
305+
self._set_edgecolor(color)
295306

296307
def set_ec(self, color):
297308
"""alias for set_edgecolor"""
298309
return self.set_edgecolor(color)
299310

311+
def _set_facecolor(self, color):
312+
if color is None:
313+
color = mpl.rcParams['patch.facecolor']
314+
alpha = self._alpha if self._fill else 0
315+
self._facecolor = colors.to_rgba(color, alpha)
316+
self.stale = True
317+
300318
def set_facecolor(self, color):
301319
"""
302320
Set the patch face color
303321
304322
ACCEPTS: mpl color spec, or None for default, or 'none' for no color
305323
"""
306-
if color is None:
307-
color = mpl.rcParams['patch.facecolor']
308-
# save: otherwise changing _fill may lose alpha information
309324
self._original_facecolor = color
310-
self._facecolor = colors.to_rgba(color, self._alpha)
311-
if not self._fill:
312-
self._facecolor = list(self._facecolor)
313-
self._facecolor[3] = 0
314-
self.stale = True
325+
self._set_facecolor(color)
315326

316327
def set_fc(self, color):
317328
"""alias for set_facecolor"""
@@ -343,10 +354,9 @@ def set_alpha(self, alpha):
343354
except TypeError:
344355
raise TypeError('alpha must be a float or None')
345356
artist.Artist.set_alpha(self, alpha)
346-
# using self._fill and self._alpha
347-
self.set_facecolor(self._original_facecolor)
348-
self.set_edgecolor(self._original_edgecolor)
349-
self.stale = True
357+
self._set_facecolor(self._facecolor)
358+
self._set_edgecolor(self._original_edgecolor)
359+
# stale is already True
350360

351361
def set_linewidth(self, w):
352362
"""
@@ -355,14 +365,9 @@ def set_linewidth(self, w):
355365
ACCEPTS: float or None for default
356366
"""
357367
if w is None:
358-
if (not self._fill or
359-
self._edge_default or
360-
mpl.rcParams['_internal.classic_mode']):
361-
w = mpl.rcParams['patch.linewidth']
362-
if w is None:
363-
w = mpl.rcParams['axes.linewidth']
364-
else:
365-
w = 0
368+
w = mpl.rcParams['patch.linewidth']
369+
if w is None:
370+
w = mpl.rcParams['axes.linewidth']
366371

367372
self._linewidth = float(w)
368373
# scale the dash pattern by the linewidth
@@ -428,7 +433,8 @@ def set_fill(self, b):
428433
ACCEPTS: [True | False]
429434
"""
430435
self._fill = bool(b)
431-
self.set_facecolor(self._original_facecolor)
436+
self._set_facecolor(self._original_facecolor)
437+
self._set_edgecolor(self._original_edgecolor)
432438
self.stale = True
433439

434440
def get_fill(self):

‎lib/matplotlib/rcsetup.py

Copy file name to clipboardExpand all lines: lib/matplotlib/rcsetup.py
+7-6Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ def validate_color(s):
364364
'return a valid color arg'
365365
try:
366366
if s.lower() == 'none':
367-
return 'None'
367+
return 'none'
368368
except AttributeError:
369369
pass
370370

@@ -906,7 +906,7 @@ def validate_animation_writer_path(p):
906906
'lines.linewidth': [1.5, validate_float], # line width in points
907907
'lines.linestyle': ['-', six.text_type], # solid line
908908
'lines.color': ['C0', validate_color], # first color in color cycle
909-
'lines.marker': ['None', six.text_type], # black
909+
'lines.marker': ['None', six.text_type], # marker name
910910
'lines.markeredgewidth': [1.0, validate_float],
911911
'lines.markersize': [6, validate_float], # markersize, in points
912912
'lines.antialiased': [True, validate_bool], # antialiased (no jaggies)
@@ -922,10 +922,11 @@ def validate_animation_writer_path(p):
922922
'markers.fillstyle': ['full', validate_fillstyle],
923923

924924
## patch props
925-
'patch.linewidth': [None, validate_float_or_None], # line width in points
926-
'patch.edgecolor': ['k', validate_color], # black
927-
'patch.facecolor': ['C0', validate_color], # first color in color cycle
928-
'patch.antialiased': [True, validate_bool], # antialiased (no jaggies)
925+
'patch.linewidth': [1.0, validate_float], # line width in points
926+
'patch.edgecolor': ['k', validate_color],
927+
'patch.force_edgecolor' : [False, validate_bool],
928+
'patch.facecolor': ['C0', validate_color], # first color in cycle
929+
'patch.antialiased': [True, validate_bool], # antialiased (no jaggies)
929930

930931
## hatch props
931932
'hatch.linewidth': [1.0, validate_float],

‎lib/matplotlib/tests/test_artist.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_artist.py
+14-15Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -182,21 +182,20 @@ def test_remove():
182182
@image_comparison(baseline_images=["default_edges"], remove_text=True,
183183
extensions=['png'], style='default')
184184
def test_default_edges():
185-
with mpl.rc_context({'patch.linewidth': None}):
186-
fig, [[ax1, ax2], [ax3, ax4]] = plt.subplots(2, 2)
187-
188-
ax1.plot(np.arange(10), np.arange(10), 'x',
189-
np.arange(10) + 1, np.arange(10), 'o')
190-
ax2.bar(np.arange(10), np.arange(10))
191-
ax3.text(0, 0, "BOX", size=24, bbox=dict(boxstyle='sawtooth'))
192-
ax3.set_xlim((-1, 1))
193-
ax3.set_ylim((-1, 1))
194-
pp1 = mpatches.PathPatch(
195-
mpath.Path([(0, 0), (1, 0), (1, 1), (0, 0)],
196-
[mpath.Path.MOVETO, mpath.Path.CURVE3,
197-
mpath.Path.CURVE3, mpath.Path.CLOSEPOLY]),
198-
fc="none", transform=ax4.transData)
199-
ax4.add_patch(pp1)
185+
fig, [[ax1, ax2], [ax3, ax4]] = plt.subplots(2, 2)
186+
187+
ax1.plot(np.arange(10), np.arange(10), 'x',
188+
np.arange(10) + 1, np.arange(10), 'o')
189+
ax2.bar(np.arange(10), np.arange(10))
190+
ax3.text(0, 0, "BOX", size=24, bbox=dict(boxstyle='sawtooth'))
191+
ax3.set_xlim((-1, 1))
192+
ax3.set_ylim((-1, 1))
193+
pp1 = mpatches.PathPatch(
194+
mpath.Path([(0, 0), (1, 0), (1, 1), (0, 0)],
195+
[mpath.Path.MOVETO, mpath.Path.CURVE3,
196+
mpath.Path.CURVE3, mpath.Path.CLOSEPOLY]),
197+
fc="none", transform=ax4.transData)
198+
ax4.add_patch(pp1)
200199

201200

202201
@cleanup

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.