Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a89443c

Browse files
tacaswelltimhoffm
andcommitted
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 Co-authored-by: Tim Hoffmann <[email protected]>
1 parent 947f1b8 commit a89443c

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

lib/matplotlib/axes/_axes.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4490,6 +4490,8 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
44904490
"s must be a scalar, "
44914491
"or float array-like with the same size as x and y")
44924492

4493+
# get the original edgecolor the user passed before we normalize
4494+
orig_edgecolor = edgecolors or kwargs.get('edgecolor', None)
44934495
c, colors, edgecolors = \
44944496
self._parse_scatter_color_args(
44954497
c, edgecolors, kwargs, x.size,
@@ -4518,6 +4520,36 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
45184520
path = marker_obj.get_path().transformed(
45194521
marker_obj.get_transform())
45204522
if not marker_obj.is_filled():
4523+
if orig_edgecolor is not None:
4524+
_api._warn_external(
4525+
f"You passed a edgecolor/edgecolors ({orig_edgecolor!r}) "
4526+
f"for an unfilled marker ({marker!r}). Matplotlib is "
4527+
"ignoring the edgecolor in favor of the facecolor. This "
4528+
"behavior may change in the future."
4529+
)
4530+
# We need to handle markers that can not be filled (like
4531+
# '+' and 'x') differently than markers that can be
4532+
# filled, but have their fillstyle set to 'none'. This is
4533+
# to get:
4534+
#
4535+
# - respecting the fillestyle if set
4536+
# - maintaining back-compatibility for querying the facecolor of
4537+
# the un-fillable markers.
4538+
#
4539+
# While not an ideal situation, but is better than the
4540+
# alternatives.
4541+
if marker_obj.get_fillstyle() == 'none':
4542+
# promote the facecolor to be the edgecolor
4543+
edgecolors = colors
4544+
# set the facecolor to 'none' (at the last chance) because
4545+
# we can not not fill a path if the facecolor is non-null.
4546+
# (which is defendable at the renderer level)
4547+
colors = 'none'
4548+
else:
4549+
# if we are not nulling the face color we can do this
4550+
# simpler
4551+
edgecolors = 'face'
4552+
45214553
if linewidths is None:
45224554
linewidths = rcParams['lines.linewidth']
45234555
elif np.iterable(linewidths):
@@ -4529,8 +4561,8 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
45294561

45304562
collection = mcoll.PathCollection(
45314563
(path,), scales,
4532-
facecolors=colors if marker_obj.is_filled() else 'none',
4533-
edgecolors=edgecolors if marker_obj.is_filled() else colors,
4564+
facecolors=colors,
4565+
edgecolors=edgecolors,
45344566
linewidths=linewidths,
45354567
offsets=offsets,
45364568
transOffset=kwargs.pop('transform', self.transData),

lib/matplotlib/tests/test_axes.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,6 +2145,17 @@ def test_scatter_unfilled(self):
21452145
[0.5, 0.5, 0.5, 1]])
21462146
assert_array_equal(coll.get_linewidths(), [1.1, 1.2, 1.3])
21472147

2148+
@pytest.mark.style('default')
2149+
def test_scatter_unfillable(self):
2150+
coll = plt.scatter([0, 1, 2], [1, 3, 2], c=['0.1', '0.3', '0.5'],
2151+
marker='x',
2152+
linewidths=[1.1, 1.2, 1.3])
2153+
assert_array_equal(coll.get_facecolors(), coll.get_edgecolors())
2154+
assert_array_equal(coll.get_edgecolors(), [[0.1, 0.1, 0.1, 1],
2155+
[0.3, 0.3, 0.3, 1],
2156+
[0.5, 0.5, 0.5, 1]])
2157+
assert_array_equal(coll.get_linewidths(), [1.1, 1.2, 1.3])
2158+
21482159
def test_scatter_size_arg_size(self):
21492160
x = np.arange(4)
21502161
with pytest.raises(ValueError, match='same size as x and y'):
@@ -6931,3 +6942,13 @@ def test_patch_bounds(): # PR 19078
69316942
bot = 1.9*np.sin(15*np.pi/180)**2
69326943
np.testing.assert_array_almost_equal_nulp(
69336944
np.array((-0.525, -(bot+0.05), 1.05, bot+0.1)), ax.dataLim.bounds, 16)
6945+
6946+
6947+
@pytest.mark.style('default')
6948+
def test_warn_ignored_scatter_kwargs():
6949+
with pytest.warns(UserWarning,
6950+
match=r"You passed a edgecolor/edgecolors"):
6951+
6952+
c = plt.scatter(
6953+
[0], [0], marker="+", s=500, facecolor="r", edgecolor="b"
6954+
)

0 commit comments

Comments
 (0)