Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use edgecolor rather than linewidth to control edge display. #6904

Merged
merged 3 commits into from Aug 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
103 changes: 51 additions & 52 deletions lib/matplotlib/collections.py
Expand Up @@ -128,9 +128,10 @@ def __init__(self,
# list of unbroadcast/scaled linewidths
self._us_lw = [0]
self._linewidths = [0]
self._is_filled = True # May be modified by set_facecolor().

self.set_edgecolor(edgecolors)
self.set_facecolor(facecolors)
self.set_edgecolor(edgecolors)
self.set_linewidth(linewidths)
self.set_linestyle(linestyles)
self.set_antialiased(antialiaseds)
Expand Down Expand Up @@ -492,14 +493,9 @@ def set_linewidth(self, lw):
ACCEPTS: float or sequence of floats
"""
if lw is None:
if (self._edge_default or
mpl.rcParams['_internal.classic_mode'] or
not self._is_filled):
lw = mpl.rcParams['patch.linewidth']
if lw is None:
lw = mpl.rcParams['lines.linewidth']
else:
lw = 0
lw = mpl.rcParams['patch.linewidth']
if lw is None:
lw = mpl.rcParams['lines.linewidth']
# get the un-scaled/broadcast lw
self._us_lw = self._get_value(lw)

Expand Down Expand Up @@ -644,6 +640,20 @@ def set_color(self, c):
self.set_facecolor(c)
self.set_edgecolor(c)

def _set_facecolor(self, c):
if c is None:
c = mpl.rcParams['patch.facecolor']

self._is_filled = True
try:
if c.lower() == 'none':
self._is_filled = False
except AttributeError:
pass
self._facecolors = mcolors.to_rgba_array(c, self._alpha)
self.stale = True


def set_facecolor(self, c):
"""
Set the facecolor(s) of the collection. *c* can be a
Expand All @@ -655,17 +665,9 @@ def set_facecolor(self, c):

ACCEPTS: matplotlib color spec or sequence of specs
"""
self._is_filled = True
try:
if c.lower() == 'none':
self._is_filled = False
except AttributeError:
pass
if c is None:
c = mpl.rcParams['patch.facecolor']
self._facecolors_original = c
self._facecolors = mcolors.to_rgba_array(c, self._alpha)
self.stale = True
self._original_facecolor = c
self._set_facecolor(c)


def set_facecolors(self, c):
"""alias for set_facecolor"""
Expand All @@ -683,38 +685,45 @@ def get_edgecolor(self):
return self._edgecolors
get_edgecolors = get_edgecolor

def set_edgecolor(self, c):
"""
Set the edgecolor(s) of the collection. *c* can be a
matplotlib color spec (all patches have same color), or a
sequence of specs; if it is a sequence the patches will
cycle through the sequence.

If *c* is 'face', the edge color will always be the same as
the face color. If it is 'none', the patch boundary will not
be drawn.

ACCEPTS: matplotlib color spec or sequence of specs
"""
def _set_edgecolor(self, c):
if c is None:
if (mpl.rcParams['patch.force_edgecolor'] or
not self._is_filled or self._edge_default):
c = mpl.rcParams['patch.edgecolor']
else:
c = 'none'
self._is_stroked = True
try:
if c.lower() == 'none':
self._is_stroked = False
except AttributeError:
pass

try:
if c.lower() == 'face':
if c.lower() == 'face': # Special case: lookup in "get" method.
self._edgecolors = 'face'
self._edgecolors_original = 'face'
return
except AttributeError:
pass
if c is None:
c = mpl.rcParams['patch.edgecolor']
self._edgecolors_original = c
self._edgecolors = mcolors.to_rgba_array(c, self._alpha)
self.stale = True

def set_edgecolor(self, c):
"""
Set the edgecolor(s) of the collection. *c* can be a
matplotlib color spec (all patches have same color), or a
sequence of specs; if it is a sequence the patches will
cycle through the sequence.

If *c* is 'face', the edge color will always be the same as
the face color. If it is 'none', the patch boundary will not
be drawn.

ACCEPTS: matplotlib color spec or sequence of specs
"""
self._original_edgecolor = c
self._set_edgecolor(c)

def set_edgecolors(self, c):
"""alias for set_edgecolor"""
return self.set_edgecolor(c)
Expand All @@ -732,18 +741,8 @@ def set_alpha(self, alpha):
except TypeError:
raise TypeError('alpha must be a float or None')
artist.Artist.set_alpha(self, alpha)
try:
self._facecolors = mcolors.to_rgba_array(
self._facecolors_original, self._alpha)
except (AttributeError, TypeError, IndexError):
pass
try:
if (not isinstance(self._edgecolors_original, six.string_types)
or self._edgecolors_original != str('face')):
self._edgecolors = mcolors.to_rgba_array(
self._edgecolors_original, self._alpha)
except (AttributeError, TypeError, IndexError):
pass
self._set_facecolor(self._original_facecolor)
self._set_edgecolor(self._original_edgecolor)

def get_linewidths(self):
return self._linewidths
Expand Down Expand Up @@ -779,9 +778,9 @@ def update_from(self, other):

artist.Artist.update_from(self, other)
self._antialiaseds = other._antialiaseds
self._edgecolors_original = other._edgecolors_original
self._original_edgecolor = other._original_edgecolor
self._edgecolors = other._edgecolors
self._facecolors_original = other._facecolors_original
self._original_facecolor = other._original_facecolor
self._facecolors = other._facecolors
self._linewidths = other._linewidths
self._linestyles = other._linestyles
Expand Down
1 change: 1 addition & 0 deletions lib/matplotlib/mpl-data/stylelib/classic.mplstyle
Expand Up @@ -29,6 +29,7 @@ markers.fillstyle: full
# information on patch properties
patch.linewidth : 1.0 # edge width in points
patch.facecolor : b
patch.force_edgecolor : True
patch.edgecolor : k
patch.antialiased : True # render patches in antialiased (no jaggies)

Expand Down
78 changes: 42 additions & 36 deletions lib/matplotlib/patches.py
Expand Up @@ -154,18 +154,26 @@ def get_verts(self):
return polygons[0]
return []

def _process_radius(self, radius):
if radius is not None:
return radius
if cbook.is_numlike(self._picker):
_radius = self._picker
else:
if self.get_edgecolor()[3] == 0:
_radius = 0
else:
_radius = self.get_linewidth()
return _radius

def contains(self, mouseevent, radius=None):
"""Test whether the mouse event occurred in the patch.

Returns T/F, {}
"""
if six.callable(self._contains):
return self._contains(self, mouseevent)
if radius is None:
if cbook.is_numlike(self._picker):
radius = self._picker
else:
radius = self.get_linewidth()
radius = self._process_radius(radius)
inside = self.get_path().contains_point(
(mouseevent.x, mouseevent.y), self.get_transform(), radius)
return inside, {}
Expand All @@ -175,11 +183,7 @@ def contains_point(self, point, radius=None):
Returns *True* if the given point is inside the path
(transformed with its transform attribute).
"""
if radius is None:
if cbook.is_numlike(self._picker):
radius = self._picker
else:
radius = self.get_linewidth()
radius = self._process_radius(radius)
return self.get_path().contains_point(point,
self.get_transform(),
radius)
Expand Down Expand Up @@ -281,37 +285,44 @@ def set_aa(self, aa):
"""alias for set_antialiased"""
return self.set_antialiased(aa)

def _set_edgecolor(self, color):
if color is None:
if (mpl.rcParams['patch.force_edgecolor'] or
not self._fill or self._edge_default):
color = mpl.rcParams['patch.edgecolor']
else:
color = 'none'
self._edgecolor = colors.to_rgba(color, self._alpha)
self.stale = True

def set_edgecolor(self, color):
"""
Set the patch edge color

ACCEPTS: mpl color spec, or None for default, or 'none' for no color
ACCEPTS: mpl color spec, None, 'none', or 'auto'
"""
if color is None:
color = mpl.rcParams['patch.edgecolor']
self._original_edgecolor = color
self._edgecolor = colors.to_rgba(color, self._alpha)
self.stale = True
self._set_edgecolor(color)

def set_ec(self, color):
"""alias for set_edgecolor"""
return self.set_edgecolor(color)

def _set_facecolor(self, color):
if color is None:
color = mpl.rcParams['patch.facecolor']
alpha = self._alpha if self._fill else 0
self._facecolor = colors.to_rgba(color, alpha)
self.stale = True

def set_facecolor(self, color):
"""
Set the patch face color

ACCEPTS: mpl color spec, or None for default, or 'none' for no color
"""
if color is None:
color = mpl.rcParams['patch.facecolor']
# save: otherwise changing _fill may lose alpha information
self._original_facecolor = color
self._facecolor = colors.to_rgba(color, self._alpha)
if not self._fill:
self._facecolor = list(self._facecolor)
self._facecolor[3] = 0
self.stale = True
self._set_facecolor(color)

def set_fc(self, color):
"""alias for set_facecolor"""
Expand Down Expand Up @@ -343,10 +354,9 @@ def set_alpha(self, alpha):
except TypeError:
raise TypeError('alpha must be a float or None')
artist.Artist.set_alpha(self, alpha)
# using self._fill and self._alpha
self.set_facecolor(self._original_facecolor)
self.set_edgecolor(self._original_edgecolor)
self.stale = True
self._set_facecolor(self._facecolor)
self._set_edgecolor(self._original_edgecolor)
# stale is already True

def set_linewidth(self, w):
"""
Expand All @@ -355,14 +365,9 @@ def set_linewidth(self, w):
ACCEPTS: float or None for default
"""
if w is None:
if (not self._fill or
self._edge_default or
mpl.rcParams['_internal.classic_mode']):
w = mpl.rcParams['patch.linewidth']
if w is None:
w = mpl.rcParams['axes.linewidth']
else:
w = 0
w = mpl.rcParams['patch.linewidth']
if w is None:
w = mpl.rcParams['axes.linewidth']

self._linewidth = float(w)
# scale the dash pattern by the linewidth
Expand Down Expand Up @@ -428,7 +433,8 @@ def set_fill(self, b):
ACCEPTS: [True | False]
"""
self._fill = bool(b)
self.set_facecolor(self._original_facecolor)
self._set_facecolor(self._original_facecolor)
self._set_edgecolor(self._original_edgecolor)
self.stale = True

def get_fill(self):
Expand Down
13 changes: 7 additions & 6 deletions lib/matplotlib/rcsetup.py
Expand Up @@ -364,7 +364,7 @@ def validate_color(s):
'return a valid color arg'
try:
if s.lower() == 'none':
return 'None'
return 'none'
except AttributeError:
pass

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

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

## hatch props
'hatch.linewidth': [1.0, validate_float],
Expand Down
29 changes: 14 additions & 15 deletions lib/matplotlib/tests/test_artist.py
Expand Up @@ -182,21 +182,20 @@ def test_remove():
@image_comparison(baseline_images=["default_edges"], remove_text=True,
extensions=['png'], style='default')
def test_default_edges():
with mpl.rc_context({'patch.linewidth': None}):
fig, [[ax1, ax2], [ax3, ax4]] = plt.subplots(2, 2)

ax1.plot(np.arange(10), np.arange(10), 'x',
np.arange(10) + 1, np.arange(10), 'o')
ax2.bar(np.arange(10), np.arange(10))
ax3.text(0, 0, "BOX", size=24, bbox=dict(boxstyle='sawtooth'))
ax3.set_xlim((-1, 1))
ax3.set_ylim((-1, 1))
pp1 = mpatches.PathPatch(
mpath.Path([(0, 0), (1, 0), (1, 1), (0, 0)],
[mpath.Path.MOVETO, mpath.Path.CURVE3,
mpath.Path.CURVE3, mpath.Path.CLOSEPOLY]),
fc="none", transform=ax4.transData)
ax4.add_patch(pp1)
fig, [[ax1, ax2], [ax3, ax4]] = plt.subplots(2, 2)

ax1.plot(np.arange(10), np.arange(10), 'x',
np.arange(10) + 1, np.arange(10), 'o')
ax2.bar(np.arange(10), np.arange(10))
ax3.text(0, 0, "BOX", size=24, bbox=dict(boxstyle='sawtooth'))
ax3.set_xlim((-1, 1))
ax3.set_ylim((-1, 1))
pp1 = mpatches.PathPatch(
mpath.Path([(0, 0), (1, 0), (1, 1), (0, 0)],
[mpath.Path.MOVETO, mpath.Path.CURVE3,
mpath.Path.CURVE3, mpath.Path.CLOSEPOLY]),
fc="none", transform=ax4.transData)
ax4.add_patch(pp1)


@cleanup
Expand Down