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 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
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
@@ -730,10 +736,14 @@ def set_antialiased(self, aa):
730
736
aa : bool or list of bools
731
737
"""
732
738
if aa is None :
733
- aa = mpl . rcParams [ 'patch.antialiased' ]
739
+ aa = self . _get_default_antialiased ()
734
740
self ._antialiaseds = np .atleast_1d (np .asarray (aa , bool ))
735
741
self .stale = True
736
742
743
+ def _get_default_antialiased (self ):
744
+ # This may be overridden in a subclass.
745
+ return mpl .rcParams ['patch.antialiased' ]
746
+
737
747
def set_color (self , c ):
738
748
"""
739
749
Set both the edgecolor and the facecolor.
@@ -750,16 +760,14 @@ def set_color(self, c):
750
760
self .set_facecolor (c )
751
761
self .set_edgecolor (c )
752
762
763
+ def _get_default_facecolor (self ):
764
+ # This may be overridden in a subclass.
765
+ return mpl .rcParams ['patch.facecolor' ]
766
+
753
767
def _set_facecolor (self , c ):
754
768
if c is None :
755
- c = mpl . rcParams [ 'patch.facecolor' ]
769
+ c = self . _get_default_facecolor ()
756
770
757
- self ._is_filled = True
758
- try :
759
- if c .lower () == 'none' :
760
- self ._is_filled = False
761
- except AttributeError :
762
- pass
763
771
self ._facecolors = mcolors .to_rgba_array (c , self ._alpha )
764
772
self .stale = True
765
773
@@ -775,6 +783,8 @@ def set_facecolor(self, c):
775
783
----------
776
784
c : color or list of colors
777
785
"""
786
+ if isinstance (c , str ) and c .lower () in ("none" , "face" ):
787
+ c = c .lower ()
778
788
self ._original_facecolor = c
779
789
self ._set_facecolor (c )
780
790
@@ -787,29 +797,24 @@ def get_edgecolor(self):
787
797
else :
788
798
return self ._edgecolors
789
799
800
+ def _get_default_edgecolor (self ):
801
+ # This may be overridden in a subclass.
802
+ return mpl .rcParams ['patch.edgecolor' ]
803
+
790
804
def _set_edgecolor (self , c ):
791
805
set_hatch_color = True
792
806
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 ()
796
811
else :
797
812
c = 'none'
798
813
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
813
818
self ._edgecolors = mcolors .to_rgba_array (c , self ._alpha )
814
819
if set_hatch_color and len (self ._edgecolors ):
815
820
self ._hatch_color = tuple (self ._edgecolors [0 ])
@@ -825,6 +830,11 @@ def set_edgecolor(self, c):
825
830
The collection edgecolor(s). If a sequence, the patches cycle
826
831
through it. If 'face', match the facecolor.
827
832
"""
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 ()
828
838
self ._original_edgecolor = c
829
839
self ._set_edgecolor (c )
830
840
@@ -853,36 +863,81 @@ def get_linewidth(self):
853
863
def get_linestyle (self ):
854
864
return self ._linestyles
855
865
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
+
856
900
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 ( ):
864
908
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 )
881
936
self .stale = True
882
937
883
938
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" )
886
941
887
942
def update_from (self , other ):
888
943
"""Copy properties from other to self."""
@@ -1350,18 +1405,9 @@ class LineCollection(Collection):
1350
1405
1351
1406
_edge_default = True
1352
1407
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
1365
1411
** kwargs
1366
1412
):
1367
1413
"""
@@ -1394,29 +1440,25 @@ def __init__(self, segments, # Can be None.
1394
1440
`~.path.Path.CLOSEPOLY`.
1395
1441
1396
1442
**kwargs
1397
- Forwareded to `.Collection`.
1443
+ Forwarded to `.Collection`.
1398
1444
"""
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' )
1407
1459
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 ,
1417
1460
zorder = zorder ,
1418
1461
** kwargs )
1419
-
1420
1462
self .set_segments (segments )
1421
1463
1422
1464
def set_segments (self , segments ):
@@ -1468,19 +1510,32 @@ def _add_offsets(self, segs):
1468
1510
segs [i ] = segs [i ] + offsets [io :io + 1 ]
1469
1511
return segs
1470
1512
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
+
1471
1525
def set_color (self , c ):
1472
1526
"""
1473
- Set the color (s) of the LineCollection.
1527
+ Set the edgecolor (s) of the LineCollection.
1474
1528
1475
1529
Parameters
1476
1530
----------
1477
1531
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
1480
1534
cycle through the sequence.
1481
1535
"""
1482
1536
self .set_edgecolor (c )
1483
- self .stale = True
1537
+
1538
+ set_colors = set_color
1484
1539
1485
1540
def get_color (self ):
1486
1541
return self ._edgecolors
@@ -1851,7 +1906,6 @@ def __init__(self, triangulation, **kwargs):
1851
1906
super ().__init__ (** kwargs )
1852
1907
self ._triangulation = triangulation
1853
1908
self ._shading = 'gouraud'
1854
- self ._is_filled = True
1855
1909
1856
1910
self ._bbox = transforms .Bbox .unit ()
1857
1911
0 commit comments