2D Image with Histogram#

Display a 2-D image with physical axes, a colourmap, and an interactive histogram below — all wired together with draggable threshold widgets.

Layout#

A GridSpec with two rows puts the image on top and a bar-chart histogram below. Two VLineWidget handles on the histogram mark the display_min / display_max thresholds; dragging them updates the image colour scale in real time.

Key bindings on the image panel: R reset view · C toggle colorbar · L / S cycle colour-scale modes.

import numpy as np
import anyplotlib as apl


rng = np.random.default_rng(1)

# ── Synthetic diffraction pattern ─────────────────────────────────────────────
N = 256
x = np.linspace(-5, 5, N)   # physical axis in nm
y = np.linspace(-5, 5, N)
XX, YY = np.meshgrid(x, y)
R = np.sqrt(XX ** 2 + YY ** 2)


def _ring(r, r0, width, amp):
    return amp * np.exp(-0.5 * ((r - r0) / width) ** 2)


image = (
    _ring(R, 0.0, 0.30, 1.00)    # central spot
    + _ring(R, 2.1, 0.15, 0.55)  # first-order ring
    + _ring(R, 4.2, 0.15, 0.25)  # second-order ring
    + rng.normal(scale=0.04, size=(N, N))
)

# ── Layout: image (top, 3×) + histogram bar chart (bottom, 1×) ────────────────
gs = apl.GridSpec(2, 1, height_ratios=[3, 1])
fig = apl.Figure(figsize=(500, 640))
ax_img  = fig.add_subplot(gs[0, 0])
ax_hist = fig.add_subplot(gs[1, 0])

# ── Image panel ───────────────────────────────────────────────────────────────
v = ax_img.imshow(image, axes=[x, y], units="nm")
v.set_colormap("inferno")

vmin_init = float(image.min())
vmax_init = float(image.max())
v.set_clim(vmin=vmin_init, vmax=vmax_init)

# First-order spot markers
dx = x[1] - x[0]


def phys_to_px(val):
    return (np.asarray(val) - x[0]) / dx


spot_nm = np.array([[ 2.1,  0.0], [-2.1,  0.0],
                    [ 0.0,  2.1], [ 0.0, -2.1]])
spot_px = np.column_stack([phys_to_px(spot_nm[:, 0]),
                           phys_to_px(spot_nm[:, 1])])
v.add_circles(spot_px, name="spots", radius=7,
              edgecolors="#00e5ff", facecolors="#00e5ff22",
              labels=["g1", "g1_bar", "g2", "g2_bar"])

# ── Histogram bar chart ────────────────────────────────────────────────────────
counts, edges = np.histogram(image.ravel(), bins=64)
bin_centers   = 0.5 * (edges[:-1] + edges[1:])

h = ax_hist.bar(counts, x_centers=bin_centers, orient="v",
                color="#4fc3f7", y_units="count")

# ── Draggable threshold handles on the histogram ──────────────────────────────
wlo = h.add_vline_widget(vmin_init, color="#ff6e40")   # low-threshold handle
whi = h.add_vline_widget(vmax_init, color="#ffffff")   # high-threshold handle


@wlo.on_release
def _apply_low(event):
    """Update image display_min when the low handle is released."""
    v.set_clim(vmin=event.x)


@whi.on_release
def _apply_high(event):
    """Update image display_max when the high handle is released."""
    v.set_clim(vmax=event.x)


fig

Adjust colour map#

set_colormap() switches the palette; set_clim() adjusts the display range.

v.set_colormap("viridis")
v.set_clim(vmin=0.0, vmax=0.8)

fig

Total running time of the script: (0 minutes 0.107 seconds)

Gallery generated by Sphinx-Gallery