Python and Viv · Plotting
A line plot
What to notice
figure("title", "xlabel", "ylabel")replacesplt.subplots()and the threeset_calls. The figure is drawn by whatever reads the program's output: on this site, the page draws it; on the command line,viv run damped.viv | viv plot -o damped.svgwrites an SVG.plot(t, x, "label")isax.plot(t, x, label=...), and every series has a label, which is also its legend entry. A dashed line is a separate call,style("envelope", "dash"), where matplotlib takes a format string"--".- Markers without a line are
scatter(...), where matplotlib usesax.plot(..., "o"). np.linspace(0, 10, N)islinspace(0.0, 10.0, N), andnp.expandnp.cosof an array areexpandcosof an array.- Selecting the peaks with a comprehension and fancy indexing (
t[peaks]) becomes one loop that appends to two arrays. - There is no
savefig: a Viv program's figure is its output.
Python damped.py · 36 lines
Viv damped.viv · 41 lines
py2viv refuses damped.py
1 imports
4import numpy as np
5import matplotlib
6matplotlib.use("Agg")
7import matplotlib.pyplot as plt
2# nothing to import: figure, plot and scatter are builtins
py2viv refuses this program:
damped.py:5:1: not numeric Python: `import matplotlib`
import matplotlib
^^^^^^^^^^^^^^^^^
`matplotlib` is not in the numeric subset (math, numpy, viv).
damped.py:6:1: not numeric Python: a use of `matplotlib` (from `matplotlib`, refused at its import)
matplotlib.use("Agg")
^^^^^^^^^^
Not in the numeric subset.
damped.py:7:1: not numeric Python: `import matplotlib.pyplot`
import matplotlib.pyplot as plt
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`matplotlib.pyplot` is not in the numeric subset (math, numpy, viv).
damped.py:20:11: not numeric Python: a use of `plt` (from `matplotlib.pyplot`, refused at its import)
fig, ax = plt.subplots()
^^^
Not in the numeric subset.
damped.py:21:1: not numeric Python: the method `.set_title` of a value of unknown type (it comes from a construct refused elsewhere)
ax.set_title("A damped oscillation")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Fix the refusal that produced it.
damped.py:22:1: not numeric Python: the method `.set_xlabel` of a value of unknown type (it comes from a construct refused elsewhere)
ax.set_xlabel("t")
^^^^^^^^^^^^^^^^^^
Fix the refusal that produced it.
damped.py:23:1: not numeric Python: the method `.set_ylabel` of a value of unknown type (it comes from a construct refused elsewhere)
ax.set_ylabel("x")
^^^^^^^^^^^^^^^^^^
Fix the refusal that produced it.
damped.py:26:1: not numeric Python: the method `.plot` of a value of unknown type (it comes from a construct refused elsewhere)
ax.plot(t, x, label="x(t)")
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Fix the refusal that produced it.
damped.py:27:1: not numeric Python: the method `.plot` of a value of unknown type (it comes from a construct refused elsewhere)
ax.plot(t, env, "--", label="envelope")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Fix the refusal that produced it.
damped.py:28:1: not numeric Python: the method `.plot` of a value of unknown type (it comes from a construct refused elsewhere)
ax.plot(t[peaks], x[peaks], "o", label="peaks")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Fix the refusal that produced it.
damped.py:29:1: not numeric Python: the method `.legend` of a value of unknown type (it comes from a construct refused elsewhere)
ax.legend()
^^^^^^^^^^^
Fix the refusal that produced it.
damped.py:32:1: not numeric Python: the method `.savefig` of a value of unknown type (it comes from a construct refused elsewhere)
fig.savefig("damped.png", dpi=100)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Fix the refusal that produced it.
12 constructs outside the numeric subset (tools/py2viv/SUBSET.md) 2 the data: a damped oscillation and its envelope
10N = 400
11t = np.linspace(0.0, 10.0, N)
12x = np.exp(-t / 4.0) * np.cos(2.0 * t)
13env = np.exp(-t / 4.0)
5N = 400
6t = linspace(0.0, 10.0, N)
7x = exp(-t / 4.0) * cos(2.0 * t)
8env = exp(-t / 4.0)
(refused)
3 the peaks, where x is larger than both neighbors
16peaks = [i for i in range(1, N - 1) if x[i] > x[i - 1] and x[i] > x[i + 1]]
17print("peaks at t =", " ".join(f"{t[i]:.3f}" for i in peaks))
11pt = []
12px = []
13parts = []
14for i from 1 to N - 1 {
15 if x[i] > x[i - 1] and x[i] > x[i + 1] {
16 pt = append(pt, t[i])
17 px = append(px, x[i])
18 parts = append(parts, f"{t[i]:.3f}")
19 }
20}
21print("peaks at t =", join(" ", parts))
(refused)
4 a figure with a title and axis labels
20fig, ax = plt.subplots()
21ax.set_title("A damped oscillation")
22ax.set_xlabel("t")
23ax.set_ylabel("x")
24figure("A damped oscillation", "t", "x")
(refused)
5 two lines and a set of points
26ax.plot(t, x, label="x(t)")
27ax.plot(t, env, "--", label="envelope")
28ax.plot(t[peaks], x[peaks], "o", label="peaks")
29ax.legend()
27plot(t, x, "x(t)")
28plot(t, env, "envelope")
29style("envelope", "dash")
30scatter(pt, px, "peaks")
(refused)
6 save it
32fig.savefig("damped.png", dpi=100)
33print("saved damped.png")
33# the figure is printed as records; the page, `viv plot` or a notebook draws them
(refused)
7 checks
36assert len(peaks) == 3
36test "three peaks" {
37 assert_true(len(pt) == 3)
38}
(refused)
What they print
differs — Matplotlib writes a PNG and the Python side prints that it saved it; Viv prints the figure as text records (figure, plot, style, scatter), which a page, a notebook or viv plot draws. Those lines are left out of the comparison; the peaks line is compared.
Dimmed lines are left out of the comparison. Each Viv test block prints one PASS line; the Python checks the same facts with assert, which prints nothing. The remaining lines match.
$ python3 damped.py
peaks at t = 3.083 6.216 9.373saved damped.png
$ viv run damped.viv
peaks at t = 3.083 6.216 9.373figure: A damped oscillation ; t ; xplot: x(t) ; [0, 0.02506265664160401, 0.05012531328320802, 0.07518796992481203, 0.10025062656641603, 0.12531328320802004, 0.15037593984962405, 0.17543859649122806, 0.20050125313283207, 0.22556390977443608, 0.250626566416 … (15934 more characters)plot: envelope ; [0, 0.02506265664160401, 0.05012531328320802, 0.07518796992481203, 0.10025062656641603, 0.12531328320802004, 0.15037593984962405, 0.17543859649122806, 0.20050125313283207, 0.22556390977443608, 0.25062656 … (15633 more characters)style: envelope ; dashscatter: peaks ; ; [3.08270676691729317e+00, 6.21553884711779414e+00, 9.37343358395989945e+00] ; [4.59494696831576899e-01, 2.09493020298257449e-01, 9.54989354598924228e-02]PASS three peaks
viv plot (an SVG); on a post or a notebook the page draws them.