Mpltoolbox demo#

[1]:
%matplotlib widget
import matplotlib.pyplot as plt
import mpltoolbox as tbx
import numpy as np


def new_figure():
    fig, ax = plt.subplots(dpi=96)
    ax.set_xlim(0, 100)
    ax.set_ylim(0, 100)
    return fig, ax

Points#

Use the Points tool to add markers to a plot.

Controls

  • Left-click to make new point

  • Left-click and hold on point to move point

  • Middle-click (or Ctrl + left-click) to delete point

[2]:
fig, ax = new_figure()

points = tbx.Points(ax=ax)

Lines#

Use the Lines tool to add lines to a plot. The argument n should be used to set the number of vertices per line.

Controls

  • Left-click to make new lines

  • Left-click and hold on line vertex to move vertex

  • Right-click and hold to drag/move the entire line

  • Middle-click (or Ctrl + left-click) to delete line

[3]:
fig, ax = new_figure()

lines = tbx.Lines(ax=ax, n=2)

Rectangles#

Use the Rectangles tool to add rectangles to a plot.

Controls

  • Left-click and hold to make new rectangle

  • Left-click and hold on ellipse vertex to resize

  • Right-click and hold to drag/move rectangle

  • Middle-click (or Ctrl + left-click) to delete rectangle

[4]:
fig, ax = new_figure()

rects = tbx.Rectangles(ax=ax)

Ellipses#

Use the Ellipses tool to add ellipses to a plot.

Controls

  • Left-click and hold to make new ellipse

  • Left-click and hold on ellipse vertex to resize

  • Right-click and hold to drag/move ellipse

  • Middle-click (or Ctrl + left-click) to delete ellipse

[5]:
fig, ax = new_figure()

ellipses = tbx.Ellipses(ax=ax)

Polygons#

Use the Polygons tool to add closed polygons to a plot.

Controls

  • Left-click to make new polygon

  • Left-click and hold on polygon vertex to move vertex

  • Right-click and hold to drag/move the entire polygon

  • Middle-click (or Ctrl + left-click) to delete polygon

[6]:
fig, ax = new_figure()

polygons = tbx.Polygons(ax=ax)

Spans#

Use the Vspans tool to add vertical spans to a plot.

Controls

  • Left-click and hold to make new span

  • Left-click and hold on span vertex to resize

  • Right-click and hold to drag/move span

  • Middle-click (or Ctrl + left-click) to delete span

[7]:
fig, ax = new_figure()

vspans = tbx.Vspans(ax=ax)

Use the Hspans tool to add horizontal spans to a plot.

[8]:
fig, ax = new_figure()

hspans = tbx.Hspans(ax=ax)

Callbacks#

Every tool in the mpltoolbox comes with entry points for adding callbacks to different events. The different events are:

  • on_create: called when drawing the shape (rectangle, line or polygon) is complete

  • on_change: called when the shape has changed in any way (position, size…)

  • on_remove: called when the shape is deleted (middle-click, or Ctrl + left-click)

  • on_vertex_press: called when a vertex is clicked (left-click)

  • on_vertex_move: called when a vertex is moved

  • on_vertex_release: called when the mouse button is released after clicking a vertex

  • on_drag_press: called when the entire shape (rectangle, line, etc..) is right clicked to initiate drag

  • on_drag_move: called for every movement during shape drag (right-click and hold)

  • on_drag_release: called when the shape is released after drag

Below is a couple of examples on how these callbacks are used.

Example: adding markers to slice a 3d data cube#

We first make some three-dimensional data:

[9]:
N = 200
M = 300
L = 100
xx = np.arange(N, dtype=np.float64)
yy = np.arange(M, dtype=np.float64)
zz = np.arange(L, dtype=np.float64)
x, y, z = np.meshgrid(xx, yy, zz, indexing='ij')
b = N / 20.0
c = M / 2.0
d = L / 2.0
r = np.sqrt(((x - c) / b) ** 2 + ((y - c) / b) ** 2 + ((z - d) / b) ** 2)
a = 10.0 * np.sin(r) + np.random.random([N, M, L])

Create a figure to display the first z slice of the data as a two-dimensional image, as well as an empty subplot below:

[10]:
fig, ax = plt.subplots(2, 1, figsize=(7, 7))
fig.canvas.header_visible = False
ax[0].imshow(a[..., 0], interpolation="none", origin="lower")
ax[0].set(xlabel='x', ylabel='y')
ax[1].set(xlabel='z')
fig.tight_layout()

Then we add a Points tool where:

  • When a dot is added on the image, a line is created in the lower panel, showing a one-dimensional z slice at the location of the marker

  • When a dot is moved, the z line is updated accordingly

  • When a dot is removed, we remove the corresponding z profile

[11]:
def make_line(new_point):
    (line,) = ax[1].plot(a[int(new_point.y), int(new_point.x), :])
    new_point.associated = line


def update_line(new_point):
    new_point.associated.set_ydata(a[int(new_point.y), int(new_point.x), :])


def remove_line(point):
    point.associated.remove()


points = tbx.Points(ax=ax[0], mec='white')
points.on_create(make_line)
points.on_change(update_line)
points.on_remove(remove_line)

Now click on the 2D image to add point markers and z profiles on the line plot below.