pie
ExamplesDocs

Topics

  • Canvas
  • Reactivity
  • Broadcasting
  • Autodiff
  • Animation
  • Python
unitgridOpacitycanvasColor

Broadcasting

  • Points from linspace
  • A grid of circles
  • A parabola made of straight lines

Pass an array where a function expects one item, and the function runs once per item. With several arrays, their shapes are matched the way numpy does it: line the shapes up from the right, and each pair of sizes must be equal or one of them must be 1. A size of 1 is repeated to fit.

Points from linspace

np.linspace(-4, 4, 9) gives 9 numbers from -4 to 4. Lifted with pie.lift, it gives an array node instead. Pass it to pie.point and you get 9 points.

pie.clear()
import numpy as np
linspace = pie.lift(np.linspace, pie.Array[pie.Scalar])
sin = pie.lift(np.sin, pie.Array[pie.Scalar])

xs = linspace(-4, 4, 9)
pie.point(xs, 0)
pie.point(xs, sin(xs), fill='crimson')

xs has shape (9,) and 0 is a single number, so the first call makes points (x, 0). In the second, xs and sin(xs) both have shape (9,), so they pair up item by item.

Now a grid. A Python list of lists is an array too: [[-3], [-2], [-1]] has shape (3, 1).

grid = pie.point(xs, [[-3], [-2], [-1]], fill='teal')
print(grid)

(9,) against (3, 1) gives (3, 9): 3 rows of 9 points.


A grid of circles

Centers with shape (3,) and radii with shape (4, 1) give circles with shape (4, 3): every radius around every center.

pie.clear()
import numpy as np
centers = pie.point([-3, 0, 3], 0)
radii = (np.arange(1, 5) / 2)[:, None].tolist()  # [[0.5], [1.0], [1.5], [2.0]]
circles = pie.circle(centers, radii)
print(circles)

A numpy array must be turned into a list with .tolist() before it goes into a pie.* call.

An array node can be indexed like a numpy array. Color one column and one row:

pie.set_stroke(circles[:, 1], 'crimson')  # every radius around the middle center
pie.set_stroke(circles[3], 'teal')        # the largest radius around every center

A parabola made of straight lines

Join (t, 0) on the x-axis to (0, L − t) on the y-axis, for many values of t from 0 to L. No line is curved, but together they outline a curve: a parabola. The curve that touches every line of a family is called its envelope.

pie.clear()
import numpy as np
linspace = pie.lift(np.linspace, pie.Array[pie.Scalar])
def remaining(L, t):
    return L - t
rest = pie.lift(remaining, pie.Array[pie.Scalar])

L = pie.scalar(5, out='L')
ts = linspace(0, L, 21)
starts = pie.point(ts, 0, hidden=True)
ends = pie.point(0, rest(L, ts), hidden=True)
pie.line(starts, ends, stroke='teal')

starts and ends both have shape (21,), so pie.line makes 21 lines. They follow L:

pie.translate_scalar_to(L, 3, animate=True)
pie.translate_scalar_to(L, 5, animate=True)

Now all four quadrants at once. np.outer multiplies a list of 4 signs by the 21 values of t, so each coordinate gets shape (4, 21), and pie.line makes 84 lines.

pie.clear()
outer = pie.lift(np.outer, pie.Array[pie.Scalar])
L = pie.scalar(5, out='L')
ts = linspace(0, L, 21)
xs = outer([1, -1, -1, 1], ts)
ys = outer([1, 1, -1, -1], rest(L, ts))
pie.line(pie.point(xs, 0, hidden=True), pie.point(0, ys, hidden=True), stroke='purple')