Using the RDML7 package
RDML7 authors
2026-10-14
Introduction
The RDML7 package provides tools for importing,
exporting, validating, inspecting, modifying, and converting
quantitative PCR (qPCR) data represented by the Real-time PCR Data
Markup Language (RDML).
RDML stores both fluorescence measurements and experimental metadata
in a structured format. The format is designed to make qPCR experiments
easier to exchange, reproduce, and reanalyse.
RDML7 is a major redesign of the original RDML R package
described in:
Rödiger S, Burdukiewicz M, Spiess A-N, Blagodatskikh K. Enabling
reproducible real-time quantitative PCR research: the RDML package.
Bioinformatics 33(24), 4012–4014. https://doi.org/10.1093/bioinformatics/btx528
The original package used an R6 object model. RDML7 uses S7
classes and a primarily functional API. The
main workflow is now:
file
|
v
readRDML()
|
v
rdmlType
|
+---- asTable() -------- metadata / curve index
|
+---- getFData() ------- fluorescence data
|
+---- setFData() ------- add or replace fluorescence data
|
+---- summary() ---- summary
|
+---- validateRDML() --- validation
|
+---- asDendrogram() --- hierarchy
|
+---- mergeRDMLs() ----- merge RDML objects
|
+---- writeRDML() ------ RDML / XML / RDES / other registered formats
The old names such as AsTable(),
GetFData(), SetFData(),
AsDendrogram(), asXML(), and
MergeRDMLs() are retained as compatibility wrappers where
possible. New code should use the camelCase API.
Main changes from the original RDML package
The most important changes are:
- S7 object model instead of R6.
- Value semantics: functions that modify an object
return a modified object, which should normally be assigned back.
- CamelCase functional API, for example
asTable() and getFData().
- Centralised file I/O with
readRDML()
and writeRDML().
- Extensible format registry with automatic format
detection.
- Direct support for importer modules through a
canonical intermediate representation.
- Validation and summary functions for RDML
objects.
- RDES import/export in addition to RDML and
vendor/table formats.
- A revised
asTable() interface with documented fields
and reusable {field} name templates.
A migration summary is shown below.
RDML$new(filename = file) |
readRDML(file) |
RDML$new() |
rdmlType() |
x$AsTable() / AsTable(x) |
asTable(x) |
x$GetFData() / GetFData(x) |
getFData(x) |
x$SetFData() / SetFData(x) |
x <- setFData(x, ...) |
x$AsDendrogram() / AsDendrogram(x) |
asDendrogram(x) |
x$asXML() |
asXML(x) or writeRDML(x, ...) |
MergeRDMLs(...) |
mergeRDMLs(...) |
| file-specific constructor logic |
readRDML() + format registry |
Loading RDML7
The package contains example RDML files that can be used throughout
this vignette.
filename <- system.file(
"extdata",
"lc96_bACTXY.rdml",
package = "RDML7"
)
filename
#> [1] "C:/tmp/RtmpKYPudu/Rinst45747907173b/RDML7/extdata/lc96_bACTXY.rdml"
Reading files
readRDML()
Use readRDML() as the main entry point for file
import.
lc96 <- readRDML(filename)
#>
#> Loading experiment: ca1eb225-ecea-4793-9804-87bfbb45f81d
#> run: 65aeb1ec-b377-4ef6-b03f-92898d47488b
The default format selection is automatic. If a format is ambiguous,
it can be specified explicitly.
lc96 <- readRDML(
filename,
format = "rdml"
)
This replaces the old pattern:
# Original RDML package
# lc96 <- RDML$new(filename = filename)
RDML7 object structure
RDML7 mirrors the hierarchy of the RDML schema. The principal
top-level fields include:
dateMade
dateUpdated
id
experimenter
documentation
dye
sample
target
thermalCyclingConditions
experiment
The important hierarchy containing fluorescence data is
approximately:
rdmlType
`-- experiment
`-- run
`-- react
`-- data
|-- adp amplification data points
`-- mdp melting data points
S7 property access
RDML7 schema objects are S7 objects. Use $ to access
their properties.
lc96$version
#> [1] "1.3"
lc96$experiment[[1]]$id$id
#> [1] "ca1eb225-ecea-4793-9804-87bfbb45f81d"
Collections such as experiments, runs, samples, and targets are keyed
by their RDML identifiers. This makes it possible to inspect identifiers
first and then select an element.
expname <- names(lc96$experiment)[1]
experiment <- lc96$experiment[[expname]]
names(experiment$run)
#> [1] "65aeb1ec-b377-4ef6-b03f-92898d47488b"
For routine data analysis, direct traversal of the full hierarchy is
usually unnecessary. asTable() and getFData()
provide a flatter interface.
Summarising and validating RDML data
summary()
Use summary() for a compact overview of an RDML
object.
This is preferable to manually counting nested experiments, runs,
reactions, targets, and curve types.
validateRDML() and isValidRDML()
RDML7 provides validation (as for RDML 1.3 version) functions in
addition to S7 property validators.
validateRDML(lc96)
isValidRDML(lc96)
Use validation before exporting data or after programmatically
modifying a large RDML object.
Visualising the hierarchy
asDendrogram() creates a dendrogram representation of
the experiment structure.
This is the RDML7 replacement for the old
x$AsDendrogram() method.
Creating a table representation with asTable()
asTable() creates one metadata row per RDML
dataType. This table is the main bridge between the
hierarchical RDML object and ordinary tabular R workflows.
tbl <- asTable(lc96)
head(tbl)
#> Ключ: «fdataName»
#> fdataName expId
#> <char> <char>
#> 1: D03_Sample 39_std_IPC ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 2: D03_Sample 39_std_X ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 3: D03_Sample 39_std_Y ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 4: D03_Sample 39_std_bACT ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 5: D04_Sample 39_std_IPC ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 6: D04_Sample 39_std_X ca1eb225-ecea-4793-9804-87bfbb45f81d
#> runId reactId position sample target
#> <char> <char> <char> <char> <char>
#> 1: 65aeb1ec-b377-4ef6-b03f-92898d47488b 39 D03 Sample 39 IPC
#> 2: 65aeb1ec-b377-4ef6-b03f-92898d47488b 39 D03 Sample 39 X
#> 3: 65aeb1ec-b377-4ef6-b03f-92898d47488b 39 D03 Sample 39 Y
#> 4: 65aeb1ec-b377-4ef6-b03f-92898d47488b 39 D03 Sample 39 bACT
#> 5: 65aeb1ec-b377-4ef6-b03f-92898d47488b 40 D04 Sample 39 IPC
#> 6: 65aeb1ec-b377-4ef6-b03f-92898d47488b 40 D04 Sample 39 X
#> targetDyeId sampleType adp mdp
#> <char> <char> <lgcl> <lgcl>
#> 1: Cy5 std TRUE FALSE
#> 2: Hex std TRUE FALSE
#> 3: Texas Red std TRUE FALSE
#> 4: FAM std TRUE FALSE
#> 5: Cy5 std TRUE FALSE
#> 6: Hex std TRUE FALSE
The standard scalar fields are:
fdataName — unique name used to identify a fluorescence
series;
expId — experiment identifier;
runId — run identifier;
reactId — reaction identifier;
position — plate/tube position;
sample — sample identifier;
target — target identifier;
targetDyeId — dye associated with the target;
sampleType — sample type;
adp — amplification data are present;
mdp — melting data are present.
The camelCase names replace the old fdata.name,
exp.id, run.id, react.id,
sample.type, and target.dyeId columns.
Selecting standard columns
The revised interface uses columns to select built-in
output columns.
tbl_small <- asTable(
lc96,
columns = c(
"expId",
"runId",
"position",
"sample",
"sampleType",
"target"
)
)
head(tbl_small)
#> Ключ: «fdataName»
#> fdataName expId
#> <char> <char>
#> 1: D03_Sample 39_std_IPC ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 2: D03_Sample 39_std_X ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 3: D03_Sample 39_std_Y ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 4: D03_Sample 39_std_bACT ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 5: D04_Sample 39_std_IPC ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 6: D04_Sample 39_std_X ca1eb225-ecea-4793-9804-87bfbb45f81d
#> runId position sample sampleType target
#> <char> <char> <char> <char> <char>
#> 1: 65aeb1ec-b377-4ef6-b03f-92898d47488b D03 Sample 39 std IPC
#> 2: 65aeb1ec-b377-4ef6-b03f-92898d47488b D03 Sample 39 std X
#> 3: 65aeb1ec-b377-4ef6-b03f-92898d47488b D03 Sample 39 std Y
#> 4: 65aeb1ec-b377-4ef6-b03f-92898d47488b D03 Sample 39 std bACT
#> 5: 65aeb1ec-b377-4ef6-b03f-92898d47488b D04 Sample 39 std IPC
#> 6: 65aeb1ec-b377-4ef6-b03f-92898d47488b D04 Sample 39 std X
Without columns, all built-in columns are returned.
namePattern templates
fdataName must identify a fluorescence series. RDML7
supports readable {field} templates:
tbl <- asTable(
lc96,
namePattern =
"{expId}_{runId}_{position}_{sample}_{sampleType}_{target}"
)
head(tbl$fdataName)
#> [1] "ca1eb225-ecea-4793-9804-87bfbb45f81d_65aeb1ec-b377-4ef6-b03f-92898d47488b_D03_Sample 39_std_IPC"
#> [2] "ca1eb225-ecea-4793-9804-87bfbb45f81d_65aeb1ec-b377-4ef6-b03f-92898d47488b_D03_Sample 39_std_X"
#> [3] "ca1eb225-ecea-4793-9804-87bfbb45f81d_65aeb1ec-b377-4ef6-b03f-92898d47488b_D03_Sample 39_std_Y"
#> [4] "ca1eb225-ecea-4793-9804-87bfbb45f81d_65aeb1ec-b377-4ef6-b03f-92898d47488b_D03_Sample 39_std_bACT"
#> [5] "ca1eb225-ecea-4793-9804-87bfbb45f81d_65aeb1ec-b377-4ef6-b03f-92898d47488b_D04_Sample 39_std_IPC"
#> [6] "ca1eb225-ecea-4793-9804-87bfbb45f81d_65aeb1ec-b377-4ef6-b03f-92898d47488b_D04_Sample 39_std_X"
Available built-in template fields are:
{expId}
{runId}
{reactId}
{position}
{sample}
{target}
{targetDyeId}
{sampleType}
{adp}
{mdp}
Custom columns supplied through ... are also available
to namePattern.
Including expId and runId is recommended
when an object may contain more than one experiment or run. It
substantially reduces accidental duplicate fdataName
values.To avoid duplication asTable automatically adds
number indices to duplicated fdataName values. But it’s
generate warning.
Adding custom columns
Custom columns no longer need a separate addColumns
argument. Supply a named expression directly through
....
request <- asTable(
lc96,
columns = c(
"expId",
"runId",
"position",
"reactId",
"sample",
"sampleType",
"target"
),
sampleTarget = paste(
sample,
target,
sep = ":"
))
head(request)
#> Ключ: «fdataName»
#> fdataName expId
#> <char> <char>
#> 1: D03_Sample 39_std_IPC ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 2: D03_Sample 39_std_X ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 3: D03_Sample 39_std_Y ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 4: D03_Sample 39_std_bACT ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 5: D04_Sample 39_std_IPC ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 6: D04_Sample 39_std_X ca1eb225-ecea-4793-9804-87bfbb45f81d
#> runId position reactId sample sampleType
#> <char> <char> <char> <char> <char>
#> 1: 65aeb1ec-b377-4ef6-b03f-92898d47488b D03 39 Sample 39 std
#> 2: 65aeb1ec-b377-4ef6-b03f-92898d47488b D03 39 Sample 39 std
#> 3: 65aeb1ec-b377-4ef6-b03f-92898d47488b D03 39 Sample 39 std
#> 4: 65aeb1ec-b377-4ef6-b03f-92898d47488b D03 39 Sample 39 std
#> 5: 65aeb1ec-b377-4ef6-b03f-92898d47488b D04 40 Sample 39 std
#> 6: 65aeb1ec-b377-4ef6-b03f-92898d47488b D04 40 Sample 39 std
#> target sampleTarget
#> <char> <char>
#> 1: IPC Sample 39:IPC
#> 2: X Sample 39:X
#> 3: Y Sample 39:Y
#> 4: bACT Sample 39:bACT
#> 5: IPC Sample 39:IPC
#> 6: X Sample 39:X
The ready-to-use scalar fields available in custom expressions
are:
expId, runId, reactId, position, sample, target,
targetDyeId, sampleType, adp, mdp
Advanced custom columns
For metadata not exposed as a built-in scalar field, ...
also provides the current structured RDML objects:
experiment
run
react
data
samples
targets
dateMade
dateUpdated
id
experimenter
documentation
dye
thermalCyclingConditions
These objects are intended for advanced extraction. Because they are
structured S7/RDML objects, they are not inserted directly into
namePattern.
For example, a scalar property can be extracted from the current
data object and then used as a template field:
tbl <- asTable(
lc96,
cq = data$cq,
namePattern =
"{position}:{sample}_{target}-{cq}"
)
Once cq is created as a scalar custom column,
{cq} becomes available in namePattern.
This design means users do not need to know internal
helper functions such as .rdmlIdChr(),
.rdmlReactPosition(), or .rdmlSampleType()
merely to construct an fdataName.
Example: deriving concentration from a sample name
User metadata can also be derived from existing scalar fields. For
example, if a concentration is encoded as a separate
underscore-delimited component of the sample name:
r96 <- readRDML(system.file(
"extdata",
"cd53_efficiency.r96",
package = "RDML7"
))
concValues <- c("1", "0.5", "0.1", "0.01")
tbl <- asTable(
r96,
concentration = {
parts <- strsplit(sample, "_", fixed = TRUE)[[1]]
value <- parts[parts %in% concValues]
if (length(value)) {
as.numeric(value[[1]])
} else {
NA_real_
}
}
)
head(tbl)
This approach avoids falsely extracting a number that is only part of
another identifier.
Legacy default and addColumns
default and addColumns may be retained for
compatibility with older code, but new code should normally use:
columns + named expressions in ...
This gives asTable() a single, predictable
column-selection model.
Getting fluorescence data
Fluorescence data are stored separately from the flattened metadata
table. Use getFData() to extract them. You can provide
special request to access some part of data or access all
available without request (executes asTable() with default
parameters under the hood) - see later.
Amplification data (adp)
Default data is adp.
amp <- getFData(lc96, request)
head(amp)
#> Ключ: «cyc»
#> cyc D03_Sample 39_std_IPC D03_Sample 39_std_X D03_Sample 39_std_Y
#> <num> <num> <num> <num>
#> 1: 1 0.0183606 0.0335976 0.0499775
#> 2: 2 0.0180048 0.0325430 0.0484642
#> 3: 3 0.0177101 0.0320003 0.0475724
#> 4: 4 0.0175328 0.0316902 0.0469673
#> 5: 5 0.0173891 0.0313358 0.0464253
#> 6: 6 0.0172979 0.0311102 0.0460783
#> D03_Sample 39_std_bACT D04_Sample 39_std_IPC D04_Sample 39_std_X
#> <num> <num> <num>
#> 1: 0.0765203 0.0198442 0.0358064
#> 2: 0.0740042 0.0192934 0.0345357
#> 3: 0.0723341 0.0190384 0.0338550
#> 4: 0.0713094 0.0189303 0.0335737
#> 5: 0.0699647 0.0188875 0.0334760
#> 6: 0.0692598 0.0188215 0.0332843
#> D04_Sample 39_std_Y D04_Sample 39_std_bACT D05_Sample 41_std_IPC
#> <num> <num> <num>
#> 1: 0.0536608 0.0815654 0.0191602
#> 2: 0.0517852 0.0785972 0.0188048
#> 3: 0.0508504 0.0768843 0.0187248
#> 4: 0.0504487 0.0758016 0.0186919
#> 5: 0.0501193 0.0749237 0.0186583
#> 6: 0.0500132 0.0746428 0.0186720
#> D05_Sample 41_std_X D05_Sample 41_std_Y D05_Sample 41_std_bACT
#> <num> <num> <num>
#> 1: 0.0339051 0.0517698 0.0779549
#> 2: 0.0327662 0.0501112 0.0751758
#> 3: 0.0323423 0.0496300 0.0740962
#> 4: 0.0322557 0.0495610 0.0736120
#> 5: 0.0319371 0.0493506 0.0728351
#> 6: 0.0318878 0.0491510 0.0727694
#> D06_Sample 41_std_IPC D06_Sample 41_std_X D06_Sample 41_std_Y
#> <num> <num> <num>
#> 1: 0.0207541 0.0370556 0.0566644
#> 2: 0.0202325 0.0356479 0.0547598
#> 3: 0.0199968 0.0350582 0.0540312
#> 4: 0.0198780 0.0346749 0.0534543
#> 5: 0.0198824 0.0345360 0.0532268
#> 6: 0.0199653 0.0343352 0.0531516
#> D06_Sample 41_std_bACT D07_Sample 43_std_IPC D07_Sample 43_std_X
#> <num> <num> <num>
#> 1: 0.0856682 0.0175444 0.0310695
#> 2: 0.0826272 0.0169826 0.0296340
#> 3: 0.0811635 0.0167133 0.0290403
#> 4: 0.0801425 0.0165369 0.0286743
#> 5: 0.0794916 0.0164757 0.0284034
#> 6: 0.0791170 0.0164641 0.0281735
#> D07_Sample 43_std_Y D07_Sample 43_std_bACT D08_Sample 43_std_IPC
#> <num> <num> <num>
#> 1: 0.0473832 0.0718652 0.0200607
#> 2: 0.0453774 0.0689529 0.0196742
#> 3: 0.0445243 0.0671860 0.0194035
#> 4: 0.0439118 0.0662575 0.0192953
#> 5: 0.0435639 0.0656260 0.0192834
#> 6: 0.0432672 0.0650626 0.0192326
#> D08_Sample 43_std_X D08_Sample 43_std_Y D08_Sample 43_std_bACT
#> <num> <num> <num>
#> 1: 0.0356145 0.0544387 0.0818625
#> 2: 0.0345259 0.0528708 0.0792517
#> 3: 0.0338534 0.0519989 0.0776971
#> 4: 0.0334567 0.0514629 0.0764136
#> 5: 0.0333187 0.0511263 0.0759889
#> 6: 0.0330787 0.0508951 0.0755568
#> D09_Sample 45_std_IPC D09_Sample 45_std_X D09_Sample 45_std_Y
#> <num> <num> <num>
#> 1: 0.0185860 0.0336384 0.0508826
#> 2: 0.0181555 0.0322999 0.0489802
#> 3: 0.0178374 0.0316383 0.0480418
#> 4: 0.0176324 0.0310238 0.0472458
#> 5: 0.0176419 0.0308866 0.0470960
#> 6: 0.0177665 0.0308295 0.0470439
#> D09_Sample 45_std_bACT D10_Sample 45_std_IPC D10_Sample 45_std_X
#> <num> <num> <num>
#> 1: 0.0782385 0.0203383 0.0360929
#> 2: 0.0753689 0.0200826 0.0352363
#> 3: 0.0736838 0.0198944 0.0346983
#> 4: 0.0723196 0.0198353 0.0342507
#> 5: 0.0717019 0.0199068 0.0340923
#> 6: 0.0714182 0.0199474 0.0341286
#> D10_Sample 45_std_Y D10_Sample 45_std_bACT E03_Sample 51_std_IPC
#> <num> <num> <num>
#> 1: 0.0554231 0.0853050 0.0178333
#> 2: 0.0541550 0.0831106 0.0176003
#> 3: 0.0533848 0.0817363 0.0174533
#> 4: 0.0528364 0.0806183 0.0174767
#> 5: 0.0525911 0.0802673 0.0174976
#> 6: 0.0525880 0.0799331 0.0176317
#> E03_Sample 51_std_X E03_Sample 51_std_Y E03_Sample 51_std_bACT
#> <num> <num> <num>
#> 1: 0.0329191 0.0494571 0.0752976
#> 2: 0.0319224 0.0481465 0.0730672
#> 3: 0.0314371 0.0475546 0.0716360
#> 4: 0.0312886 0.0473839 0.0712866
#> 5: 0.0311553 0.0472380 0.0707699
#> 6: 0.0311438 0.0473775 0.0706796
#> E04_Sample 51_std_IPC E04_Sample 51_std_X E04_Sample 51_std_Y
#> <num> <num> <num>
#> 1: 0.0191185 0.0341296 0.0517345
#> 2: 0.0187005 0.0330325 0.0502056
#> 3: 0.0184264 0.0323452 0.0491989
#> 4: 0.0182750 0.0320491 0.0486962
#> 5: 0.0182767 0.0319013 0.0484829
#> 6: 0.0183389 0.0319011 0.0484655
#> E04_Sample 51_std_bACT E05_Sample 53_unkn_IPC E05_Sample 53_unkn_X
#> <num> <num> <num>
#> 1: 0.0794618 0.0191654 0.0351678
#> 2: 0.0768112 0.0187222 0.0342129
#> 3: 0.0750117 0.0186089 0.0337373
#> 4: 0.0735410 0.0184260 0.0334261
#> 5: 0.0732064 0.0183844 0.0331846
#> 6: 0.0727683 0.0183905 0.0329880
#> E05_Sample 53_unkn_Y E05_Sample 53_unkn_bACT E06_Sample 54_unkn_IPC
#> <num> <num> <num>
#> 1: 0.0526014 0.0790541 0.0180577
#> 2: 0.0511012 0.0763099 0.0175595
#> 3: 0.0504312 0.0750849 0.0172984
#> 4: 0.0498503 0.0742467 0.0171720
#> 5: 0.0495193 0.0735078 0.0170461
#> 6: 0.0492999 0.0727997 0.0174254
#> E06_Sample 54_unkn_X E06_Sample 54_unkn_Y E06_Sample 54_unkn_bACT
#> <num> <num> <num>
#> 1: 0.0323227 0.0497062 0.0746011
#> 2: 0.0311048 0.0477509 0.0718295
#> 3: 0.0303910 0.0469619 0.0700444
#> 4: 0.0299897 0.0464032 0.0689996
#> 5: 0.0297086 0.0459665 0.0681219
#> 6: 0.0301393 0.0467093 0.0692167
#> E07_Sample 55_unkn_IPC E07_Sample 55_unkn_X E07_Sample 55_unkn_Y
#> <num> <num> <num>
#> 1: 0.0196414 0.0343248 0.0530040
#> 2: 0.0192629 0.0333167 0.0516058
#> 3: 0.0191915 0.0329667 0.0511760
#> 4: 0.0191301 0.0327180 0.0508276
#> 5: 0.0191429 0.0324963 0.0506607
#> 6: 0.0191732 0.0323865 0.0505238
#> E07_Sample 55_unkn_bACT E08_Sample 56_unkn_IPC E08_Sample 56_unkn_X
#> <num> <num> <num>
#> 1: 0.0796174 0.0185813 0.0327999
#> 2: 0.0770337 0.0181217 0.0315971
#> 3: 0.0760521 0.0178966 0.0309754
#> 4: 0.0755209 0.0178717 0.0307675
#> 5: 0.0749050 0.0178558 0.0305352
#> 6: 0.0744834 0.0178572 0.0304046
#> E08_Sample 56_unkn_Y E08_Sample 56_unkn_bACT E09_Sample 57_unkn_IPC
#> <num> <num> <num>
#> 1: 0.0497605 0.0763902 0.0186737
#> 2: 0.0480795 0.0736332 0.0181635
#> 3: 0.0473462 0.0721514 0.0179202
#> 4: 0.0469277 0.0716271 0.0178013
#> 5: 0.0466651 0.0707240 0.0177887
#> 6: 0.0466256 0.0703912 0.0178492
#> E09_Sample 57_unkn_X E09_Sample 57_unkn_Y E09_Sample 57_unkn_bACT
#> <num> <num> <num>
#> 1: 0.0328913 0.0502748 0.0769695
#> 2: 0.0317731 0.0485992 0.0742408
#> 3: 0.0310958 0.0475705 0.0726216
#> 4: 0.0306493 0.0470146 0.0716452
#> 5: 0.0304404 0.0469395 0.0709691
#> 6: 0.0303937 0.0467636 0.0706903
#> E10_Sample 58_unkn_IPC E10_Sample 58_unkn_X E10_Sample 58_unkn_Y
#> <num> <num> <num>
#> 1: 0.0198076 0.0345351 0.0529905
#> 2: 0.0193775 0.0332707 0.0511514
#> 3: 0.0190470 0.0324626 0.0501097
#> 4: 0.0188502 0.0320468 0.0493770
#> 5: 0.0188191 0.0317203 0.0490187
#> 6: 0.0189098 0.0316947 0.0489793
#> E10_Sample 58_unkn_bACT
#> <num>
#> 1: 0.0808244
#> 2: 0.0779781
#> 3: 0.0762271
#> 4: 0.0748687
#> 5: 0.0741372
#> 6: 0.0738226
For amplification data, the wide table uses cyc as its
primary coordinate. If cycle temperatures are present, tmp
may also be available.
Melting data (mdp)
biorad <- readRDML(system.file(
"extdata",
"BioRad_qPCR_melt.rdml",
package = "RDML7"
))
#>
#> Loading experiment: All Wells
#> run: Amp Step 3_FAM
#>
#> run: Amp Step 3_Cy5
#>
#> Combining Bio-Rad runs
melt <- getFData(
biorad,
dpType = "mdp"
)
head(melt)
#> Ключ: «tmp»
#> tmp A01_Alm12_pos_Cy5 A01_Alm12_pos_EvaGreen A02_Alm12_pos_Cy5
#> <num> <num> <num> <num>
#> 1: 35 2756.696 2763.424 2773.549
#> 2: 36 2756.427 2762.044 2773.658
#> 3: 37 2755.606 2761.538 2773.060
#> 4: 38 2754.828 2761.131 2772.298
#> 5: 39 2753.944 2761.432 2771.104
#> 6: 40 2753.553 2761.993 2769.961
#> A02_Alm12_pos_EvaGreen A03_Alm13_pos_Cy5 A03_Alm13_pos_EvaGreen
#> <num> <num> <num>
#> 1: 2873.025 2742.910 3052.787
#> 2: 2873.490 2744.053 3045.722
#> 3: 2872.137 2744.902 3036.568
#> 4: 2870.911 2745.605 3027.403
#> 5: 2869.085 2745.972 3017.348
#> 6: 2867.012 2746.133 3006.884
#> A04_Alm13_pos_Cy5 A04_Alm13_pos_EvaGreen A05_Alm14_pos_Cy5
#> <num> <num> <num>
#> 1: 2746.844 3080.472 2769.365
#> 2: 2747.364 3074.555 2769.943
#> 3: 2747.194 3066.430 2769.771
#> 4: 2747.010 3058.135 2769.473
#> 5: 2746.638 3048.621 2768.866
#> 6: 2746.478 3038.660 2768.158
#> A05_Alm14_pos_EvaGreen A06_Alm14_pos_Cy5 A06_Alm14_pos_EvaGreen
#> <num> <num> <num>
#> 1: 3274.659 2780.037 3420.850
#> 2: 3260.485 2779.134 3406.961
#> 3: 3242.934 2778.603 3388.401
#> 4: 3225.100 2777.859 3369.726
#> 5: 3205.429 2777.288 3348.903
#> 6: 3185.546 2776.973 3327.265
#> A07_katG 315_unkn_Cy5 A07_katG 315_unkn_EvaGreen A08_katG 315_unkn_Cy5
#> <num> <num> <num>
#> 1: 2789.874 3186.918 2765.162
#> 2: 2788.184 3176.197 2763.108
#> 3: 2786.631 3160.919 2762.324
#> 4: 2785.046 3145.450 2761.476
#> 5: 2783.440 3127.665 2761.093
#> 6: 2782.113 3109.363 2760.839
#> A08_katG 315_unkn_EvaGreen A09_H2O_ntc_Cy5 A09_H2O_ntc_EvaGreen
#> <num> <num> <num>
#> 1: 2886.544 2799.886 2966.643
#> 2: 2873.045 2800.627 2951.056
#> 3: 2856.397 2800.243 2930.423
#> 4: 2839.687 2799.959 2909.759
#> 5: 2821.571 2799.111 2886.796
#> 6: 2803.040 2798.460 2863.552
#> A10_H2O_ntc_Cy5 A10_H2O_ntc_EvaGreen D01_Alm12_pos_Cy5-2
#> <num> <num> <num>
#> 1: 2770.013 2912.120 3029.842
#> 2: 2770.333 2897.536 2981.122
#> 3: 2770.212 2879.021 2937.551
#> 4: 2770.012 2860.436 2895.814
#> 5: 2769.426 2839.864 2858.862
#> 6: 2769.049 2819.133 2827.073
#> D01_Alm12_pos_EvaGreen D02_Alm12_pos_Cy5-2 D02_Alm12_pos_EvaGreen
#> <num> <num> <num>
#> 1: 3249.911 3111.624 3130.243
#> 2: 3248.812 3054.088 3127.589
#> 3: 3246.821 3001.551 3123.570
#> 4: 3244.042 2951.363 3118.885
#> 5: 3239.934 2906.673 3112.844
#> 6: 3234.515 2868.178 3105.478
#> D03_Alm13_pos_Cy5-2 D03_Alm13_pos_EvaGreen D04_Alm13_pos_Cy5-2
#> <num> <num> <num>
#> 1: 3177.210 2892.511 3230.802
#> 2: 3122.861 2897.547 3169.641
#> 3: 3070.189 2901.540 3110.204
#> 4: 3018.797 2905.218 3052.316
#> 5: 2970.171 2907.869 2997.615
#> 6: 2925.582 2909.278 2947.708
#> D04_Alm13_pos_EvaGreen D05_Alm14_pos_Cy5-2 D05_Alm14_pos_EvaGreen
#> <num> <num> <num>
#> 1: 2897.084 3834.142 3007.557
#> 2: 2904.210 3749.747 3010.505
#> 3: 2909.674 3658.824 3012.562
#> 4: 2914.579 3567.399 3014.506
#> 5: 2917.967 3473.200 3015.672
#> 6: 2919.770 3379.075 3016.321
#> D06_Alm14_pos_Cy5-2 D06_Alm14_pos_EvaGreen D07_katG 315_unkn_Cy5-2
#> <num> <num> <num>
#> 1: 3704.775 2949.503 4759.427
#> 2: 3630.238 2952.510 4715.604
#> 3: 3548.570 2954.214 4666.245
#> 4: 3466.663 2955.879 4616.444
#> 5: 3381.847 2956.814 4563.872
#> 6: 3297.544 2957.345 4510.842
#> D07_katG 315_unkn_EvaGreen D08_katG 315_unkn_Cy5-2
#> <num> <num>
#> 1: 2867.968 4620.729
#> 2: 2864.048 4581.642
#> 3: 2858.544 4536.475
#> 4: 2853.213 4491.069
#> 5: 2847.496 4442.651
#> 6: 2842.057 4393.480
#> D08_katG 315_unkn_EvaGreen D09_H2O_ntc_Cy5-2 D09_H2O_ntc_EvaGreen
#> <num> <num> <num>
#> 1: 2823.160 2691.723 2832.783
#> 2: 2816.158 2692.969 2815.562
#> 3: 2809.917 2693.935 2794.965
#> 4: 2803.811 2694.902 2774.229
#> 5: 2798.283 2695.685 2751.654
#> 6: 2793.139 2696.460 2728.161
#> D10_H2O_ntc_Cy5-2 D10_H2O_ntc_EvaGreen H01_Alm12_pos_Cy5-2_rr
#> <num> <num> <num>
#> 1: 2726.723 3140.937 2769.448
#> 2: 2725.322 3123.298 2763.957
#> 3: 2724.844 3100.413 2760.002
#> 4: 2724.377 3077.349 2756.102
#> 5: 2724.290 3051.524 2752.876
#> 6: 2724.353 3024.968 2750.178
#> H01_Alm12_pos_EvaGreen H02_Alm12_pos_Cy5-2_rr H02_Alm12_pos_EvaGreen
#> <num> <num> <num>
#> 1: 3203.395 2772.874 3280.179
#> 2: 3193.828 2766.819 3269.991
#> 3: 3183.147 2762.863 3257.336
#> 4: 3172.441 2758.907 3244.322
#> 5: 3161.100 2755.771 3229.904
#> 6: 3149.400 2752.933 3214.990
#> H03_Alm13_pos_Cy5-2_rr H03_Alm13_pos_EvaGreen H04_Alm13_pos_Cy5-2_rr
#> <num> <num> <num>
#> 1: 2834.579 3151.868 2825.395
#> 2: 2825.138 3143.335 2817.148
#> 3: 2815.621 3135.343 2808.790
#> 4: 2806.086 3127.204 2800.246
#> 5: 2796.594 3119.124 2791.697
#> 6: 2787.476 3110.741 2783.157
#> H04_Alm13_pos_EvaGreen H05_Alm14_pos_Cy5-2_rr H05_Alm14_pos_EvaGreen
#> <num> <num> <num>
#> 1: 3122.619 3077.596 3175.637
#> 2: 3114.527 3055.775 3165.526
#> 3: 3106.466 3034.333 3155.793
#> 4: 3098.070 3012.344 3145.971
#> 5: 3089.467 2990.026 3136.116
#> 6: 3080.319 2966.911 3125.618
#> H06_Alm14_pos_Cy5-2_rr H06_Alm14_pos_EvaGreen H07_katG 315_unkn_Cy5-2_rr
#> <num> <num> <num>
#> 1: 3186.674 3359.428 4799.703
#> 2: 3161.281 3347.999 4746.312
#> 3: 3134.485 3335.472 4692.246
#> 4: 3107.100 3322.806 4638.466
#> 5: 3078.686 3309.481 4584.585
#> 6: 3049.764 3295.479 4530.886
#> H07_katG 315_unkn_EvaGreen H08_katG 315_unkn_Cy5-2_rr
#> <num> <num>
#> 1: 3090.593 4676.935
#> 2: 3083.679 4626.677
#> 3: 3077.828 4575.587
#> 4: 3071.916 4524.437
#> 5: 3066.526 4472.843
#> 6: 3061.000 4421.124
#> H08_katG 315_unkn_EvaGreen H09_H2O_ntc_Cy5-2_rr H09_H2O_ntc_EvaGreen
#> <num> <num> <num>
#> 1: 3039.149 2820.862 3461.191
#> 2: 3033.924 2817.041 3436.213
#> 3: 3028.838 2815.319 3410.819
#> 4: 3023.567 2813.531 3385.083
#> 5: 3018.277 2812.587 3358.900
#> 6: 3013.045 2811.805 3332.186
#> H10_H2O_ntc_Cy5-2_rr H10_H2O_ntc_EvaGreen
#> <num> <num>
#> 1: 3631.431 3802.533
#> 2: 3609.960 3782.780
#> 3: 3587.895 3762.903
#> 4: 3565.871 3742.670
#> 5: 3543.622 3721.994
#> 6: 3521.279 3700.934
For melting data, the coordinate is tmp.
Long-table output
For plotting and grouped statistical analysis, use
longTable = TRUE.
ampLong <- getFData(lc96, longTable = TRUE)
head(ampLong)
#> fdataName expId
#> <char> <char>
#> 1: D03_Sample 39_std_IPC ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 2: D03_Sample 39_std_IPC ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 3: D03_Sample 39_std_IPC ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 4: D03_Sample 39_std_IPC ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 5: D03_Sample 39_std_IPC ca1eb225-ecea-4793-9804-87bfbb45f81d
#> 6: D03_Sample 39_std_IPC ca1eb225-ecea-4793-9804-87bfbb45f81d
#> runId reactId position sample target
#> <char> <char> <char> <char> <char>
#> 1: 65aeb1ec-b377-4ef6-b03f-92898d47488b 39 D03 Sample 39 IPC
#> 2: 65aeb1ec-b377-4ef6-b03f-92898d47488b 39 D03 Sample 39 IPC
#> 3: 65aeb1ec-b377-4ef6-b03f-92898d47488b 39 D03 Sample 39 IPC
#> 4: 65aeb1ec-b377-4ef6-b03f-92898d47488b 39 D03 Sample 39 IPC
#> 5: 65aeb1ec-b377-4ef6-b03f-92898d47488b 39 D03 Sample 39 IPC
#> 6: 65aeb1ec-b377-4ef6-b03f-92898d47488b 39 D03 Sample 39 IPC
#> targetDyeId sampleType adp mdp cyc tmp fluor
#> <char> <char> <lgcl> <lgcl> <num> <num> <num>
#> 1: Cy5 std TRUE FALSE 1 68.0022 0.0183606
#> 2: Cy5 std TRUE FALSE 2 68.0213 0.0180048
#> 3: Cy5 std TRUE FALSE 3 68.0291 0.0177101
#> 4: Cy5 std TRUE FALSE 4 68.0300 0.0175328
#> 5: Cy5 std TRUE FALSE 5 68.0198 0.0173891
#> 6: Cy5 std TRUE FALSE 6 68.0231 0.0172979
The long representation combines fluorescence points with the
metadata from the request table.
Plotting with ggplot2
library(ggplot2)
ggplot(
stdAmp,
aes(
x = cyc,
y = fluor,
group = fdataName,
colour = target
)
) +
geom_line()
Adding or replacing fluorescence data
RDML7 uses value semantics. setFData()
returns the modified object, so assign it back:
Do not rely on the in-place mutation semantics of the old R6
implementation.
setFData() accepts:
- a wide fluorescence table;
- a description table;
fdataType = "adp" or "mdp";
conflict = "error", "keep", or
"replace".
The fluorescence table has a first coordinate column
(cyc or tmp) and one column per fluorescence
series. The series names must match
description$fdataName.
Creating an RDML object from tables
A minimal RDML object can be created with rdmlType() and
populated with setFData().
fdata <- data.frame(
cyc = 1:6,
c1 = c(10, 11, 13, 18, 35, 80),
c2 = c(9, 10, 12, 16, 29, 65)
)
description <- data.frame(
fdataName = c("c1", "c2"),
expId = c("exp1", "exp1"),
runId = c("run1", "run1"),
reactId = c("1", "2"),
sample = c("sample1", "sample2"),
sampleType = c("unkn", "unkn"),
target = c("gene1", "gene1"),
targetDyeId = c("FAM", "FAM"),
stringsAsFactors = FALSE
)
sim <- rdmlType()
sim <- setFData(
sim,
fdata = fdata,
description = description,
fdataType = "adp"
)
asTable(sim)
#> Ключ: «fdataName»
#> fdataName expId runId reactId position sample target
#> <char> <char> <char> <char> <char> <char> <char>
#> 1: A01_sample1_unkn_gene1 exp1 run1 1 A01 sample1 gene1
#> 2: A02_sample2_unkn_gene1 exp1 run1 2 A02 sample2 gene1
#> targetDyeId sampleType adp mdp
#> <char> <char> <lgcl> <lgcl>
#> 1: FAM unkn TRUE FALSE
#> 2: FAM unkn TRUE FALSE
The required description columns are:
fdataName
expId
runId
reactId
target
Sample and target metadata are used when new schema objects are
created. Missing experiments, runs, reactions, samples, targets, and
dyes are created as needed.
For conflicting existing data:
sim <- setFData(
sim,
fdata,
description,
fdataType = "adp",
conflict = "replace"
)
The conflict policies are:
"error" — stop on a conflict;
"keep" — keep existing data;
"replace" — replace existing data.
Importing vendor and table data
File import is now handled by readRDML() and the format
registry.
For example:
x <- readRDML("instrument-export-file")
If automatic detection is ambiguous:
x <- readRDML(
"instrument-export-file",
format = "registered-format-name"
)
Always use:
listRDMLFormats()
#> format extensions read write
#> 1 abi eds TRUE FALSE
#> 2 rotorgene rex TRUE FALSE
#> 3 excel xlsx, xls TRUE FALSE
#> 4 csv csv TRUE FALSE
#> 5 dtprime r96 TRUE FALSE
#> 6 fqd txt TRUE FALSE
#> 7 innova-qstd qstd TRUE FALSE
#> 8 rdes tsv, csv, txt TRUE TRUE
#> 9 rdml-xml xml TRUE TRUE
#> 10 rdml rdml, rdm TRUE TRUE
#> 11 roche-lc96 lc96p TRUE FALSE
to inspect the format names actually registered in the installed
version of RDML7.
The source tree includes importers for RDML/XML, RDES, ABI, Roche,
Rotor-Gene, DTprime, FQD, CSV, Excel/table data, and other supported
input families. The registry is the authoritative runtime list.
RDES import and export
RDML7 includes RDES support. The example data installed with the
package include amplification and melting RDES TSV files.
rdesAmp <- system.file(
"extdata",
"RDES_v1_0_example_amplification.tsv",
package = "RDML7"
)
rdesMelt <- system.file(
"extdata",
"RDES_v1_0_example_melting.tsv",
package = "RDML7"
)
c(rdesAmp, rdesMelt)
#> [1] "C:/tmp/RtmpKYPudu/Rinst45747907173b/RDML7/extdata/RDES_v1_0_example_amplification.tsv"
#> [2] "C:/tmp/RtmpKYPudu/Rinst45747907173b/RDML7/extdata/RDES_v1_0_example_melting.tsv"
Import uses the same generic entry point:
rdes <- readRDML(rdesAmp)
Export is likewise routed through writeRDML() according
to the requested output format.
Merging RDML objects
Use mergeRDMLs() to combine RDML objects.
file1 <- system.file(
"extdata",
"lc96_bACTXY.rdml",
package = "RDML7"
)
file2 <- system.file(
"extdata",
"stepone_std.rdml",
package = "RDML7"
)
base <- readRDML(file1)
incoming <- readRDML(file2)
merged <- mergeRDMLs(
base,
incoming,
dataConflict = "error"
)
asDendrogram(merged)
dataConflict controls what happens when equivalent data
locations contain different values:
"incoming" — use the value from the incoming
object;
"base" — preserve the value already present in the base
object;
"error" — stop rather than resolve the conflict
silently.
For merging independent files, "error" is useful while
developing a pipeline because unexpected ID collisions become visible
immediately.
A directory of files can be processed in a list:
files <- list.files(
system.file("extdata", package = "RDML7"),
full.names = TRUE
)
files <- files[!file.info(files)$isdir]
rdmls <- lapply(files, function(file) readRDML(file))
merged <- mergeRDMLs(
rdmls,
dataConflict = "error"
)
merged <- mergeRDMLs(
rdmls
)
rm(rdmls)
asDendrogram(merged)
rm(merged)
If experiment identifiers are not unique between input files, rename
them before merging.
Serialising and writing RDML
asXML()
Use asXML() when the XML representation itself is
needed:
xml <- asXML(r96)
cat(
substr(
xml,
1,
500
)
)
writeRDML()
Use writeRDML() for normal file output:
writeRDML(
lc96,
"lc96-copy.rdml",
overwrite = TRUE
)
For RDML archives, the package writes the XML payload as
rdml_data.xml inside the archive.
The writer is selected through the same registry used by
readRDML().
Validation before export
A useful export workflow is:
validation <- validateRDML(lc96)
if (isValidRDML(lc96)) {
writeRDML(
lc96,
"validated.rdml",
overwrite = TRUE
)
}
Loss-aware conversions
Different external formats do not necessarily represent every RDML
feature. The importer/exporter API can describe known information loss
using newRDMLLossRecord().
When developing a format plugin, declare known lossy transformations
rather than silently discarding unsupported information.
This allows higher-level I/O code to decide whether loss should
produce a warning, an error, or be explicitly allowed.
editRDML()
editRDML() remains available as an editing
interface.
For reproducible analyses, scripted operations with
asTable(), getFData(),
setFData(), and the S7 object model should remain the
primary workflow, while an editor is useful for interactive inspection
and manual changes.
Working with external analysis packages
RDML7 intentionally keeps fluorescence extraction separate from
downstream qPCR analysis. Once curves have been obtained with
getFData(), they can be passed to other R packages.
For example:
curves <- getFData(
lc96,
dpType = "adp",
longTable = FALSE
)
# The first column contains cycle coordinates.
cycles <- curves[[1]]
# Remaining columns contain fluorescence series and can be passed to
# modelling, preprocessing, Cq estimation, or visualisation code.
This separation allows RDML7 to focus on data interchange, metadata,
validation, conversion, and object manipulation while specialised
packages perform curve analysis.
See details and examples in Using RDML with other R
packages vignette.
Recommended workflow
For most analyses, the following pattern is sufficient:
library(RDML7)
# 1. Import
x <- readRDML("experiment.rdml")
# 2. Inspect and validate
summary(x)
validateRDML(x)
# 3. Build the curve index / metadata table
meta <- asTable(
x,
namePattern =
"{expId}_{runId}_{position}_{sample}_{sampleType}_{target}"
)
# 4. Select curves
selected <- meta[
meta$sampleType == "std" &
meta$adp,
]
# 5. Extract fluorescence
amp <- getFData(
x,
request = selected,
dpType = "adp",
longTable = TRUE
)
# 6. Analyse or modify data
# ...
# 7. Write a new RDML file if needed
writeRDML(
x,
"experiment-processed.rdml",
overwrite = TRUE
)
Legacy API compatibility
Legacy wrappers are exported to ease migration of existing analysis
scripts.
Examples include:
AsTable -> asTable
GetFData -> getFData
SetFData -> setFData
AsDendrogram -> asDendrogram
asXML -> asXML
MergeRDMLs -> mergeRDMLs
Some old dotted argument names are also translated by compatibility
code to their CamelCase equivalents, for example:
show.progress -> showProgress
conditions.sep -> conditionsSep
fdata.type -> fdataType
serial.number -> serialNumber
name.pattern -> namePattern
long.table -> longTable
sample.type -> sampleType
target.dyeId -> targetDyeId
dp.type -> dpType
plot.dendrogram -> plotDendrogram
data.conflict -> dataConflict
Compatibility wrappers are intended to keep old scripts usable. New
code and new documentation should use the canonical names.
Function overview
The following groups summarise the most important public RDML7
functionality.
Core object and schema
rdmlType()
idType()
idReferenceType()
experimentType()
runType()
reactType()
dataType()
sampleType()
targetType()
dyeType()
thermalCyclingConditionsType()
...
File I/O
readRDML()
writeRDML()
asXML()
detectRDMLFormat()
listRDMLFormats()
Inspection and validation
summary()
validateRDML()
isValidRDML()
asDendrogram()
Manipulation
mergeRDMLs()
editRDML()
Extensible import/export
registerRDMLFormat()
unregisterRDMLFormat()
loadRDMLModule()
newRDMLImportSeries()
newRDMLImportData()
buildRDMLImport()
newRDMLLossRecord()
RDML7 public API naming convention rules
- Actions start with a verb:
readRDML(),
validateRDML().
- Conversion/coercion uses standard R
as...:
asTable(), asDendrogram(),
asXML().
- Predicates start with
is...:
isValidRDML().
- Helper-object constructors start with
new....
- RDML schema/S7 type constructors keep the schema noun name:
rdmlType(), sampleType(),
targetType(), dataType(), etc.
Summary
RDML7 keeps the main ideas of the original RDML package—structured
qPCR metadata, fluorescence extraction, table-based filtering, creation
of RDML objects from user data, and interoperability with other R
analysis packages—but substantially changes the implementation and
public API.
The central concepts for new code are:
- read files with
readRDML();
- treat
rdmlType and nested schema elements as S7
objects;
- use
asTable() as the metadata/curve index;
- use
{field} templates for readable and documented
fdataName generation;
- add custom
asTable() columns directly through
...;
- use
getFData() and setFData() for
fluorescence;
- remember that modification uses value semantics;
- validate with
validateRDML() /
isValidRDML();
- write through
writeRDML();
- discover and extend formats through the format registry.
For the current runtime list of supported file handlers, always
prefer:
over a hard-coded list in analysis code.
Further reading
vignette("CreateRDML", package = "RDML")
vignette("RDES", package = "RDML")
vignette("format-plugins", package = "RDML")
vignette("usingRDML_with_other_R_packages", package = "RDML")