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