Olink NPX
Olink’s proximity extension assay measures proteins with pairs of antibodies, each carrying a DNA oligo. When both antibodies bind their target, the oligos extend into a barcode, and the barcode is quantified by qPCR or by sequencing. The number that comes out is NPX, Normalized Protein eXpression, a relative concentration on the log2 scale. One unit of NPX difference is a two-fold difference in protein concentration.
The NPX export
Section titled “The NPX export”Olink’s software exports the results of a run as a long table: one row per
sample per assay. The export comes as .xlsx, .csv or .parquet, and the
columns are the same in each.
| Column | Content |
|---|---|
SampleID |
The sample identifier |
OlinkID |
The assay identifier, e.g. OID00101 |
UniProt |
The UniProt accession of the target protein |
Assay |
The assay name, usually the gene symbol |
Panel |
The panel name, e.g. Inflammation |
PlateID |
The plate the sample ran on |
QC_Warning |
PASS or WARN, from the built-in controls |
LOD |
The limit of detection for the assay on this plate |
NPX |
The measurement itself, log2 scale |
MissingFreq |
The fraction of samples missing for the assay |
The example below reads a synthetic export with the same layout: two plates, 16 samples, 6 assays.
library(OlinkAnalyze)
npx <- read_NPX("/opt/data/npx_export.csv")dim(npx)head(as.data.frame(npx)[, c("SampleID", "Assay", "PlateID", "QC_Warning", "LOD", "NPX")], 4)[1] 96 12 SampleID Assay PlateID QC_Warning LOD NPX1 Sample_01 IL6 Plate1 PASS 0.8 4.592 Sample_01 TNF Plate1 PASS 1.2 2.913 Sample_01 CXCL8 Plate1 PASS 0.5 6.094 Sample_01 LEP Plate1 PASS 2.5 3.33read_NPX detects the export layout, checks the columns and returns a tibble.
It reads the xlsx and parquet variants with the same call. Real exports add
project columns the core facility merged in, such as treatment groups and time
points, and read_NPX carries them through untouched.
The QC flag and the LOD
Section titled “The QC flag and the LOD”Two columns do the quality control work, and both come from the file rather than
from analysis. QC_Warning flags samples whose built-in controls failed: Olink
plates carry extension and detection controls, and a WARN means the measurement
for that sample is suspect. NPX values below the LOD are reported, not censored,
and the convention is to keep them and flag them rather than delete them.
library(dplyr)
npx %>% count(QC_Warning)
# Values below the LOD are reported in the file.below_lod <- npx %>% filter(NPX < LOD)nrow(below_lod)
# Per assay: the median and the count below LOD.npx %>% group_by(Assay) %>% summarise(median_npx = median(NPX), below_lod_n = sum(NPX < LOD), .groups = "drop")# A tibble: 2 × 2 QC_Warning n <chr> <int>1 PASS 902 WARN 6[1] 16# A tibble: 6 × 3 Assay median_npx below_lod_n <chr> <dbl> <int>1 CXCL8 5.94 02 GCG 5.6 03 IL6 4.47 04 INS 2.84 95 LEP 2.59 76 TNF 2.94 0Six rows carry the WARN flag, which is one sample failing across all six assays. Sixteen rows sit below the LOD, and they concentrate in two assays, INS and LEP. An assay with most of its values below LOD is a candidate for exclusion, and the per-assay table is where that decision starts.
Multi-plate studies
Section titled “Multi-plate studies”A study larger than one plate needs bridging. Shared bridge samples run on every
plate, and the per-plate difference on those samples corrects the rest.
OlinkAnalyze implements this as olink_normalization. The export format stays
the same; the normalisation adds columns rather than changing the layout. On
the newer Explore HT platform the readout is sequencing rather than qPCR, the
export arrives as parquet, and the same reader applies.
Summary
Section titled “Summary”- Olink measures proteins as NPX, a relative concentration on the log2 scale.
- The export is a long table, one row per sample per assay, as xlsx, csv or
parquet, read by
OlinkAnalyze::read_NPX. QC_WarningandLODcome from the file. Keep below-LOD values and flag them; do not delete them silently.- Multi-plate studies need bridging normalisation across shared samples.