Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5fa07f2

Browse files
committed
Getting cycling to work!
* Sort batch setting of artist properties for consistency * Improved error notification on bad properties (but still leaves artist in a mixed state...) * Finer-grained defaults handling in axes._base * Backwards-compatible fixes to makefill() * Improved unit test case * Fixed some situations where color was assumed to be in the cycles.
1 parent 9965f5f commit 5fa07f2

6 files changed

Lines changed: 95 additions & 41 deletions

File tree

lib/matplotlib/artist.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -900,13 +900,20 @@ def properties(self):
900900

901901
def set(self, **kwargs):
902902
"""
903-
A tkstyle set command, pass *kwargs* to set properties
903+
A property batch setter. Pass *kwargs* to set properties.
904+
Will handle property name collisions (e.g., if both
905+
'color' and 'facecolor' are specified, the property
906+
with higher priority gets set last).
907+
904908
"""
905909
ret = []
906-
for k, v in six.iteritems(kwargs):
910+
for k, v in sorted(kwargs.items(), reverse=True):
907911
k = k.lower()
908912
funcName = "set_%s" % k
909-
func = getattr(self, funcName)
913+
func = getattr(self, funcName, None)
914+
if func is None:
915+
raise TypeError('There is no %s property "%s"' %
916+
(self.__class__.__name__, k))
910917
ret.extend([func(v)])
911918
return ret
912919

@@ -1406,14 +1413,17 @@ def setp(obj, *args, **kwargs):
14061413
funcvals = []
14071414
for i in range(0, len(args) - 1, 2):
14081415
funcvals.append((args[i], args[i + 1]))
1409-
funcvals.extend(kwargs.items())
1416+
funcvals.extend(sorted(kwargs.items(), reverse=True))
14101417

14111418
ret = []
14121419
for o in objs:
14131420
for s, val in funcvals:
14141421
s = s.lower()
14151422
funcName = "set_%s" % s
1416-
func = getattr(o, funcName)
1423+
func = getattr(o, funcName, None)
1424+
if func is None:
1425+
raise TypeError('There is no %s property "%s"' %
1426+
(o.__class__.__name__, s))
14171427
ret.extend([func(val)])
14181428
return [x for x in cbook.flatten(ret)]
14191429

lib/matplotlib/axes/_base.py

Lines changed: 63 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -181,23 +181,16 @@ def __call__(self, *args, **kwargs):
181181
ret = self._grab_next_args(*args, **kwargs)
182182
return ret
183183

184+
184185
def set_lineprops(self, line, **kwargs):
185186
assert self.command == 'plot', 'set_lineprops only works with "plot"'
186-
for key, val in six.iteritems(kwargs):
187-
funcName = "set_%s" % key
188-
if not hasattr(line, funcName):
189-
raise TypeError('There is no line property "%s"' % key)
190-
func = getattr(line, funcName)
191-
func(val)
187+
line.set(**kwargs)
188+
192189

193190
def set_patchprops(self, fill_poly, **kwargs):
194191
assert self.command == 'fill', 'set_patchprops only works with "fill"'
195-
for key, val in six.iteritems(kwargs):
196-
funcName = "set_%s" % key
197-
if not hasattr(fill_poly, funcName):
198-
raise TypeError('There is no patch property "%s"' % key)
199-
func = getattr(fill_poly, funcName)
200-
func(val)
192+
fill_poly.set(**kwargs)
193+
201194

202195
def _xy_from_xy(self, x, y):
203196
if self.axes.xaxis is not None and self.axes.yaxis is not None:
@@ -235,37 +228,79 @@ def _xy_from_xy(self, x, y):
235228
y = y[:, np.newaxis]
236229
return x, y
237230

238-
def _setdefaults(self, kw, kwargs):
239-
# Only advance the cycler if the cycler
240-
# has information that is not specified
241-
# in the supplied kw and kwargs dicts
242-
if any([kw.get(k, None) is None and kwargs.get(k, None) is None
243-
for k in self._prop_keys]):
231+
232+
def _getdefaults(self, *kwargs):
233+
"""
234+
Only advance the cycler if the cycler has information that
235+
is not specified in any of the supplied tuple of dicts
236+
237+
Returns a dictionary or None.
238+
239+
"""
240+
if any([all([kw.get(k, None) is None for kw in kwargs])
241+
for k in self._prop_keys]):
244242
default_dict = six.next(self.prop_cycler)
245243
else:
246244
default_dict = None
245+
return default_dict
246+
247+
248+
def _setdefaults(self, default_dict, *kwargs):
249+
"""
250+
Given a defaults dictionary (or None), and a other dictionaries,
251+
update the other dictionaries with information in defaults if
252+
none of the other dictionaries contains that information.
253+
254+
"""
255+
if default_dict is None:
256+
return
257+
for k in default_dict:
258+
if all([kw.get(k, None) is None for kw in kwargs]):
259+
for kw in kwargs:
260+
kw[k] = default_dict[k]
247261

248-
for k in self._prop_keys:
249-
if (default_dict is not None and
250-
kw.get(k, None) is None and
251-
kwargs.get(k, None) is None):
252-
kwargs[k] = kw[k] = default_dict[k]
253262

254263
def _makeline(self, x, y, kw, kwargs):
255264
kw = kw.copy() # Don't modify the original kw.
256265
kwargs = kwargs.copy()
257-
self._setdefaults(kw, kwargs)
266+
default_dict = self._getdefaults(kw, kwargs)
267+
self._setdefaults(default_dict, kw, kwargs)
258268
seg = mlines.Line2D(x, y, **kw)
259269
self.set_lineprops(seg, **kwargs)
260270
return seg
261271

272+
262273
def _makefill(self, x, y, kw, kwargs):
263274
kw = kw.copy() # Don't modify the original kw.
264275
kwargs = kwargs.copy()
265-
# Might be problematic with fallback names such as
266-
# 'facecolor' and such. Possibly fixed by traitlets?
267-
self._setdefaults(kw, kwargs)
276+
277+
# Only using the first dictionary to use as basis
278+
# for getting defaults for back-compat reasons.
279+
# Doing it with both seems to mess things up in
280+
# various places (probably due to logic bugs elsewhere).
281+
default_dict = self._getdefaults(kw)
282+
self._setdefaults(default_dict, kw)
283+
284+
# Looks like we don't want "color" to be interpreted to
285+
# mean both facecolor and edgecolor for some reason.
286+
# So the "kw" dictionary is thrown out, and only its
287+
# 'color' value is kept and translated as a 'facecolor'.
288+
# This design should probably be revisited as it increases
289+
# complexity.
268290
facecolor = kw.get('color', None)
291+
292+
# Throw out 'color' as it is now handled as a facecolor
293+
# Need to copy this dictionary or else the next time around
294+
# in the cycle, the dictionary will be missing this entry
295+
# completely!
296+
if default_dict is not None:
297+
default_dict = default_dict.copy()
298+
default_dict.pop('color', None)
299+
300+
# To get other properties set from the cycler
301+
# modify the kwargs dictionary.
302+
self._setdefaults(default_dict, kwargs)
303+
269304
seg = mpatches.Polygon(np.hstack((x[:, np.newaxis],
270305
y[:, np.newaxis])),
271306
facecolor=facecolor,
@@ -274,6 +309,7 @@ def _makefill(self, x, y, kw, kwargs):
274309
self.set_patchprops(seg, **kwargs)
275310
return seg
276311

312+
277313
def _plot_args(self, tup, kwargs):
278314
ret = []
279315
if len(tup) > 1 and is_string_like(tup[-1]):

lib/matplotlib/stackplot.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,23 @@ def stackplot(axes, x, *args, **kwargs):
102102
raise ValueError(errstr)
103103

104104
# Color between x = 0 and the first array.
105+
if 'color' in axes._get_lines._prop_keys:
106+
color = six.next(axes._get_lines.prop_cycler)['color']
107+
else:
108+
color = None
105109
r.append(axes.fill_between(x, first_line, stack[0, :],
106-
facecolor=six.next(axes._get_lines.prop_cycler)['color'],
110+
facecolor=color,
107111
label= six.next(labels, None),
108112
**kwargs))
109113

110114
# Color between array i-1 and array i
111115
for i in xrange(len(y) - 1):
112-
color = six.next(axes._get_lines.prop_cycler)['color']
116+
if 'color' in axes._get_lines._prop_keys:
117+
color = six.next(axes._get_lines.prop_cycler)['color']
118+
else:
119+
color = None
113120
r.append(axes.fill_between(x, stack[i, :], stack[i + 1, :],
114-
facecolor= color,
121+
facecolor=color,
115122
label= six.next(labels, None),
116123
**kwargs))
117124
return r

lib/matplotlib/streamplot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
8282
if transform is None:
8383
transform = axes.transData
8484

85-
if color is None:
85+
if color is None and 'color' in axes._get_lines._prop_keys:
8686
color = six.next(axes._get_lines.prop_cycler)['color']
8787

8888
if linewidth is None:
1.34 KB
Loading

lib/matplotlib/tests/test_cycles.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,17 @@ def test_fillcycle_basic():
4545
fig = plt.figure()
4646
ax = fig.add_subplot(111)
4747
ax.set_prop_cycle(cycler('color', ['r', 'g', 'y']) +
48-
cycler('hatch', ['xx', 'O', '|-']))
48+
cycler('hatch', ['xx', 'O', '|-']) +
49+
cycler('linestyle', ['-', '--', ':']))
4950
xs = np.arange(10)
5051
ys = 0.25 * xs**.5 + 2
51-
ax.fill(xs, ys, label='red, x', facecolor='none')
52+
ax.fill(xs, ys, label='red, x')
5253
ys = 0.45 * xs**.5 + 3
53-
ax.fill(xs, ys, label='green, circle', facecolor='none')
54+
ax.fill(xs, ys, label='green, circle')
5455
ys = 0.65 * xs**.5 + 4
55-
ax.fill(xs, ys, label='yellow, cross', facecolor='none')
56+
ax.fill(xs, ys, label='yellow, cross')
5657
ys = 0.85 * xs**.5 + 5
57-
ax.fill(xs, ys, label='red2, x2', facecolor='none')
58+
ax.fill(xs, ys, label='red2, xx')
5859
ax.legend(loc='upper left')
5960

6061

0 commit comments

Comments
 (0)