Skip to main content
Ctrl+K

cellink

  • Tutorials
    • Tutorial: Pseudobulk eQTL Analysis with cellink
    • Tutorial: eQTL Analysis with JaxQTL and TensorQTL using cellink
    • Tutorial: Annotating Genetic Variants with cellink
    • Tutorial: Rare Variant Association Testing with cellink
    • Tutorial: LD Clumping and Identifying Independent Signals with cellink
    • Tutorial: Colocalization Analysis - Linking eQTLs to GWAS Signals with cellink
    • Tutorial: Integrating GWAS with Single-Cell Data using cellink
    • Tutorial: Spatially Resolved GWAS Mapping with gsMap
    • Tutorial: eQTL Analysis with SAIGE-QTL using cellink
    • Tutorial: Using EHR Data as Donor-Level Input in cellink
    • Tutorial: Using the MILDataset and PyTorch DataLoader in cellink
  • API
    • DonorData
      • cellink.DonorData
    • Preprocessing pp
      • cellink.pp.variant_qc
      • cellink.pp.cell_level_obs_filter
      • cellink.pp.donor_level_obs_filter
      • cellink.pp.donor_level_var_filter
      • cellink.pp.log_transform
      • cellink.pp.low_abundance_filter
      • cellink.pp.missing_values_filter
      • cellink.pp.normalize
    • Input-Output io
      • cellink.io.from_sgkit_dataset
      • cellink.io.read_plink
      • cellink.io.read_bgen
      • cellink.io.read_sgkit_zarr
      • cellink.io.read_pgen_zarr
      • cellink.io.stream_pgen_to_zarr
      • cellink.io.to_plink
      • cellink.io.write_variants_to_vcf
    • Tools tl
      • cellink.tl.get_snp_df
      • cellink.tl.run_favor
      • cellink.tl.run_snpeff
      • cellink.tl.run_vep
      • cellink.tl.add_vep_annos_to_gdata
      • cellink.tl.combine_annotations
      • cellink.tl.aggregate_annotations_for_varm
      • cellink.tl.run_burden_test
      • cellink.tl.run_skat_test
      • cellink.tl.beta_weighting
    • External tools tl.external
      • cellink.tl.external.calculate_ld
      • cellink.tl.external.run_jaxqtl
      • cellink.tl.external.read_jaxqtl_results
      • cellink.tl.external.run_mixmil
      • cellink.tl.external.calculate_pcs
      • cellink.tl.external.run_tensorqtl
      • cellink.tl.external.read_tensorqtl_results
      • cellink.tl.external.run_scdrs
      • cellink.tl.external.run_seismic
      • cellink.tl.external.run_magma_pipeline
      • cellink.tl.external.run_saigeqtl
      • cellink.tl.external.configure_saigeqtl_runner
      • cellink.tl.external.get_saigeqtl_runner
      • cellink.tl.external.make_group_file
      • cellink.tl.external.read_saigeqtl_results
      • cellink.tl.external.load_gsmap_results
      • cellink.tl.external.format_gsmap_sumstats
    • Plotting
      • cellink.pl.locus
      • cellink.pl.manhattan
      • cellink.pl.qq
      • cellink.pl.expression_by_genotype
      • cellink.pl.volcano
    • Machine Learning ml
      • cellink.ml.MILDataset
      • cellink.ml.mil_collate_fn
      • cellink.ml.DonorMILModel
    • Association Testing at
      • cellink.at.acat_test
      • cellink.at.compute_acat
      • cellink.at.GWAS
      • cellink.at.Skat
    • Utils
      • cellink.utils.column_normalize
      • cellink.utils.gaussianize
      • cellink.utils.one_hot_encode_genotypes
      • cellink.utils.dosage_per_strand
    • Resources
      • cellink.resources.get_1000genomes
      • cellink.resources.get_1000genomes_grch38
      • cellink.resources.get_dummy_onek1k
      • cellink.resources.get_onek1k
      • cellink.resources.get_eqtl_catalog_dataset_associations
      • cellink.resources.get_eqtl_catalog_datasets
      • cellink.resources.get_gwas_catalog_studies
      • cellink.resources.get_gwas_catalog_study
      • cellink.resources.get_gwas_catalog_study_summary_stats
      • cellink.resources.get_pgs_catalog_score
      • cellink.resources.get_pgs_catalog_scores
      • cellink.resources.get_1000genomes_ld_scores
      • cellink.resources.get_1000genomes_ld_weights
  • Changelog
  • Contributing guide
  • References
  • .ipynb

Tutorial: Using EHR Data as Donor-Level Input in cellink

Contents

  • Setup and Configuration
  • Create Repeated EHR Measurements
  • Construct the EHRData Object
  • Simulate Single-Cell RNA-seq Data
  • Combine EHR and Single-Cell Data via DonorData

Tutorial: Using EHR Data as Donor-Level Input in cellink#

The cellink package was originally developed for integrating single-cell measurements with donor-level genetic data, but its modular design allows you to swap in any structured donor-level modality. In this tutorial, we demonstrate how to use electronic health records (EHR) as the donor-level input, replacing genotypes.

This unlocks a wide range of applications — for example, using blood pressure, lab values, or medical history in combination with cell-level transcriptomics.

Setup and Configuration#

We start by importing relevant modules and creating local directories to store input/output files. This ensures that any annotation tools have a consistent file structure to work with.

import numpy as np
import pandas as pd
import anndata as ad
import ehrdata as ed
from cellink import DonorData

Create Repeated EHR Measurements#

We begin by simulating repeated clinical measurements for two patients across three visits. These measurements could represent time-varying vital signs or lab results.

patients = pd.DataFrame(
    {
        "patient_id": ["P001", "P002"],
        "birthdate": ["1980-01-01", "1975-05-15"],
        "gender": ["M", "F"]
    }
).set_index("patient_id")

clinical_parameters = pd.DataFrame(
    {
        "parameter_id": ["BP_Systolic", "BP_Diastolic"],
        "name": ["Systolic Blood Pressure", "Diastolic Blood Pressure"],
        "unit": ["mmHg", "mmHg"],
    }
).set_index("parameter_id")

visit_dates = pd.DataFrame({
    "visit_number": ["1", "2", "3"],
    "visit_id": ["V001", "V002", "V003"]
}).set_index("visit_number")

repeated_measurements = np.array([
    [
        [120, 118, 121],
        [81, 80, 82],
    ],
    [
        [130, 135, 125],
        [84, 81, 80],
    ]
])

Construct the EHRData Object#

We wrap the patient information, clinical parameters, and repeated measurements into an EHRData object. This object mirrors the structure expected by cellink, and will later be used in place of genetic data.

ehr = ed.EHRData(
    r=repeated_measurements,
    obs=patients,
    var=clinical_parameters,
    t=visit_dates,
)

ehr.obs["donor_id"] = ["D0", "D1"]
ehr.obs.index = ehr.obs["donor_id"]

Simulate Single-Cell RNA-seq Data#

To demonstrate multimodal integration, we generate a synthetic single-cell RNA-seq dataset. Each cell is assigned to a donor and annotated with a predicted cell type. We filter to keep only CD8 Naive cells.

n_cells = 200
n_genes = 100

X = np.random.poisson(1.5, size=(n_cells, n_genes)).astype(np.float32)

cell_obs = pd.DataFrame({
    "cell_id": [f"C{i}" for i in range(n_cells)],
    "donor_id": np.random.choice(["D0", "D1"], size=n_cells),
    "predicted.celltype.l2": np.random.choice(["CD8 Naive", "CD4 TCM"], size=n_cells)
}).set_index("cell_id")

gene_var = pd.DataFrame(index=[f"gene_{i}" for i in range(n_genes)])

adata = ad.AnnData(X=X, obs=cell_obs, var=gene_var)
adata = adata[adata.obs["predicted.celltype.l2"] == "CD8 Naive", :].copy()

Combine EHR and Single-Cell Data via DonorData#

We now use DonorData to merge the donor-level EHR data with the cell-level transcriptomics. This object enables unified access and is used throughout the cellink pipeline.

dd = DonorData(G=ehr, C=adata).copy()
dd
╔═ DonorData(n_donors=2, n_cells_per_donor=[54-55], donor_id='donor_id') ═══════════════════════════╗
║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║
║ ┃ G (donors)                                  ┃ C (cells)                                       ┃ ║
║ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ ║
║ │ AnnData object with n_obs × n_vars = 2 × 2  │ AnnData object with n_obs × n_vars = 109 × 100  │ ║
║ │     obs: 'birthdate', 'gender', 'donor_id'  │     obs: 'donor_id', 'predicted.celltype.l2'    │ ║
║ │     var: 'name', 'unit'                     │                                                 │ ║
║ │     layers: 'r_layer'                       │                                                 │ ║
║ └─────────────────────────────────────────────┴─────────────────────────────────────────────────┘ ║
╚═══════════════════════════════════════════════════════════════════════════════════════════════════╝

previous

Tutorial: eQTL Analysis with SAIGE-QTL using cellink

next

Tutorial: Using the MILDataset and PyTorch DataLoader in cellink

Contents
  • Setup and Configuration
  • Create Repeated EHR Measurements
  • Construct the EHRData Object
  • Simulate Single-Cell RNA-seq Data
  • Combine EHR and Single-Cell Data via DonorData

By Jan Engelmann, Lucas Arnoldt, Eva Holtkamp

© Copyright 2026, Theislab..