A blocking factor can now be corrected for, not just annotated.
parameters: block_centre: takes center -- divide each block by its own
geometric mean -- or baseline, which divides by the block's
baseline_group arm so a value reads as a fold change against its own
control. off is the default, so declaring block: on its own never changes
a number. The correction is multiplicative, so a block's gain goes and the
size of its response stays: a patient who responds twice as strongly still
reads twice as strongly. It reaches the heatmaps and the comparison plots,
which is where a block's own level gets in the way; the ion images are left
alone, because an image should show the intensity that was measured. A
corrected report gains blocked in its filename so it cannot overwrite an
uncorrected one, and says at the top what was done. blockCentre() is
exported for use outside the report.
stitchAcquisitions() gains overlap, for pieces of one tissue that share a
strip -- a re-acquired edge, a generously cut margin. "error" remains the
default, because averaging two pieces or silently dropping one invents a
pixel; "first" and "last" keep that piece where they collide and report
how many were dropped. parameters: stitch_overlap: sets it from the YAML.
fData() now carries collision_eV and cone_V from the ion library, so
the report's feature table identifies a transition without a trip back to the
raw data: two transitions can share a precursor and a product and differ only
in collision energy. Acquisitions cached by an earlier version keep their old
feature table until re-read with readMRM(overwrite = TRUE).
The ion-image section opens with an animation: one frame per feature, each
showing every section at once, ordered by pathway and under a pathway colour
key. Each frame carries a filled box in its pathway's colour with the pathway
written inside it, the metabolite beside it, and the intensity the colour
scale is capped at -- the panels within a frame are comparable, between frames
they are not, and that number says by how much. It answers "how is each
metabolite distributed across this study" in one object, and is written beside
the report as a .gif for talks and posters as well as embedded in it. On by
default; output: ion_gif: takes enabled, features ("all" or a list)
and seconds per frame. Needs the magick package, and says so rather than
failing when it is absent.
output: ion_images: scale_within: chooses which panels share a colour
scale: all (one for the study, the previous and default behaviour), block
(one per patient, sex or slide) or group. With a single scale across a study
whose sections differ in intensity, the weakest reads as empty and the
strongest saturates; per-block scales let each use its full range, and every
panel states the value it is capped at, so the blocks stay comparable by
number even when they are not by colour.
The grid follows from the design rather than being configured: a block is a
column, its groups are the rows, and replicates run across a row -- so the
panel reads across for replicates and down for treatment whether a block holds
one replicate per arm (an ex vivo pairing) or four (a mouse cohort). The
canvas is sized from that grid, and each column carries its own colour bar.
This rendering is drawn with imageR(); without scale_within the report
uses Cardinal's image() exactly as before.
heatmap_style: auto no longer chooses the contribution heatmap when the
z-score behind it cannot resolve anything. That score is taken within a
region, so the region is what has to be big enough: two rows in a region score
to +/-0.707 whatever the data says, and one cannot be scored at all -- a panel
of saturated colour carrying only a sign. Counting rows per group missed this,
because regions multiply the rows per group without giving the z-score more to
work with. auto now needs 3+ rows in a group and 3+ in every region;
an explicit per_sample or contribution is still honoured as given.
A sample's group is now given by group: rather than label:, which is what
it has always been -- runStudy() reads it straight into the sample map's
group column. parameters: baseline_label: becomes baseline_group: for
the same reason: it names a value of that key. Both old names keep
working, so existing configs run unchanged; validateConfig() says how many
samples still use label: so a study can be updated when convenient. The
label: under ratios: entries: is a different thing -- a ratio's display
name -- and is unaffected.
One percentile now caps every image in the report -- the animation, the
dropdown's first rendering and the concentration images -- set by
output: ion_images: percentile: (default 95), with each caption stating the
value it used instead of naming a fixed one. Previously the animation was
fixed at 95, the dropdown computed its own 95, and the concentration images
silently took imageR()'s default of 99. parameters: perc: is unchanged in
meaning and stays separate: it caps the .txt images written for other
software, which want their dynamic range rather than a readable map. Its
default moved from 97 to 99 for that reason; a perc: set in a config is
used as before.
readMRM() keeps each pixel's stage position (x_stage,
y_stage, in mm) alongside its grid indices, and stitchAcquisitions() uses
it to place every piece where it was acquired: above, below or beside, in any
order, with the space between pieces left empty. Pieces must share a pixel
size; each is moved to the nearest position on a common grid and the largest
shift is reported. Previously every piece started at (1, 1), so real pieces
could not be stitched at all, and the documentation wrongly said Waters
coordinates were absolute. Objects without stage positions (older caches)
behave as before.pieces: for such a sample: each piece lists its own
pos:/neg: panels, which are merged within the piece and then stitched.
Each piece is normalised to its internal standard and SNR-filtered against
its own background before stitching, since the pieces are separate
acquisitions.labelROIs() labels regions of interest within the tissue -- airways,
vessels, parenchyma -- after selectTissuePixels(). Several regions can
share a label and are numbered (airway_01, airway_02, ...). Regions are
saved per acquisition as roi_labels.csv, beside the untouched tissue mask,
and copy_to applies them to the other panels over the same area.roi: block sets the region views: compare puts groups side by
side within each region type ("between_groups", the default), region types
side by side within each group ("between_rois") or both; unit says
whether a row or point is a sample's region type or a single region -- one or
the other, since a comparison has a single unit; heatmap: False leaves the
region heatmap out. A point is never a pixel: the pixels of one region are
repeated measurements of the same tissue. Tissue outside every region is
unassigned and left out unless include_unassigned: True, and the tables
workbook gains an ROI_summary sheet.quantileHm() gains sample_block, which divides the rows into blocks --
one per region of interest, typically -- splits the panel by them and
z-scores each block against itself. Scoring across regions would mostly
report that airways and parenchyma differ, which is not what the panel is
being asked. A block of one sample has no spread to score against and is
drawn in na_col. Without the argument the panel is exactly as before.quantileHm() no longer loses its sample names when a study contains a
feature with no variance. The unscoreable column returned an unnamed vector,
and apply() drops the names for the whole matrix when one result's differ,
so the row labels vanished -- but only for studies that happened to hold a
flat feature.a and two b regions each, so
runExample() renders the regions section and the vignette can show what
labelled regions look like without a drawing device.output: colocalisation now names the level the correlation section is
computed at, and only one is ever drawn: 'sample' (all pixels of each
sample), 'roi' (the pixels of each region type), False, or auto. It is
by far the slowest part of the report -- every feature against every other,
over every pixel, repeated per group -- so auto correlates within the
regions when a study has them, which is both the cheaper computation and the
more specific question, and is off otherwise. It is also off whenever a
sample merges several acquisitions, since most pixel pairs would then cross
acquisitions. True is read as 'sample', so existing configs keep the
section they had.combineMSIs() fills a pData() column that some objects lack with NA,
rather than failing inside cbind().Authors@R are split,
so R's citation style takes an initial from each.bindPanels() no longer documents cross-panel colocalisation as meaningful
on the merged object, and now explains that pixels are matched on
per-acquisition indices, which is only correct when both rasters start at
the same stage position.quantileHm() no longer draws features it cannot score as uniformly low. A
feature with no variance across samples, or a missing value, used to be sent
to the bottom of the colour scale, where it was indistinguishable from a
feature depleted in every sample. Both are now drawn in the new na_col
(default "grey88"), matching contributionHm().parameters$heatmap_quantiles sets which pixel quantiles get a heatmap
section, defaulting to the 0.25, 0.5, 0.75, 0.95, 0.98 that were previously
hard-coded, so an existing config renders exactly as before. The useful set
depends on the chemistry -- a feature confined to a few pixels shows at the
95th and not at the median, a diffuse one the other way round -- and it is
also the lever to pull if heatmap_scale: "both" makes a report longer than
you want, since two quantiles on two scales is usually more informative than
five on one.parameters$heatmap_scale also accepts "both", which draws each quantile
section twice -- once on the shared scale and once per-feature -- under
sub-headings that say what each one can and cannot be used for. The two
answer sequential questions rather than competing ones: the shared panel
says which features separate the groups, the per-feature panel says what one
feature's profile looks like. Reading them in that order also guards against
the per-feature panel's failure mode, where a feature with no group effect is
drawn just as vividly as the strongest one. "both" is a report setting;
contributionHm() itself still draws one heatmap.contributionHm() gains scale. "shared" (default, unchanged behaviour)
keeps every feature on one colour scale so features can be compared with each
other; "feature" normalises each feature by its own extreme, so every
column fills the ramp whatever its actual spread. The second is the reading
[quantileHm()] gives, but keeping the group-mean hue and the contribution
opacity -- use it to look along one feature, never across features. The
legend states which scale is in force. Exposed in the study YAML as
parameters$heatmap_scale, and checked by validateConfig().?quantileHm previously
mentioned only that z-scores are "clipped to [-1, 1]" and never said the
z-scoring is per feature, so nothing warned a reader that its colours are not
comparable between features.?contributionHm gains a section on comparing features with each other: one
cap for the panel versus one per column, that "shared" ranks by effect size
rather than fold change, that the group-mean z-score is bounded at +/- 1 for a
balanced design so the cap can be read as a fraction of the separation the
design can show, and the two limits on that comparison (the deviation is
estimated from few samples, and is pooled across groups so the scale
compresses at the top).?quantileHm gains a section explaining why it has no scale argument: it
colours the per-sample z-score, which is standardised per feature before
anything is drawn, so no choice of colour limits can restore a comparison
between features. contributionHm() escapes this by colouring the group mean
of those z-scores, which is not renormalised per feature.?quantileHm now records that a feature with no variance across samples is
drawn at the bottom of the ramp rather than as missing, so an entirely
single-coloured column should be checked against the values. (The behaviour
itself is unchanged in this release.)Changes in response to the Bioconductor package review (Contributions #115).
Function names are now camelCase throughout, following the Bioconductor
style guidance. The convention applied is: acronyms upper case (MRM, MSI,
SNR, NA), other abbreviations camel (Hm, Cal). Renamed:
align_features() to alignFeatures(), bind_panels() to bindPanels(),
build_feature_meta() to buildFeatureMeta(), combine_MSIs() to
combineMSIs(), contribution_hm() to contributionHm(),
create_cal_curve() to createCalCurve(), createMSIDatamatrix() to
createMSIDataMatrix(), generate_txt_images() to generateTxtImages(),
int2snr() to int2SNR(), plot_cal_coverage() to plotCalCoverage(),
quant_palettes() to quantPalettes(), quantile_hm() to quantileHm(),
read_mrm() to readMRM(), remove_blank_mzs() to removeBlankMzs(),
run_example() to runExample(), run_study() to runStudy(),
select_tissue_pixels() to selectTissuePixels(), stitch_acquisitions()
to stitchAcquisitions(), summarise_cal_levels() to
summariseCalLevels(), trim_MSI() to trimMSI(), validate_config() to
validateConfig(), and zero2na() to zero2NA(). The S3 class
quant_validation is now quantValidation.
No deprecated aliases are provided. The package has never appeared in a
Bioconductor release, so there are no downstream users to protect and
Bioconductor's deprecation cycle does not apply. Existing scripts must be
updated. The S4 class quant_MSImagingExperiment is unchanged.
Argument checking made consistent. The exported plain functions that did
not validate their inputs now do: alignFeatures(), bindPanels(),
trimMSI(), buildFeatureMeta(), and the summarising helper shared by
quantileHm() and contributionHm(). Checks test for
MSImagingExperiment, which quant_MSImagingExperiment extends, so both are
accepted. buildFeatureMeta() previously returned a full-height frame of
NA rows when the ion library lacked precursor_mz / product_mz; it now
errors.
?alignFeatures documented obj1 and obj2 as quant_MSImagingExperiment
when the code has always accepted any MSImagingExperiment. The
documentation was wrong and has been corrected.
Fixed two warnings emitted during report generation.
out-of-range values treated as 0 in coercion to raw came from rmarkdown's
resource discovery: passing intermediates_dir= to rmarkdown::render()
makes it render a preview copy of the template with a .md extension, which
skips knitr, so an unexpanded sprintf placeholder in an HTML attribute
reached utils::URLdecode(). The tag is now built with paste0(). The
pandoc Div ... unclosed, closing implicitly warning came from HTML block
fences emitted without surrounding blank lines, whose parse depended on the
markdown_in_html_blocks extension; the fences are now padded, and the
statements between them are guarded so an error cannot skip a closing tag.
The sample-contribution key on contributionHm() is drawn in neutral grey
and labelled low / high. It previously used the top colour of the fill
palette, so red meant both "high z-score" and "contributed to the group
mean".
Long feature-class and sample-group legend labels are wrapped, and the report heatmap device is no longer capped at a width that silently cropped the right-hand legends off wide studies.
contributionHm(), a heatmap that encodes the group mean as hue and
each sample's agreement with it as opacity, so a group mean resting on one
replicate is visible rather than hidden.stitchAcquisitions() for assembling several acquisitions of one
section into a single image.combine check in validateConfig(), which referenced the wrong
object and sat in the ion-library block rather than the samples block.mz_tolerance default 0.4, was 0.05). A triple quadrupole running MRM
selects Q1 and Q3 at unit resolution, so a product ion written as 308.1 and
one written as 308.3 are the same measurement; matching more tightly than
the instrument resolves made annotation depend on how many decimal places
were typed into the library. Applies to readMRM(), buildFeatureMeta(),
alignFeatures() and bindPanels(). Precursor and product must still
both agree.ambiguity gains a "combine" mode, now the default. A transition matching
several library entries is named for all of them, joined with " || " --
e.g. "LTC4 || 14_15-LTC4", isomers 0.03 Da apart on the product ion that no
acquisition can separate. Annotation columns come from the closest entry.
"error", "warn" and "nearest" are unchanged.Type is refused: one feature cannot
be both analyte and internal standard.show methods export, which was declared in NAMESPACE without the
generic being imported from methods.runExample() / generateTxtImages(): trimming empty background
borders no longer removes the last background pixels when the tissue fills a
perfect rectangle, which had left int2SNR() with nothing to reference.show() methods for the calibrationInfo, tissueInfo and
quant_MSImagingExperiment classes.snr_overrides) and per-report SNR_used
reporting.bindPanels() for coordinate-matched merging of cross-panel /
cross-polarity acquisitions of the same tissue.buildFeatureMeta() to join ion-library metadata to features by m/z.selectTissuePixels() now writes x/y),
portable across MRM panels of the same sample.readMRM() to handle single- and multi-analyte imaging folders.summariseCalLevels(), createCalCurve(), int2conc())
can be driven from the study YAML via a calibration: block.