Metadata-Version: 2.4
Name: mesc-io
Version: 0.5.0
Summary: Read Femtonics .mesc two-photon recordings, in the units the native reader shows
Author: Lynn Smith
License-Expression: MIT
Project-URL: Homepage, https://github.com/LynnYuSmith/mesc-io
Project-URL: Repository, https://github.com/LynnYuSmith/mesc-io
Project-URL: Changelog, https://github.com/LynnYuSmith/mesc-io/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/LynnYuSmith/mesc-io/issues
Keywords: mesc,femtonics,two-photon,calcium-imaging,microscopy,hdf5
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Topic :: Scientific/Engineering :: Image Processing
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: h5py>=3.6
Requires-Dist: numpy>=1.21
Provides-Extra: tiff
Requires-Dist: tifffile>=2021.11; extra == "tiff"
Provides-Extra: imagej
Requires-Dist: roifile>=2022.9; extra == "imagej"
Provides-Extra: register
Requires-Dist: suite2p<1.0,>=0.14; extra == "register"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: roifile>=2022.9; extra == "dev"
Dynamic: license-file

# mesc-io

[![tests](https://github.com/LynnYuSmith/mesc-io/actions/workflows/tests.yml/badge.svg)](https://github.com/LynnYuSmith/mesc-io/actions/workflows/tests.yml) [![PyPI](https://img.shields.io/pypi/v/mesc-io)](https://pypi.org/project/mesc-io/)

Read Femtonics `.mesc` two-photon recordings in Python — the frames in the units the native
reader shows, every unit's metadata, an export, a write-back, and a viewer that draws ROIs and
computes their dF/F.

![the viewer on a synthetic recording: four spots, three of them blinking, their dF/F below](https://raw.githubusercontent.com/LynnYuSmith/mesc-io/main/docs/viewer.png)

## Install

```
pip install mesc-io
pip install "mesc-io[tiff,imagej]"     # + TIFF export, ImageJ ROI export
```

Needs Python 3.9 or newer, numpy and h5py; nothing else for reading and viewing. Motion
correction (`mesc-io register`) is an extra, `[register]`, and pulls in Suite2p 0.14.

## Python

```python
from mesc_io import MescFile

with MescFile("recording.mesc") as f:
    for u in f.units():
        print(u.path, u.shape, u.frame_rate_hz, u.pixel_size_um)

    frames = f.read("MUnit_0", channel=0)              # reader units, float64
    frames = f.read("MUnit_0", reader_units=False)     # the stored integers
    for block in f.iter_frames("MUnit_0", block=500):  # bigger than memory
        ...
```

`read` refuses over 4 GB by default (`max_gb=None` to override). A unit name that matches in
more than one session is refused, not resolved to the first; `MSession_1/MUnit_0` always works.

## Command line

```
mesc-io info      recording.mesc                            # units, rates, pixel sizes
mesc-io check     recording.mesc                            # what the file disagrees with itself about
mesc-io export    recording.mesc MUnit_0 u0.h5              # or u0.tif — a Fiji hyperstack
mesc-io export    recording.mesc all out_folder --tiff      # every unit, one .tif each
mesc-io writeback recording.mesc out.mesc MUnit_0 u0.h5     # processed frames back in
mesc-io view      recording.mesc                            # the recording in a browser
```

`info` and `check` take `--json`.

### Opening a recording in Fiji

Fiji has no reader for `.mesc` (Bio-Formats lists none for Femtonics). `export … .tif` writes what
Fiji opens with File ▸ Open as a calibrated hyperstack: every channel (`--channel N` for one), in
composite mode with each channel in its own colour and display range; the frame interval for a
recording or the slice spacing for a z-stack; x and y pixel sizes in µm; and the unit's comment,
the units and each channel's conversion under Image ▸ Show Info. Values are in reader units
(float32), as the native reader shows them; `--stored-units` keeps the file's integers. Frames are
streamed, so a unit larger than memory exports too.

### Motion correction

```
mesc-io register recording.mesc recording_MC.mesc          # one reference per unit
mesc-io preset save soma --block-size 128 --max-shift-nr 5 # name a set of settings
mesc-io register recording.mesc out.mesc --preset soma     # use it; a flag still wins
```

Needs `pip install "mesc-io[register]"`. The defaults are the calcium-imaging pipeline's own
correction; z-stacks and units too short to register are skipped and said so. Groups, presets,
where they are kept and how to share them: [docs/registration.md](docs/registration.md).

### The viewer

`mesc-io view` opens the recording in a private browser window: units on the left with a
thumbnail each and the unit's own metadata (rate, pixel size, the stage position and the
position from the zero set on the rig); the image in
the middle — scrub it, average a window of N frames, zoom into a place by dragging a box;
ROIs on the right (spot, rectangle, polygon; drag to move, type a size); every ROI's time
course along the bottom, raw or dF/F by our pipeline's method (`mesc_io.dff`, numpy only,
held against the pipeline's functions in the tests), stacked or overlaid, zoomed by dragging a box. ROIs belong to the
unit they were drawn on and are saved as you go, in one folder, `~/mesc-viewer/`, never beside
the raw file; so is the view itself, so reopening the file puts you back where you were.
A z-stack is shown in slices and microns, with a max projection, a **3D** view you can turn
(MIP, semi-transparent, or coloured by depth) and **XYZ** orthogonal views through one crosshair.
With **overlay** on, a two-channel stack is shown in both: green and magenta, each channel through
its own window and with its own floor, white where both are bright (depth colouring stays one
channel). In 3D, **point** marks the brightest voxel under a click (numbered, with its µm position,
slice and each channel's value; also shown in XYZ), **measure** gives the distance between two
points in µm — shift+click goes on into a path, an axon's length — **box** clips the stack to six
limits and **slab** draws only a thickness around the current slice, as MIP. **object** grows a
connected region from a clicked seed (voxels at least a share of its peak, within a radius) and
gives its volume in µm³, centre, extent and each channel's mean; it is outlined in XYZ. A **γ** per
channel brightens the dim parts (below 1) or darkens them (above 1) in 3D, XYZ and the 3D PNG; at 1
the picture is unchanged.

**surface** in XYZ marks where the tissue begins: a few clicks in the XZ / YZ panes, just above the
first slice where the label appears, and a surface is fitted through them — flat from one mark, a
tilted plane from three, a curved one from six spread over the stack (a brain under a window is
rarely level). It is drawn in the panes, the tilt is given in degrees, and every 3D point and the
crosshair get their depth below it in µm, into the tissue: the brighter side of the stack, or the
side you set. **csv** saves the marks, the fit and the points' depths; the marks are kept with the view.

**mosaic** (shown when a file holds two or more z-stacks with a stage position) lays every tile out
as one field where the stage put it, a plane at a time, with hard seams — each pixel from the tile
whose centre is nearest, never an average of two places. **auto** stitches it from the overlaps:
every overlapping pair matched in 3D (x, y and the slice), one correction per tile by least squares,
each seam labelled with its correlation and what the solve left of it. **edit** moves a tile by hand
(drag; arrows a pixel, [ ] a slice, h hides; ⌘Z undoes), **flatten** puts every tile's marked surface
on one plane, double-click opens a tile in XYZ. **crop** + planes from–to + **TIFF** cut a piece out as
a Fiji hyperstack, placed exactly as on screen; **layout** saves the corrections as JSON. The same is
in Python: `mesc_io.mosaic.tiles / register / compose / to_tiff`.

**ruler** (beside the ROI tools) measures in µm between two clicks on the image; **PNG** saves what
is on screen for a figure — the image at whole pixels with the ROIs, the ruler, a scale bar and a
caption, or the 3D view — and **png** beside csv the traces.

The picture is drawn in **fixed limits**: by default the display window the recording was
saved with on the rig (the file's own LUT, typically 0–2000 in reader units), the same for every
frame, so a frame that is dimmer looks dimmer — bleaching, a change of laser power or a field
drifting out of focus show while you scrub. Type other limits per unit and channel (they live in
the view, never in the file; **file** brings the saved ones back), or switch to **auto %**, which
stretches the recording on percentiles of the whole unit — one window for every frame, so
scrubbing does not flicker. Each channel
has a palette: its colour from the file, a single colour, or one of 25 of Fabio Crameri's
perceptually uniform Scientific colour maps (batlow, oslo, lajolla, vik, roma, …). **Overlay**
puts all channels in one picture, each through its own limits and colour.

Layout and decisions: [docs/viewer_design.md](docs/viewer_design.md).

To try it without a recording, make one:

```
python tools/make_synthetic.py            # writes synthetic_view.mesc: 3 units, 4 spots, 3 of them blinking
mesc-io view synthetic_view.mesc
```

## Development

```
pip install -e ".[tiff,dev]"
pytest
```

The package lives under `src/`, so tests run against the installed copy. CI runs the suite on
Python 3.9, 3.12 and 3.13 on Linux, macOS and Windows, plus one job with Suite2p for the
registration tests; the browser checks (`tests/*_real_chrome.js`) run in a real Chrome and are
not part of pytest.

## Acknowledgements

F. Kamari, for the idea. Claude Code, for the debugging.

## Licence

MIT — see [LICENSE](LICENSE).

The viewer's colour maps include Fabio Crameri's Scientific colour maps (v8.0, MIT, © 2020 Fabio
Crameri; [licence](src/mesc_io/third_party/crameri_LICENSE.txt)). If a figure made with them goes
into a paper, cite: Crameri, F. (2018). *Scientific colour maps*. Zenodo.
https://doi.org/10.5281/zenodo.1243862
