Skip to content

Commit 18cc8bf

Browse files
committed
scatter: fix marker kwarg bug. Closes matplotlib#4073, matplotlib#3895.
I also tried to clean up some of the scatter code and documentation, together with related documentation in collections. I added a test.
1 parent ee4f072 commit 18cc8bf

File tree

4 files changed

+66
-42
lines changed

4 files changed

+66
-42
lines changed

lib/matplotlib/axes/_axes.py

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3511,7 +3511,8 @@ def dopatch(xs, ys, **kwargs):
35113511
@docstring.dedent_interpd
35123512
def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None,
35133513
vmin=None, vmax=None, alpha=None, linewidths=None,
3514-
verts=None, **kwargs):
3514+
verts=None, edgecolors=None,
3515+
**kwargs):
35153516
"""
35163517
Make a scatter plot of x vs y, where x and y are sequence like objects
35173518
of the same lengths.
@@ -3531,11 +3532,14 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None,
35313532
(see below). Note that `c` should not be a single numeric RGB or
35323533
RGBA sequence because that is indistinguishable from an array of
35333534
values to be colormapped. `c` can be a 2-D array in which the
3534-
rows are RGB or RGBA, however.
3535+
rows are RGB or RGBA, however, including the case of a single
3536+
row to specify the same color for all points.
35353537
35363538
marker : `~matplotlib.markers.MarkerStyle`, optional, default: 'o'
35373539
See `~matplotlib.markers` for more information on the different
3538-
styles of markers scatter supports.
3540+
styles of markers scatter supports. `marker` can be either
3541+
an instance of the class or the text shorthand for a particular
3542+
marker.
35393543
35403544
cmap : `~matplotlib.colors.Colormap`, optional, default: None
35413545
A `~matplotlib.colors.Colormap` instance or registered name.
@@ -3557,10 +3561,14 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None,
35573561
The alpha blending value, between 0 (transparent) and 1 (opaque)
35583562
35593563
linewidths : scalar or array_like, optional, default: None
3560-
If None, defaults to (lines.linewidth,). Note that this is a
3561-
tuple, and if you set the linewidths argument you must set it as a
3562-
sequence of floats, as required by
3563-
`~matplotlib.collections.RegularPolyCollection`.
3564+
If None, defaults to (lines.linewidth,).
3565+
3566+
edgecolors : color or sequence of color, optional, default: None
3567+
If None, defaults to (patch.edgecolor).
3568+
If 'face', the edge color will always be the same as
3569+
the face color. If it is 'none', the patch boundary will not
3570+
be drawn. For non-filled markers, the `edgecolors` kwarg
3571+
is ignored; color is determined by `c`.
35643572
35653573
Returns
35663574
-------
@@ -3598,43 +3606,41 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None,
35983606

35993607
s = np.ma.ravel(s) # This doesn't have to match x, y in size.
36003608

3601-
c_is_stringy = is_string_like(c) or is_sequence_of_strings(c)
3602-
if not c_is_stringy:
3603-
c = np.asanyarray(c)
3604-
if c.size == x.size:
3605-
c = np.ma.ravel(c)
3609+
# After this block, c_array will be None unless
3610+
# c is an array for mapping. The potential ambiguity
3611+
# with a sequence of 3 or 4 numbers is resolved in
3612+
# favor mapping, not rgb or rgba.
3613+
try:
3614+
c_array = np.asanyarray(c, dtype=float)
3615+
if c_array.shape == x.shape:
3616+
c = np.ma.ravel(c_array)
3617+
else:
3618+
# Wrong shape; it must not be intended for mapping.
3619+
c_array = None
3620+
except ValueError:
3621+
# Failed to make a floating-point array; c must be color specs.
3622+
c_array = None
3623+
3624+
if c_array is None:
3625+
colors = c # must be acceptable as PathCollection facecolors
3626+
else:
3627+
colors = None # use cmap, norm after collection is created
36063628

3629+
# c will be unchanged unless it is the same length as x:
36073630
x, y, s, c = cbook.delete_masked_points(x, y, s, c)
36083631

36093632
scales = s # Renamed for readability below.
36103633

3611-
if c_is_stringy:
3612-
colors = mcolors.colorConverter.to_rgba_array(c, alpha)
3613-
else:
3614-
# The inherent ambiguity is resolved in favor of color
3615-
# mapping, not interpretation as rgb or rgba:
3616-
if c.size == x.size:
3617-
colors = None # use cmap, norm after collection is created
3618-
else:
3619-
colors = mcolors.colorConverter.to_rgba_array(c, alpha)
3620-
3621-
faceted = kwargs.pop('faceted', None)
3622-
edgecolors = kwargs.get('edgecolors', None)
3623-
if faceted is not None:
3624-
cbook.warn_deprecated(
3625-
'1.2', name='faceted', alternative='edgecolor',
3626-
obj_type='option')
3627-
if faceted:
3628-
edgecolors = None
3629-
else:
3630-
edgecolors = 'none'
3631-
36323634
# to be API compatible
36333635
if marker is None and not (verts is None):
36343636
marker = (verts, 0)
36353637
verts = None
36363638

3637-
marker_obj = mmarkers.MarkerStyle(marker)
3639+
if isinstance(marker, mmarkers.MarkerStyle):
3640+
marker_obj = marker
3641+
else:
3642+
marker_obj = mmarkers.MarkerStyle(marker)
3643+
36383644
path = marker_obj.get_path().transformed(
36393645
marker_obj.get_transform())
36403646
if not marker_obj.is_filled():
@@ -3649,9 +3655,9 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None,
36493655
linewidths=linewidths,
36503656
offsets=offsets,
36513657
transOffset=kwargs.pop('transform', self.transData),
3658+
alpha=alpha
36523659
)
36533660
collection.set_transform(mtransforms.IdentityTransform())
3654-
collection.set_alpha(alpha)
36553661
collection.update(kwargs)
36563662

36573663
if colors is None:

lib/matplotlib/collections.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -559,13 +559,13 @@ def set_color(self, c):
559559
def set_facecolor(self, c):
560560
"""
561561
Set the facecolor(s) of the collection. *c* can be a
562-
matplotlib color arg (all patches have same color), or a
563-
sequence of rgba tuples; if it is a sequence the patches will
562+
matplotlib color spec (all patches have same color), or a
563+
sequence of specs; if it is a sequence the patches will
564564
cycle through the sequence.
565565
566566
If *c* is 'none', the patch will not be filled.
567567
568-
ACCEPTS: matplotlib color arg or sequence of rgba tuples
568+
ACCEPTS: matplotlib color spec or sequence of specs
569569
"""
570570
self._is_filled = True
571571
try:
@@ -596,15 +596,15 @@ def get_edgecolor(self):
596596
def set_edgecolor(self, c):
597597
"""
598598
Set the edgecolor(s) of the collection. *c* can be a
599-
matplotlib color arg (all patches have same color), or a
600-
sequence of rgba tuples; if it is a sequence the patches will
599+
matplotlib color spec (all patches have same color), or a
600+
sequence of specs; if it is a sequence the patches will
601601
cycle through the sequence.
602602
603603
If *c* is 'face', the edge color will always be the same as
604604
the face color. If it is 'none', the patch boundary will not
605605
be drawn.
606606
607-
ACCEPTS: matplotlib color arg or sequence of rgba tuples
607+
ACCEPTS: matplotlib color spec or sequence of specs
608608
"""
609609
self._is_stroked = True
610610
try:
Loading

lib/matplotlib/tests/test_axes.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import matplotlib
1717
from matplotlib.testing.decorators import image_comparison, cleanup
1818
import matplotlib.pyplot as plt
19+
import matplotlib.markers as mmarkers
1920
from numpy.testing import assert_array_equal
2021
import warnings
2122

@@ -1091,7 +1092,24 @@ def test_hist2d_transpose():
10911092
@image_comparison(baseline_images=['scatter'])
10921093
def test_scatter_plot():
10931094
ax = plt.axes()
1094-
ax.scatter([3, 4, 2, 6], [2, 5, 2, 3], c=['r', 'y', 'b', 'lime'], s=[24, 15, 19, 29])
1095+
ax.scatter([3, 4, 2, 6], [2, 5, 2, 3],
1096+
c=['r', 'y', 'b', 'lime'], s=[24, 15, 19, 29])
1097+
1098+
1099+
@image_comparison(baseline_images=['scatter_marker'], remove_text=True,
1100+
extensions=['png'])
1101+
def test_scatter_marker():
1102+
fig, (ax0, ax1) = plt.subplots(ncols=2)
1103+
ax0.scatter([3, 4, 2, 6], [2, 5, 2, 3],
1104+
c=[(1, 0, 0), 'y', 'b', 'lime'],
1105+
s=[60, 50, 40, 30],
1106+
edgecolors=['k', 'r', 'g', 'b'],
1107+
marker='s')
1108+
ax1.scatter([3, 4, 2, 6], [2, 5, 2, 3],
1109+
c=[(1, 0, 0), 'y', 'b', 'lime'],
1110+
s=[60, 50, 40, 30],
1111+
edgecolors=['k', 'r', 'g', 'b'],
1112+
marker=mmarkers.MarkerStyle('o', fillstyle='top'))
10951113

10961114

10971115
@cleanup

0 commit comments

Comments
 (0)