IO — Quick Demo#

Load any electron microscopy file with one line. IO.file() returns an IOResult that every widget accepts directly.

[1]:
try:
    %load_ext autoreload
    %autoreload 2
    %env ANYWIDGET_HMR=1
except Exception:
    pass
env: ANYWIDGET_HMR=1
[2]:
import numpy as np
import tempfile, pathlib
from quantem.widget import IO, Show2D, Show3D

Single file#

[3]:
# Create a synthetic HRTEM image and save as .npy
rng = np.random.default_rng(42)
size = 256
y, x = np.mgrid[:size, :size]
img = np.zeros((size, size), dtype=np.float32)
for freq, angle in [(0.08, 0.0), (0.06, np.pi / 3), (0.10, np.pi / 6)]:
    img += np.cos(2 * np.pi * freq * (x * np.cos(angle) + y * np.sin(angle)))
r = np.sqrt((x - size // 2)**2 + (y - size // 2)**2)
img *= 1.0 / (1 + np.exp(-0.05 * (size // 3 - r)))
img += rng.normal(0, 0.3, (size, size)).astype(np.float32)
tmp = tempfile.mkdtemp()
npy_path = pathlib.Path(tmp) / "hrtem.npy"
np.save(npy_path, img)
result = IO.file(npy_path)
print(result)
Show2D(result, title="HRTEM (from .npy)", cmap="gray")
IOResult
  shape:      256 x 256
  dtype:      float32
  title:      hrtem
[3]:

Multiple files → stack#

[4]:
# Save a focal series as separate .npy files
paths = []
for i in range(5):
    defocus = (i - 2) * 0.5
    frame = img * np.cos(defocus * r * 0.02).astype(np.float32)
    frame += rng.normal(0, 0.2, (size, size)).astype(np.float32)
    p = pathlib.Path(tmp) / f"focal_{i:03d}.npy"
    np.save(p, frame)
    paths.append(p)
result = IO.file(paths)
print(result)
Show3D(result, title="Focal Series")
IOResult
  shape:      5 x 256 x 256
  dtype:      float32
  title:      tmpnu_giu2w
  labels:     ['focal_000', 'focal_001', 'focal_002', ...] (5 total)
[4]:

Folder → stack#

[5]:
# Save PNGs to a folder, then load the whole folder
from PIL import Image
png_dir = pathlib.Path(tmp) / "png_series"
png_dir.mkdir(exist_ok=True)
for i in range(4):
    frame = img + rng.normal(0, 0.4, (size, size)).astype(np.float32)
    arr_u8 = np.clip((frame - frame.min()) / (frame.max() - frame.min()) * 255, 0, 255).astype(np.uint8)
    Image.fromarray(arr_u8).save(png_dir / f"frame_{i:03d}.png")
result = IO.folder(png_dir, file_type="png")
print(result)
Show3D(result, title="PNG Folder")
IOResult
  shape:      4 x 256 x 256
  dtype:      float32
  title:      png_series
  labels:     ['frame_000', 'frame_001', 'frame_002', 'frame_003']
[5]:

IOResult duck typing#

IOResult forwards NumPy methods — use .sum(), .mean(), .shape, etc. directly.

[6]:
result = IO.folder(png_dir, file_type="png")
print(f"shape:  {result.shape}")
print(f"mean:   {result.mean():.2f}")
print(f"dtype:  {result.dtype}")
# Collapse stack to mean projection
mean_proj = result.mean(axis=0)
Show2D(mean_proj, title="Mean Projection")
shape:  (4, 256, 256)
mean:   124.10
dtype:  float32
[6]:

Supported formats#

[7]:
IO.supported_formats()
[7]:
['ali',
 'app5',
 'asw',
 'bcf',
 'blo',
 'bmp',
 'csv',
 'de5',
 'dens',
 'dib',
 'dm3',
 'dm4',
 'eds',
 'elid',
 'emd',
 'emi',
 'ems',
 'emsa',
 'gif',
 'h5',
 'hdf5',
 'hspy',
 'img',
 'jpe',
 'jpeg',
 'jpg',
 'map',
 'mas',
 'mib',
 'mrc',
 'mrcz',
 'msa',
 'msp',
 'nc',
 'npy',
 'npz',
 'nxs',
 'pbm',
 'pcx',
 'pgm',
 'png',
 'ppm',
 'pro',
 'prz',
 'pts',
 'rpl',
 'ser',
 'spc',
 'spd',
 'spi',
 'spx',
 'sur',
 'tif',
 'tiff',
 'tvf',
 'tvips',
 'unf',
 'wdf',
 'xbm',
 'xml',
 'zspy']