Skip to content

Commit ab39326

Browse files
committed
simplify
1 parent db8bfba commit ab39326

File tree

4 files changed

+62
-63
lines changed

4 files changed

+62
-63
lines changed

lib/matplotlib/_style_helpers.py

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,44 @@
11
import collections.abc
22
import itertools
33

4-
import numpy as np
5-
64
import matplotlib.cbook as cbook
75
import matplotlib.colors as mcolors
86
import matplotlib.lines as mlines
97

108

9+
1110
def check_non_empty(key, value):
1211
"""Raise a TypeError if an empty sequence is passed"""
13-
if (not cbook.is_scalar_or_string(value) and
14-
isinstance(value, collections.abc.Sized) and len(value) == 0):
12+
if isinstance(value, collections.abc.Sized) and len(value) == 0:
1513
raise TypeError(f'{key} must not be an empty sequence')
1614

1715

18-
def style_generator(kw):
16+
def iterate_styles(kw):
1917
"""
2018
Helper for handling style sequences (e.g. facecolor=['r', 'b', 'k']) within plotting
21-
methods that repeatedly call other plotting methods (e.g. hist, stackplot). Remove
22-
style keywords from the given dictionary. Return the reduced dictionary together
23-
with a generator which provides a series of dictionaries to be used in each call to
24-
the wrapped function.
19+
methods that repeatedly call other plotting methods (e.g. hist, stackplot).
20+
21+
Given a dictionary of keyword parameters, yield a series of copies of the
22+
dictionary. Style parameters expressed as sequences are replaced in the copy with
23+
the next element of the sequence.
24+
25+
Note 'color' is deliberately not handled since the calling methods have their own
26+
handling for that.
2527
"""
2628
kw_iterators = {}
2729
remaining_kw = {}
2830
for key, value in kw.items():
29-
if key in ['facecolor', 'edgecolor']:
30-
if value is None or cbook._str_lower_equal(value, 'none'):
31-
kw_iterators[key] = itertools.repeat(value)
32-
else:
33-
check_non_empty(key, value)
34-
kw_iterators[key] = itertools.cycle(mcolors.to_rgba_array(value))
31+
if cbook.is_scalar_or_string(value):
32+
# No iteration required
33+
remaining_kw[key] = value
34+
35+
elif key in ['facecolor', 'edgecolor']:
36+
check_non_empty(key, value)
37+
kw_iterators[key] = itertools.cycle(mcolors.to_rgba_array(value))
3538

3639
elif key in ['hatch', 'linewidth']:
3740
check_non_empty(key, value)
38-
kw_iterators[key] = itertools.cycle(np.atleast_1d(value))
41+
kw_iterators[key] = itertools.cycle(value)
3942

4043
elif key == 'linestyle':
4144
check_non_empty(key, value)
@@ -44,8 +47,6 @@ def style_generator(kw):
4447
else:
4548
remaining_kw[key] = value
4649

47-
def style_gen():
48-
while True:
49-
yield {key: next(val) for key, val in kw_iterators.items()}
5050

51-
return remaining_kw, style_gen()
51+
while True:
52+
yield {key: next(val) for key, val in kw_iterators.items()} | remaining_kw

lib/matplotlib/axes/_axes.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3324,7 +3324,7 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
33243324
# TODO: do we want to be more restrictive and check lengths?
33253325
colors = itertools.cycle(colors)
33263326

3327-
kwargs, style_gen = _style_helpers.style_generator(kwargs)
3327+
kwargs_gen = _style_helpers.iterate_styles(kwargs)
33283328

33293329
bar_width = (group_distance /
33303330
(num_datasets + (num_datasets - 1) * bar_spacing + group_spacing))
@@ -3339,16 +3339,15 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
33393339
# place the bars, but only use numerical positions, categorical tick labels
33403340
# are handled separately below
33413341
bar_containers = []
3342-
for i, (hs, label, color, styles) in enumerate(zip(heights, labels, colors,
3343-
style_gen)):
3342+
for i, (hs, label, color) in enumerate(zip(heights, labels, colors)):
33443343
lefts = (group_centers - 0.5 * group_distance + margin_abs
33453344
+ i * (bar_width + bar_spacing_abs))
33463345
if orientation == "vertical":
33473346
bc = self.bar(lefts, hs, width=bar_width, align="edge",
3348-
label=label, color=color, **styles, **kwargs)
3347+
label=label, color=color, **next(kwargs_gen))
33493348
else:
33503349
bc = self.barh(lefts, hs, height=bar_width, align="edge",
3351-
label=label, color=color, **styles, **kwargs)
3350+
label=label, color=color, **next(kwargs_gen))
33523351
bar_containers.append(bc)
33533352

33543353
if tick_labels is not None:
@@ -7641,18 +7640,18 @@ def hist(self, x, bins=None, range=None, density=False, weights=None,
76417640
if histtype == "step":
76427641
kwargs.setdefault('edgecolor', colors)
76437642

7644-
kwargs, style_gen = _style_helpers.style_generator(kwargs)
7643+
kwargs_gen = _style_helpers.iterate_styles(kwargs)
76457644

76467645
for patch, lbl in itertools.zip_longest(patches, labels):
76477646
if not patch:
76487647
continue
7648+
kw = next(kwargs_gen)
76497649
p = patch[0]
7650-
kwargs.update(next(style_gen))
7651-
p._internal_update(kwargs)
7650+
p._internal_update(kw)
76527651
if lbl is not None:
76537652
p.set_label(lbl)
76547653
for p in patch[1:]:
7655-
p._internal_update(kwargs)
7654+
p._internal_update(kw)
76567655
p.set_label('_nolegend_')
76577656

76587657
if nx == 1:

lib/matplotlib/stackplot.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def stackplot(axes, x, *args,
9696
kwargs = cbook.normalize_kwargs(kwargs, collections.PolyCollection)
9797
kwargs.setdefault('facecolor', colors)
9898

99-
kwargs, style_gen = _style_helpers.style_generator(kwargs)
99+
kwargs_gen = _style_helpers.iterate_styles(kwargs)
100100

101101
# Assume data passed has not been 'stacked', so stack it here.
102102
# We'll need a float buffer for the upcoming calculations.
@@ -136,13 +136,13 @@ def stackplot(axes, x, *args,
136136
# Color between x = 0 and the first array.
137137
coll = axes.fill_between(x, first_line, stack[0, :],
138138
label=next(labels, None),
139-
**next(style_gen), **kwargs)
139+
**next(kwargs_gen))
140140
coll.sticky_edges.y[:] = [0]
141141
r = [coll]
142142

143143
# Color between array i-1 and array i
144144
for i in range(len(y) - 1):
145145
r.append(axes.fill_between(x, stack[i, :], stack[i + 1, :],
146146
label=next(labels, None),
147-
**next(style_gen), **kwargs))
147+
**next(kwargs_gen)))
148148
return r

lib/matplotlib/tests/test__style_helpers.py

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,76 +2,75 @@
22

33
import matplotlib.colors as mcolors
44
from matplotlib.lines import _get_dash_pattern
5-
from matplotlib._style_helpers import style_generator
5+
from matplotlib._style_helpers import iterate_styles
66

77

88
@pytest.mark.parametrize('key, value', [('facecolor', ["b", "g", "r"]),
99
('edgecolor', ["b", "g", "r"]),
1010
('hatch', ["/", "\\", "."]),
1111
('linestyle', ["-", "--", ":"]),
1212
('linewidth', [1, 1.5, 2])])
13-
def test_style_generator_list(key, value):
13+
def test_iterate_styles_list(key, value):
1414
kw = {'foo': 12, key: value}
15-
new_kw, gen = style_generator(kw)
16-
17-
assert new_kw == {'foo': 12}
15+
gen_kw = iterate_styles(kw)
1816

1917
for v in value * 2: # Result should repeat
20-
style_dict = next(gen)
21-
assert len(style_dict) == 1
18+
kw_dict = next(gen_kw)
19+
assert len(kw_dict) == 2
20+
assert kw_dict['foo'] == 12
2221
if key.endswith('color'):
23-
assert mcolors.same_color(v, style_dict[key])
22+
assert mcolors.same_color(v, kw_dict[key])
2423
elif key == 'linestyle':
25-
assert _get_dash_pattern(v) == style_dict[key]
24+
assert _get_dash_pattern(v) == kw_dict[key]
2625
else:
27-
assert v == style_dict[key]
26+
assert v == kw_dict[key]
2827

2928

3029
@pytest.mark.parametrize('key, value', [('facecolor', "b"),
3130
('edgecolor', "b"),
3231
('hatch', "/"),
3332
('linestyle', "-"),
3433
('linewidth', 1)])
35-
def test_style_generator_single(key, value):
34+
def test_iterate_styles_single(key, value):
3635
kw = {'foo': 12, key: value}
37-
new_kw, gen = style_generator(kw)
36+
gen_kw = iterate_styles(kw)
3837

39-
assert new_kw == {'foo': 12}
4038
for _ in range(2): # Result should repeat
41-
style_dict = next(gen)
39+
kw_dict = next(gen_kw)
40+
assert len(kw_dict) == 2
41+
assert kw_dict['foo'] == 12
4242
if key.endswith('color'):
43-
assert mcolors.same_color(value, style_dict[key])
44-
elif key == 'linestyle':
45-
assert _get_dash_pattern(value) == style_dict[key]
43+
assert mcolors.same_color(value, kw_dict[key])
4644
else:
47-
assert value == style_dict[key]
45+
assert value == kw_dict[key]
4846

4947

5048
@pytest.mark.parametrize('key', ['facecolor', 'hatch', 'linestyle'])
51-
def test_style_generator_empty(key):
49+
def test_iterate_styles_empty(key):
5250
kw = {key: []}
51+
gen_kw = iterate_styles(kw)
5352
with pytest.raises(TypeError, match=f'{key} must not be an empty sequence'):
54-
style_generator(kw)
53+
next(gen_kw)
5554

5655

57-
def test_style_generator_sequence_type_styles():
56+
def test_iterate_styles_sequence_type_styles():
5857
kw = {'facecolor': ('r', 0.5),
5958
'edgecolor': [0.5, 0.5, 0.5],
6059
'linestyle': (0, (1, 1))}
6160

62-
_, gen = style_generator(kw)
61+
gen_kw = iterate_styles(kw)
6362
for _ in range(2): # Result should repeat
64-
style_dict = next(gen)
65-
mcolors.same_color(kw['facecolor'], style_dict['facecolor'])
66-
mcolors.same_color(kw['edgecolor'], style_dict['edgecolor'])
67-
kw['linestyle'] == style_dict['linestyle']
63+
kw_dict = next(gen_kw)
64+
mcolors.same_color(kw['facecolor'], kw_dict['facecolor'])
65+
mcolors.same_color(kw['edgecolor'], kw_dict['edgecolor'])
66+
kw['linestyle'] == kw_dict['linestyle']
6867

6968

70-
def test_style_generator_none():
69+
def test_iterate_styles_none():
7170
kw = {'facecolor': 'none',
7271
'edgecolor': 'none'}
73-
_, gen = style_generator(kw)
72+
gen_kw = iterate_styles(kw)
7473
for _ in range(2): # Result should repeat
75-
style_dict = next(gen)
76-
assert style_dict['facecolor'] == 'none'
77-
assert style_dict['edgecolor'] == 'none'
74+
kw_dict = next(gen_kw)
75+
assert kw_dict['facecolor'] == 'none'
76+
assert kw_dict['edgecolor'] == 'none'

0 commit comments

Comments
 (0)