8000 Clarify color priorities in collections · matplotlib/matplotlib@29bd9c2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 29bd9c2

Browse files
committed
Clarify color priorities in collections
1 parent 1b1afe1 commit 29bd9c2

File tree

4 files changed

+84
-61
lines changed

4 files changed

+84
-61
lines changed

lib/matplotlib/collections.py

Lines changed: 79 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,9 @@ def __init__(self,
168168
# list of unbroadcast/scaled linewidths
169169
self._us_lw = [0]
170170
self._linewidths = [0]
171-
self._is_filled = True # May be modified by set_facecolor().
171+
# Flags: do colors come from mapping an array?
172+
self._face_is_mapped = True
173+
self._edge_is_mapped = False
172174

173175
self._hatch_color = mcolors.to_rgba(mpl.rcParams['hatch.color'])
174176
self.set_facecolor(facecolors)
@@ -757,12 +759,6 @@ def _set_facecolor(self, c):
757759
if c is None:
758760
c = mpl.rcParams['patch.facecolor']
759761

760-
self._is_filled = True
761-
try:
762-
if c.lower() == 'none':
763-
self._is_filled = False
764-
except AttributeError:
765-
pass
766762
self._facecolors = mcolors.to_rgba_array(c, self._alpha)
767763
self.stale = True
768764

@@ -778,6 +774,8 @@ def set_facecolor(self, c):
778774
----------
779775
c : color or list of colors
780776
"""
777+
if isinstance(c, str) and c.lower() in ("none", "face"):
778+
c = c.lower()
781779
self._original_facecolor = c
782780
self._set_facecolor(c)
783781

@@ -790,35 +788,28 @@ def get_edgecolor(self):
790788
else:
791789
return self._edgecolors
792790

793-
def _set_edgecolor(self, c):
791+
def _set_edgecolor(self, c, default=None):
794792
set_hatch_color = True
795793
if c is None:
796-
if (mpl.rcParams['patch.force_edgecolor'] or
797-
not self._is_filled or self._edge_default):
798-
c = mpl.rcParams['patch.edgecolor']
794+
if default is None:
795+
if (mpl.rcParams['patch.force_edgecolor'] or
796+
not self._face_is_mapped or self._edge_default):
797+
c = mpl.rcParams['patch.edgecolor']
798+
else:
799+
c = 'none'
800+
set_hatch_color = False
799801
else:
800-
c = 'none'
801-
set_hatch_color = False
802-
803-
self._is_stroked = True
804-
try:
805-
if c.lower() == 'none':
806-
self._is_stroked = False
807-
except AttributeError:
808-
pass
809-
810-
try:
811-
if c.lower() == 'face': # Special case: lookup in "get" method.
812-
self._edgecolors = 'face'
813-
return
814-
except AttributeError:
815-
pass
802+
c = default
803+
if isinstance(c, str) and c == 'face':
804+
self._edgecolors = 'face'
805+
self.stale = True
806+
return
816807
self._edgecolors = mcolors.to_rgba_array(c, self._alpha)
817808
if set_hatch_color and len(self._edgecolors):
818809
self._hatch_color = tuple(self._edgecolors[0])
819810
self.stale = True
820811

821-
def set_edgecolor(self, c):
812+
def set_edgecolor(self, c, default=None):
822813
"""
823814
Set the edgecolor(s) of the collection.
824815
@@ -828,8 +819,13 @@ def set_edgecolor(self, c):
828819
The collection edgecolor(s). If a sequence, the patches cycle
829820
through it. If 'face', match the facecolor.
830821
"""
822+
# We pass through a default value for use in LineCollection.
823+
# This allows us to maintain None as the default indicator in
824+
# _original_edgecolor.
825+
if isinstance(c, str) and c.lower() in ("none", "face"):
826+
c = c.lower()
831827
self._original_edgecolor = c
832-
self._set_edgecolor(c)
828+
self._set_edgecolor(c, default=default)
833829

834830
def set_alpha(self, alpha):
835831
"""
@@ -856,9 +852,36 @@ def get_linewidth(self):
856852
def get_linestyle(self):
857853
return self._linestyles
858854

859-
def update_scalarmappable(self):
860-
"""Update colors from the scalar mappable array, if it is not None."""
855+
def _set_mappable_flags(self):
861856
if self._A is None:
857+
self._edge_is_mapped = False
858+
self._face_is_mapped = False
859+
return False # Nothing to map
860+
861+
# Typical mapping: centers, not edges.
862+
self._face_is_mapped = True
863+
self._edge_is_mapped = False
864+
865+
# Make the colors None or a string. (If None, it is a default.)
866+
fc = self._original_facecolor
867+
if not (fc is None or isinstance(fc, str)):
868+
fc = 'array'
869+
ec = self._original_edgecolor
870+
if not(ec is None or isinstance(ec, str)):
871+
ec = 'array'
872+
873+
# Handle special cases.
874+
if fc == 'none':
875+
self._face_is_mapped = False
876+
if ec in ('face', 'none', None):
877+
self._edge_is_mapped = True
878+
if ec == 'face':
879+
self._edge_is_mapped = self._face_is_mapped
880+
return self._face_is_mapped or self._edge_is_mapped
881+
882+
def update_scalarmappable(self):
883+
"""Update colors from the scalar mappable array, if any."""
884+
if not self._set_mappable_flags():
862885
return
863886
# QuadMesh can map 2d arrays (but pcolormesh supplies 1d array)
864887
if self._A.ndim > 1 and not isinstance(self, QuadMesh):
@@ -877,15 +900,16 @@ def update_scalarmappable(self):
877900
# pcolormesh, scatter, maybe others flatten their _A
878901
self._alpha = self._alpha.reshape(self._A.shape)
879902

880-
if self._is_filled:
903+
if self._face_is_mapped:
881904
self._facecolors = self.to_rgba(self._A, self._alpha)
882-
elif self._is_stroked:
905+
if self._edge_is_mapped:
883906
self._edgecolors = self.to_rgba(self._A, self._alpha)
884907
self.stale = True
885908

909+
@cbook.deprecated("3.4")
886910
def get_fill(self):
887-
"""Return whether fill is set."""
888-
return self._is_filled
911+
"""Return whether facecolor is currently mapped."""
912+
return self._face_is_mapped
889913

890914
def update_from(self, other):
891915
"""Copy properties from other to self."""
@@ -1396,30 +1420,31 @@ def __init__(self, segments, # Can be None.
13961420
"interior" can be specified by appropriate usage of
13971421
`~.path.Path.CLOSEPOLY`.
13981422
**kwargs
1399-
Forwareded to `.Collection`.
1423+
Forwarded to `.Collection`.
14001424
"""
1401-
if colors is None:
1402-
colors = mpl.rcParams['lines.color']
1403-
if linewidths is None:
1404-
linewidths = (mpl.rcParams['lines.linewidth'],)
1405-
if antialiaseds is None:
1406-
antialiaseds = (mpl.rcParams['lines.antialiased'],)
1425+
kw_plural = dict(linewidths=linewidths,
1426+
colors=colors,
1427+
facecolors=facecolors,
1428+
antialiaseds=antialiaseds,
1429+
linestyles=linestyles,)
1430+
1431+
kw = {k: kwargs.pop(k[:-1], val) for k, val in kw_plural.items()}
1432+
kw.update(kwargs)
1433+
colors = kw.pop('colors')
1434+
if kw['linewidths'] is None:
1435+
kw['linewidths'] = (mpl.rcParams['lines.linewidth'],)
1436+
if kw['antialiaseds'] is None:
1437+
kw['antialiaseds'] = (mpl.rcParams['lines.antialiased'],)
14071438

1408-
colors = mcolors.to_rgba_array(colors)
14091439
super().__init__(
1410-
edgecolors=colors,
1411-
facecolors=facecolors,
1412-
linewidths=linewidths,
1413-
linestyles=linestyles,
1414-
antialiaseds=antialiaseds,
14151440
offsets=offsets,
14161441
transOffset=transOffset,
14171442
norm=norm,
14181443
cmap=cmap,
14191444
zorder=zorder,
1420-
**kwargs)
1421-
1445+
**kw)
14221446
self.set_segments(segments)
1447+
self.set_color(colors) # sets edgecolors, including default
14231448

14241449
def set_segments(self, segments):
14251450
if segments is None:
@@ -1477,12 +1502,11 @@ def set_color(self, c):
14771502
Parameters
14781503
----------
14791504
c : color or list of colors
1480-
Single color (all patches have same color), or a
1481-
sequence of rgba tuples; if it is a sequence the patches will
1505+
Single color (all lines have same color), or a
1506+
sequence of rgba tuples; if it is a sequence the lines will
14821507
cycle through the sequence.
14831508
"""
1484-
self.set_edgecolor(c)
1485-
self.stale = True
1509+
self.set_edgecolor(c, default=mpl.rcParams['lines.color'])
14861510

14871511
def get_color(self):
14881512
return self._edgecolors
@@ -1857,7 +1881,7 @@ def __init__(self, triangulation, **kwargs):
18571881
super().__init__(**kwargs)
18581882
self._triangulation = triangulation
18591883
self._shading = 'gouraud'
1860-
self._is_filled = True
1884+
self._face_is_mapped = True
18611885

18621886
self._bbox = transforms.Bbox.unit()
18631887

lib/matplotlib/legend_handler.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -707,8 +707,10 @@ def get_first(prop_array):
707707
legend_handle.set_edgecolor(first_color(edgecolor))
708708
facecolor = getattr(orig_handle, '_original_facecolor',
709709
orig_handle.get_facecolor())
710-
legend_handle.set_facecolor(first_color(facecolor))
711-
legend_handle.set_fill(orig_handle.get_fill())
710+
fillcolor = first_color(facecolor)
711+
legend_handle.set_facecolor(fillcolor)
712+
fill = not (isinstance(fillcolor, str) and fillcolor == "none")
713+
legend_handle.set_fill(fill)
712714
legend_handle.set_hatch(orig_handle.get_hatch())
713715
legend_handle.set_linewidth(get_first(orig_handle.get_linewidths()))
714716
legend_handle.set_linestyle(get_first(orig_handle.get_linestyles()))

lib/matplotlib/patches.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4145,9 +4145,6 @@ def get_path_in_displaycoord(self):
41454145
self.get_linewidth() * dpi_cor,
41464146
self.get_mutation_aspect())
41474147

4148-
# if not fillable:
4149-
# self._fill = False
4150-
41514148
return _path, fillable
41524149

41534150
def draw(self, renderer):

lib/matplotlib/streamplot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
117117
line_colors = []
118118
color = np.ma.masked_invalid(color)
119119
else:
120-
line_kw['color'] = color
120+
line_kw['colors'] = color
121121
arrow_kw['color'] = color
122122

123123
if isinstance(linewidth, np.ndarray):

0 commit comments

Comments
 (0)
0