Quick Start

This page walks through the most common operations using synthetic data that is included with the package.

Creating Synthetic Data

import numpy as np
import matplotlib.pyplot as plt
import escape
from escape.storage.example_data import make_scan, make_pump_probe_scan

# Ten-step delay scan, 500 events per step
sig = make_scan(
    n_steps=10,
    n_events_per_step=500,
    scan_par_name="delay_ps",
    scan_par_values=np.linspace(-1, 4, 10),
    name="bragg_intensity",
    seed=0,
)

print(sig)
print(sig.scan)

Per-Step Statistics and Plotting

# Per-step statistics
means  = sig.scan.nanmean()
stds   = sig.scan.nanstd()
counts = sig.scan.count()

# Built-in scan plot (median ± σ/√N)
fig, ax = plt.subplots()
sig.scan.plot(axis=ax, fmt="o-")
ax.set_xlabel("delay / ps")
ax.set_ylabel("Bragg intensity (a.u.)")
plt.tight_layout()
plt.show()

Boolean Filtering

# Keep only events with signal above a threshold
strong = sig.filter(0.7, 1.5)   # keep 0.7 ≤ sig ≤ 1.5

print(f"Before filter: {len(sig)} events")
print(f"After  filter: {len(strong)} events")

# Re-plot on the filtered data
fig, ax = plt.subplots()
strong.scan.plot(axis=ax, fmt="s-", label="filtered")
sig.scan.plot(axis=ax, fmt="o--", label="all")
ax.legend()
plt.show()

Normalisation with Index Alignment

sig, i0, pump_on, delay = make_pump_probe_scan(n_steps=10, seed=1)

# Division auto-aligns on common pulse IDs
sig_norm = sig / i0

# Separate pump-on and pump-off shots
sig_on  = sig_norm[~pump_on]   # laser ON
sig_off = sig_norm[pump_on]    # laser OFF (reference)

# Per-step pump/probe ratio
ratio = sig_on.scan / sig_off.scan.nanmean(axis=0)

fig, ax = plt.subplots()
ratio.scan.plot(axis=ax, fmt="o-")
ax.axhline(1.0, ls="--", color="k")
ax.set_xlabel("delay / ps")
ax.set_ylabel("relative signal")
plt.tight_layout()
plt.show()

Applying a Custom Function with map_index_blocks

from escape.storage.example_data import make_image_scan

imgs = make_image_scan(n_steps=3, n_events_per_step=50, seed=2)

# Sum a region of interest per event
roi = imgs[:, 25:45, 25:45]
roi_sum = roi.nansum(axis=(1, 2))

print(roi_sum.shape)   # (150,)

# Or apply a custom function to each chunk:
def hot_pixel_mask(block, threshold=200):
    out = block.copy()
    out[out > threshold] = np.nan
    return out

imgs_clean = imgs.map_index_blocks(hot_pixel_mask, 200)
mean_img = imgs_clean.scan[0].mean(axis=0).compute()

fig, ax = plt.subplots()
ax.imshow(mean_img, cmap="viridis")
ax.set_title("Mean image (step 0, hot-pixel masked)")
plt.tight_layout()
plt.show()

Storing Results to HDF5

import h5py

with h5py.File("quickstart_results.h5", "w") as fh:
    sig.store(fh, "signal")
    i0.store(fh,  "i0")
    ratio.store(fh, "ratio")

# Reload
with h5py.File("quickstart_results.h5", "r") as fh:
    ratio_loaded = escape.Array.load_from_h5(fh, "ratio")

print(ratio_loaded.scan)