Skip to content

Commit c582e83

Browse files
committed
MNT: use get_fillstyle not is_filled to null facecolor
This is brittle, but matches the behavior in Line2D. MarkerStyle objects have two coupled, but not fully redundant methods for determining if the maker is filled: the `is_filled` and `get_fillstyle` methods. If `ms.get_fillstyle() == 'none'` then `ms.is_filled() is False`, however the converse is not True. In particular the markers that can not be filled (because the Paths they are made out of can not be closed) have `ms.get_fillstyle() == 'full'` and `ms.is_filled() is False`. In Line2D we filter on the value of `get_fillstyle` not on `is_filled` so do the same in `Axes.scatter`. In Line2D we do the validation at draw time (because Line2D holds onto its MarkerStyle object instead of just extracting the path). The logic for fillstyle on Markers came in via #447/ 213459e. closes #17849 Revises #17543 / d86cc2b
1 parent 506b108 commit c582e83

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

lib/matplotlib/axes/_axes.py

+34-2
Original file line numberDiff line numberDiff line change
@@ -4365,6 +4365,8 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
43654365
"s must be a scalar, "
43664366
"or float array-like with the same size as x and y")
43674367

4368+
# get the original edgecolor the user passed before we normalize
4369+
orig_edgecolor = edgecolors or kwargs.get('edgecolor', None)
43684370
c, colors, edgecolors = \
43694371
self._parse_scatter_color_args(
43704372
c, edgecolors, kwargs, x.size,
@@ -4393,6 +4395,36 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
43934395
path = marker_obj.get_path().transformed(
43944396
marker_obj.get_transform())
43954397
if not marker_obj.is_filled():
4398+
if orig_edgecolor is not None:
4399+
cbook._warn_external(
4400+
f"You passed a edgecolor/edgecolors ({orig_edgecolor!r}) "
4401+
f"for an unfilled marker ({marker!r}). Matplotlib is "
4402+
"ignoring the edge color in favor of the facecolor. This "
4403+
"behavior may change in the future."
4404+
)
4405+
# We need to handle markers that can not be filled (like
4406+
# '+' and 'x') differently than markers that can be
4407+
# filled, but have their fillstyle set to 'none'. This is
4408+
# to get:
4409+
#
4410+
# - respecting the fillestyle if set
4411+
# - maintaining back-compatibility for querying the facecolor of
4412+
# the un-fillable markers.
4413+
#
4414+
# While not an ideal situation, but is better than the
4415+
# alternatives.
4416+
if marker_obj.get_fillstyle() == 'none':
4417+
# promote the face color to be the edgecolor
4418+
edgecolors = colors
4419+
# set the facecolor to None (at the last chance) because
4420+
# we can not not fill a path if the facecolor is non-null.
4421+
# (which is defendable at the renderer level)
4422+
colors = 'none'
4423+
else:
4424+
# if we are not nulling the face color we can do this
4425+
# simpler
4426+
edgecolors = 'face'
4427+
43964428
if linewidths is None:
43974429
linewidths = rcParams['lines.linewidth']
43984430
elif np.iterable(linewidths):
@@ -4404,8 +4436,8 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
44044436

44054437
collection = mcoll.PathCollection(
44064438
(path,), scales,
4407-
facecolors=colors if marker_obj.is_filled() else 'none',
4408-
edgecolors=edgecolors if marker_obj.is_filled() else colors,
4439+
facecolors=colors,
4440+
edgecolors=edgecolors,
44094441
linewidths=linewidths,
44104442
offsets=offsets,
44114443
transOffset=kwargs.pop('transform', self.transData),

lib/matplotlib/tests/test_axes.py

+21
Original file line numberDiff line numberDiff line change
@@ -2134,6 +2134,17 @@ def test_scatter_unfilled(self):
21342134
[0.5, 0.5, 0.5, 1]])
21352135
assert_array_equal(coll.get_linewidths(), [1.1, 1.2, 1.3])
21362136

2137+
@pytest.mark.style('default')
2138+
def test_scatter_unfillable(self):
2139+
coll = plt.scatter([0, 1, 2], [1, 3, 2], c=['0.1', '0.3', '0.5'],
2140+
marker='x',
2141+
linewidths=[1.1, 1.2, 1.3])
2142+
assert_array_equal(coll.get_facecolors(), coll.get_edgecolors())
2143+
assert_array_equal(coll.get_edgecolors(), [[0.1, 0.1, 0.1, 1],
2144+
[0.3, 0.3, 0.3, 1],
2145+
[0.5, 0.5, 0.5, 1]])
2146+
assert_array_equal(coll.get_linewidths(), [1.1, 1.2, 1.3])
2147+
21372148
def test_scatter_size_arg_size(self):
21382149
x = np.arange(4)
21392150
with pytest.raises(ValueError, match='same size as x and y'):
@@ -6824,3 +6835,13 @@ def test_ylabel_ha_with_position(ha):
68246835
ax.set_ylabel("test", y=1, ha=ha)
68256836
ax.yaxis.set_label_position("right")
68266837
assert ax.yaxis.get_label().get_ha() == ha
6838+
6839+
6840+
@pytest.mark.style('default')
6841+
def test_warn_ignored_scatter_kwargs():
6842+
with pytest.warns(UserWarning,
6843+
match=r"You passed a edgecolor/edgecolors"):
6844+
6845+
c = plt.scatter(
6846+
[0], [0], marker="+", s=500, facecolor="r", edgecolor="b"
6847+
)

0 commit comments

Comments
 (0)