Skip to content

Navigation Menu

Sign in
Appearance settings

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 7bf436c

Browse filesBrowse files
committed
Merge pull request #6904 from efiring/scatter_edgecolor
MNT: Use edgecolor rather than linewidth to control edge display.
1 parent 9982e40 commit 7bf436c
Copy full SHA for 7bf436c

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
@@ -130,9 +130,10 @@ def __init__(self,
130130
# list of unbroadcast/scaled linewidths
131131
self._us_lw = [0]
132132
self._linewidths = [0]
133+
self._is_filled = True # May be modified by set_facecolor().
133134

134-
self.set_edgecolor(edgecolors)
135135
self.set_facecolor(facecolors)
136+
self.set_edgecolor(edgecolors)
136137
self.set_linewidth(linewidths)
137138
self.set_linestyle(linestyles)
138139
self.set_antialiased(antialiaseds)
@@ -494,14 +495,9 @@ def set_linewidth(self, lw):
494495
ACCEPTS: float or sequence of floats
495496
"""
496497
if lw is None:
497-
if (self._edge_default or
498-
mpl.rcParams['_internal.classic_mode'] or
499-
not self._is_filled):
500-
lw = mpl.rcParams['patch.linewidth']
501-
if lw is None:
502-
lw = mpl.rcParams['lines.linewidth']
503-
else:
504-
lw = 0
498+
lw = mpl.rcParams['patch.linewidth']
499+
if lw is None:
500+
lw = mpl.rcParams['lines.linewidth']
505501
# get the un-scaled/broadcast lw
506502
self._us_lw = self._get_value(lw)
507503

@@ -646,6 +642,20 @@ def set_color(self, c):
646642
self.set_facecolor(c)
647643
self.set_edgecolor(c)
648644

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

672674
def set_facecolors(self, c):
673675
"""alias for set_facecolor"""
@@ -685,38 +687,45 @@ def get_edgecolor(self):
685687
return self._edgecolors
686688
get_edgecolors = get_edgecolor
687689

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

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

750749
def get_linewidths(self):
751750
return self._linewidths
@@ -781,9 +780,9 @@ def update_from(self, other):
781780

782781
artist.Artist.update_from(self, other)
783782
self._antialiaseds = other._antialiaseds
784-
self._edgecolors_original = other._edgecolors_original
783+
self._original_edgecolor = other._original_edgecolor
785784
self._edgecolors = other._edgecolors
786-
self._facecolors_original = other._facecolors_original
785+
self._original_facecolor = other._original_facecolor
787786
self._facecolors = other._facecolors
788787
self._linewidths = other._linewidths
789788
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

@@ -891,7 +891,7 @@ def validate_hist_bins(s):
891891
'lines.linewidth': [1.5, validate_float], # line width in points
892892
'lines.linestyle': ['-', six.text_type], # solid line
893893
'lines.color': ['C0', validate_color], # first color in color cycle
894-
'lines.marker': ['None', six.text_type], # black
894+
'lines.marker': ['None', six.text_type], # marker name
895895
'lines.markeredgewidth': [1.0, validate_float],
896896
'lines.markersize': [6, validate_float], # markersize, in points
897897
'lines.antialiased': [True, validate_bool], # antialiased (no jaggies)
@@ -907,10 +907,11 @@ def validate_hist_bins(s):
907907
'markers.fillstyle': ['full', validate_fillstyle],
908908

909909
## patch props
910-
'patch.linewidth': [None, validate_float_or_None], # line width in points
911-
'patch.edgecolor': ['k', validate_color], # black
912-
'patch.facecolor': ['C0', validate_color], # first color in color cycle
913-
'patch.antialiased': [True, validate_bool], # antialiased (no jaggies)
910+
'patch.linewidth': [1.0, validate_float], # line width in points
911+
'patch.edgecolor': ['k', validate_color],
912+
'patch.force_edgecolor' : [False, validate_bool],
913+
'patch.facecolor': ['C0', validate_color], # first color in cycle
914+
'patch.antialiased': [True, validate_bool], # antialiased (no jaggies)
914915

915916
## hatch props
916917
'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
@@ -181,21 +181,20 @@ def test_remove():
181181
@image_comparison(baseline_images=["default_edges"], remove_text=True,
182182
extensions=['png'], style='default')
183183
def test_default_edges():
184-
with mpl.rc_context({'patch.linewidth': None}):
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)
184+
fig, [[ax1, ax2], [ax3, ax4]] = plt.subplots(2, 2)
185+
186+
ax1.plot(np.arange(10), np.arange(10), 'x',
187+
np.arange(10) + 1, np.arange(10), 'o')
188+
ax2.bar(np.arange(10), np.arange(10))
189+
ax3.text(0, 0, "BOX", size=24, bbox=dict(boxstyle='sawtooth'))
190+
ax3.set_xlim((-1, 1))
191+
ax3.set_ylim((-1, 1))
192+
pp1 = mpatches.PathPatch(
193+
mpath.Path([(0, 0), (1, 0), (1, 1), (0, 0)],
194+
[mpath.Path.MOVETO, mpath.Path.CURVE3,
195+
mpath.Path.CURVE3, mpath.Path.CLOSEPOLY]),
196+
fc="none", transform=ax4.transData)
197+
ax4.add_patch(pp1)
199198

200199

201200
@cleanup

0 commit comments

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