Skip to content

Commit 034ed7e

Browse files
committed
Merge remote-tracking branch 'origin/unittest' into mpl3.9.1
2 parents eba0aa3 + 549052a commit 034ed7e

22 files changed

+2233
-11
lines changed

baseline/test_colorbar.png

102 KB
Loading

baseline/test_standardized_input.png

63.1 KB
Loading

env.yml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: proplot
2+
channels:
3+
- conda-forge
4+
dependencies:
5+
- python >=3.6,
6+
- ipykernel >=5.1
7+
- matplotlib 3.4.3,
8+
- numpy
9+
- pytest
10+
- pytest-mpl
11+
- pandas
12+

proplot/tests/test_1dplots.py

+344
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Test 1D plotting overrides.
4+
"""
5+
import numpy as np
6+
import numpy.ma as ma
7+
import pandas as pd
8+
9+
import proplot as pplt
10+
11+
state = np.random.RandomState(51423)
12+
13+
14+
@pplt.tests.image_compare
15+
def test_auto_reverse():
16+
"""
17+
Test enabled and disabled auto reverse.
18+
"""
19+
x = np.arange(10)[::-1]
20+
y = np.arange(10)
21+
z = state.rand(10, 10)
22+
fig, axs = pplt.subplots(ncols=2, nrows=3, share=0)
23+
# axs[0].format(xreverse=False) # should fail
24+
axs[0].plot(x, y)
25+
axs[1].format(xlim=(0, 9)) # manual override
26+
axs[1].plot(x, y)
27+
axs[2].plotx(x, y)
28+
axs[3].format(ylim=(0, 9)) # manual override
29+
axs[3].plotx(x, y)
30+
axs[4].pcolor(x, y[::-1], z)
31+
axs[5].format(xlim=(0, 9), ylim=(0, 9)) # manual override!
32+
axs[5].pcolor(x, y[::-1], z)
33+
fig.format(suptitle='Auto-reverse test', collabels=['reverse', 'fixed'])
34+
35+
36+
@pplt.tests.image_compare
37+
def test_cmap_cycles():
38+
"""
39+
Test sampling of multiple continuous colormaps.
40+
"""
41+
cycle = pplt.Cycle(
42+
'Boreal', 'Grays', 'Fire', 'Glacial', 'yellow',
43+
left=[0.4] * 5, right=[0.6] * 5,
44+
samples=[3, 4, 5, 2, 1],
45+
)
46+
fig, ax = pplt.subplots()
47+
data = state.rand(10, len(cycle)).cumsum(axis=1)
48+
data = pd.DataFrame(data, columns=list('abcdefghijklmno'))
49+
ax.plot(data, cycle=cycle, linewidth=2, legend='b')
50+
51+
52+
@pplt.tests.image_compare
53+
def test_column_iteration():
54+
"""
55+
Test scatter column iteration.
56+
"""
57+
fig, axs = pplt.subplots(ncols=2)
58+
axs[0].plot(state.rand(5, 5), state.rand(5, 5), lw=5)
59+
axs[1].scatter(
60+
state.rand(5, 5), state.rand(5, 5), state.rand(5, 5), state.rand(5, 5)
61+
)
62+
63+
64+
@pplt.tests.image_compare
65+
def test_bar_stack():
66+
"""
67+
Test bar and area stacking.
68+
"""
69+
# TODO: Add test here
70+
71+
72+
@pplt.tests.image_compare
73+
def test_bar_width():
74+
"""
75+
Test relative and absolute widths.
76+
"""
77+
fig, axs = pplt.subplots(ncols=3)
78+
x = np.arange(10)
79+
y = state.rand(10, 2)
80+
for i, ax in enumerate(axs):
81+
ax.bar(x * (2 * i + 1), y, width=0.8, absolute_width=i == 1)
82+
83+
84+
@pplt.tests.image_compare
85+
def test_bar_vectors():
86+
"""
87+
Test vector arguments to bar plots.
88+
"""
89+
fig, ax = pplt.subplots(refwidth=3, facecolor='orange0')
90+
ax.bar(
91+
np.arange(10),
92+
np.arange(1, 11),
93+
linewidth=3,
94+
# facecolor=(np.repeat(0.1, 3) * np.arange(1, 11)[:, None]).tolist(),
95+
edgecolor=[f'gray{i}' for i in range(9, -1, -1)],
96+
facecolor=[f'gray{i}' for i in range(10)],
97+
alpha=np.linspace(0.1, 1, 10),
98+
hatch=[None, '//'] * 5,
99+
)
100+
101+
102+
@pplt.tests.image_compare
103+
def test_boxplot_colors():
104+
"""
105+
Test box colors and cycle colors.
106+
"""
107+
fig = pplt.figure(share=False)
108+
ax = fig.subplot(221)
109+
box_data = state.uniform(-3, 3, size=(1000, 5))
110+
violin_data = state.normal(0, 1, size=(1000, 5))
111+
ax.box(box_data, fillcolor=['red', 'blue', 'green', 'orange', 'yellow'])
112+
ax = fig.subplot(222)
113+
ax.violin(violin_data, fillcolor=['gray1', 'gray7'], hatches=[None, '//'], means=True, barstds=2) # noqa: E501
114+
ax = fig.subplot(223)
115+
ax.boxh(box_data, cycle='pastel2')
116+
ax = fig.subplot(224)
117+
ax.violinh(violin_data, cycle='pastel1')
118+
119+
120+
@pplt.tests.image_compare
121+
def test_boxplot_vectors():
122+
"""
123+
Test vector property arguments.
124+
"""
125+
coords = (0.5, 1, 2)
126+
counts = (10, 20, 100)
127+
labels = ['foo', 'bar', 'baz']
128+
datas = []
129+
for count in counts:
130+
data = state.rand(count)
131+
datas.append(data)
132+
datas = np.array(datas, dtype=object)
133+
fig, ax = pplt.subplot(refwidth=3)
134+
ax.boxplot(
135+
coords,
136+
datas,
137+
lw=2,
138+
notch=False,
139+
whis=(10, 90),
140+
cycle='538',
141+
fillalpha=[0.5, 0.5, 1],
142+
hatch=[None, '//', '**'],
143+
boxlw=[2, 1, 1],
144+
)
145+
ax.format(xticklabels=labels)
146+
147+
148+
@pplt.tests.image_compare
149+
def test_histogram_types():
150+
"""
151+
Test the different histogram types using basic keywords.
152+
"""
153+
fig, axs = pplt.subplots(ncols=2, nrows=2, share=False)
154+
data = state.normal(size=(100, 5))
155+
data += np.arange(5)
156+
kws = ({'stack': 0}, {'stack': 1}, {'fill': 0}, {'fill': 1, 'alpha': 0.5})
157+
for ax, kw in zip(axs, kws):
158+
ax.hist(data, ec='k', **kw)
159+
160+
161+
@pplt.tests.image_compare
162+
def test_invalid_plot():
163+
"""
164+
Test lines with missing or invalid values.
165+
"""
166+
fig, axs = pplt.subplots(ncols=2)
167+
data = state.normal(size=(100, 5))
168+
for j in range(5):
169+
data[:, j] = np.sort(data[:, j])
170+
data[:19 * (j + 1), j] = np.nan
171+
# data[:20, :] = np.nan
172+
data_masked = ma.masked_invalid(data) # should be same result
173+
for ax, dat in zip(axs, (data, data_masked)):
174+
ax.plot(dat, means=True, shade=True)
175+
176+
177+
@pplt.tests.image_compare
178+
def test_invalid_dist():
179+
"""
180+
Test distributions with missing or invalid data.
181+
"""
182+
fig, axs = pplt.subplots(ncols=2, nrows=2)
183+
data = state.normal(size=(100, 5))
184+
for i in range(5): # test uneven numbers of invalid values
185+
data[:10 * (i + 1), :] = np.nan
186+
data_masked = ma.masked_invalid(data) # should be same result
187+
for ax, dat in zip(axs[:2], (data, data_masked)):
188+
ax.violin(dat, means=True)
189+
for ax, dat in zip(axs[2:], (data, data_masked)):
190+
ax.box(dat, fill=True, means=True)
191+
192+
193+
@pplt.tests.image_compare
194+
def test_pie_charts():
195+
"""
196+
Test basic pie plots. No examples in user guide right now.
197+
"""
198+
pplt.rc.inlinefmt = 'svg'
199+
labels = ['foo', 'bar', 'baz', 'biff', 'buzz']
200+
array = np.arange(1, 6)
201+
data = pd.Series(array, index=labels)
202+
fig = pplt.figure()
203+
ax = fig.subplot(121)
204+
ax.pie(array, edgefix=True, labels=labels, ec='k', cycle='reds')
205+
ax = fig.subplot(122)
206+
ax.pie(data, ec='k', cycle='blues')
207+
208+
209+
@pplt.tests.image_compare
210+
def test_parametric_labels():
211+
"""
212+
Test passing strings as parametric 'color values'. This is likely
213+
a common use case.
214+
"""
215+
pplt.rc.inlinefmt = 'svg'
216+
fig, ax = pplt.subplots()
217+
ax.parametric(
218+
state.rand(5), c=list('abcde'), lw=20, colorbar='b', cmap_kw={'left': 0.2}
219+
)
220+
221+
222+
@pplt.tests.image_compare
223+
def test_parametric_colors():
224+
"""
225+
Test color input arguments. Should be able to make monochromatic
226+
plots for case where we want `line` without sticky x/y edges.
227+
"""
228+
fig, axs = pplt.subplots(ncols=2, nrows=2)
229+
colors = (
230+
[(0, 1, 1), (0, 1, 0), (1, 0, 0), (0, 0, 1), (1, 1, 0)],
231+
['b', 'r', 'g', 'm', 'c', 'y'],
232+
'black',
233+
(0.5, 0.5, 0.5),
234+
)
235+
for ax, color in zip(axs, colors):
236+
ax.parametric(
237+
state.rand(5), state.rand(5),
238+
linewidth=2, label='label', color=color, colorbar='b', legend='b'
239+
)
240+
241+
242+
@pplt.tests.image_compare
243+
def test_scatter_args():
244+
"""
245+
Test diverse scatter keyword parsing and RGB scaling.
246+
"""
247+
x, y = state.randn(50), state.randn(50)
248+
data = state.rand(50, 3)
249+
fig, axs = pplt.subplots(ncols=4, share=0)
250+
ax = axs[0]
251+
ax.scatter(x, y, s=80, fc='none', edgecolors='r')
252+
ax = axs[1]
253+
ax.scatter(data, c=data, cmap='reds') # column iteration
254+
ax = axs[2]
255+
with pplt.tests.warns(pplt.internals.ProplotWarning) as record:
256+
ax.scatter(data[:, 0], c=data, cmap='reds') # actual colors
257+
assert len(record) == 1
258+
ax = axs[3]
259+
ax.scatter(data, mean=True, shadestd=1, barstd=0.5) # distribution
260+
ax.format(xlim=(-0.1, 2.1))
261+
262+
263+
@pplt.tests.image_compare
264+
def test_scatter_inbounds():
265+
"""
266+
Test in-bounds scatter plots.
267+
"""
268+
fig, axs = pplt.subplots(ncols=2, share=False)
269+
N = 100
270+
fig.format(xlim=(0, 20))
271+
for i, ax in enumerate(axs):
272+
c = ax.scatter(np.arange(N), np.arange(N), c=np.arange(N), inbounds=bool(i))
273+
ax.colorbar(c, loc='b')
274+
275+
276+
@pplt.tests.image_compare
277+
def test_scatter_alpha():
278+
"""
279+
Test behavior with multiple alpha values.
280+
"""
281+
fig, ax = pplt.subplots()
282+
data = state.rand(10)
283+
alpha = np.linspace(0.1, 1, data.size)
284+
with pplt.tests.warns(pplt.internals.ProplotWarning) as record:
285+
ax.scatter(data, alpha=alpha)
286+
assert len(record) == 1
287+
with pplt.tests.warns(pplt.internals.ProplotWarning) as record:
288+
ax.scatter(data + 1, c=np.arange(data.size), cmap='BuRd', alpha=alpha)
289+
assert len(record) == 1
290+
ax.scatter(data + 2, color='k', alpha=alpha)
291+
ax.scatter(data + 3, color=[f'red{i}' for i in range(data.size)], alpha=alpha)
292+
293+
294+
@pplt.tests.image_compare
295+
def test_scatter_cycle():
296+
"""
297+
Test scatter property cycling.
298+
"""
299+
fig, ax = pplt.subplots()
300+
cycle = pplt.Cycle(
301+
'538',
302+
marker=['X', 'o', 's', 'd'],
303+
sizes=[20, 100],
304+
edgecolors=['r', 'k']
305+
)
306+
ax.scatter(
307+
state.rand(10, 4),
308+
state.rand(10, 4),
309+
cycle=cycle,
310+
area_size=False,
311+
)
312+
313+
314+
@pplt.tests.image_compare
315+
def test_scatter_sizes():
316+
"""
317+
Test marker size scaling.
318+
"""
319+
# Compare setting size to input size
320+
size = 20
321+
with pplt.rc.context({'lines.markersize': size}):
322+
fig = pplt.figure()
323+
ax = fig.subplot(121, margin=0.15)
324+
for i in range(3):
325+
kw = {'absolute_size': i == 2}
326+
if i == 1:
327+
kw['smin'] = 0
328+
kw['smax'] = size ** 2 # should be same as relying on lines.markersize
329+
ax.scatter(np.arange(5), [0.25 * (1 + i)] * 5, size ** 2, **kw)
330+
# Test various size arguments
331+
ax = fig.subplot(122, margin=0.15)
332+
data = state.rand(5) * 500
333+
ax.scatter(
334+
np.arange(5), [0.25] * 5,
335+
c='blue7', sizes=[5, 10, 15, 20, 25], area_size=False, absolute_size=True,
336+
)
337+
ax.scatter(
338+
np.arange(5), [0.50] * 5, c='red7', sizes=data, absolute_size=True
339+
)
340+
ax.scatter(
341+
np.arange(5), [0.75] * 5, c='red7', sizes=data, absolute_size=False
342+
)
343+
for i, d in enumerate(data):
344+
ax.text(i, 0.5, format(d, '.0f'), va='center', ha='center')

0 commit comments

Comments
 (0)