3
3
import itertools
4
4
import logging
5
5
import math
6
+ import operator
6
7
from numbers import Number
7
8
import warnings
8
9
@@ -4004,6 +4005,151 @@ def dopatch(xs, ys, **kwargs):
4004
4005
return dict (whiskers = whiskers , caps = caps , boxes = boxes ,
4005
4006
medians = medians , fliers = fliers , means = means )
4006
4007
4008
+ def _parse_scatter_color_args (self , c , edgecolors , kwargs , xshape , yshape ):
4009
+ """
4010
+ Helper function to process color related arguments of `.Axes.scatter`.
4011
+
4012
+ Argument precedence for facecolors:
4013
+
4014
+ - c (if not None)
4015
+ - kwargs['facecolors']
4016
+ - kwargs['facecolor']
4017
+ - kwargs['color'] (==kwcolor)
4018
+ - 'b' if in classic mode else next color from color cycle
4019
+
4020
+ Argument precedence for edgecolors:
4021
+
4022
+ - edgecolors (is an explicit kw argument in scatter())
4023
+ - kwargs['edgecolor']
4024
+ - kwargs['color'] (==kwcolor)
4025
+ - 'face' if not in classic mode else None
4026
+
4027
+ Arguments
4028
+ ---------
4029
+ c : color or sequence or sequence of color or None
4030
+ See argument description of `.Axes.scatter`.
4031
+ edgecolors : color or sequence of color or {'face', 'none'} or None
4032
+ See argument description of `.Axes.scatter`.
4033
+ kwargs : dict
4034
+ Additional kwargs. If these keys exist, we pop and process them:
4035
+ 'facecolors', 'facecolor', 'edgecolor', 'color'
4036
+ Note: The dict is modified by this function.
4037
+ xshape, yshape : tuple of int
4038
+ The shape of the x and y arrays passed to `.Axes.scatter`.
4039
+
4040
+ Returns
4041
+ -------
4042
+ c
4043
+ The input *c* if it was not *None*, else some color specification
4044
+ derived from the other inputs or defaults.
4045
+ colors : array(N, 4) or None
4046
+ The facecolors as RGBA values or *None* if a colormap is used.
4047
+ edgecolors
4048
+ The edgecolor specification.
4049
+
4050
+ """
4051
+ xsize = functools .reduce (operator .mul , xshape , 1 )
4052
+ ysize = functools .reduce (operator .mul , yshape , 1 )
4053
+
4054
+ facecolors = kwargs .pop ('facecolors' , None )
4055
+ facecolors = kwargs .pop ('facecolor' , facecolors )
4056
+ edgecolors = kwargs .pop ('edgecolor' , edgecolors )
4057
+
4058
+ kwcolor = kwargs .pop ('color' , None )
4059
+
4060
+ if kwcolor is not None and c is not None :
4061
+ raise ValueError ("Supply a 'c' argument or a 'color'"
4062
+ " kwarg but not both; they differ but"
4063
+ " their functionalities overlap." )
4064
+
4065
+ if kwcolor is not None :
4066
+ try :
4067
+ mcolors .to_rgba_array (kwcolor )
4068
+ except ValueError :
4069
+ raise ValueError ("'color' kwarg must be an mpl color"
4070
+ " spec or sequence of color specs.\n "
4071
+ "For a sequence of values to be color-mapped,"
4072
+ " use the 'c' argument instead." )
4073
+ if edgecolors is None :
4074
+ edgecolors = kwcolor
4075
+ if facecolors is None :
4076
+ facecolors = kwcolor
4077
+
4078
+ if edgecolors is None and not rcParams ['_internal.classic_mode' ]:
4079
+ edgecolors = 'face'
4080
+
4081
+ c_is_none = c is None
4082
+ if c is None :
4083
+ if facecolors is not None :
4084
+ c = facecolors
4085
+ else :
4086
+ c = ('b' if rcParams ['_internal.classic_mode' ] else
4087
+ self ._get_patches_for_fill .get_next_color ())
4088
+
4089
+ # After this block, c_array will be None unless
4090
+ # c is an array for mapping. The potential ambiguity
4091
+ # with a sequence of 3 or 4 numbers is resolved in
4092
+ # favor of mapping, not rgb or rgba.
4093
+ # Convenience vars to track shape mismatch *and* conversion failures.
4094
+ valid_shape = True # will be put to the test!
4095
+ n_elem = - 1 # used only for (some) exceptions
4096
+
4097
+ if (c_is_none or
4098
+ kwcolor is not None or
4099
+ isinstance (c , str ) or
4100
+ (isinstance (c , collections .abc .Iterable ) and
4101
+ isinstance (c [0 ], str ))):
4102
+ c_array = None
4103
+ else :
4104
+ try : # First, does 'c' look suitable for value-mapping?
4105
+ c_array = np .asanyarray (c , dtype = float )
4106
+ n_elem = c_array .shape [0 ]
4107
+ if c_array .shape in [xshape , yshape ]:
4108
+ c = np .ma .ravel (c_array )
4109
+ else :
4110
+ if c_array .shape in ((3 ,), (4 ,)):
4111
+ _log .warning (
4112
+ "'c' argument looks like a single numeric RGB or "
4113
+ "RGBA sequence, which should be avoided as value-"
4114
+ "mapping will have precedence in case its length "
4115
+ "matches with 'x' & 'y'. Please use a 2-D array "
4116
+ "with a single row if you really want to specify "
4117
+ "the same RGB or RGBA value for all points." )
4118
+ # Wrong size; it must not be intended for mapping.
4119
+ valid_shape = False
4120
+ c_array = None
4121
+ except ValueError :
4122
+ # Failed to make a floating-point array; c must be color specs.
4123
+ c_array = None
4124
+ if c_array is None :
4125
+ try : # Then is 'c' acceptable as PathCollection facecolors?
4126
+ colors = mcolors .to_rgba_array (c )
4127
+ n_elem = colors .shape [0 ]
4128
+ if colors .shape [0 ] not in (0 , 1 , xsize , ysize ):
4129
+ # NB: remember that a single color is also acceptable.
4130
+ # Besides *colors* will be an empty array if c == 'none'.
4131
+ valid_shape = False
4132
+ raise ValueError
4133
+ except ValueError :
4134
+ if not valid_shape : # but at least one conversion succeeded.
4135
+ raise ValueError (
4136
+ "'c' argument has {nc} elements, which is not "
4137
+ "acceptable for use with 'x' with size {xs}, "
4138
+ "'y' with size {ys}."
4139
+ .format (nc = n_elem , xs = xsize , ys = ysize )
4140
+ )
4141
+ # Both the mapping *and* the RGBA conversion failed: pretty
4142
+ # severe failure => one may appreciate a verbose feedback.
4143
+ raise ValueError (
4144
+ "'c' argument must either be valid as mpl color(s) "
4145
+ "or as numbers to be mapped to colors. "
4146
+ "Here c = {}." # <- beware, could be long depending on c.
4147
+ .format (c )
4148
+ )
4149
+ else :
4150
+ colors = None # use cmap, norm after collection is created
4151
+ return c , colors , edgecolors
4152
+
4007
4153
@_preprocess_data (replace_names = ["x" , "y" , "s" , "linewidths" ,
4008
4154
"edgecolors" , "c" , "facecolor" ,
4009
4155
"facecolors" , "color" ],
@@ -4117,128 +4263,27 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
4117
4263
4118
4264
"""
4119
4265
# Process **kwargs to handle aliases, conflicts with explicit kwargs:
4120
- facecolors = None
4121
- edgecolors = kwargs .pop ('edgecolor' , edgecolors )
4122
- fc = kwargs .pop ('facecolors' , None )
4123
- fc = kwargs .pop ('facecolor' , fc )
4124
- if fc is not None :
4125
- facecolors = fc
4126
- co = kwargs .pop ('color' , None )
4127
- if co is not None :
4128
- try :
4129
- mcolors .to_rgba_array (co )
4130
- except ValueError :
4131
- raise ValueError ("'color' kwarg must be an mpl color"
4132
- " spec or sequence of color specs.\n "
4133
- "For a sequence of values to be color-mapped,"
4134
- " use the 'c' argument instead." )
4135
- if edgecolors is None :
4136
- edgecolors = co
4137
- if facecolors is None :
4138
- facecolors = co
4139
- if c is not None :
4140
- raise ValueError ("Supply a 'c' argument or a 'color'"
4141
- " kwarg but not both; they differ but"
4142
- " their functionalities overlap." )
4143
- if c is None :
4144
- if facecolors is not None :
4145
- c = facecolors
4146
- else :
4147
- if rcParams ['_internal.classic_mode' ]:
4148
- c = 'b' # The original default
4149
- else :
4150
- c = self ._get_patches_for_fill .get_next_color ()
4151
- c_none = True
4152
- else :
4153
- c_none = False
4154
-
4155
- if edgecolors is None and not rcParams ['_internal.classic_mode' ]:
4156
- edgecolors = 'face'
4157
4266
4158
4267
self ._process_unit_info (xdata = x , ydata = y , kwargs = kwargs )
4159
4268
x = self .convert_xunits (x )
4160
4269
y = self .convert_yunits (y )
4161
4270
4162
4271
# np.ma.ravel yields an ndarray, not a masked array,
4163
4272
# unless its argument is a masked array.
4164
- xy_shape = ( np .shape (x ), np .shape (y ) )
4273
+ xshape , yshape = np .shape (x ), np .shape (y )
4165
4274
x = np .ma .ravel (x )
4166
4275
y = np .ma .ravel (y )
4167
4276
if x .size != y .size :
4168
4277
raise ValueError ("x and y must be the same size" )
4169
4278
4170
4279
if s is None :
4171
- if rcParams ['_internal.classic_mode' ]:
4172
- s = 20
4173
- else :
4174
- s = rcParams ['lines.markersize' ] ** 2.0
4175
-
4280
+ s = (20 if rcParams ['_internal.classic_mode' ] else
4281
+ rcParams ['lines.markersize' ] ** 2.0 )
4176
4282
s = np .ma .ravel (s ) # This doesn't have to match x, y in size.
4177
4283
4178
- # After this block, c_array will be None unless
4179
- # c is an array for mapping. The potential ambiguity
4180
- # with a sequence of 3 or 4 numbers is resolved in
4181
- # favor of mapping, not rgb or rgba.
4182
-
4183
- # Convenience vars to track shape mismatch *and* conversion failures.
4184
- valid_shape = True # will be put to the test!
4185
- n_elem = - 1 # used only for (some) exceptions
4186
-
4187
- if (c_none or
4188
- co is not None or
4189
- isinstance (c , str ) or
4190
- (isinstance (c , collections .abc .Iterable ) and
4191
- isinstance (c [0 ], str ))):
4192
- c_array = None
4193
- else :
4194
- try : # First, does 'c' look suitable for value-mapping?
4195
- c_array = np .asanyarray (c , dtype = float )
4196
- n_elem = c_array .shape [0 ]
4197
- if c_array .shape in xy_shape :
4198
- c = np .ma .ravel (c_array )
4199
- else :
4200
- if c_array .shape in ((3 ,), (4 ,)):
4201
- _log .warning (
4202
- "'c' argument looks like a single numeric RGB or "
4203
- "RGBA sequence, which should be avoided as value-"
4204
- "mapping will have precedence in case its length "
4205
- "matches with 'x' & 'y'. Please use a 2-D array "
4206
- "with a single row if you really want to specify "
4207
- "the same RGB or RGBA value for all points." )
4208
- # Wrong size; it must not be intended for mapping.
4209
- valid_shape = False
4210
- c_array = None
4211
- except ValueError :
4212
- # Failed to make a floating-point array; c must be color specs.
4213
- c_array = None
4214
-
4215
- if c_array is None :
4216
- try : # Then is 'c' acceptable as PathCollection facecolors?
4217
- colors = mcolors .to_rgba_array (c )
4218
- n_elem = colors .shape [0 ]
4219
- if colors .shape [0 ] not in (0 , 1 , x .size , y .size ):
4220
- # NB: remember that a single color is also acceptable.
4221
- # Besides *colors* will be an empty array if c == 'none'.
4222
- valid_shape = False
4223
- raise ValueError
4224
- except ValueError :
4225
- if not valid_shape : # but at least one conversion succeeded.
4226
- raise ValueError (
4227
- "'c' argument has {nc} elements, which is not "
4228
- "acceptable for use with 'x' with size {xs}, "
4229
- "'y' with size {ys}."
4230
- .format (nc = n_elem , xs = x .size , ys = y .size )
4231
- )
4232
- # Both the mapping *and* the RGBA conversion failed: pretty
4233
- # severe failure => one may appreciate a verbose feedback.
4234
- raise ValueError (
4235
- "'c' argument must either be valid as mpl color(s) "
4236
- "or as numbers to be mapped to colors. "
4237
- "Here c = {}." # <- beware, could be long depending on c.
4238
- .format (c )
4239
- )
4240
- else :
4241
- colors = None # use cmap, norm after collection is created
4284
+ c , colors , edgecolors = \
4285
+ self ._parse_scatter_color_args (c , edgecolors , kwargs ,
4286
+ xshape , yshape )
4242
4287
4243
4288
# `delete_masked_points` only modifies arguments of the same length as
4244
4289
# `x`.
0 commit comments