CLI Reference¶
In plain words
Change how Thyra converts explains the common options one task at a time. This page lists every option.
INPUT -- Path to input MSI file or directory (.imzML, .d, .raw, a
Rapiflex acquisition folder, or .mzpeak)
OUTPUT -- Path for output .zarr directory
thyra also has three metadata subcommands, thyra metadata,
thyra validate and thyra export-metaspace -- see
Metadata subcommands.
Grouped help
thyra --help lists every option under a category heading, in this order:
Conversion, Logging, Ion mobility grid (advanced), Resampling (advanced),
imzML-specific, Bruker-specific, Waters-specific, Other, and a General
section holding --version and --help. The sections on this page follow
the same order. The one page section with no matching help group is
Performance, which now records only options that were
removed or that select nothing -- there is nothing left there for --help
to list.
Exit status¶
| Code | Meaning |
|---|---|
0 |
Conversion completed and the output store was written |
1 |
Conversion failed |
2 |
Invalid command-line arguments (click usage error) |
A refusal Thyra planned for -- a .d directory with no analysis files, a
Waters raster whose stage never moved, a mass range with no extent, a source
in which no pixel carries a spectrum -- prints its message once at ERROR and
nothing else. The traceback behind it is kept for -v DEBUG, and a traceback
at ERROR now means an exception nobody planned for, which is worth reporting
as a bug.
A conversion that would store nothing is one of those failures. If no
position carries a spectrum -- an all-zero source, every spectrum empty,
every peak outside a narrowed --resample-min-mz/--resample-max-mz range,
every coordinate off the declared grid -- the conversion exits 1 and
leaves no store, rather than exiting 0 with a zarr holding no table. The
message names which of those happened. A multi-slice source with some
empty planes is not affected: those planes are dropped with a warning and
the rest of the store is written.
A failed conversion renames any partially written store to
<output>.zarr.failed, so the output path stays free for a retry and an
incomplete store is never left where a finished one is expected. An
interrupted conversion is a failed one: Ctrl-C exits 1 and takes the
same path, so the partial store is moved aside and the scratch directories
the conversion built (.thyra_summed_* and its siblings, next to the
output) are removed rather than left behind. A Ctrl-C after the store is
saved comes too late to matter: the store is complete, stays in place, and
thyra exits 0. This makes thyra safe to
chain in a shell script or CI job:
Conversion¶
| Option | Default | Description |
|---|---|---|
--pixel-size FLOAT |
auto-detect | Pixel size in micrometers, applied to both axes. Auto-detection keeps the source's own x and y pitch separately, so an anisotropic raster stays anisotropic; passing this declares it square |
--region TEXT |
all | Convert one region of a timsTOF .d, by .mis Area Name or by DB RegionNumber. Checked against the dataset's own region list whether it has one region or several; a value that matches no Area Name is read as a RegionNumber, and says so. Every other format refuses it; list_regions lists the regions of any input |
--resample / --no-resample |
enabled | Mass axis resampling |
--include-optical / --no-optical |
enabled | Include optical images in output |
--mobility-table / --no-mobility-table |
enabled | Also write the mobility-resolved sibling table when the source shares one set of (m/z, ion mobility) features across pixels (see Output Format) |
--mobility-heatmap / --no-mobility-heatmap |
enabled | When the source has an ion mobility dimension, store the mean mass-mobility frame on the summed table as uns["mobility_heatmap"]; on a Bruker TDF it is fed from the summed table's own passes, on other sources (imzML, Waters drift time) it is one extra pass, and a processed imzML first reads its mobility values for the range (see Output Format) |
--mobility-grid / --no-mobility-grid |
disabled | When the source carries ion mobility per pixel rather than as a shared feature list (Bruker TDF, processed imzML, Waters drift time), bin the point cloud onto a common mobility grid and write the same mobility-resolved sibling table, a much larger table built out of core so any acquisition fits. On a Bruker TDF it is fed from the summed table's own two passes (no extra read of the source) and its marginal reproduces the summed table exactly under the default --tdf-spectrum scan_sum; on a processed imzML or a Waters run it takes extra passes, and its marginal is exact when points stay on their nearest mass bin (on Waters, under --waters-spectrum profile). Ignored, with a warning, on a continuous imzML, which has a shared feature list (see Output Format) |
--msms-table / --no-msms-table |
enabled | When the source isolates several precursors per pixel in disjoint mobility slices (Bruker PASEF), also write them split apart as a demultiplexed sibling table; fed from the summed table's own two passes (no extra read of the source); the split adds back up to the summed table exactly under the default --tdf-spectrum scan_sum (see Output Format) |
--format is deprecated
spatialdata was the only value --format ever accepted, and it is the
only output format Thyra writes, so no invocation could ever change what
the flag selects. It is still accepted, so existing scripts keep running,
but it is no longer listed in --help. Any other value still fails
before any data is read.
Examples¶
# Basic conversion -- format, pixel size, and resampling all auto-detected
thyra input.imzML output.zarr
# Specify pixel size manually (when metadata is unavailable)
thyra input.imzML output.zarr --pixel-size 25
# Convert one region, named the way flexImaging names it
thyra data.d output.zarr --region 03
# Or by the database's own region number
thyra data.d output.zarr --region 0
# Skip optical images
thyra data.d output.zarr --no-optical
Naming a region
--region takes a string, and the value is matched against the .mis
Area Names first. Only if nothing matches is it parsed as a DB
RegionNumber, which starts at 0. Passing something that is neither is an
error that lists the area names it did find.
The two numbering schemes do not have to agree, which is exactly why area
'03' need not be RegionNumber 3. For a multi-region dataset Thyra logs
the whole mapping at INFO during startup -- a header line
Region mapping (DB RegionNumber -> .mis Area Name): followed by one
RegionNumber <n> -> Area '<name>' (<n> frames) line per region -- so a
plain run already tells you which is which, and how many frames each
holds, before you pick one.
Logging¶
| Option | Default | Description |
|---|---|---|
-v, --log-level LEVEL |
INFO |
Logging level: DEBUG, INFO, WARNING, ERROR, CRITICAL |
--log-file PATH |
none | Write logs to file |
Examples¶
# Verbose output -- shows pixel size detection, resampling config, timing
thyra input.imzML output.zarr -v DEBUG
# Save logs to file for later review
thyra input.imzML output.zarr --log-file conversion.log
Debugging conversions
When something looks wrong in the output, re-run with -v DEBUG --log-file
debug.log. The log will contain pixel size detection details, resampling
parameters, region info, and timing for each step.
Ion Mobility Grid (Advanced)¶
These size the grid --mobility-grid bins onto. They do nothing without it,
and passing one without it is logged at WARNING. A continuous imzML
with a shared feature list needs no grid: there --mobility-grid and these
are ignored, with a WARNING.
| Option | Default | Description |
|---|---|---|
--mobility-bins INTEGER |
the heatmap's channels | Mobility channels the grid divides the range into. At least 1. Unset, the grid takes the heatmap's own channels: 256, or one per drift bin on a Waters run (200 bins measured) |
--mobility-min FLOAT |
axis minimum | Lower edge of the grid, in the axis unit (1/K0 for TIMS, ms for Waters drift time). May be zero or negative -- it is a position on an axis, not a quantity -- but must be below --mobility-max |
--mobility-max FLOAT |
axis maximum | Upper edge of the grid |
Examples¶
# The mobility-resolved table for a TIMS acquisition, at the default
# 256 channels over the range the acquisition actually used
thyra tims_data.d output.zarr --mobility-grid
# A narrower range at finer resolution, giving up the heatmap alignment
thyra tims_data.d output.zarr --mobility-grid --mobility-bins 512 --mobility-min 1.05 --mobility-max 1.25
The grid table is built out of core
Like the summed table, the grid table is built in two passes: the first counts the occupied (m/z bin, channel) cells and
the second scatters every pixel straight into memmapped CSC arrays in a
scratch directory next to the output (.thyra_mobility_*, removed once
the table is written). On a Bruker TDF those are the summed table's own
two passes: each frame is read once per pass and the read serves the
summed spectrum, the heatmap, the grid and the MS/MS split alike (see
Design Decisions). Memory is the count array over the grid's span --
142 MB on a default-resampled timsTOF axis -- plus one frame, whatever the
number of pixels; disk is 12 bytes per stored non-zero while the table is
being built. Measured on a whole 26,087-pixel timsTOF acquisition on a
40,000-bin axis (7.3M features, 1.59 billion non-zeros, 18 GB of scratch):
the table's own phases peaked at 3.2 GB of private memory above the
interpreter's baseline, in the var frame rather than in the matrix.
A mobility-resolved table wants a coarser mass axis than the default
The table's features are (m/z bin, mobility channel) pairs, so the mass
axis' width is multiplied by the channel count (256 on a timsTOF). A default resampled timsTOF axis is
around 140,000 bins; 200 frames of one measured acquisition filled 3.9
million of the resulting pairs, and a whole 26,000-pixel acquisition
occupies 21 million. The table is refused when the var frame those
pairs make is projected to take more than half of the machine's free
memory (about 338 bytes per pair, measured), and warned about past a
quarter. Reach for --resample-bins when the whole image is wanted
resolved on a smaller machine.
The defaults are an alignment, and the grid changes the TIC
The default channels are exactly what uns["mobility_heatmap"] bins
over -- 256 over the mobility axis' own value range, or one per Waters
drift bin -- so a box drawn on the heatmap selects grid channels by
integer index. --mobility-bins (even --mobility-bins 256),
--mobility-min and --mobility-max each give that up.
The grid is built from raw scans, and its marginal over channels
reproduces the summed table only when that table was built the same
way, which the default --tdf-spectrum scan_sum is. An explicit
vendor_centroid is kept, said at WARNING, and the mismatch is
recorded in the grid's uns block.
Resampling (Advanced)¶
These options control how spectra are mapped onto a common mass axis. In most cases the defaults work well -- Thyra auto-detects the instrument type and chooses an appropriate method, axis law and bin width. Start with no flags; the table after this one says when each option is actually needed.
| Option | Default | Description |
|---|---|---|
--resample-method METHOD |
auto |
auto, nearest_neighbor, or tic_preserving. A value that contradicts the detector's own choice is applied, and warned about |
--mass-axis-type TYPE |
auto |
auto, constant, linear_tof, reflector_tof, tof, orbitrap, fticr |
--tof-law A B |
auto | Coefficients of the tof width law sqrt(A m + B m^2) mDa (A in mDa2/Da, B dimensionless). Only for an instrument Thyra has no pair for; an MRT centroid run, a PHI run or a timsTOF supplies its own |
--resample-bins INTEGER |
auto | Number of bins (mutually exclusive with --resample-width-at-mz) |
--resample-min-mz FLOAT |
auto | Minimum m/z value. Inclusive: a peak sitting exactly on it lands in the first bin |
--resample-max-mz FLOAT |
auto | Maximum m/z value. Inclusive, as above; peaks outside the range are dropped, never folded into the edge bins |
--resample-width-at-mz FLOAT |
auto | Mass width in Da at reference m/z for physics-based binning |
--resample-reference-mz FLOAT |
1000.0 |
Reference m/z for width specification |
--mass-axis-plan FILE |
none | A plan file from plan_mass_axis, so several data sets share one mass axis. It fixes the axis, so it cannot be combined with --no-resample or the axis options above |
--resample-gap-tolerance FLOAT |
none | tic_preserving only: discard target bins farther than this many Da from any measured m/z, instead of interpolating across the gap |
Which of these you actually need¶
Every instrument Thyra recognises gets a measured default: the method, the axis law and the bin width all come from the detector that matched the file (see Resampling). The flags exist for the cases the defaults cannot know about.
| You want to | Use | Leave alone |
|---|---|---|
| Convert a file from a recognised instrument | nothing | everything here |
| A finer or coarser axis than the default | --resample-width-at-mz (with --resample-reference-mz) |
--mass-axis-type: the law stays the instrument's, only the width moves |
| A fixed number of bins instead of a width | --resample-bins |
|
| A narrower mass window | --resample-min-mz / --resample-max-mz |
|
| An axis law for an instrument Thyra could not identify | --mass-axis-type |
Note that a manual axis type also resets the width to the axis type's own default (5 mDa at m/z 1000; 17 mDa at 300 for linear_tof), since a width tuned for one law is not a default for another |
The measured tof law on a timsTOF, or on a new TOF you have fitted |
--mass-axis-type tof, plus --tof-law A B only when Thyra has no pair for the instrument |
|
| Force interpolation on data Thyra would bin | --resample-method tic_preserving, and --resample-gap-tolerance if the m/z arrays are sparse |
The conversion warns when the method contradicts the detector, and names the tolerance flag. Take it seriously: on a sparse source, interpolation without a tolerance filled the axis and stored 1,400x the non-zeros |
| One axis shared by several data sets | --mass-axis-plan FILE, written by plan_mass_axis |
every axis option above: the plan fixes them |
| The raw m/z values, no common axis | --no-resample |
The bin width of a tof axis is set the same way as any other: the width at
the reference m/z. Thyra derives the bins per peak width from it (3 by
default), so there is no separate flag for that quantity.
Choosing a resampling method
nearest_neighbor-- Each target bin takes the nearest original m/z value. Correct for centroid data, where peaks are discrete masses.tic_preserving-- Linear interpolation, rescaled so the total ion current is unchanged. Bins wide enough to skip source samples are rebinned instead, so a coarse axis keeps narrow peaks. Correct for profile data on a target axis whose bin widths scale the same way the source points are spaced.auto-- Pickstic_preservingonly where the source grid's law is known and the target axis follows it: Bruker rapifleX and other Bruker MALDI-TOF data, but not timsTOF (uniform in m/z, ontoconstant), and the Waters profile trace (uniform in flight time, ontolinear_tof). Everything else getsnearest_neighbor-- including profile data from an instrument Thyra cannot identify, because the interpolating method is only exact when the two axis laws match. See Resampling for the full decision table.
A very fine axis is refused before it is built
Everything a conversion holds per m/z bin -- the axis, the var frame
with its index, the running intensity totals, the pre-scan's count array
and anndata's copies during the write -- comes to about 200 bytes,
measured. So the bin count is checked against the machine's free memory
before the axis is materialised: past half of it the conversion is
refused with the projection and the free memory printed, and past a
quarter it is attempted with a WARNING. With 8 GB of memory free, the
refusal starts at around 21 million bins. --resample-bins and a small
--resample-width-at-mz are the two ways to ask for more than that; a
wide-range source at a fine width reaches it without either.
Choosing a mass axis type
The axis type determines how bin widths scale with m/z:
constant-- Uniform bin width (Da). Used for Bruker MALDI-TOF data, whose spectra arrive evenly spaced in m/z, and for profile data Thyra cannot identify.linear_tof-- Width scales as sqrt(m/z). Matches a linear (axial) TOF, whose flight time grows as sqrt(m/z).reflector_tof-- Width scales linearly with m/z (constant relative resolution). Matches reflector TOF.tof-- Width follows a measured peak-width lawsqrt(A m + B m^2), of which the two above are the limits. See the two-term TOF law.orbitrap-- Width scales as m/z^(3/2). Matches Orbitrap resolution.fticr-- Width scales as m/z^2. Matches FTICR resolution.auto-- Detected from instrument metadata.
Examples¶
# An Orbitrap imzML whose analyser Thyra could not identify: name the axis
# and leave the method on auto, which bins rather than interpolates
thyra input.imzML output.zarr --mass-axis-type orbitrap
# Fixed number of bins
thyra input.imzML output.zarr --resample-bins 50000
# Restrict mass range
thyra input.imzML output.zarr --resample-min-mz 100 --resample-max-mz 1000
# Specify bin width at a reference m/z (physics-based)
thyra input.imzML output.zarr \
--resample-width-at-mz 0.01 \
--resample-reference-mz 500
Performance¶
No options: every conversion streams, and every table is CSC.
Every conversion streams
There is no streaming mode to switch on: every conversion makes two passes over the source -- one to count, one to scatter straight into memory-mapped CSC arrays -- and writes each table from those arrays, so the matrix is never held in RAM whatever the dataset's size. On a small file the second pass costs about a third of the run; Design Decisions explains why there is one converter.
Options kept or removed for old scripts
--streaming auto|true|falseis still accepted so existing scripts keep running, but it selects nothing.--optimize-chunksis still accepted but does nothing, logs a warning, and will be dropped in a future release. Chunk sizes are chosen at write time.-
--sparse-formatwas removed in v3.22: passing it fails as an unknown option. Every table is CSC, the layout an ion image reads down, because one m/z across all pixels is one contiguous column. For the row-wise layout, convert after reading:
imzML-Specific¶
A vendor option on another vendor's file is logged as ignored
Each of the format-specific groups below -- imzML, Bruker, Waters -- and
the ion mobility grid options are accepted on any input and do nothing on
a source they do not apply to. Passing one on another format is now
logged at WARNING, naming the option and both formats, so a script that
has been carrying a dead flag says so on the next run rather than
producing a store byte-identical to the plain one in silence.
| Option | Default | Description |
|---|---|---|
--spectrum-type TYPE |
auto |
auto, profile, or centroid -- declare the spectrum representation instead of detecting it. imzML only |
By default Thyra reads the representation the file declares (MS:1000127
centroid / MS:1000128 profile), wherever in the document it is written, and
only guesses when the file declares neither. --spectrum-type overrides all of
that.
SCiLS Lab exposes the same control as --rep_type PROFILE|CENTROID (2026b User
Guide, p.81).
This changes stored values
The representation is not just a label: it feeds instrument detection, which picks the mass-axis type, which decides the bin spacing. Overriding it changes the axis a dataset is resampled onto, and therefore the numbers written to the store. It changes nothing for anyone who does not pass it.
Use it when a file declares the wrong thing -- that does happen. When the override contradicts an explicit declaration Thyra logs a warning naming both values; it is in the normal output, so check it and the result.
Examples¶
# The file says centroid but it is really profile data
thyra input.imzML output.zarr --spectrum-type profile
# See what detection concludes first: a plain run logs the detected
# spectrum type and the resampling it chose
thyra input.imzML output.zarr
Bruker-Specific¶
Grouped here because this is where they are reached for. All but
--intensity-threshold only apply to Bruker timsTOF .d directories, and
--interactive-calibration to solariX ones as well; on any other input they
are logged as ignored. --intensity-threshold is honoured by every reader,
and is here because continuous-mode Bruker data is what usually needs it.
| Option | Default | Description |
|---|---|---|
--use-recalibrated / --no-recalibrated |
enabled | Apply the newest calibration state in calibration.sqlite, TSF and TDF alike; off, the analysis database's own calibration. timsTOF only |
--interactive-calibration |
off | Display available calibration states. timsTOF and solariX |
--intensity-threshold FLOAT |
none | Minimum intensity filter. Every format |
--tdf-spectrum {scan_sum,vendor_centroid} |
scan_sum |
How a TDF (TIMS) frame's mobility scans collapse into one spectrum per pixel. Bruker TDF only |
Examples¶
# Use raw (non-recalibrated) m/z values
thyra data.d output.zarr --no-recalibrated
# List the calibration states the file carries. Display only: it cannot
# choose one, and the conversion then runs as it would without the flag
thyra data.d output.zarr --interactive-calibration
# Filter low-intensity signals (useful for continuous-mode Bruker data)
thyra data.d output.zarr --intensity-threshold 100
# TIMS data: reproduce Bruker's centroided spectrum instead of the raw scan sum
thyra tims_data.d output.zarr --tdf-spectrum vendor_centroid
TDF: the mobility ramp is summed, not sliced
Every scan of a TIMS frame is read. scan_sum (default) sums every scan
per digitizer index and keeps all of the ion current, which is also
Bruker's own per-frame total; vendor_centroid is Bruker's frame-level
peak picker over the full ramp (the same peaks as TSF line spectra and
SCiLS Lab's import), at 79 to 99 percent of the current and a third to
two thirds of the points. See Supported Formats
and Design Decisions.
Intensity threshold
The --intensity-threshold option drops all peaks below the given value
before writing to zarr. This reduces file size but is irreversible.
Use with care -- inspect the data with -v DEBUG first to choose an
appropriate threshold.
With ion mobility, a peak's intensity is its sum over all mobility scans
of the pixel. Every table keeps or drops the peak by that one sum. The
store records the threshold as intensity_threshold.
Only real measurements count toward that sum. A NaN, an infinite or a negative intensity adds nothing, and neither does a point whose m/z is not a finite number.
Waters-Specific¶
This option only applies when converting Waters .raw directories; on any
other input it is logged as ignored.
| Option | Default | Description |
|---|---|---|
--waters-spectrum {centroid,profile} |
profile on a SELECT SERIES MRT, centroid on every other Waters instrument |
What MassLynx hands back for one pixel: the vendor peak picker, or the sampled trace behind it |
Examples¶
# An MRT run: the profile trace on a linear_tof axis at 1.3 mDa, no flags needed
thyra mrt_run.raw output.zarr
# The same run through the vendor peak picker instead (the tof law, 1.75 mDa)
thyra mrt_run.raw output.zarr --waters-spectrum centroid
# A Synapt run's profile trace; the bin width follows its own digitiser
thyra synapt_run.raw output.zarr --waters-spectrum profile
When the profile is worth its size
MassLynx centroiding reports a single peak wherever the sampled trace has two maxima a few mDa apart, and puts it partway between them. On a SELECT SERIES MRT brain section, four separate 8-9 mDa doublets between m/z 760 and 830 -- including the 13C2 isotopologue of PC 34:1 [M+K]+ against PC 34:0 [M+K]+ -- came back as one centroid in 96-100% of the pixels that resolved them, 4-8 ppm from either true mass. The profile keeps them apart, for about 3 times the store, and is not slower: MassLynx centroids on demand, so a profile read skips that work. On a Synapt G2-Si the centroider was found to merge nothing the profile resolves, which is why only the MRT defaults to it; see Supported Formats.
The other reason to pass profile
A long imaging run outgrows one _FUNC*.DAT file, and MassLynx continues
it in a new function. It will not centroid the last of them, so a
centroid conversion leaves that chunk out and logs how many pixels
(16.6% of one Synapt G1 run) and this flag. Reading the trace converts
every chunk, because then they all come back the same way -- budget the
disk for it, since the profile store for that run is estimated at 74 GB
against 241 MB. See
Which functions hold the image.
Other¶
| Option | Default | Description |
|---|---|---|
--dataset-id TEXT |
msi_dataset |
Dataset identifier used in element keys. Letters, digits, underscores, dots and hyphens only, and not ., .. or a leading __: it names every element in the store, so SpatialData's naming rule applies to it. Checked before any pass over the source |
--sample-id TEXT |
none | Names the sample in the store's metadata (msi_metadata.sample.sample_id). Never read from the file, and not part of any element name. Stored as typed, so never a patient's name. Checked before any pass over the source |
--handle-3d |
off | Process as 3D volume instead of 2D slices |
--z-spacing FLOAT |
in-plane pixel size (x) | Distance between consecutive slices, in um. Only used with --handle-3d |
Examples¶
# Custom dataset ID (affects table and image key names)
thyra input.imzML output.zarr --dataset-id hippocampus
# -> table key: hippocampus_z0, TIC key: hippocampus_z0_tic
# Combine z-slices into a single 3D table
thyra volume.imzML output.zarr --handle-3d
# 20 um sections acquired on a 50 um raster
thyra volume.imzML output.zarr --handle-3d --pixel-size 50 --z-spacing 20
Set --z-spacing whenever you know it¶
--pixel-size is the in-plane raster pitch. It says nothing about how far
apart consecutive slices are: that distance is set by the microtome that cut the
sections, not by the stage that rastered them, and the two match only by
coincidence.
With no --z-spacing, Thyra reuses the in-plane pitch (the x one, when the
raster is anisotropic and there is no single in-plane pitch to reuse), warns,
and records z_spacing_source: "assumed_isotropic" in the store so the guess
stays distinguishable from a measurement. The volume's voxel values are
unaffected either way — what is wrong is its depth, so a viewer reading it in micrometres
renders the stack squashed or stretched along z.
There is no way to detect this from the data. imzML has no term for slice spacing, and 3D MSI acquisitions are frequently non-consecutive sections, so the number has to come from whoever cut them.
It does nothing without --handle-3d
Without 3D handling each slice is written as its own 2D image and there is
no z axis to space out. Passing --z-spacing on its own is logged as
ignored rather than silently accepted.
--handle-3d on a single-slice acquisition
One plane has no slice-to-slice distance, so no z_spacing_um is applied
or recorded and a --z-spacing given alongside is logged as ignored. The
store is still written as a volume of one plane, which changes the element
keys -- the table is {id}, not {id}_z0 -- but not the values.
Metadata subcommands¶
validate and export-metaspace take either a converted .zarr store
or a standalone metadata .json document. Only the metadata block is
read, never the intensity data, so both are instant on stores of any
size. metadata starts from the other end: it takes a raw source and
writes the document a conversion would have stored. See
Metadata Schema for the schema itself.
thyra metadata¶
Writes the msi_metadata document for a raw source without converting
it. INPUT is a file or folder in any format Thyra reads. For every
format but Waters, no spectra are decoded, no vendor SDK is loaded and
nothing is written beside the input, so this is a header read on a dataset
of any size. A Waters run is described through the MassLynx library, which
reads every scan: it takes a while, and needs Windows or Linux.
| Option | Default | Description |
|---|---|---|
--merge PATH |
none | JSON file overlaid onto the metadata before validation |
-o, --output PATH |
stdout | Output file; - is stdout too |
Exit status is 0 when the document conforms (warnings allowed), 1
when it does not, 2 for usage errors. The document is written either
way, and the validation issues go to stderr -- so thyra metadata src
-o meta.json leaves you a document to look at whatever the exit status
was, and thyra metadata src > meta.json keeps stdout clean.
The document names the source rather than locating it: source_path
carries raw_data.d, not the directory it was read from. A document is
written to be sent to somebody, and nothing in it should have to be
edited out first.
# Look at what a folder says before spending hours converting it
thyra metadata raw_data.d
# Keep it, with the fields the file cannot know filled in
thyra metadata raw_data.d --merge sample.json -o meta.json
A source with no image still has metadata
The one field the schema requires is the pixel size, because every
document Thyra had written until now described an image. A Bruker
.d from a run that imaged nothing -- an electrospray acquisition
on a timsTOF-family instrument -- states its instrument, polarity,
precursor schedule and acquisition time exactly as an imaging run
does, and states no pixel size, because there is no
raster. thyra metadata writes that document, reports the one
validation error, and exits 1. Converting such a file is refused
with a message that says so. The split that would make the document
valid is proposed in
Design Decisions.
thyra validate¶
Validates the uns["msi_metadata"] block (or a JSON document) against
the schema: structure, schema version, and ontology terms. For a store,
it also checks each table's var and that its m/z axis matches the
recorded provenance.mass_axis.
| Option | Default | Description |
|---|---|---|
--merge PATH |
none | JSON file overlaid onto the metadata before validation |
--json |
off | Machine-readable report on stdout instead of text |
Exit status follows the conversion command's convention: 0 when every
document conforms (warnings allowed), 1 otherwise, 2 for usage
errors -- so thyra validate can gate a CI pipeline.
thyra validate output.zarr
thyra validate output.zarr --merge sample.json
thyra validate metadata.json --json
thyra export-metaspace¶
Writes the METASPACE submission metadata
JSON for a dataset. Required fields the store cannot know (organism,
condition, ...) are emitted empty and reported as warnings on stderr;
supply them with --merge or fill them on the submission form.
| Option | Default | Description |
|---|---|---|
--merge PATH |
none | JSON file overlaid onto the metadata before export |
--table NAME |
the only one | Table to export when the store has several |
-o, --output PATH |
<input>.metaspace.json |
Output file; - for stdout |
thyra export-metaspace output.zarr --merge sample.json
thyra export-metaspace output.zarr -o - # print to stdout
The other two commands¶
Installing Thyra puts three commands on your path, not one.
thyra-example-data¶
Writes the small synthetic imzML dataset the tutorial uses. No download, no vendor SDK.
OUTPUT -- Path for the .imzML (default:
example_data/synthetic_brain.imzML). A non-.imzML suffix is replaced.
| Option | Default | Description |
|---|---|---|
--pixels-x INTEGER |
48 |
Grid width in pixels |
--pixels-y INTEGER |
36 |
Grid height in pixels |
--pixel-size FLOAT |
25.0 |
Pixel size in micrometers written to the metadata |
--mz-bins INTEGER |
4000 |
Number of points on the m/z axis |
--seed INTEGER |
0 |
Random seed |
--verbose |
off | Verbose output |
# The tutorial's dataset: 48 x 36 pixels, 4,000 m/z points, seed 0
thyra-example-data example_data/synthetic_brain.imzML
# A larger phantom on a coarser axis
thyra-example-data big.imzML --pixels-x 200 --pixels-y 150 --mz-bins 2000
--seed is what makes the tutorial reproducible
The seed fixes the data: the same --seed gives the same m/z axis and
the same intensities on every machine, which is why the tutorial can
print exact numbers and expect yours to match. Change the seed and the
numbers change with it.
It does not make the files byte-identical, and is not meant to. Each
imzML gets a fresh UUID and the SHA-1 of its own .ibd, as a real
acquisition would.
thyra-check-ontology¶
Validates the CV (controlled vocabulary) terms in an imzML file against Thyra's ontology cache, and reports any it does not recognise.
INPUT -- An .imzML file, or a directory to check every file in.
| Option | Default | Description |
|---|---|---|
--output PATH |
none | Save results as JSON instead of printing them |
--verbose |
off | Verbose output, including the per-file summary |