Map Gene Expression and RNA-seq Data to the CDISC SDTM Genomics Findings (GF) Domain in R

Tabulate transcription findings — RNA-seq-derived TPM, FPKM, and qPCR relative expression — into the CDISC GF domain as numeric results, with the measure in GFSTRESN and its unit in GFSTRESU

Pharma & Clinical

The full gene-expression workflow for the CDISC SDTM Genomics Findings (GF) domain. Building on the GF-domain fundamentals and the variant lesson, this lesson maps transcription findings — normalized RNA-seq expression (TPM, FPKM, normalized counts) and qPCR relative expression (fold-change, Ct/Cq) — into GF Findings records. Unlike a variant call, which is a character result, gene expression is a measured quantity: the value lands in the numeric result variable GFSTRESN with its unit in GFSTRESU, the assay in GFMETHOD, and the gene in GFTESTCD/GFTEST. Learn what each expression measure means and where it maps, why single-gene qPCR, a panel, and RNA-seq-derived per-gene expression differ only by method, and — the cardinal rule — why GF holds the reported expression measure, never the FASTQ reads or the raw count matrix. All with base R and sdtm.oak, every code an illustrative placeholder to verify against CDISC controlled terminology.

Published

July 1, 2026

Modified

July 7, 2026

TipKey takeaways
  • Gene expression is a numeric GF finding. Where a variant call is a character result (DETECTED), a gene-expression measure — how actively a gene is transcribed — is a number. In the CDISC SDTM (Study Data Tabulation Model) GF (Genomics Findings) domain it lands in the numeric result variable GFSTRESN, with its unit in GFSTRESU — not the character GFSTRESC a variant uses.
  • The unit is the crux — never drop it. An expression number is meaningless without its unit: TPM (transcripts per million), FPKM/RPKM, a normalized count, a qPCR fold-change, a Ct/Cq cycle value. Carry the original unit in GFORRESU and the standardized one in GFSTRESU.
  • GFCAT marks it as expression, not variation. The transcription category (illustratively GENE EXPRESSION) separates these findings from the GENETIC VARIATION rows of the variant lesson — same domain, same Findings shape, a different category and a numeric result.
  • The assay lives in GFMETHOD; the gene lives in GFTESTCD/GFTEST. Single-gene qPCR, a targeted expression panel, and RNA-seq-derived per-gene expression differ only by method — one GF row per gene, per specimen, whatever measured it.
  • GF holds the expression measure, never the reads. A PD-L1 TPM value is a GF finding; the FASTQ reads and the raw RNA-seq count matrix it was quantified from are out of SDTM scope — the sequencing and quantification are upstream analysis.

Introduction

The RNA-seq run produced roughly 20,000 gene-expression values per tumour. The submission does not want the reads, and it does not want all 20,000 genes — it wants the PD-L1 expression, the EGFR expression, the proliferation marker, tabulated like every other finding. That is the job of the GF domain for transcription data.

Gene expression is how actively a gene is transcribed into RNA — the biological signal a tumour’s biology runs on, and a biomarker regulators increasingly ask for. RNA-seq (RNA sequencing) and qPCR (quantitative polymerase chain reaction) are the two assays that measure it. This lesson maps their results into GF (Genomics Findings), the CDISC (Clinical Data Interchange Standards Consortium) SDTM (Study Data Tabulation Model) Findings-class domain for pharmacogenomic data.

It assumes you already know what GF is. If not, start with the Genomics Findings (GF) domain — its structure, the Findings-class variables, the biospecimen link, and the cardinal rule that GF tabulates the called finding, never the raw FASTQ/BAM/VCF files. The mutation and variant lesson mapped the variation half of GF — genomic changes as character calls. This lesson maps the other half: transcription. Together they complete the genomics cluster: fundamentals → variants → expression.

The distinction that drives everything below: a variant is a character result; expression is a number. Here is where we are headed — a small RNA-seq expression panel, three genes on three lung-tumour specimens, each value a GF record waiting to be tabulated:

A subject-by-gene heatmap of RNA-seq gene-expression values for three lung-tumour subjects. Rows are subjects (01-701-1033, 01-701-1034, 01-701-1047); columns are three genes (CD274/PD-L1, EGFR, MKI67). Each tile is shaded on a continuous azure scale from lighter (low expression) to darker (high expression) and labelled with its TPM value: subject 1033 has CD274 48.2, EGFR 112.5, MKI67 76.3; subject 1034 has CD274 6.4, EGFR 88.1, MKI67 41.7; subject 1047 has CD274 21.9, EGFR 54.0, MKI67 95.2. The point is that a matrix of numeric expression measures becomes a set of tidy, numeric SDTM findings, one per gene per specimen.

Each tile is one GF record — a gene’s expression on a collected specimen, a number with a unit. By the end of this lesson you will have built all of them from a raw expression export, added the unit and the method, and linked each back to its biospecimen.

Note

This is tabulation, not analysis — and that is the whole point. The Bioinformatics pillar teaches the upstream work: aligning RNA-seq reads, quantifying per-gene expression, and running differential-expression analysis. This lesson starts where that ends — from a table of already-quantified expression values — and tabulates them downstream into CDISC SDTM for a submission. Quantify the expression there; tabulate the reported measure here. The two never overlap.

Why expression maps differently from a variant

A variant call and an expression measure are both GF findings, but they fill different result variables — and getting that right is the whole lesson. Recall that GF, like every Findings domain, splits a result into a collected side (--ORRES, as the lab reported it) and a standardized side, and the standardized side has two variables: a character one (GFSTRESC) and a numeric one (GFSTRESN).

Finding Nature Collected Standardized character Standardized numeric + unit
Variant (variation lesson) Categorical call GFORRES = p.L858R GFSTRESC = DETECTED — (no meaningful number)
Gene expression (this lesson) Measured quantity GFORRES = 48.2, GFORRESU = TPM GFSTRESC = 48.2 GFSTRESN = 48.2, GFSTRESU = TPM

The rule: a measured expression value lands in GFSTRESN (numeric) with its unit in GFSTRESU, exactly as a lab result like haemoglobin lands in LBSTRESN/LBSTRESU. A variant call has no meaningful number, so it uses GFSTRESC and leaves GFSTRESN empty; an expression value has no detected/not-detected call, so it populates the numeric variables. Put an expression number in a character field with no GFSTRESN, and a reviewer cannot compute on it — the single most common expression-mapping mistake.

GFCAT marks the split at the category level too: variant rows carry GENETIC VARIATION; expression rows carry a transcription category, illustratively GENE EXPRESSION. Unlike the test code, GFCAT and GFSCAT are sponsor-defined groupings with no published CDISC codelist — only the Genomic Findings test code (GFTESTCD, C181178) and test name (GFTEST, C181179) carry controlled terminology, with the GF domain detailed in SDTMIG v3.4, the SDTM Implementation Guide that published GF — choose category values consistently and document them, never assert one as CDISC-official.

The expression measures — and their units

The unit is the finding. An expression number without its unit is unusable, and each assay reports its own measure. Know the ones you will meet, what each means, and where it maps in GF:

Measure What it is Typical unit GF result
TPM (transcripts per million) RNA-seq normalized abundance; per sample the values sum to one million, so a TPM is a gene’s share of the transcript pool — comparable across samples TPM GFSTRESN + GFSTRESU = TPM
FPKM / RPKM (fragments / reads per kilobase per million) Older RNA-seq normalization; corrects for gene length and depth but is not comparable across samples the way TPM is FPKM / RPKM GFSTRESN + GFSTRESU = FPKM
Normalized count An RNA-seq count scaled by a library-size / size factor (e.g. by a differential-expression pipeline) normalized count GFSTRESN + GFSTRESU = normalized count
Relative expression / fold-change qPCR result vs a reference gene and a calibrator (the 2^−ΔΔCt method) — how many-fold a gene is up or down fold change GFSTRESN + GFSTRESU = fold change
Ct / Cq (cycle threshold / quantification cycle) The raw qPCR cycle at which signal crosses threshold; lower Cq means more starting template, so it is inversely related to expression Ct (cycles) GFSTRESN + GFSTRESU = Ct

Two things to internalize. First, TPM is the RNA-seq default worth reaching for because, unlike FPKM/RPKM, it is consistent across samples — RPKM/FPKM were the original RNA-seq measures (Mortazavi et al. 2008) but their per-sample totals differ, so a raw FPKM is not directly comparable between subjects. Second, qPCR reports a relative measure, not an absolute one: the 2^−ΔΔCt relative-expression method gives a fold-change against a reference gene and calibrator, and the underlying Cq is defined by the MIQE guidelines (Minimum Information for Publication of Quantitative Real-Time PCR Experiments) — carry whichever the lab reported, and its unit, verbatim.

The lesson: whatever the measure, the value goes in GFSTRESN and the unit in GFSTRESU. The measure changes with the assay; the mapping target does not.

Build a GF domain from an RNA-seq expression export

Two inputs drive the build: the raw expression export from the assay, and knowledge of the GF structure to map it into. An RNA-seq pipeline hands you one row per gene per sample — a subject, the specimen, the gene, the quantified value, and the unit. We build that raw table first. The specimen references (SPEC4.1, SPEC5.1, SPEC6.1) are real biospecimen IDs from the be example data we link to later — the three lung-tumour specimens the variant lesson also used.

library(sdtm.oak)

# A raw RNA-seq expression export: one row per gene per specimen. TPM (transcripts
# per million) is the normalized expression measure; the reads and the full count
# matrix are NOT here — they stay upstream and never reach SDTM. PD-L1 is the protein
# name for the gene CD274 (a checkpoint-immunotherapy biomarker); MKI67 marks proliferation.
expr_raw <- data.frame(
  SUBJ   = c("01-701-1033","01-701-1033","01-701-1033",
             "01-701-1034","01-701-1034","01-701-1034",
             "01-701-1047","01-701-1047","01-701-1047"),
  SPECREF = c("SPEC4.1","SPEC4.1","SPEC4.1",
              "SPEC5.1","SPEC5.1","SPEC5.1",
              "SPEC6.1","SPEC6.1","SPEC6.1"),
  GENE   = c("CD274","EGFR","MKI67", "CD274","EGFR","MKI67", "CD274","EGFR","MKI67"),
  TPM    = c(48.2, 112.5, 76.3, 6.4, 88.1, 41.7, 21.9, 54.0, 95.2),
  UNIT   = rep("TPM", 9),
  ASSAY  = rep("RNA-seq", 9),
  COLLDT = c("2025-09-10","2025-09-10","2025-09-10",
             "2025-10-05","2025-10-05","2025-10-05",
             "2025-11-01","2025-11-01","2025-11-01"),
  stringsAsFactors = FALSE
)

head(expr_raw)
         SUBJ SPECREF  GENE   TPM UNIT   ASSAY     COLLDT
1 01-701-1033 SPEC4.1 CD274  48.2  TPM RNA-seq 2025-09-10
2 01-701-1033 SPEC4.1  EGFR 112.5  TPM RNA-seq 2025-09-10
3 01-701-1033 SPEC4.1 MKI67  76.3  TPM RNA-seq 2025-09-10
4 01-701-1034 SPEC5.1 CD274   6.4  TPM RNA-seq 2025-10-05
5 01-701-1034 SPEC5.1  EGFR  88.1  TPM RNA-seq 2025-10-05
6 01-701-1034 SPEC5.1 MKI67  41.7  TPM RNA-seq 2025-10-05

Each row is one expression finding: a subject, the tumour specimen (SPECREF), the gene, the quantified TPM value, and its unit. There are three genes here — not 20,000: the submission carries the pre-specified biomarker genes, not the whole transcriptome. And note what is absent: no reads, no count matrix, only the reported measure.

Map the raw export to the GF structure

Now fill the GF columns from the raw fields with base R. The value is numeric, so — unlike a variant — it populates GFSTRESN, and its unit populates GFORRESU/GFSTRESU. GFCAT is the transcription category for every row; GFMETHOD records the assay. We build GFTESTCD from the gene following the GF suffix-fragment convention — and flag it plainly as illustrative, to be verified against C181178, not asserted as an official code.

# GFTESTCD below is ILLUSTRATIVE (gene root + "EXP"), following the GF suffix-fragment
# convention. The authoritative code list is NCI EVS subset C181178 — verify there.
# Expression is a NUMBER: it lands in GFSTRESN (numeric) with its unit in GFSTRESU,
# NOT in the character GFSTRESC a variant call uses.
gf <- data.frame(
  STUDYID  = "CDISCPILOT01",
  DOMAIN   = "GF",
  USUBJID  = expr_raw$SUBJ,
  GFREFID  = expr_raw$SPECREF,                          # links to the biospecimen
  GFTESTCD = paste0(expr_raw$GENE, "EXP"),              # illustrative — verify vs C181178
  GFTEST   = paste(expr_raw$GENE, "Expression"),
  GFCAT    = "GENE EXPRESSION",                         # illustrative transcription category
  GFORRES  = as.character(expr_raw$TPM),                # the value, as reported
  GFORRESU = expr_raw$UNIT,                             # original unit (TPM)
  GFSTRESC = as.character(expr_raw$TPM),                # standardized character form
  GFSTRESN = expr_raw$TPM,                              # standardized NUMERIC value
  GFSTRESU = expr_raw$UNIT,                             # standardized unit (TPM)
  GFSPEC   = "TUMOR TISSUE",
  GFMETHOD = expr_raw$ASSAY,                            # the assay: RNA-seq
  GFDTC    = expr_raw$COLLDT,
  stringsAsFactors = FALSE
)

gf[, c("USUBJID", "GFTESTCD", "GFCAT", "GFORRES", "GFSTRESN", "GFSTRESU", "GFMETHOD")]
      USUBJID GFTESTCD           GFCAT GFORRES GFSTRESN GFSTRESU GFMETHOD
1 01-701-1033 CD274EXP GENE EXPRESSION    48.2     48.2      TPM  RNA-seq
2 01-701-1033  EGFREXP GENE EXPRESSION   112.5    112.5      TPM  RNA-seq
3 01-701-1033 MKI67EXP GENE EXPRESSION    76.3     76.3      TPM  RNA-seq
4 01-701-1034 CD274EXP GENE EXPRESSION     6.4      6.4      TPM  RNA-seq
5 01-701-1034  EGFREXP GENE EXPRESSION    88.1     88.1      TPM  RNA-seq
6 01-701-1034 MKI67EXP GENE EXPRESSION    41.7     41.7      TPM  RNA-seq
7 01-701-1047 CD274EXP GENE EXPRESSION    21.9     21.9      TPM  RNA-seq
8 01-701-1047  EGFREXP GENE EXPRESSION      54     54.0      TPM  RNA-seq
9 01-701-1047 MKI67EXP GENE EXPRESSION    95.2     95.2      TPM  RNA-seq

Every gene’s expression is now a row: the numeric value in GFSTRESN, its unit in GFSTRESU, the transcription category in GFCAT, and the assay in GFMETHOD. The character GFSTRESC carries the value as text (Findings domains populate both forms), but the number in GFSTRESN is what a reviewer computes on — and what would be empty on a variant row.

Number the records with derive_seq

A conformant Findings record needs a sequence number unique within each subject. derive_seq() from sdtm.oak — the pharmaverse raw-to-SDTM engine — orders the rows and numbers them per subject, exactly as it does for LBSEQ or VSSEQ.

gf <- derive_seq(gf, tgt_var = "GFSEQ",
                 rec_vars = c("USUBJID", "GFTESTCD"),
                 sbj_vars = "USUBJID")
gf <- as.data.frame(gf)
gf <- gf[, c("STUDYID", "DOMAIN", "USUBJID", "GFSEQ", "GFREFID", "GFTESTCD", "GFTEST",
             "GFCAT", "GFORRES", "GFORRESU", "GFSTRESN", "GFSTRESU", "GFSPEC",
             "GFMETHOD", "GFDTC")]

head(gf[, c("USUBJID", "GFSEQ", "GFTESTCD", "GFSTRESN", "GFSTRESU", "GFSPEC")])
      USUBJID GFSEQ GFTESTCD GFSTRESN GFSTRESU       GFSPEC
1 01-701-1033     1 CD274EXP     48.2      TPM TUMOR TISSUE
2 01-701-1033     2  EGFREXP    112.5      TPM TUMOR TISSUE
3 01-701-1033     3 MKI67EXP     76.3      TPM TUMOR TISSUE
4 01-701-1034     1 CD274EXP      6.4      TPM TUMOR TISSUE
5 01-701-1034     2  EGFREXP     88.1      TPM TUMOR TISSUE
6 01-701-1034     3 MKI67EXP     41.7      TPM TUMOR TISSUE

That is a conformant GF skeleton for expression: identifiers, a per-subject GFSEQ, the topic test code, and — the crux — a numeric result with a unit, each tied to a TUMOR TISSUE specimen. A quick structural check confirms the contract, including the two things an expression finding must never miss: a number and its unit.

cat("one domain code:              ", length(unique(gf$DOMAIN)) == 1, "\n")
one domain code:               TRUE 
cat("GFSEQ unique within subject:  ", !any(duplicated(gf[c("USUBJID", "GFSEQ")])), "\n")
GFSEQ unique within subject:   TRUE 
cat("every value is numeric:       ", all(!is.na(gf$GFSTRESN)), "\n")
every value is numeric:        TRUE 
cat("every numeric value has a unit:", all(nchar(gf$GFSTRESU) > 0), "\n")
every numeric value has a unit: TRUE 

Four TRUEs — structurally sound, and crucially every GFSTRESN carries a GFSTRESU. In production a conformance tool (Pinnacle 21) runs the full rule set a regulator would; here the point is that an expression GF domain is an ordinary numeric Findings build, once the expression is quantified.

Same finding, a different method: qPCR

RNA-seq is not the only way to measure expression. qPCR measures a single gene (or a small panel) and reports a relative result — a fold-change against a reference gene and calibrator. The finding is still gene expression; only the method and the unit change. Watch how the same GF mapping absorbs it — a different GFMETHOD, a different GFSTRESU, the value still in GFSTRESN:

# A single-gene qPCR export: CD274 (PD-L1) relative expression by the 2^-ddCt method,
# reported as a fold-change vs a normal-tissue calibrator. Different assay, different
# unit — same numeric GF mapping (value in GFSTRESN, unit in GFSTRESU).
qpcr_raw <- data.frame(
  SUBJ   = c("01-701-1033","01-701-1034","01-701-1047"),
  SPECREF = c("SPEC4.1","SPEC5.1","SPEC6.1"),
  GENE   = rep("CD274", 3),
  FC     = c(3.2, 0.8, 1.9),                 # fold-change (2^-ddCt) vs calibrator
  UNIT   = rep("fold change", 3),
  ASSAY  = rep("RT-qPCR", 3),
  COLLDT = c("2025-09-10","2025-10-05","2025-11-01"),
  stringsAsFactors = FALSE
)

gf_qpcr <- data.frame(
  STUDYID  = "CDISCPILOT01",
  DOMAIN   = "GF",
  USUBJID  = qpcr_raw$SUBJ,
  GFREFID  = qpcr_raw$SPECREF,
  GFTESTCD = paste0(qpcr_raw$GENE, "EXP"),   # illustrative — verify vs C181178
  GFTEST   = paste(qpcr_raw$GENE, "Expression"),
  GFCAT    = "GENE EXPRESSION",
  GFORRES  = as.character(qpcr_raw$FC),
  GFORRESU = qpcr_raw$UNIT,
  GFSTRESN = qpcr_raw$FC,                     # the numeric value again
  GFSTRESU = qpcr_raw$UNIT,                   # but the unit is fold change, not TPM
  GFSPEC   = "TUMOR TISSUE",
  GFMETHOD = qpcr_raw$ASSAY,                  # RT-qPCR, not RNA-seq
  GFDTC    = qpcr_raw$COLLDT,
  stringsAsFactors = FALSE
)

gf_qpcr[, c("USUBJID", "GFTESTCD", "GFSTRESN", "GFSTRESU", "GFMETHOD")]
      USUBJID GFTESTCD GFSTRESN    GFSTRESU GFMETHOD
1 01-701-1033 CD274EXP      3.2 fold change  RT-qPCR
2 01-701-1034 CD274EXP      0.8 fold change  RT-qPCR
3 01-701-1047 CD274EXP      1.9 fold change  RT-qPCR

Same gene (CD274), same category, same numeric target — but GFMETHOD is RT-qPCR and GFSTRESU is fold change, not TPM. That is why the unit and method are not decoration: without them, a 3.2 fold-change and a 48.2 TPM look like the same kind of number and are not remotely comparable. This is also why RNA-seq per-gene expression, a targeted expression panel, and single-gene qPCR are one domain, many methods — the row structure never changes, GFMETHOD and GFSTRESU record what produced the value.

Common issues

You put a raw RNA-seq count matrix (or the FASTQ reads) in GF and nothing fits. It never will — raw reads and the full count matrix are out of SDTM scope, the same way BAM/VCF files are for variants. GF tabulates the reported expression measure (a TPM value, a fold-change) for the pre-specified genes, not the sequencing output it was quantified from. Extract the reported values into GF rows; archive the reads and the matrix in the study’s genomic repository and reference them, don’t tabulate them.

You store the expression number but forget the unit. A 48.2 with no unit is unusable — is it TPM, FPKM, a fold-change? Populate GFORRESU (original) and GFSTRESU (standardized) on every numeric expression row. A GFSTRESN without a GFSTRESU fails the most basic review of a numeric finding.

You put the expression value in the character result and leave GFSTRESN empty. Expression is a measured quantity: it belongs in the numeric GFSTRESN (a reviewer computes on it), not only in the character GFSTRESC. That character-only pattern is right for a variant call (DETECTED), wrong for a number.

You reuse the variant category for an expression finding. An expression row is a transcription finding, illustratively GFCAT = "GENE EXPRESSION" — not the GENETIC VARIATION of the variant lesson. Mixing them makes a reviewer unable to separate the two kinds of finding. Confirm the exact category term against C181178 rather than asserting either as official.

Frequently asked questions

As a numeric Findings record. Each gene’s expression on a specimen is one GF (Genomics Findings) row with GFCAT set to a transcription category (illustratively GENE EXPRESSION), the gene in GFTESTCD/GFTEST, the assay in GFMETHOD, and — the crux — the measured value in the numeric GFSTRESN with its unit in GFSTRESU. That is different from a variant call, which is a character result (GFSTRESC = DETECTED). Verify the codes and category against NCI EVS subset C181178.

No. GF stores the reported expression measure (a TPM value, an FPKM, a qPCR fold-change), never the raw FASTQ reads or the RNA-seq count matrix they were quantified from. Those are out of SDTM scope — the sequencing, alignment, and quantification are upstream analysis (the Bioinformatics pillar); they are archived in a specialized genomic repository and referenced, while GF carries only the tabulated values a reviewer reads record by record.

The value goes in the numeric standardized result variable GFSTRESN, and the unit (TPM, FPKM, fold change, Ct) goes in GFSTRESU — with the original value and unit in GFORRES/GFORRESU. Expression is a measured quantity, so it populates the numeric result variables exactly as a lab value populates LBSTRESN/LBSTRESU. Never leave a numeric expression value in a character-only field, and never drop the unit.

Both are GF Findings records, but they differ in category and result type. A variant is GFCAT = "GENETIC VARIATION", a categorical call in the character GFSTRESC (DETECTED), with the HGVS string in GFORRES. Gene expression is a transcription category (illustratively GENE EXPRESSION), a number in GFSTRESN with a unit in GFSTRESU. Same domain, same Findings shape — a different GFCAT and the numeric result variables instead of the character one.

No — only GFMETHOD and the unit change. Single-gene qPCR, a targeted expression panel, and RNA-seq-derived per-gene expression are one domain, many methods: one GF row per gene per specimen, the value in GFSTRESN. GFMETHOD records the assay (RNA-seq, RT-qPCR), and GFSTRESU records its unit (TPM for RNA-seq, fold change or Ct for qPCR) — which is exactly why the method and unit are load-bearing: a TPM and a fold-change are not comparable numbers.

Test your understanding

The build above tabulated RNA-seq expression in TPM. Suppose a differential-expression pipeline instead reported EGFR expression for subject 01-701-1034 as a normalized count of 1840. Sketch the GF row: which GFCAT it carries, which result variables hold the value and the unit, and what GFMETHOD and GFTESTCD would be — noting that only the unit and method differ from the TPM row.

A normalized count is still a measured number, so it maps exactly like a TPM — same numeric result variable, same place for the unit — only the unit string and the method change. The category does not change: it is still a transcription finding.

The normalized-count finding is still a numeric GENE EXPRESSION GF record:

  • GFCAT stays "GENE EXPRESSION" (a transcription finding, not GENETIC VARIATION).
  • The value goes in the numeric GFSTRESN = 1840, with GFSTRESU = "normalized count" (and GFORRES = "1840", GFORRESU = "normalized count") — the same numeric target as the TPM row, a different unit string.
  • GFMETHOD names the assay/pipeline (e.g. RNA-seq), and GFTESTCD/GFTEST name the EGFR expression test — verified against C181178.
  • GFSPEC/GFREFID still tie it to the specimen.

Same domain, same numeric Findings shape — only the unit and method distinguish a normalized count from a TPM. The value always lands in GFSTRESN; the unit always lands in GFSTRESU.

A. In the character result GFSTRESC, with GFSTRESN left empty B. In the numeric result GFSTRESN, with the unit TPM in GFSTRESU C. In the raw count matrix, attached to the submission as a file

B. Gene expression is a measured quantity, so a TPM value lands in the numeric GFSTRESN with its unit in GFSTRESU — the same pattern as any lab value. A is the variant pattern (a character call with no meaningful number), wrong for a measured value. C is out of SDTM scope entirely — the raw count matrix and the reads never enter GF; only the reported expression measure does.

Conclusion

Gene expression completes the GF cluster as the numeric half of the domain. Whatever the assay — RNA-seq TPM, FPKM, a normalized count, a qPCR fold-change or Ct — the finding is one transcription record per gene per specimen: the measured value in GFSTRESN, its unit in GFSTRESU, the assay in GFMETHOD, the gene in GFTESTCD/GFTEST, and GFCAT marking it as expression rather than variation. Keep every GFTESTCD and category an illustrative placeholder until C181178 confirms it, and — the cardinal rule one more time — keep the reads and the raw count matrix out of SDTM: GF carries the reported measure, not the sequencing that produced it.

That closes the genomics cluster: the GF-domain fundamentals established the Findings-class structure and the findings-not-raw boundary; the variant lesson mapped genetic variation as character calls; and this lesson mapped transcription as numeric findings. Three lessons, one domain — every genomic result a precision-medicine trial produces, submission-ready.

Note

This lesson is reproducible: every result on this page was produced by the code shown — copy any block and run it to reproduce them. The runtime is the judge.

Reuse

Citation

BibTeX citation:
@online{2026,
  author = {},
  title = {Map {Gene} {Expression} and {RNA-seq} {Data} to the {CDISC}
    {SDTM} {Genomics} {Findings} {(GF)} {Domain} in {R}},
  date = {2026-07-01},
  url = {https://www.datanovia.com/learn/pharma-clinical/02-sdtm-programming/gene-expression-rnaseq-gf},
  langid = {en}
}
For attribution, please cite this work as:
“Map Gene Expression and RNA-Seq Data to the CDISC SDTM Genomics Findings (GF) Domain in R.” 2026. July 1. https://www.datanovia.com/learn/pharma-clinical/02-sdtm-programming/gene-expression-rnaseq-gf.