Skip to content

Backport PR #17499: Fix scatter singlecolor #17501

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
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
32 changes: 21 additions & 11 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4212,19 +4212,26 @@ def invalid_shape_exception(csize, xsize):
except ValueError:
pass # Failed to convert to float array; must be color specs.
else:
# handle the documented special case of a 2D array with 1
# row which as RGB(A) to broadcast.
if c.shape == (1, 4) or c.shape == (1, 3):
c_is_mapped = False
if c.size != xsize:
valid_shape = False
# If c can be either mapped values or a RGB(A) color, prefer
# the former if shapes match, the latter otherwise.
if c.size == xsize:
elif c.size == xsize:
c = c.ravel()
c_is_mapped = True
else: # Wrong size; it must not be intended for mapping.
if c.shape in ((3,), (4,)):
_log.warning(
"'c' argument looks like a single numeric RGB or "
"*c* argument looks like a single numeric RGB or "
"RGBA sequence, which should be avoided as value-"
"mapping will have precedence in case its length "
"matches with 'x' & 'y'. Please use a 2-D array "
"with a single row if you really want to specify "
"matches with *x* & *y*. Please use the *color* "
"keyword-argument or provide a 2-D array "
"with a single row if you intend to specify "
"the same RGB or RGBA value for all points.")
valid_shape = False
if not c_is_mapped:
Expand Down Expand Up @@ -4268,14 +4275,14 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
The marker size in points**2.
Default is ``rcParams['lines.markersize'] ** 2``.

c : color, sequence, or sequence of colors, optional
The marker color. Possible values:
c : array-like or list of colors or color, optional
The marker colors. Possible values:

- A single color format string.
- A sequence of colors of length n.
- A scalar or sequence of n numbers to be mapped to colors using
*cmap* and *norm*.
- A 2-D array in which the rows are RGB or RGBA.
- A sequence of colors of length n.
- A single color format string.

Note that *c* should not be a single numeric RGB or RGBA sequence
because that is indistinguishable from an array of values to be
Expand All @@ -4284,9 +4291,12 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
matching will have precedence in case of a size matching with *x*
and *y*.

Defaults to ``None``. In that case the marker color is determined
by the value of ``color``, ``facecolor`` or ``facecolors``. In case
those are not specified or ``None``, the marker color is determined
If you wish to specify a single color for all points
prefer the *color* keyword argument.

Defaults to `None`. In that case the marker color is determined
by the value of *color*, *facecolor* or *facecolors*. In case
those are not specified or `None`, the marker color is determined
by the next color of the ``Axes``' current "shape and fill" color
cycle. This cycle defaults to :rc:`axes.prop_cycle`.

Expand Down
16 changes: 16 additions & 0 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2088,6 +2088,22 @@ def get_next_color():
c=c_case, edgecolors="black", kwargs={}, xsize=xsize,
get_next_color_func=get_next_color)

@pytest.mark.style('default')
@check_figures_equal(extensions=["png"])
def test_scatter_single_color_c(self, fig_test, fig_ref):
rgb = [[1, 0.5, 0.05]]
rgba = [[1, 0.5, 0.05, .5]]

# set via color kwarg
ax_ref = fig_ref.subplots()
ax_ref.scatter(np.ones(3), range(3), color=rgb)
ax_ref.scatter(np.ones(4)*2, range(4), color=rgba)

# set via broadcasting via c
ax_test = fig_test.subplots()
ax_test.scatter(np.ones(3), range(3), c=rgb)
ax_test.scatter(np.ones(4)*2, range(4), c=rgba)


def _params(c=None, xsize=2, **kwargs):
edgecolors = kwargs.pop('edgecolors', None)
Expand Down