2
2
import itertools
3
3
import logging
4
4
import math
5
+ import operator
5
6
from numbers import Number
6
7
import warnings
7
8
@@ -3760,6 +3761,146 @@ def dopatch(xs, ys, **kwargs):
3760
3761
return dict (whiskers = whiskers , caps = caps , boxes = boxes ,
3761
3762
medians = medians , fliers = fliers , means = means )
3762
3763
3764
+ def _parse_scatter_color_args (self , c , edgecolors , kwargs , xshape , yshape ):
3765
+ """
3766
+ Helper function to process color related arguments of `.Axes.scatter`.
3767
+
3768
+ Argument precedence for facecolors:
3769
+
3770
+ - c (if not None)
3771
+ - kwargs['facecolors']
3772
+ - kwargs['facecolor']
3773
+ - kwargs['color'] (==kwcolor)
3774
+ - 'b' if in classic mode else next color from color cycle
3775
+
3776
+ Argument precedence for edgecolors:
3777
+
3778
+ - edgecolors (is an explicit kw argument in scatter())
3779
+ - kwargs['edgecolor']
3780
+ - kwargs['color'] (==kwcolor)
3781
+ - 'face' if not in classic mode else None
3782
+
3783
+ Arguments
3784
+ ---------
3785
+ c : color or sequence or sequence of color or None
3786
+ See argument description of `.Axes.scatter`.
3787
+ edgecolors : color or sequence of color or {'face', 'none'} or None
3788
+ See argument description of `.Axes.scatter`.
3789
+ kwargs : dict
3790
+ Additional kwargs. If these keys exist, we pop and process them:
3791
+ 'facecolors', 'facecolor', 'edgecolor', 'color'
3792
+ Note: The dict is modified by this function.
3793
+ xshape, yshape : tuple of int
3794
+ The shape of the x and y arrays passed to `.Axes.scatter`.
3795
+
3796
+ Returns
3797
+ -------
3798
+ c
3799
+ The input *c* if it was not *None*, else some color specification
3800
+ derived from the other inputs or defaults.
3801
+ colors : array(N, 4) or None
3802
+ The facecolors as RGBA values or *None* if a colormap is used.
3803
+ edgecolors
3804
+ The edgecolor specification.
3805
+
3806
+ """
3807
+ xsize = functools .reduce (operator .mul , xshape , 1 )
3808
+ ysize = functools .reduce (operator .mul , yshape , 1 )
3809
+
3810
+ facecolors = kwargs .pop ('facecolors' , None )
3811
+ facecolors = kwargs .pop ('facecolor' , facecolors )
3812
+ edgecolors = kwargs .pop ('edgecolor' , edgecolors )
3813
+
3814
+ kwcolor = kwargs .pop ('color' , None )
3815
+
3816
+ if kwcolor is not None and c is not None :
3817
+ raise ValueError ("Supply a 'c' argument or a 'color'"
3818
+ " kwarg but not both; they differ but"
3819
+ " their functionalities overlap." )
3820
+
3821
+ if kwcolor is not None :
3822
+ try :
3823
+ mcolors .to_rgba_array (kwcolor )
3824
+ except ValueError :
3825
+ raise ValueError ("'color' kwarg must be an mpl color"
3826
+ " spec or sequence of color specs.\n "
3827
+ "For a sequence of values to be color-mapped,"
3828
+ " use the 'c' argument instead." )
3829
+ if edgecolors is None :
3830
+ edgecolors = kwcolor
3831
+ if facecolors is None :
3832
+ facecolors = kwcolor
3833
+
3834
+ if edgecolors is None and not rcParams ['_internal.classic_mode' ]:
3835
+ edgecolors = 'face'
3836
+
3837
+ c_is_none = c is None
3838
+ if c is None :
3839
+ if facecolors is not None :
3840
+ c = facecolors
3841
+ else :
3842
+ c = ('b' if rcParams ['_internal.classic_mode' ] else
3843
+ self ._get_patches_for_fill .get_next_color ())
3844
+
3845
+ # After this block, c_array will be None unless
3846
+ # c is an array for mapping. The potential ambiguity
3847
+ # with a sequence of 3 or 4 numbers is resolved in
3848
+ # favor of mapping, not rgb or rgba.
3849
+ # Convenience vars to track shape mismatch *and* conversion failures.
3850
+ valid_shape = True # will be put to the test!
3851
+ n_elem = - 1 # used only for (some) exceptions
3852
+ if c_is_none or kwcolor is not None :
3853
+ c_array = None
3854
+ else :
3855
+ try : # First, does 'c' look suitable for value-mapping?
3856
+ c_array = np .asanyarray (c , dtype = float )
3857
+ n_elem = c_array .shape [0 ]
3858
+ if c_array .shape in [xshape , yshape ]:
3859
+ c = np .ma .ravel (c_array )
3860
+ else :
3861
+ if c_array .shape in ((3 ,), (4 ,)):
3862
+ _log .warning (
3863
+ "'c' argument looks like a single numeric RGB or "
3864
+ "RGBA sequence, which should be avoided as value-"
3865
+ "mapping will have precedence in case its length "
3866
+ "matches with 'x' & 'y'. Please use a 2-D array "
3867
+ "with a single row if you really want to specify "
3868
+ "the same RGB or RGBA value for all points." )
3869
+ # Wrong size; it must not be intended for mapping.
3870
+ valid_shape = False
3871
+ c_array = None
3872
+ except ValueError :
3873
+ # Failed to make a floating-point array; c must be color specs.
3874
+ c_array = None
3875
+ if c_array is None :
3876
+ try : # Then is 'c' acceptable as PathCollection facecolors?
3877
+ colors = mcolors .to_rgba_array (c )
3878
+ n_elem = colors .shape [0 ]
3879
+ if colors .shape [0 ] not in (0 , 1 , xsize , ysize ):
3880
+ # NB: remember that a single color is also acceptable.
3881
+ # Besides *colors* will be an empty array if c == 'none'.
3882
+ valid_shape = False
3883
+ raise ValueError
3884
+ except ValueError :
3885
+ if not valid_shape : # but at least one conversion succeeded.
3886
+ raise ValueError (
3887
+ "'c' argument has {nc} elements, which is not "
3888
+ "acceptable for use with 'x' with size {xs}, "
3889
+ "'y' with size {ys}."
3890
+ .format (nc = n_elem , xs = xsize , ys = ysize )
3891
+ )
3892
+ # Both the mapping *and* the RGBA conversion failed: pretty
3893
+ # severe failure => one may appreciate a verbose feedback.
3894
+ raise ValueError (
3895
+ "'c' argument must either be valid as mpl color(s) "
3896
+ "or as numbers to be mapped to colors. "
3897
+ "Here c = {}." # <- beware, could be long depending on c.
3898
+ .format (c )
3899
+ )
3900
+ else :
3901
+ colors = None # use cmap, norm after collection is created
3902
+ return c , colors , edgecolors
3903
+
3763
3904
@_preprocess_data (replace_names = ["x" , "y" , "s" , "linewidths" ,
3764
3905
"edgecolors" , "c" , "facecolor" ,
3765
3906
"facecolors" , "color" ],
@@ -3865,124 +4006,27 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
3865
4006
3866
4007
"""
3867
4008
# Process **kwargs to handle aliases, conflicts with explicit kwargs:
3868
- facecolors = None
3869
- edgecolors = kwargs .pop ('edgecolor' , edgecolors )
3870
- fc = kwargs .pop ('facecolors' , None )
3871
- fc = kwargs .pop ('facecolor' , fc )
3872
- if fc is not None :
3873
- facecolors = fc
3874
- co = kwargs .pop ('color' , None )
3875
- if co is not None :
3876
- try :
3877
- mcolors .to_rgba_array (co )
3878
- except ValueError :
3879
- raise ValueError ("'color' kwarg must be an mpl color"
3880
- " spec or sequence of color specs.\n "
3881
- "For a sequence of values to be color-mapped,"
3882
- " use the 'c' argument instead." )
3883
- if edgecolors is None :
3884
- edgecolors = co
3885
- if facecolors is None :
3886
- facecolors = co
3887
- if c is not None :
3888
- raise ValueError ("Supply a 'c' argument or a 'color'"
3889
- " kwarg but not both; they differ but"
3890
- " their functionalities overlap." )
3891
- if c is None :
3892
- if facecolors is not None :
3893
- c = facecolors
3894
- else :
3895
- if rcParams ['_internal.classic_mode' ]:
3896
- c = 'b' # The original default
3897
- else :
3898
- c = self ._get_patches_for_fill .get_next_color ()
3899
- c_none = True
3900
- else :
3901
- c_none = False
3902
-
3903
- if edgecolors is None and not rcParams ['_internal.classic_mode' ]:
3904
- edgecolors = 'face'
3905
4009
3906
4010
self ._process_unit_info (xdata = x , ydata = y , kwargs = kwargs )
3907
4011
x = self .convert_xunits (x )
3908
4012
y = self .convert_yunits (y )
3909
4013
3910
4014
# np.ma.ravel yields an ndarray, not a masked array,
3911
4015
# unless its argument is a masked array.
3912
- xy_shape = ( np .shape (x ), np .shape (y ) )
4016
+ xshape , yshape = np .shape (x ), np .shape (y )
3913
4017
x = np .ma .ravel (x )
3914
4018
y = np .ma .ravel (y )
3915
4019
if x .size != y .size :
3916
4020
raise ValueError ("x and y must be the same size" )
3917
4021
3918
4022
if s is None :
3919
- if rcParams ['_internal.classic_mode' ]:
3920
- s = 20
3921
- else :
3922
- s = rcParams ['lines.markersize' ] ** 2.0
3923
-
4023
+ s = (20 if rcParams ['_internal.classic_mode' ] else
4024
+ rcParams ['lines.markersize' ] ** 2.0 )
3924
4025
s = np .ma .ravel (s ) # This doesn't have to match x, y in size.
3925
4026
3926
- # After this block, c_array will be None unless
3927
- # c is an array for mapping. The potential ambiguity
3928
- # with a sequence of 3 or 4 numbers is resolved in
3929
- # 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
-
3935
- if c_none or co is not None :
3936
- c_array = None
3937
- else :
3938
- try : # First, does 'c' look suitable for value-mapping?
3939
- c_array = np .asanyarray (c , dtype = float )
3940
- n_elem = c_array .shape [0 ]
3941
- if c_array .shape in xy_shape :
3942
- c = np .ma .ravel (c_array )
3943
- else :
3944
- if c_array .shape in ((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." )
3952
- # Wrong size; it must not be intended for mapping.
3953
- valid_shape = False
3954
- c_array = None
3955
- except ValueError :
3956
- # Failed to make a floating-point array; c must be color specs.
3957
- c_array = None
3958
-
3959
- if c_array is None :
3960
- try : # Then is 'c' acceptable as PathCollection facecolors?
3961
- colors = mcolors .to_rgba_array (c )
3962
- n_elem = colors .shape [0 ]
3963
- if colors .shape [0 ] not in (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
- raise ValueError
3968
- except ValueError :
3969
- if not valid_shape : # but at least one conversion succeeded.
3970
- raise ValueError (
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
- raise ValueError (
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
- )
3984
- else :
3985
- colors = None # use cmap, norm after collection is created
4027
+ c , colors , edgecolors = \
4028
+ self ._parse_scatter_color_args (c , edgecolors , kwargs ,
4029
+ xshape , yshape )
3986
4030
3987
4031
# `delete_masked_points` only modifies arguments of the same length as
3988
4032
# `x`.
0 commit comments