Skip to content

Commit ada791e

Browse files
committed
Partial commit
1 parent 9c07e63 commit ada791e

13 files changed

+1705
-19
lines changed

Diff for: .travis.yml

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
# Travis Continuos Integration
22
# Currently only tests notebook files
33
# Based on https://conda.pydata.org/docs/travis.html
4-
sudo: false # use container based build
4+
dist: xenial
55
language: python
6-
dist: focal
6+
77
notifications:
88
email: false
99

10-
python:
11-
- "3.6"
10+
jobs:
11+
include:
12+
- env: NAME="Latest Everything."
13+
python: 3.9
14+
- env: NAME="Oldest Version."
15+
python: 3.6
1216

1317
before_install:
1418
- |
@@ -37,6 +41,3 @@ install:
3741

3842
script:
3943
- ci/run-linter.sh
40-
- pushd docs
41-
- make html
42-
- popd

Diff for: ci/run-linter.sh

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ flake8 proplot docs --exclude .ipynb_checkpoints --max-line-length=88 --ignore=W
1212
echo '[isort]'
1313
isort --recursive --check-only --line-width=88 --skip __init__.py --multi-line=3 --force-grid-wrap=0 --trailing-comma proplot
1414

15+
echo '[pytest]'
16+
pytest proplot
17+
1518
# echo '[black]'
1619
# black --check -S proplot
1720

Diff for: docs/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@
213213
napoleon_preprocess_types = True
214214
napoleon_type_aliases = {
215215
# Python or inherited terms
216-
# NOTE: float, int, and str are automatically included
216+
# NOTE: built-in types are automatically included
217217
'callable': ':py:func:`callable`',
218218
'sequence': ':term:`sequence`',
219219
'dict-like': ':term:`dict-like <mapping>`',

Diff for: proplot/tests/test_1dplots.py

+285
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
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+
12+
def test_cmap_cycles():
13+
"""
14+
Test sampling of multiple continuous colormaps.
15+
"""
16+
cycle = pplt.Cycle(
17+
'Boreal', 'Grays', 'Fire', 'Glacial', 'yellow',
18+
left=[0.4] * 5, right=[0.6] * 5,
19+
samples=[3, 4, 5, 2, 1],
20+
)
21+
fig, ax = pplt.subplots()
22+
data = np.random.rand(10, len(cycle)).cumsum(axis=1)
23+
data = pd.DataFrame(data, columns=list('abcdefghijklmno'))
24+
ax.plot(data, cycle=cycle, linewidth=2, legend='b')
25+
26+
27+
def test_auto_reverse():
28+
"""
29+
Test enabled and disabled auto reverse.
30+
"""
31+
x = np.arange(10)[::-1]
32+
y = np.arange(10)
33+
z = np.random.rand(10, 10)
34+
fig, axs = pplt.subplots(ncols=2, nrows=2, share=False)
35+
# axs[0].format(xreverse=False) # should fail
36+
axs[0].plot(x, y)
37+
axs[1].format(xlim=(0, 9)) # manual override
38+
axs[1].plot(x, y)
39+
axs[2].pcolor(x, y[::-1], z)
40+
axs[3].format(xlim=(0, 9), ylim=(0, 9)) # manual override!
41+
axs[3].pcolor(x, y[::-1], z)
42+
43+
44+
def test_invalid_values():
45+
"""
46+
Test distributions with missing or invalid values.
47+
"""
48+
fig, axs = pplt.subplots(ncols=2)
49+
data = np.random.normal(size=(100, 5))
50+
for j in range(5):
51+
data[:, j] = np.sort(data[:, j])
52+
data[:19 * (j + 1), j] = np.nan
53+
# data[:20, :] = np.nan
54+
data_masked = ma.masked_invalid(data) # should be same result
55+
for ax, dat in zip(axs, (data, data_masked)):
56+
ax.plot(dat, means=True, shade=True)
57+
58+
fig, axs = pplt.subplots(ncols=2, nrows=2)
59+
data = np.random.normal(size=(100, 5))
60+
for i in range(5): # test uneven numbers of invalid values
61+
data[:10 * (i + 1), :] = np.nan
62+
data_masked = ma.masked_invalid(data) # should be same result
63+
for ax, dat in zip(axs[:2], (data, data_masked)):
64+
ax.violin(dat, means=True)
65+
for ax, dat in zip(axs[2:], (data, data_masked)):
66+
ax.box(dat, fill=True, means=True)
67+
68+
69+
def test_histogram_types():
70+
"""
71+
Test the different histogram types using basic keywords.
72+
"""
73+
fig, axs = pplt.subplots(ncols=2, nrows=2, share=False)
74+
data = np.random.normal(size=(100, 5))
75+
data += np.arange(5)
76+
kws = ({'stack': 0}, {'stack': 1}, {'fill': 0}, {'fill': 1, 'alpha': 0.5})
77+
for ax, kw in zip(axs, kws):
78+
ax.hist(data, ec='k', **kw)
79+
80+
81+
def test_scatter_inbounds():
82+
"""
83+
Test in-bounds scatter plots.
84+
"""
85+
fig, axs = pplt.subplots(ncols=2, share=False)
86+
N = 100
87+
fig.format(xlim=(0, 20))
88+
for i, ax in enumerate(axs):
89+
c = ax.scatter(np.arange(N), np.arange(N), c=np.arange(N), inbounds=i)
90+
ax.colorbar(c, loc='b')
91+
92+
93+
def test_scatter_columns():
94+
"""
95+
Test scatter column iteration and property cycling. Note we cannot
96+
retrieve metadata from `s` and `c`.
97+
"""
98+
fig, ax = pplt.subplots()
99+
cycle = pplt.Cycle(
100+
'538', marker=['X', 'o', 's', 'd'], sizes=[50, 100], edgecolors=['r', 'k']
101+
)
102+
ax.scatter(np.random.rand(10, 4), np.random.rand(10, 4), cycle=cycle)
103+
104+
fig, axs = pplt.subplots(ncols=2)
105+
axs[0].plot(np.random.rand(5, 5), np.random.rand(5, 5), lw=5)
106+
axs[1].scatter(
107+
np.random.rand(5, 5), np.random.rand(5, 5), s=np.random.rand(5, 5) * 300
108+
)
109+
110+
111+
def test_scatter_colors():
112+
"""
113+
Test diverse scatter keyword parsing and RGB scaling.
114+
"""
115+
# Test sizes and face or edge colors
116+
x = np.random.randn(60)
117+
y = np.random.randn(60)
118+
119+
fig, axs = pplt.subplots()
120+
axs.scatter(x, y, s=80, fc='none', edgecolors='r')
121+
122+
# Test RGB color scaling.
123+
fig, axs = pplt.subplots(ncols=3)
124+
data = np.random.rand(50, 3)
125+
ax = axs[0]
126+
ax.scatter(data, c=data, cmap='reds')
127+
ax = axs[1]
128+
ax.scatter(data[:, 0], c=data, cmap='reds', ) # cycle='foo') # should warn
129+
ax = axs[2]
130+
ax.scatter(data, mean=True, shadestd=1, barstd=0.5)
131+
ax.format(xlim=(-0.1, 2.1))
132+
133+
134+
def test_scatter_sizes():
135+
"""
136+
Test marker size scaling.
137+
"""
138+
fig = pplt.figure()
139+
ax = fig.subplot(margin=0.15)
140+
data = np.random.rand(5) * 500
141+
ax.scatter(
142+
np.arange(5),
143+
[0.25] * 5,
144+
c='blue7',
145+
sizes=['5pt', '10pt', '15pt', '20pt', '25pt']
146+
)
147+
ax.scatter(
148+
np.arange(5),
149+
[0.50] * 5,
150+
c='red7',
151+
sizes=data,
152+
absolute_size=True
153+
)
154+
ax.scatter(
155+
np.arange(5),
156+
[0.75] * 5,
157+
c='red7',
158+
sizes=data,
159+
absolute_size=True
160+
)
161+
for i, d in enumerate(data):
162+
ax.text(i, 0.5, format(d, '.0f'), va='center', ha='center')
163+
164+
fig, axs = pplt.subplots(ncols=3)
165+
pplt.rc.reset()
166+
pplt.rc['lines.markersize'] = 20
167+
N = 50
168+
x = np.random.rand(N)
169+
y = np.random.rand(N)
170+
for i, ax in enumerate(axs):
171+
kw = {'absolute_size': i == 2}
172+
if i == 1:
173+
kw['smax'] = 20 ** 2 # should be same as relying on lines.markersize
174+
ax.scatter(x, y, x * y, **kw)
175+
176+
177+
def test_bar_width():
178+
"""
179+
Test relative and absolute widths.
180+
"""
181+
fig, axs = pplt.subplots(ncols=3)
182+
x = np.arange(10)
183+
y = np.random.rand(10, 2)
184+
for i, ax in enumerate(axs):
185+
ax.bar(x * (2 * i + 1), y, width=0.8, absolute_width=i == 1)
186+
187+
188+
def test_pie_charts():
189+
"""
190+
Test basic pie plots. No examples in user guide right now.
191+
"""
192+
pplt.rc.inlinefmt = 'svg'
193+
labels = ['foo', 'bar', 'baz', 'biff', 'buzz']
194+
array = np.arange(1, 6)
195+
data = pd.Series(array, index=labels)
196+
fig = pplt.figure()
197+
ax = fig.subplot(121)
198+
ax.pie(array, edgefix=True, labels=labels, ec='k', cycle='reds')
199+
ax = fig.subplot(122)
200+
ax.pie(data, ec='k', cycle='blues')
201+
202+
203+
def test_box_violin_plots():
204+
"""
205+
Test new default behavior of passing cycles to box/violin commands.
206+
"""
207+
fig = pplt.figure()
208+
ax = fig.subplot(121)
209+
ax.box(
210+
np.random.uniform(-3, 3, size=(1000, 5)),
211+
# cycle='blues_r',
212+
fillcolor=['red', 'blue', 'green', 'orange', 'yellow'],
213+
# ec='face',
214+
)
215+
ax = fig.subplot(122)
216+
ax.violin(
217+
np.random.normal(0, 1, size=(1000, 5)),
218+
# cycle='greys',
219+
fillcolor=['gray1', 'gray7'],
220+
means=True,
221+
barstds=2,
222+
)
223+
224+
# Sample data
225+
N = 500
226+
state = np.random.RandomState(51423)
227+
data1 = state.normal(size=(N, 5)) + 2 * (state.rand(N, 5) - 0.5) * np.arange(5)
228+
data1 = pd.DataFrame(data1, columns=pd.Index(list('abcde'), name='label'))
229+
data2 = state.rand(100, 7)
230+
data2 = pd.DataFrame(data2, columns=pd.Index(list('abcdefg'), name='label'))
231+
232+
# Figure
233+
fig, axs = pplt.subplots([[1, 1, 2, 2], [0, 3, 3, 0]], span=False)
234+
axs.format(
235+
abc='A.', titleloc='l', grid=False,
236+
suptitle='Boxes and violins demo'
237+
)
238+
239+
# Box plots
240+
ax = axs[0]
241+
obj1 = ax.box(data1, means=True, marker='x', meancolor='r', fillcolor='gray4')
242+
print(obj1)
243+
ax.format(title='Box plots')
244+
245+
# Violin plots
246+
ax = axs[1]
247+
obj2 = ax.violin(data1, fillcolor='gray6', means=True, points=100)
248+
print(obj2)
249+
ax.format(title='Violin plots')
250+
251+
# Boxes with different colors
252+
ax = axs[2]
253+
ax.format(title='Multiple colors', ymargin=0.15)
254+
ax.boxh(data2, cycle='pastel2')
255+
256+
257+
def test_parametric_labels():
258+
"""
259+
Test passing strings as parametric 'color values'. Likely a common use case.
260+
"""
261+
pplt.rc.inlinefmt = 'svg'
262+
fig, ax = pplt.subplots()
263+
ax.parametric(
264+
np.random.rand(5), c=list('abcde'), lw=20, colorbar='b', cmap_kw={'left': 0.2}
265+
)
266+
267+
268+
def test_parametric_color_input():
269+
"""
270+
Test color input arguments. Should be able to make monochromatic
271+
plots for case where we want `line` without sticky x/y edges.
272+
"""
273+
fig, axs = pplt.subplots(ncols=2, nrows=2)
274+
colors = (
275+
[(0, 1, 1), (0, 1, 0), (1, 0, 0), (0, 0, 1), (1, 1, 0)],
276+
['b', 'r', 'g', 'm', 'c', 'y'],
277+
'black',
278+
(0.5, 0.5, 0.5),
279+
# [(0.5, 0.5, 0.5)],
280+
)
281+
for ax, color in zip(axs, colors):
282+
ax.parametric(
283+
np.random.rand(5), np.random.rand(5),
284+
linewidth=2, label='label', color=color, colorbar='b', legend='b'
285+
)

0 commit comments

Comments
 (0)