pie
ExamplesDocs

Exampless

  • Canvas
  • Reactivity
  • Broadcasting
  • Autodiff
  • Animation
  • UIs
  • Sorting
  • Line fit
  • Convex hull
  • Live convex hull
  • Dijkstra's algorithm
  • k-means
  • Gaussian mixture
  • PCA
  • SVM
  • Differential equations
  • Python
  • Matplotlib on the canvas
unitgridOpacitycanvasColororiginXoriginY

Matplotlib on the canvas

  • Changing a distribution's parameters
  • A 3D surface

Changing a distribution's parameters

plt.show() draws a figure once, under the editor. To keep a figure in step with the canvas, make it from a lifted function, which reruns when its input nodes change.

The function below draws a normal curve to a PNG and returns it as text. ui/plot.tsx adds pie.ui.plot, which shows that text as an image. The circle on the canvas is built from the same two numbers: its center is the mean and its radius is the standard deviation.

import base64, io
import numpy as np
from matplotlib.figure import Figure

def gaussian(mu, sigma):
    fig = Figure(figsize=(4, 3))
    ax = fig.add_subplot()
    x = np.linspace(-4, 4, 200)
    ax.plot(x, np.exp(-(x - mu)**2 / (2 * sigma**2)) / (sigma * np.sqrt(2 * np.pi)))
    ax.set_ylim(0, 2)
    buf = io.BytesIO()
    fig.savefig(buf, format='png')
    return 'data:image/png;base64,' + base64.b64encode(buf.getvalue()).decode()

pie.clear()
mu = pie.scalar(0, out='mu')
sigma = pie.scalar(1, out='sigma')
pie.circle(pie.point(mu, 0), sigma)
pie.ui.slider(mu, min=-3, max=3, label='mu')
pie.ui.slider(sigma, min=0.2, max=3, label='sigma')
pie.ui.plot(pie.lift(gaussian, pie.Text)(mu, sigma))

Move a slider. The circle and the plot change together.

To put the plot on the canvas, hover over it and drag the ⋮⋮ grip at its left onto the canvas. It keeps updating there. Panning and zooming the canvas don't move it. Run the block again to put it back under the editor.

The function uses Figure instead of plt because plt keeps its figures open, and they would also show under the editor.

The plot only shows values. Clicking it can't change a node, so the sliders stay the way to change it.


A 3D surface

This block draws the surface z=2sin⁡xcos⁡yz = 2 \sin x \cos yz=2sinxcosy and marks one slice of it in red: the curve where the surface meets the plane at a chosen y. The canvas shows the same slice, flat on, as a second lifted function.

Running this block clears the canvas, so the sliders above disappear until you run their block again.

import base64, io
import numpy as np
from matplotlib.figure import Figure

def height(x, y):
    return 2 * np.sin(x) * np.cos(y)

grid = np.linspace(-3, 3, 40)
X, Y = np.meshgrid(grid, grid)
Z = height(X, Y)

def surface(y, angle):
    fig = Figure(figsize=(4, 4))
    ax = fig.add_subplot(projection='3d', computed_zorder=False)
    ax.plot_surface(X, Y, Z, cmap='viridis', alpha=0.8)
    ax.plot(grid, np.full_like(grid, y), height(grid, y), color='crimson', linewidth=3)
    ax.view_init(elev=30, azim=angle)
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    buf = io.BytesIO()
    fig.savefig(buf, format='png')
    return 'data:image/png;base64,' + base64.b64encode(buf.getvalue()).decode()

def slice_at(y):
    return np.column_stack([grid, height(grid, y)])

pie.clear()
y0 = pie.scalar(0.5, out='y0')
angle = pie.scalar(-60, out='angle')
curve = pie.lift(slice_at, pie.Array[pie.Point])(y0, hidden=True)
pie.line(curve[:-1], curve[1:], stroke='crimson')
pie.ui.slider(y0, min=-3, max=3, step=0.1, label='y')
pie.ui.slider(angle, min=-180, max=180, step=5, label='turn')
pie.ui.plot(pie.lift(surface, pie.Text)(y0, angle))

Move y. The red line slides across the surface, and the curve on the canvas changes with it. At y=0y = 0y=0 it is a full sine wave. Near y=±1.57y = \pm 1.57y=±1.57, where cos⁡y\cos ycosy is 0, it goes flat.

Move turn to look at the surface from another side. Only the plot changes, because the curve on the canvas doesn't depend on turn.