Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commite3a8004

Browse files
authored
Merge pull request#11383 from afvincent/fix_scatter_error_color_shape_11373
ENH: Improve *c* (color) kwarg checking in scatter and the related exceptions
2 parents0545020 +e9cdfc0 commite3a8004

File tree

2 files changed

+155
-65
lines changed

2 files changed

+155
-65
lines changed

‎lib/matplotlib/axes/_axes.py

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3792,7 +3792,9 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
37923792
Note that *c* should not be a single numeric RGB or RGBA sequence
37933793
because that is indistinguishable from an array of values to be
37943794
colormapped. If you want to specify the same RGB or RGBA value for
3795-
all points, use a 2-D array with a single row.
3795+
all points, use a 2-D array with a single row. Otherwise, value-
3796+
matching will have precedence in case of a size matching with *x*
3797+
and *y*.
37963798
37973799
marker : `~matplotlib.markers.MarkerStyle`, optional, default: 'o'
37983800
The marker style. *marker* can be either an instance of the class
@@ -3876,15 +3878,15 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
38763878
exceptValueError:
38773879
raiseValueError("'color' kwarg must be an mpl color"
38783880
" spec or sequence of color specs.\n"
3879-
"For a sequence of values to be"
3880-
"color-mapped,use the 'c'kwarg instead.")
3881+
"For a sequence of values to be color-mapped,"
3882+
" use the 'c'argument instead.")
38813883
ifedgecolorsisNone:
38823884
edgecolors=co
38833885
iffacecolorsisNone:
38843886
facecolors=co
38853887
ifcisnotNone:
3886-
raiseValueError("Supply a 'c'kwarg or a 'color' kwarg"
3887-
" but not both; they differ but"
3888+
raiseValueError("Supply a 'c'argument or a 'color'"
3889+
"kwargbut not both; they differ but"
38883890
" their functionalities overlap.")
38893891
ifcisNone:
38903892
iffacecolorsisnotNone:
@@ -3925,29 +3927,60 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
39253927
# c is an array for mapping. The potential ambiguity
39263928
# with a sequence of 3 or 4 numbers is resolved in
39273929
# favor of mapping, not rgb or rgba.
3930+
3931+
# Convenience vars to track shape mismatch *and* conversion failures.
3932+
valid_shape=True# will be put to the test!
3933+
n_elem=-1# used only for (some) exceptions
3934+
39283935
ifc_noneorcoisnotNone:
39293936
c_array=None
39303937
else:
3931-
try:
3938+
try:# First, does 'c' look suitable for value-mapping?
39323939
c_array=np.asanyarray(c,dtype=float)
3940+
n_elem=c_array.shape[0]
39333941
ifc_array.shapeinxy_shape:
39343942
c=np.ma.ravel(c_array)
39353943
else:
3944+
ifc_array.shapein ((3,), (4,)):
3945+
_log.warning(
3946+
"'c' argument looks like a single numeric RGB or "
3947+
"RGBA sequence, which should be avoided as value-"
3948+
"mapping will have precedence in case its length "
3949+
"matches with 'x' & 'y'. Please use a 2-D array "
3950+
"with a single row if you really want to specify "
3951+
"the same RGB or RGBA value for all points.")
39363952
# Wrong size; it must not be intended for mapping.
3953+
valid_shape=False
39373954
c_array=None
39383955
exceptValueError:
39393956
# Failed to make a floating-point array; c must be color specs.
39403957
c_array=None
39413958

39423959
ifc_arrayisNone:
3943-
try:
3944-
# must be acceptable as PathCollection facecolors
3960+
try:# Then is 'c' acceptable as PathCollection facecolors?
39453961
colors=mcolors.to_rgba_array(c)
3962+
n_elem=colors.shape[0]
3963+
ifcolors.shape[0]notin (0,1,x.size,y.size):
3964+
# NB: remember that a single color is also acceptable.
3965+
# Besides *colors* will be an empty array if c == 'none'.
3966+
valid_shape=False
3967+
raiseValueError
39463968
exceptValueError:
3947-
# c not acceptable as PathCollection facecolor
3948-
raiseValueError("c of shape {} not acceptable as a color "
3949-
"sequence for x with size {}, y with size {}"
3950-
.format(c.shape,x.size,y.size))
3969+
ifnotvalid_shape:# but at least one conversion succeeded.
3970+
raiseValueError(
3971+
"'c' argument has {nc} elements, which is not "
3972+
"acceptable for use with 'x' with size {xs}, "
3973+
"'y' with size {ys}."
3974+
.format(nc=n_elem,xs=x.size,ys=y.size)
3975+
)
3976+
# Both the mapping *and* the RGBA conversion failed: pretty
3977+
# severe failure => one may appreciate a verbose feedback.
3978+
raiseValueError(
3979+
"'c' argument must either be valid as mpl color(s) "
3980+
"or as numbers to be mapped to colors. "
3981+
"Here c = {}."# <- beware, could be long depending on c.
3982+
.format(c)
3983+
)
39513984
else:
39523985
colors=None# use cmap, norm after collection is created
39533986

‎lib/matplotlib/tests/test_axes.py

Lines changed: 110 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,63 +1676,120 @@ def test_hist2d_transpose():
16761676
ax.hist2d(x,y,bins=10,rasterized=True)
16771677

16781678

1679-
@image_comparison(baseline_images=['scatter','scatter'])
1680-
deftest_scatter_plot():
1681-
fig,ax=plt.subplots()
1682-
data= {"x": [3,4,2,6],"y": [2,5,2,3],"c": ['r','y','b','lime'],
1683-
"s": [24,15,19,29]}
1684-
1685-
ax.scatter(data["x"],data["y"],c=data["c"],s=data["s"])
1686-
1687-
# Reuse testcase from above for a labeled data test
1688-
fig,ax=plt.subplots()
1689-
ax.scatter("x","y",c="c",s="s",data=data)
1679+
classTestScatter(object):
1680+
@image_comparison(baseline_images=['scatter','scatter'])
1681+
deftest_scatter_plot(self):
1682+
fig,ax=plt.subplots()
1683+
data= {"x": [3,4,2,6],"y": [2,5,2,3],
1684+
"c": ['r','y','b','lime'],"s": [24,15,19,29]}
16901685

1686+
ax.scatter(data["x"],data["y"],c=data["c"],s=data["s"])
16911687

1692-
@image_comparison(baseline_images=['scatter_marker'],remove_text=True,
1693-
extensions=['png'])
1694-
deftest_scatter_marker():
1695-
fig, (ax0,ax1,ax2)=plt.subplots(ncols=3)
1696-
ax0.scatter([3,4,2,6], [2,5,2,3],
1697-
c=[(1,0,0),'y','b','lime'],
1698-
s=[60,50,40,30],
1699-
edgecolors=['k','r','g','b'],
1700-
marker='s')
1701-
ax1.scatter([3,4,2,6], [2,5,2,3],
1702-
c=[(1,0,0),'y','b','lime'],
1703-
s=[60,50,40,30],
1704-
edgecolors=['k','r','g','b'],
1705-
marker=mmarkers.MarkerStyle('o',fillstyle='top'))
1706-
# unit area ellipse
1707-
rx,ry=3,1
1708-
area=rx*ry*np.pi
1709-
theta=np.linspace(0,2*np.pi,21)
1710-
verts=np.column_stack([np.cos(theta)*rx/area,
1711-
np.sin(theta)*ry/area])
1712-
ax2.scatter([3,4,2,6], [2,5,2,3],
1713-
c=[(1,0,0),'y','b','lime'],
1714-
s=[60,50,40,30],
1715-
edgecolors=['k','r','g','b'],
1716-
marker=verts)
1717-
1718-
1719-
@image_comparison(baseline_images=['scatter_2D'],remove_text=True,
1720-
extensions=['png'])
1721-
deftest_scatter_2D():
1722-
x=np.arange(3)
1723-
y=np.arange(2)
1724-
x,y=np.meshgrid(x,y)
1725-
z=x+y
1726-
fig,ax=plt.subplots()
1727-
ax.scatter(x,y,c=z,s=200,edgecolors='face')
1688+
# Reuse testcase from above for a labeled data test
1689+
fig,ax=plt.subplots()
1690+
ax.scatter("x","y",c="c",s="s",data=data)
1691+
1692+
@image_comparison(baseline_images=['scatter_marker'],remove_text=True,
1693+
extensions=['png'])
1694+
deftest_scatter_marker(self):
1695+
fig, (ax0,ax1,ax2)=plt.subplots(ncols=3)
1696+
ax0.scatter([3,4,2,6], [2,5,2,3],
1697+
c=[(1,0,0),'y','b','lime'],
1698+
s=[60,50,40,30],
1699+
edgecolors=['k','r','g','b'],
1700+
marker='s')
1701+
ax1.scatter([3,4,2,6], [2,5,2,3],
1702+
c=[(1,0,0),'y','b','lime'],
1703+
s=[60,50,40,30],
1704+
edgecolors=['k','r','g','b'],
1705+
marker=mmarkers.MarkerStyle('o',fillstyle='top'))
1706+
# unit area ellipse
1707+
rx,ry=3,1
1708+
area=rx*ry*np.pi
1709+
theta=np.linspace(0,2*np.pi,21)
1710+
verts=np.column_stack([np.cos(theta)*rx/area,
1711+
np.sin(theta)*ry/area])
1712+
ax2.scatter([3,4,2,6], [2,5,2,3],
1713+
c=[(1,0,0),'y','b','lime'],
1714+
s=[60,50,40,30],
1715+
edgecolors=['k','r','g','b'],
1716+
verts=verts)
1717+
1718+
@image_comparison(baseline_images=['scatter_2D'],remove_text=True,
1719+
extensions=['png'])
1720+
deftest_scatter_2D(self):
1721+
x=np.arange(3)
1722+
y=np.arange(2)
1723+
x,y=np.meshgrid(x,y)
1724+
z=x+y
1725+
fig,ax=plt.subplots()
1726+
ax.scatter(x,y,c=z,s=200,edgecolors='face')
1727+
1728+
deftest_scatter_color(self):
1729+
# Try to catch cases where 'c' kwarg should have been used.
1730+
withpytest.raises(ValueError):
1731+
plt.scatter([1,2], [1,2],color=[0.1,0.2])
1732+
withpytest.raises(ValueError):
1733+
plt.scatter([1,2,3], [1,2,3],color=[1,2,3])
1734+
1735+
# Parameters for *test_scatter_c*. NB: assuming that the
1736+
# scatter plot will have 4 elements. The tuple scheme is:
1737+
# (*c* parameter case, exception regexp key or None if no exception)
1738+
params_test_scatter_c= [
1739+
# Single letter-sequences
1740+
("rgby",None),
1741+
("rgb","shape"),
1742+
("rgbrgb","shape"),
1743+
(["rgby"],"conversion"),
1744+
# Special cases
1745+
("red",None),
1746+
("none",None),
1747+
(None,None),
1748+
(["r","g","b","none"],None),
1749+
# Non-valid color spec (FWIW, 'jaune' means yellow in French)
1750+
("jaune","conversion"),
1751+
(["jaune"],"conversion"),# wrong type before wrong size
1752+
(["jaune"]*4,"conversion"),
1753+
# Value-mapping like
1754+
([0.5]*3,None),# should emit a warning for user's eyes though
1755+
([0.5]*4,None),# NB: no warning as matching size allows mapping
1756+
([0.5]*5,"shape"),
1757+
# RGB values
1758+
([[1,0,0]],None),
1759+
([[1,0,0]]*3,"shape"),
1760+
([[1,0,0]]*4,None),
1761+
([[1,0,0]]*5,"shape"),
1762+
# RGBA values
1763+
([[1,0,0,0.5]],None),
1764+
([[1,0,0,0.5]]*3,"shape"),
1765+
([[1,0,0,0.5]]*4,None),
1766+
([[1,0,0,0.5]]*5,"shape"),
1767+
# Mix of valid color specs
1768+
([[1,0,0,0.5]]*3+ [[1,0,0]],None),
1769+
([[1,0,0,0.5],"red","0.0"],"shape"),
1770+
([[1,0,0,0.5],"red","0.0","C5"],None),
1771+
([[1,0,0,0.5],"red","0.0","C5", [0,1,0]],"shape"),
1772+
# Mix of valid and non valid color specs
1773+
([[1,0,0,0.5],"red","jaune"],"conversion"),
1774+
([[1,0,0,0.5],"red","0.0","jaune"],"conversion"),
1775+
([[1,0,0,0.5],"red","0.0","C5","jaune"],"conversion"),
1776+
]
17281777

1778+
@pytest.mark.parametrize('c_case, re_key',params_test_scatter_c)
1779+
deftest_scatter_c(self,c_case,re_key):
1780+
# Additional checking of *c* (introduced in #11383).
1781+
REGEXP= {
1782+
"shape":"^'c' argument has [0-9]+ elements",# shape mismatch
1783+
"conversion":"^'c' argument must either be valid",# bad vals
1784+
}
1785+
x=y= [0,1,2,3]
1786+
fig,ax=plt.subplots()
17291787

1730-
deftest_scatter_color():
1731-
# Try to catch cases where 'c' kwarg should have been used.
1732-
withpytest.raises(ValueError):
1733-
plt.scatter([1,2], [1,2],color=[0.1,0.2])
1734-
withpytest.raises(ValueError):
1735-
plt.scatter([1,2,3], [1,2,3],color=[1,2,3])
1788+
ifre_keyisNone:
1789+
ax.scatter(x,y,c=c_case,edgecolors="black")
1790+
else:
1791+
withpytest.raises(ValueError,match=REGEXP[re_key]):
1792+
ax.scatter(x,y,c=c_case,edgecolors="black")
17361793

17371794

17381795
deftest_as_mpl_axes_api():

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp