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 c582e83

Browse filesBrowse 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
Copy full SHA for c582e83

File tree

Expand file treeCollapse file tree

2 files changed

+55
-2
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+55
-2
lines changed

‎lib/matplotlib/axes/_axes.py

Copy file name to clipboardExpand all lines: lib/matplotlib/axes/_axes.py
+34-2Lines changed: 34 additions & 2 deletions
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

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_axes.py
+21Lines changed: 21 additions & 0 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.