IO — All Features#
Comprehensive demo of IO.file(), IO.folder(), multi-file/multi-folder stacking, auto-detect, and IOResult duck typing.
[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 PIL import Image
from quantem.widget import IO, Show2D, Show3D
Setup: synthetic EM data#
Create temp files in NPY, PNG, and TIFF formats to demonstrate all loading paths.
[3]:
rng = np.random.default_rng(42)
size = 256
y, x = np.mgrid[:size, :size]
def make_lattice(seed=0, freq_shift=0.0):
"""Simulate HRTEM lattice fringes."""
r = np.sqrt((x - size // 2)**2 + (y - size // 2)**2)
img = np.zeros((size, size), dtype=np.float32)
for freq, angle in [(0.08 + freq_shift, 0.0), (0.06, np.pi / 3)]:
img += np.cos(2 * np.pi * freq * (x * np.cos(angle) + y * np.sin(angle)))
img *= 1.0 / (1 + np.exp(-0.05 * (size // 3 - r)))
img += rng.normal(0, 0.3, (size, size)).astype(np.float32)
return img
tmp = tempfile.mkdtemp()
# NPY files
npy_dir = pathlib.Path(tmp) / "npy"
npy_dir.mkdir()
for i in range(6):
np.save(npy_dir / f"frame_{i:03d}.npy", make_lattice(i, freq_shift=i * 0.005))
# PNG folders (two separate sessions)
png_dir_a = pathlib.Path(tmp) / "session_a"
png_dir_b = pathlib.Path(tmp) / "session_b"
png_dir_a.mkdir(); png_dir_b.mkdir()
for i in range(3):
frame = make_lattice(i)
arr_u8 = np.clip((frame - frame.min()) / (frame.max() - frame.min()) * 255, 0, 255).astype(np.uint8)
Image.fromarray(arr_u8).save(png_dir_a / f"img_{i:03d}.png")
for i in range(4):
frame = make_lattice(i + 10)
arr_u8 = np.clip((frame - frame.min()) / (frame.max() - frame.min()) * 255, 0, 255).astype(np.uint8)
Image.fromarray(arr_u8).save(png_dir_b / f"img_{i:03d}.png")
# TIFF files
tif_dir = pathlib.Path(tmp) / "tiff"
tif_dir.mkdir()
for i in range(4):
frame = make_lattice(i + 20)
Image.fromarray(frame).save(tif_dir / f"scan_{i:03d}.tiff")
print(f"Temp dir: {tmp}")
Temp dir: /var/folders/xz/h9zytq2x1kgcckdf20y6hn4w0000gn/T/tmp3t2v8zqh
IO.file — single file#
[4]:
result = IO.file(npy_dir / "frame_000.npy")
print(result)
Show2D(result, title="Single NPY", cmap="gray")
IOResult
shape: 256 x 256
dtype: float32
title: frame_000
[4]:
IO.file — list of files#
[5]:
npy_files = sorted(npy_dir.glob("*.npy"))
result = IO.file(npy_files)
print(result)
Show3D(result, title="NPY File List")
IOResult
shape: 6 x 256 x 256
dtype: float32
title: npy
labels: ['frame_000', 'frame_001', 'frame_002', ...] (6 total)
[5]:
IO.folder — single folder#
[6]:
result = IO.folder(png_dir_a, file_type="png")
print(result)
Show3D(result, title="PNG Folder (session A)")
IOResult
shape: 3 x 256 x 256
dtype: float32
title: session_a
labels: ['img_000', 'img_001', 'img_002']
[6]:
IO.folder — auto-detect file type#
When file_type is omitted, IO auto-detects from folder contents.
[7]:
result = IO.folder(tif_dir)
print(result)
Show3D(result, title="Auto-detected TIFF folder")
IOResult
shape: 4 x 256 x 256
dtype: float32
title: tiff
labels: ['scan_000', 'scan_001', 'scan_002', 'scan_003']
[7]:
IO.folder — multiple folders#
Pass a list of folder paths to merge into one stack. All images must share the same spatial dimensions.
[8]:
result = IO.folder([png_dir_a, png_dir_b], file_type="png")
print(result)
Show3D(result, title="Two PNG folders merged")
IOResult
shape: 7 x 256 x 256
dtype: float32
labels: ['img_000', 'img_001', 'img_002', ...] (7 total)
[8]:
IOResult duck typing#
IOResult forwards NumPy methods to its .data array.
[9]:
result = IO.folder(png_dir_a, file_type="png")
# NumPy operations work directly on IOResult
print(f"shape: {result.shape}")
print(f"dtype: {result.dtype}")
print(f"mean: {result.mean():.2f}")
print(f"std: {result.std():.2f}")
# Reduce stack to mean projection
Show2D(result.mean(axis=0), title="Mean Projection")
shape: (3, 256, 256)
dtype: float32
mean: 124.24
std: 27.15
[9]:
print(result) output#
[10]:
result = IO.folder([png_dir_a, png_dir_b], file_type="png")
print(result)
IOResult
shape: 7 x 256 x 256
dtype: float32
labels: ['img_000', 'img_001', 'img_002', ...] (7 total)
Supported formats#
[11]:
fmts = IO.supported_formats()
print(f"{len(fmts)} formats: {', '.join(fmts[:15])}, ...")
61 formats: ali, app5, asw, bcf, blo, bmp, csv, de5, dens, dib, dm3, dm4, eds, elid, emd, ...