Skip to content

MNT: set the facecolor of nofill markers #17850

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

Merged
merged 1 commit into from
Jan 29, 2021
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4490,6 +4490,10 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
"s must be a scalar, "
"or float array-like with the same size as x and y")

# get the original edgecolor the user passed before we normalize
orig_edgecolor = edgecolors
if edgecolors is None:
orig_edgecolor = kwargs.get('edgecolor', None)
c, colors, edgecolors = \
self._parse_scatter_color_args(
c, edgecolors, kwargs, x.size,
Expand Down Expand Up @@ -4518,6 +4522,36 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
path = marker_obj.get_path().transformed(
marker_obj.get_transform())
if not marker_obj.is_filled():
if orig_edgecolor is not None:
_api.warn_external(
f"You passed a edgecolor/edgecolors ({orig_edgecolor!r}) "
f"for an unfilled marker ({marker!r}). Matplotlib is "
"ignoring the edgecolor in favor of the facecolor. This "
"behavior may change in the future."
)
# We need to handle markers that can not be filled (like
# '+' and 'x') differently than markers that can be
# filled, but have their fillstyle set to 'none'. This is
# to get:
#
# - respecting the fillestyle if set
# - maintaining back-compatibility for querying the facecolor of
# the un-fillable markers.
#
# While not an ideal situation, but is better than the
# alternatives.
if marker_obj.get_fillstyle() == 'none':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still somewhat confused why we need special-casing in the drawing function. Could this not be handled in the MarkerStyle so that MarkerStyle('o', fillstyle='none') and MarkerStyle('x') have an identical behavior?

# promote the facecolor to be the edgecolor
edgecolors = colors
# set the facecolor to 'none' (at the last chance) because
# we can not not fill a path if the facecolor is non-null.
# (which is defendable at the renderer level)
colors = 'none'
else:
# if we are not nulling the face color we can do this
# simpler
edgecolors = 'face'

if linewidths is None:
linewidths = rcParams['lines.linewidth']
elif np.iterable(linewidths):
Expand All @@ -4529,8 +4563,8 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,

collection = mcoll.PathCollection(
(path,), scales,
facecolors=colors if marker_obj.is_filled() else 'none',
edgecolors=edgecolors if marker_obj.is_filled() else colors,
facecolors=colors,
edgecolors=edgecolors,
linewidths=linewidths,
offsets=offsets,
transOffset=kwargs.pop('transform', self.transData),
Expand Down
21 changes: 21 additions & 0 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2145,6 +2145,17 @@ def test_scatter_unfilled(self):
[0.5, 0.5, 0.5, 1]])
assert_array_equal(coll.get_linewidths(), [1.1, 1.2, 1.3])

@pytest.mark.style('default')
def test_scatter_unfillable(self):
coll = plt.scatter([0, 1, 2], [1, 3, 2], c=['0.1', '0.3', '0.5'],
marker='x',
linewidths=[1.1, 1.2, 1.3])
assert_array_equal(coll.get_facecolors(), coll.get_edgecolors())
assert_array_equal(coll.get_edgecolors(), [[0.1, 0.1, 0.1, 1],
[0.3, 0.3, 0.3, 1],
[0.5, 0.5, 0.5, 1]])
assert_array_equal(coll.get_linewidths(), [1.1, 1.2, 1.3])

def test_scatter_size_arg_size(self):
x = np.arange(4)
with pytest.raises(ValueError, match='same size as x and y'):
Expand Down Expand Up @@ -6939,3 +6950,13 @@ def test_patch_bounds(): # PR 19078
bot = 1.9*np.sin(15*np.pi/180)**2
np.testing.assert_array_almost_equal_nulp(
np.array((-0.525, -(bot+0.05), 1.05, bot+0.1)), ax.dataLim.bounds, 16)


@pytest.mark.style('default')
def test_warn_ignored_scatter_kwargs():
with pytest.warns(UserWarning,
match=r"You passed a edgecolor/edgecolors"):

c = plt.scatter(
[0], [0], marker="+", s=500, facecolor="r", edgecolor="b"
)