20
20
import warnings
21
21
22
22
23
+ # "color" is excluded; it is a compound setter, and its docstring differs
24
+ # in LineCollection.
23
25
@cbook ._define_aliases ({
24
26
"antialiased" : ["antialiaseds" , "aa" ],
25
27
"edgecolor" : ["edgecolors" , "ec" ],
@@ -168,8 +170,10 @@ def __init__(self,
168
170
# list of unbroadcast/scaled linewidths
169
171
self ._us_lw = [0 ]
170
172
self ._linewidths = [0 ]
171
- self ._is_filled = True # May be modified by set_facecolor().
172
-
173
+ # Flags: do colors come 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
173
177
self ._hatch_color = mcolors .to_rgba (mpl .rcParams ['hatch.color' ])
174
178
self .set_facecolor (facecolors )
175
179
self .set_edgecolor (edgecolors )
@@ -586,6 +590,10 @@ def get_offset_position(self):
586
590
"""
587
591
return self ._offset_position
588
592
593
+ def _get_default_linewidth (self ):
594
+ # This may be overridden in a subclass.
595
+ return mpl .rcParams ['patch.linewidth' ] # validated as float
596
+
589
597
def set_linewidth (self , lw ):
590
598
"""
591
599
Set the linewidth(s) for the collection. *lw* can be a scalar
@@ -597,9 +605,7 @@ def set_linewidth(self, lw):
597
605
lw : float or list of floats
598
606
"""
599
607
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 ()
603
609
# get the un-scaled/broadcast lw
604
610
self ._us_lw = np .atleast_1d (np .asarray (lw ))
605
611
@@ -750,16 +756,14 @@ def set_color(self, c):
750
756
self .set_facecolor (c )
751
757
self .set_edgecolor (c )
752
758
759
+ def _get_default_facecolor (self ):
760
+ # This may be overridden in a subclass.
761
+ return mpl .rcParams ['patch.facecolor' ]
762
+
753
763
def _set_facecolor (self , c ):
754
764
if c is None :
755
- c = mpl . rcParams [ 'patch.facecolor' ]
765
+ c = self . _get_default_facecolor ()
756
766
757
- self ._is_filled = True
758
- try :
759
- if c .lower () == 'none' :
760
- self ._is_filled = False
761
- except AttributeError :
762
- pass
763
767
self ._facecolors = mcolors .to_rgba_array (c , self ._alpha )
764
768
self .stale = True
765
769
@@ -775,6 +779,8 @@ def set_facecolor(self, c):
775
779
----------
776
780
c : color or list of colors
777
781
"""
782
+ if isinstance (c , str ) and c .lower () in ("none" , "face" ):
783
+ c = c .lower ()
778
784
self ._original_facecolor = c
779
785
self ._set_facecolor (c )
780
786
@@ -787,29 +793,24 @@ def get_edgecolor(self):
787
793
else :
788
794
return self ._edgecolors
789
795
796
+ def _get_default_edgecolor (self ):
797
+ # This may be overridden in a subclass.
798
+ return mpl .rcParams ['patch.edgecolor' ]
799
+
790
800
def _set_edgecolor (self , c ):
791
801
set_hatch_color = True
792
802
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' ]
803
+ if (mpl .rcParams ['patch.force_edgecolor' ]
804
+ or self ._edge_default
805
+ or cbook ._str_equal (self ._original_facecolor , 'none' )):
806
+ c = self ._get_default_edgecolor ()
796
807
else :
797
808
c = 'none'
798
809
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
810
+ if cbook ._str_lower_equal (c , 'face' ):
811
+ self ._edgecolors = 'face'
812
+ self .stale = True
813
+ return
813
814
self ._edgecolors = mcolors .to_rgba_array (c , self ._alpha )
814
815
if set_hatch_color and len (self ._edgecolors ):
815
816
self ._hatch_color = tuple (self ._edgecolors [0 ])
@@ -825,6 +826,11 @@ def set_edgecolor(self, c):
825
826
The collection edgecolor(s). If a sequence, the patches cycle
826
827
through it. If 'face', match the facecolor.
827
828
"""
829
+ # We pass through a default value for use in LineCollection.
830
+ # This allows us to maintain None as the default indicator in
831
+ # _original_edgecolor.
832
+ if isinstance (c , str ) and c .lower () in ("none" , "face" ):
833
+ c = c .lower ()
828
834
self ._original_edgecolor = c
829
835
self ._set_edgecolor (c )
830
836
@@ -853,36 +859,78 @@ def get_linewidth(self):
853
859
def get_linestyle (self ):
854
860
return self ._linestyles
855
861
862
+ def _set_mappable_flags (self ):
863
+ """
864
+ Determine whether edges and/or faces are color-mapped.
865
+
866
+ This is a helper for update_scalarmappable.
867
+ It sets Boolean flags '_edge_is_mapped' and '_face_is_mapped'.
868
+
869
+ Returns
870
+ -------
871
+ mapping_change: bool
872
+ True if either flag is True, or if a flag has changed.
873
+ """
874
+ edge0 = self ._edge_is_mapped
875
+ face0 = self ._face_is_mapped
876
+ self ._edge_is_mapped = False
877
+ self ._face_is_mapped = False
878
+ if self ._A is not None :
879
+ if not cbook ._str_equal (self ._original_facecolor , 'none' ):
880
+ self ._face_is_mapped = True
881
+ if cbook ._str_equal (self ._original_edgecolor , 'face' ):
882
+ self ._edge_is_mapped = True
883
+ else :
884
+ if self ._original_edgecolor is None :
885
+ self ._edge_is_mapped = True
886
+
887
+ mapped = self ._face_is_mapped or self ._edge_is_mapped
888
+ changed = (edge0 is None or face0 is None
889
+ or self ._edge_is_mapped != edge0
890
+ or self ._face_is_mapped != face0 )
891
+ return mapped or changed
892
+
856
893
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" ):
894
+ """
895
+ Update colors from the scalar mappable array, if any.
896
+
897
+ Assign colors to edges and faces based on the array and/or
898
+ colors that were directly set, as appropriate.
899
+ """
900
+ if not self ._set_mappable_flags ( ):
864
901
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 )
902
+ # Allow possibility to call 'self.set_array(None)'.
903
+ if self ._check_update ("array" ) and self ._A is not None :
904
+ # QuadMesh can map 2d arrays (but pcolormesh supplies 1d array)
905
+ if self ._A .ndim > 1 and not isinstance (self , QuadMesh ):
906
+ raise ValueError ('Collections can only map rank 1 arrays' )
907
+ if np .iterable (self ._alpha ):
908
+ if self ._alpha .size != self ._A .size :
909
+ raise ValueError (
910
+ f'Data array shape, { self ._A .shape } '
911
+ 'is incompatible with alpha array shape, '
912
+ f'{ self ._alpha .shape } . '
913
+ 'This can occur with the deprecated '
914
+ 'behavior of the "flat" shading option, '
915
+ 'in which a row and/or column of the data '
916
+ 'array is dropped.' )
917
+ # pcolormesh, scatter, maybe others flatten their _A
918
+ self ._alpha = self ._alpha .reshape (self ._A .shape )
919
+ self ._mapped_colors = self .to_rgba (self ._A , self ._alpha )
920
+
921
+ if self ._face_is_mapped :
922
+ self ._facecolors = self ._mapped_colors
923
+ else :
924
+ self ._set_facecolor (self ._original_facecolor )
925
+ if self ._edge_is_mapped :
926
+ self ._edgecolors = self ._mapped_colors
927
+ else :
928
+ self ._set_edgecolor (self ._original_edgecolor )
881
929
self .stale = True
882
930
883
931
def get_fill (self ):
884
- """Return whether fill is set ."""
885
- return self ._is_filled
932
+ """Return whether face is colored ."""
933
+ return not cbook . _str_lower_equal ( self ._original_facecolor , "none" )
886
934
887
935
def update_from (self , other ):
888
936
"""Copy properties from other to self."""
@@ -1350,18 +1398,9 @@ class LineCollection(Collection):
1350
1398
1351
1399
_edge_default = True
1352
1400
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' ,
1401
+ def __init__ (self , segments , # Can be None.
1402
+ * args , # Deprecated.
1403
+ zorder = 2 , # Collection.zorder is 1
1365
1404
** kwargs
1366
1405
):
1367
1406
"""
@@ -1394,29 +1433,25 @@ def __init__(self, segments, # Can be None.
1394
1433
`~.path.Path.CLOSEPOLY`.
1395
1434
1396
1435
**kwargs
1397
- Forwareded to `.Collection`.
1436
+ Forwarded to `.Collection`.
1398
1437
"""
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 )
1438
+ argnames = ["linewidths" , "colors" , "antialiaseds" , "linestyles" ,
1439
+ "offsets" , "transOffset" , "norm" , "cmap" , "pickradius" ,
1440
+ "zorder" , "facecolors" ]
1441
+ if args :
1442
+ argkw = {name : val for name , val in zip (argnames , args )}
1443
+ kwargs .update (argkw )
1444
+ cbook .warn_deprecated (
1445
+ "3.4" , message = "Since %(since)s, passing LineCollection "
1446
+ "arguments other than the first, 'segments', as positional "
1447
+ "arguments is deprecated, and they will become keyword-only "
1448
+ "arguments %(removal)s."
1449
+ )
1450
+ # Unfortunately, mplot3d needs this explicit setting of 'facecolors'.
1451
+ kwargs .setdefault ('facecolors' , 'none' )
1407
1452
super ().__init__ (
1408
- edgecolors = colors ,
1409
- facecolors = facecolors ,
1410
10000
code>
- linewidths = linewidths ,
1411
- linestyles = linestyles ,
1412
- antialiaseds = antialiaseds ,
1413
- offsets = offsets ,
1414
- transOffset = transOffset ,
1415
- norm = norm ,
1416
- cmap = cmap ,
1417
1453
zorder = zorder ,
1418
1454
** kwargs )
1419
-
1420
1455
self .set_segments (segments )
1421
1456
1422
1457
def set_segments (self , segments ):
@@ -1468,19 +1503,29 @@ def _add_offsets(self, segs):
1468
1503
segs [i ] = segs [i ] + offsets [io :io + 1 ]
1469
1504
return segs
1470
1505
1506
+ def _get_default_linewidth (self ):
1507
+ return mpl .rcParams ['lines.linewidth' ]
1508
+
1509
+ def _get_default_edgecolor (self ):
1510
+ return mpl .rcParams ['lines.color' ]
1511
+
1512
+ def _get_default_facecolor (self ):
1513
+ return 'none'
1514
+
1471
1515
def set_color (self , c ):
1472
1516
"""
1473
- Set the color (s) of the LineCollection.
1517
+ Set the edgecolor (s) of the LineCollection.
1474
1518
1475
1519
Parameters
1476
1520
----------
1477
1521
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
1522
+ Single color (all lines have same color), or a
1523
+ sequence of rgba tuples; if it is a sequence the lines will
1480
1524
cycle through the sequence.
1481
1525
"""
1482
1526
self .set_edgecolor (c )
1483
- self .stale = True
1527
+
1528
+ set_colors = set_color
1484
1529
1485
1530
def get_color (self ):
1486
1531
return self ._edgecolors
@@ -1855,7 +1900,6 @@ def __init__(self, triangulation, **kwargs):
1855
1900
super ().__init__ (** kwargs )
1856
1901
self ._triangulation = triangulation
1857
1902
self ._shading = 'gouraud'
1858
- self ._is_filled = True
1859
1903
1860
1904
self ._bbox = transforms .Bbox .unit ()
1861
1905
0 commit comments