Skip to main content

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.

PyPI version PyPI Downloads License: MIT

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
  • QPTiffFile backward-compatible alias (emits DeprecationWarning)

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mxtifffile-0.0.2.tar.gz (21.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mxtifffile-0.0.2-py3-none-any.whl (23.4 kB view details)

Uploaded Python 3

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

Hashes for mxtifffile-0.0.2.tar.gz
Algorithm Hash digest
SHA256 182300f84e56c8637c0fdff0a296ddc55508945599cd22d3a42d98ac426e92d2
MD5 a0d8643680e619a51fc9c97b419921cc
BLAKE2b-256 5c0746a849539857df147797989bbaf06cba5e2eca9ae5400b3cc0c0f7fbe2d0

See more details on using hashes here.

Provenance

The following attestation bundles were made for mxtifffile-0.0.2.tar.gz:

Publisher: python-publish.yml on grenkoca/mxtifffile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for mxtifffile-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 87488997dc59baa5004f85177f6ac06cd7fda1e9c76aef9173a8bbdc6e042a1d
MD5 68b5edf2cbc1437913a52c3db88fd6dd
BLAKE2b-256 030ce5d40c8bc1823eed435a33cb0a398be952211738a9cba0d4e1d942c57042

See more details on using hashes here.

Provenance

The following attestation bundles were made for mxtifffile-0.0.2-py3-none-any.whl:

Publisher: python-publish.yml on grenkoca/mxtifffile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page