A config-driven multiplex TIFF reader supporting QPTIFF, OME-TIFF, and ImageJ formats
Project description
MxTiffFile
A Python package for reading and processing multiplex fluorescence TIFF files — including QPTIFF (PerkinElmer/Akoya Fusion), OME-TIFF, and ImageJ TIFF formats.
Overview
MxTiffFile is a general-purpose multiplex TIFF reader that automatically detects the file format and extracts channel/biomarker metadata without any manual configuration. Format knowledge is defined in a bundled formats.json config file, making it easy to add support for new formats without changing Python code.
Key capabilities:
- Automatic format detection for QPTIFF, OME-TIFF, and ImageJ TIFF files
- Config-driven channel extraction — no hardcoded format assumptions
- Heuristic fallback for unrecognized formats
- Explicit error (
MxTiffFormatError) when channel names cannot be determined - Memory-efficient tools for extracting regions of interest from large images
- Support for multi-channel and multi-resolution image pyramids
QPTiffFilebackward-compatible alias (emitsDeprecationWarning)
Supported Formats
| Format | Detection | Metadata Scope |
|---|---|---|
| PerkinElmer/Akoya QPTIFF | is_qpi flag or PerkinElmer-QPI-ImageDescription XML root |
Per-page XML |
| OME-TIFF | is_ome flag or OME XML root |
File-level XML (page 0) |
| ImageJ TIFF | is_imagej flag |
ImageJ metadata dict |
OME-TIFF takes priority over ImageJ for hybrid files produced by Bio-Formats.
Basic Usage
from mxtifffile import MxTiffFile
# Open any supported multiplex TIFF
f = MxTiffFile('example_image.qptiff')
# See which format was detected
print(f.format_id) # e.g. "qptiff", "ome-tiff", or "imagej"
# Display available biomarkers
print(f.get_markers())
# Print summary of all channels
f.print_channel_summary()
# Read a single channel by biomarker name
dapi = f.read_region('DAPI')
# Read multiple channels
markers = f.read_region(['DAPI', 'CD8', 'PD-L1'])
Migrating from QPTiffFile
QPTiffFile continues to work as a drop-in alias but will emit a DeprecationWarning. Update your imports to use MxTiffFile:
# Before (deprecated)
from mxtifffile import QPTiffFile
f = QPTiffFile('image.qptiff') #note: you will use f.get_biomarkers() instead of f.get_markers()
# After
from mxtifffile import MxTiffFile
f = MxTiffFile('image.qptiff')
Advanced Usage
Heuristic Detection
For files not matched by any entry in formats.json, the reader falls back to a heuristic that searches the file's XML metadata for a configurable anchor marker name. By default this is "DAPI":
import mxtifffile
# Change the anchor marker used for heuristic detection
mxtifffile.ANCHOR_MARKER = "HOECHST"
f = mxtifffile.MxTiffFile('unknown_format.tiff')
If the heuristic succeeds, a warning is emitted: MxTiffFile: format not recognized; channel names inferred heuristically. If both config-based and heuristic detection fail, MxTiffFormatError is raised.
Handling Unknown Formats
from mxtifffile import MxTiffFile, MxTiffFormatError
try:
f = MxTiffFile('proprietary_image.tiff')
except MxTiffFormatError as e:
print(f"Could not detect format: {e}")
# The error message includes the file path, XML root tag (if any),
# and a suggestion to add a config entry or change ANCHOR_MARKER
Custom Format Configuration
Point the reader at your own formats.json to support proprietary or non-standard formats:
from mxtifffile import MxTiffFile
# Per-file custom config
f = MxTiffFile('proprietary.tiff', formats_config='/path/to/my_formats.json')
You can also pre-cache a custom config for use across multiple files:
from mxtifffile import load_formats
load_formats('/path/to/my_formats.json')
formats.json Schema
Each entry in formats.json describes how to detect a format and where to find channel metadata:
{
"formats": [
{
"id": "my-format",
"name": "My Instrument Format",
"detection": {
"xml_root_tag": "MyRootElement",
"xml_namespace": null,
"tifffile_flag": null
},
"metadata_scope": "per_page",
"channel_fields": {
"biomarker": [".//MarkerName", ".//Biomarker"],
"fluorophore": ".//Fluorophore"
}
}
]
}
metadata_scope is one of "per_page", "file_level", or "imagej". XPath lists are tried in order; the first match wins.
Installation
From PyPI
pip install mxtifffile
From Source
git clone https://github.com/grenkoca/mxtifffile.git
cd mxtifffile
pip install -e .
System Requirements
For full functionality including compressed TIFF support, you'll need:
macOS
# For Apple Silicon or Intel
brew install libaec
note: on Apple Silicon chips, you may need to install libaec via conda: https://anaconda.org/conda-forge/libaec/
Linux
# Ubuntu/Debian
sudo apt-get install libaec-dev
# CentOS/RHEL
sudo yum install libaec-devel
Dependencies
Core dependencies:
- tifffile
- numpy
Optional dependencies:
- imagecodecs (recommended for compressed TIFF support)
Usage Examples
See this link for publicly available PhenoCycler data:
# Or, pull an image directly:
wget https://downloads.openmicroscopy.org/images/Vectra-QPTIFF/perkinelmer/PKI_scans/LuCa-7color_Scan1.qptiff
Working with Regions of Interest
In [1]: from mxtifffile import MxTiffFile
In [2]: f = MxTiffFile('../Phenocycler/Data/slides/Scan1.qptiff')
In [3]: f.format_id
Out[3]: 'qptiff'
In [4]: f.read_region('DAPI')
Out[4]:
memmap([[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...
[0, 0, 0, ..., 0, 0, 0]], dtype=uint8)
You can also do more complex calls by specifying:
- a set of multiple channels by name (
layers) - various x/y locations (
pos) or subregions (shape) - different downsampled levels in the image pyramid (
level)
In [5]: f.read_region(
...: layers=['DAPI', 'FITC', 'Texas Red'],
...: pos=(500, 1000),
...: shape=(500, 500),
...: level=2
...: )
# Returns an (x, y, num_channels) array
Out[5]:
array([[[0, 0, 0],
[0, 0, 0],
...]], dtype=uint8)
The returned arrays are compatible with any library that accepts array-like objects, such as matplotlib:
In [6]: import matplotlib.pyplot as plt
In [7]: img = f.read_region(layers=['DAPI'], shape=(500, 500), level=4)
In [8]: plt.imshow(img, cmap='gray')
In [9]: plt.show()
Citation
If you use this software in your research, please cite:
@software{mxtifffile,
author = {Grenko, Caleb},
title = {MxTiffFile: A Python package for working with multiplexed image files},
url = {https://github.com/grenkoca/mxtifffile},
year = {2025},
}
Contact
The best way to get in touch is via email: grenko.caleb (at) mayo.edu
Acknowledgments
- Based on the excellent tifffile library by Christoph Gohlke
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mxtifffile-0.0.2.tar.gz.
File metadata
- Download URL: mxtifffile-0.0.2.tar.gz
- Upload date:
- Size: 21.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
182300f84e56c8637c0fdff0a296ddc55508945599cd22d3a42d98ac426e92d2
|
|
| MD5 |
a0d8643680e619a51fc9c97b419921cc
|
|
| BLAKE2b-256 |
5c0746a849539857df147797989bbaf06cba5e2eca9ae5400b3cc0c0f7fbe2d0
|
Provenance
The following attestation bundles were made for mxtifffile-0.0.2.tar.gz:
Publisher:
python-publish.yml on grenkoca/mxtifffile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mxtifffile-0.0.2.tar.gz -
Subject digest:
182300f84e56c8637c0fdff0a296ddc55508945599cd22d3a42d98ac426e92d2 - Sigstore transparency entry: 997980061
- Sigstore integration time:
-
Permalink:
grenkoca/mxtifffile@b3f7da573b1b423cdd2944de805bf6672b26c416 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/grenkoca
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@b3f7da573b1b423cdd2944de805bf6672b26c416 -
Trigger Event:
release
-
Statement type:
File details
Details for the file mxtifffile-0.0.2-py3-none-any.whl.
File metadata
- Download URL: mxtifffile-0.0.2-py3-none-any.whl
- Upload date:
- Size: 23.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
87488997dc59baa5004f85177f6ac06cd7fda1e9c76aef9173a8bbdc6e042a1d
|
|
| MD5 |
68b5edf2cbc1437913a52c3db88fd6dd
|
|
| BLAKE2b-256 |
030ce5d40c8bc1823eed435a33cb0a398be952211738a9cba0d4e1d942c57042
|
Provenance
The following attestation bundles were made for mxtifffile-0.0.2-py3-none-any.whl:
Publisher:
python-publish.yml on grenkoca/mxtifffile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mxtifffile-0.0.2-py3-none-any.whl -
Subject digest:
87488997dc59baa5004f85177f6ac06cd7fda1e9c76aef9173a8bbdc6e042a1d - Sigstore transparency entry: 997980142
- Sigstore integration time:
-
Permalink:
grenkoca/mxtifffile@b3f7da573b1b423cdd2944de805bf6672b26c416 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/grenkoca
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@b3f7da573b1b423cdd2944de805bf6672b26c416 -
Trigger Event:
release
-
Statement type: