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, ...