2020import warnings
2121
2222
23+ # "color" is excluded; it is a compound setter, and its docstring differs
24+ # in LineCollection.
2325@cbook ._define_aliases ({
2426 "antialiased" : ["antialiaseds" , "aa" ],
2527 "edgecolor" : ["edgecolors" , "ec" ],
@@ -168,8 +170,10 @@ def __init__(self,
168170 # list of unbroadcast/scaled linewidths
169171 self ._us_lw = [0 ]
170172 self ._linewidths = [0 ]
171- self ._is_filled = True # May be modified by set_facecolor().
172-
173+ # Flags set by _set_mappable_flags: are colors from mapping an array?
174+ self ._face_is_mapped = None
175+ self ._edge_is_mapped = None
176+ self ._mapped_colors = None # calculated in update_scalarmappable
173177 self ._hatch_color = mcolors .to_rgba (mpl .rcParams ['hatch.color' ])
174178 self .set_facecolor (facecolors )
175179 self .set_edgecolor (edgecolors )
@@ -586,6 +590,10 @@ def get_offset_position(self):
586590 """
587591 return self ._offset_position
588592
593+ def _get_default_linewidth (self ):
594+ # This may be overridden in a subclass.
595+ return mpl .rcParams ['patch.linewidth' ] # validated as float
596+
589597 def set_linewidth (self , lw ):
590598 """
591599 Set the linewidth(s) for the collection. *lw* can be a scalar
@@ -597,9 +605,7 @@ def set_linewidth(self, lw):
597605 lw : float or list of floats
598606 """
599607 if lw is None :
600- lw = mpl .rcParams ['patch.linewidth' ]
601- if lw is None :
602- lw = mpl .rcParams ['lines.linewidth' ]
608+ lw = self ._get_default_linewidth ()
603609 # get the un-scaled/broadcast lw
604610 self ._us_lw = np .atleast_1d (np .asarray (lw ))
605611
@@ -730,10 +736,14 @@ def set_antialiased(self, aa):
730736 aa : bool or list of bools
731737 """
732738 if aa is None :
733- aa = mpl . rcParams [ 'patch.antialiased' ]
739+ aa = self . _get_default_antialiased ()
734740 self ._antialiaseds = np .atleast_1d (np .asarray (aa , bool ))
735741 self .stale = True
736742
743+ def _get_default_antialiased (self ):
744+ # This may be overridden in a subclass.
745+ return mpl .rcParams ['patch.antialiased' ]
746+
737747 def set_color (self , c ):
738748 """
739749 Set both the edgecolor and the facecolor.
@@ -750,16 +760,14 @@ def set_color(self, c):
750760 self .set_facecolor (c )
751761 self .set_edgecolor (c )
752762
763+ def _get_default_facecolor (self ):
764+ # This may be overridden in a subclass.
765+ return mpl .rcParams ['patch.facecolor' ]
766+
753767 def _set_facecolor (self , c ):
754768 if c is None :
755- c = mpl . rcParams [ 'patch.facecolor' ]
769+ c = self . _get_default_facecolor ()
756770
757- self ._is_filled = True
758- try :
759- if c .lower () == 'none' :
760- self ._is_filled = False
761- except AttributeError :
762- pass
763771 self ._facecolors = mcolors .to_rgba_array (c , self ._alpha )
764772 self .stale = True
765773
@@ -775,6 +783,8 @@ def set_facecolor(self, c):
775783 ----------
776784 c : color or list of colors
777785 """
786+ if isinstance (c , str ) and c .lower () in ("none" , "face" ):
787+ c = c .lower ()
778788 self ._original_facecolor = c
779789 self ._set_facecolor (c )
780790
@@ -787,29 +797,24 @@ def get_edgecolor(self):
787797 else :
788798 return self ._edgecolors
789799
800+ def _get_default_edgecolor (self ):
801+ # This may be overridden in a subclass.
802+ return mpl .rcParams ['patch.edgecolor' ]
803+
790804 def _set_edgecolor (self , c ):
791805 set_hatch_color = True
792806 if c is None :
793- if (mpl .rcParams ['patch.force_edgecolor' ] or
794- not self ._is_filled or self ._edge_default ):
795- c = mpl .rcParams ['patch.edgecolor' ]
807+ if (mpl .rcParams ['patch.force_edgecolor' ]
808+ or self ._edge_default
809+ or cbook ._str_equal (self ._original_facecolor , 'none' )):
810+ c = self ._get_default_edgecolor ()
796811 else :
797812 c = 'none'
798813 set_hatch_color = False
799-
800- self ._is_stroked = True
801- try :
802- if c .lower () == 'none' :
803- self ._is_stroked = False
804- except AttributeError :
805- pass
806-
807- try :
808- if c .lower () == 'face' : # Special case: lookup in "get" method.
809- self ._edgecolors = 'face'
810- return
811- except AttributeError :
812- pass
814+ if cbook ._str_lower_equal (c , 'face' ):
815+ self ._edgecolors = 'face'
816+ self .stale = True
817+ return
813818 self ._edgecolors = mcolors .to_rgba_array (c , self ._alpha )
814819 if set_hatch_color and len (self ._edgecolors ):
815820 self ._hatch_color = tuple (self ._edgecolors [0 ])
@@ -825,6 +830,11 @@ def set_edgecolor(self, c):
825830 The collection edgecolor(s). If a sequence, the patches cycle
826831 through it. If 'face', match the facecolor.
827832 """
833+ # We pass through a default value for use in LineCollection.
834+ # This allows us to maintain None as the default indicator in
835+ # _original_edgecolor.
836+ if isinstance (c , str ) and c .lower () in ("none" , "face" ):
837+ c = c .lower ()
828838 self ._original_edgecolor = c
829839 self ._set_edgecolor (c )
830840
@@ -853,36 +863,81 @@ def get_linewidth(self):
853863 def get_linestyle (self ):
854864 return self ._linestyles
855865
866+ def _set_mappable_flags (self ):
867+ """
868+ Determine whether edges and/or faces are color-mapped.
869+
870+ This is a helper for update_scalarmappable.
871+ It sets Boolean flags '_edge_is_mapped' and '_face_is_mapped'.
872+
873+ Returns
874+ -------
875+ mapping_change : bool
876+ True if either flag is True, or if a flag has changed.
877+ """
878+ # The flags are initialized to None to ensure this returns True
879+ # the first time it is called.
880+ edge0 = self ._edge_is_mapped
881+ face0 = self ._face_is_mapped
882+ # After returning, the flags must be Booleans, not None.
883+ self ._edge_is_mapped = False
884+ self ._face_is_mapped = False
885+ if self ._A is not None :
886+ if not cbook ._str_equal (self ._original_facecolor , 'none' ):
887+ self ._face_is_mapped = True
888+ if cbook ._str_equal (self ._original_edgecolor , 'face' ):
889+ self ._edge_is_mapped = True
890+ else :
891+ if self ._original_edgecolor is None :
892+ self ._edge_is_mapped = True
893+
894+ mapped = self ._face_is_mapped or self ._edge_is_mapped
895+ changed = (edge0 is None or face0 is None
896+ or self ._edge_is_mapped != edge0
897+ or self ._face_is_mapped != face0 )
898+ return mapped or changed
899+
856900 def update_scalarmappable (self ):
857- """Update colors from the scalar mappable array, if it is not None."""
858- if self . _A is None :
859- return
860- # QuadMesh can map 2d arrays (but pcolormesh supplies 1d array)
861- if self . _A . ndim > 1 and not isinstance ( self , QuadMesh ):
862- raise ValueError ( 'Collections can only map rank 1 arrays' )
863- if not self ._check_update ( "array" ):
901+ """
902+ Update colors from the scalar mappable array, if any.
903+
904+ Assign colors to edges and faces based on the array and/or
905+ colors that were directly set, as appropriate.
906+ """
907+ if not self ._set_mappable_flags ( ):
864908 return
865- if np .iterable (self ._alpha ):
866- if self ._alpha .size != self ._A .size :
867- raise ValueError (f'Data array shape, { self ._A .shape } '
868- 'is incompatible with alpha array shape, '
869- f'{ self ._alpha .shape } . '
870- 'This can occur with the deprecated '
871- 'behavior of the "flat" shading option, '
872- 'in which a row and/or column of the data '
873- 'array is dropped.' )
874- # pcolormesh, scatter, maybe others flatten their _A
875- self ._alpha = self ._alpha .reshape (self ._A .shape )
876-
877- if self ._is_filled :
878- self ._facecolors = self .to_rgba (self ._A , self ._alpha )
879- elif self ._is_stroked :
880- self ._edgecolors = self .to_rgba (self ._A , self ._alpha )
909+ # Allow possibility to call 'self.set_array(None)'.
910+ if self ._check_update ("array" ) and self ._A is not None :
911+ # QuadMesh can map 2d arrays (but pcolormesh supplies 1d array)
912+ if self ._A .ndim > 1 and not isinstance (self , QuadMesh ):
913+ raise ValueError ('Collections can only map rank 1 arrays' )
914+ if np .iterable (self ._alpha ):
915+ if self ._alpha .size != self ._A .size :
916+ raise ValueError (
917+ f'Data array shape, { self ._A .shape } '
918+ 'is incompatible with alpha array shape, '
919+ f'{ self ._alpha .shape } . '
920+ 'This can occur with the deprecated '
921+ 'behavior of the "flat" shading option, '
922+ 'in which a row and/or column of the data '
923+ 'array is dropped.' )
924+ # pcolormesh, scatter, maybe others flatten their _A
925+ self ._alpha = self ._alpha .reshape (self ._A .shape )
926+ self ._mapped_colors = self .to_rgba (self ._A , self ._alpha )
927+
928+ if self ._face_is_mapped :
929+ self ._facecolors = self ._mapped_colors
930+ else :
931+ self ._set_facecolor (self ._original_facecolor )
932+ if self ._edge_is_mapped :
933+ self ._edgecolors = self ._mapped_colors
934+ else :
935+ self ._set_edgecolor (self ._original_edgecolor )
881936 self .stale = True
882937
883938 def get_fill (self ):
884- """Return whether fill is set ."""
885- return self ._is_filled
939+ """Return whether face is colored ."""
940+ return not cbook . _str_lower_equal ( self ._original_facecolor , "none" )
886941
887942 def update_from (self , other ):
888943 """Copy properties from other to self."""
@@ -1350,18 +1405,9 @@ class LineCollection(Collection):
13501405
13511406 _edge_default = True
13521407
1353- def __init__ (self , segments , # Can be None.
1354- linewidths = None ,
1355- colors = None ,
1356- antialiaseds = None ,
1357- linestyles = 'solid' ,
1358- offsets = None ,
1359- transOffset = None ,
1360- norm = None ,
1361- cmap = None ,
1362- pickradius = 5 ,
1363- zorder = 2 ,
1364- facecolors = 'none' ,
1408+ def __init__ (self , segments , # Can be None.
1409+ * args , # Deprecated.
1410+ zorder = 2 , # Collection.zorder is 1
13651411 ** kwargs
13661412 ):
13671413 """
@@ -1394,29 +1440,25 @@ def __init__(self, segments, # Can be None.
13941440 `~.path.Path.CLOSEPOLY`.
13951441
13961442 **kwargs
1397- Forwareded to `.Collection`.
1443+ Forwarded to `.Collection`.
13981444 """
1399- if colors is None :
1400- colors = mpl .rcParams ['lines.color' ]
1401- if linewidths is None :
1402- linewidths = (mpl .rcParams ['lines.linewidth' ],)
1403- if antialiaseds is None :
1404- antialiaseds = (mpl .rcParams ['lines.antialiased' ],)
1405-
1406- colors = mcolors .to_rgba_array (colors )
1445+ argnames = ["linewidths" , "colors" , "antialiaseds" , "linestyles" ,
1446+ "offsets" , "transOffset" , "norm" , "cmap" , "pickradius" ,
1447+ "zorder" , "facecolors" ]
1448+ if args :
1449+ argkw = {name : val for name , val in zip (argnames , args )}
1450+ kwargs .update (argkw )
1451+ cbook .warn_deprecated (
1452+ "3.4" , message = "Since %(since)s, passing LineCollection "
1453+ "arguments other than the first, 'segments', as positional "
1454+ "arguments is deprecated, and they will become keyword-only "
1455+ "arguments %(removal)s."
1456+ )
1457+ # Unfortunately, mplot3d needs this explicit setting of 'facecolors'.
1458+ kwargs .setdefault ('facecolors' , 'none' )
14071459 super ().__init__ (
1408- edgecolors = colors ,
1409- facecolors = facecolors ,
1410- linewidths = linewidths ,
1411- linestyles = linestyles ,
1412- antialiaseds = antialiaseds ,
1413- offsets = offsets ,
1414- transOffset = transOffset ,
1415- norm = norm ,
1416- cmap = cmap ,
14171460 zorder = zorder ,
14181461 ** kwargs )
1419-
14201462 self .set_segments (segments )
14211463
14221464 def set_segments (self , segments ):
@@ -1468,19 +1510,32 @@ def _add_offsets(self, segs):
14681510 segs [i ] = segs [i ] + offsets [io :io + 1 ]
14691511 return segs
14701512
1513+ def _get_default_linewidth (self ):
1514+ return mpl .rcParams ['lines.linewidth' ]
1515+
1516+ def _get_default_antialiased (self ):
1517+ return mpl .rcParams ['lines.antialiased' ]
1518+
1519+ def _get_default_edgecolor (self ):
1520+ return mpl .rcParams ['lines.color' ]
1521+
1522+ def _get_default_facecolor (self ):
1523+ return 'none'
1524+
14711525 def set_color (self , c ):
14721526 """
1473- Set the color (s) of the LineCollection.
1527+ Set the edgecolor (s) of the LineCollection.
14741528
14751529 Parameters
14761530 ----------
14771531 c : color or list of colors
1478- Single color (all patches have same color), or a
1479- sequence of rgba tuples; if it is a sequence the patches will
1532+ Single color (all lines have same color), or a
1533+ sequence of rgba tuples; if it is a sequence the lines will
14801534 cycle through the sequence.
14811535 """
14821536 self .set_edgecolor (c )
1483- self .stale = True
1537+
1538+ set_colors = set_color
14841539
14851540 def get_color (self ):
14861541 return self ._edgecolors
@@ -1851,7 +1906,6 @@ def __init__(self, triangulation, **kwargs):
18511906 super ().__init__ (** kwargs )
18521907 self ._triangulation = triangulation
18531908 self ._shading = 'gouraud'
1854- self ._is_filled = True
18551909
18561910 self ._bbox = transforms .Bbox .unit ()
18571911
0 commit comments