Skip to contents

Package: HTAN 0.99.1 (source).

Introduction

The Human Tumor Atlas Network (HTAN) has released single-cell, spatial, imaging and bulk data from thousands of biospecimens, with detailed clinical and biospecimen annotation. Finding the right file, tracing what it was made from and getting it into an analysis still means working across several systems, each with its own interface. HTAN does those steps from R. It queries HTAN’s open-access metadata locally, follows the provenance links between files, downloads open files, and reads them into Bioconductor classes.

There are other routes to HTAN data. Here is how this package relates to each:

  • The HTAN Data Portal is the place to browse and search interactively. It exports file manifests, but it is not a programming interface to the metadata.
  • ISB-CGC publishes every release’s metadata as Google BigQuery tables, which you query in SQL (from R, with bigrquery). That needs a Google Cloud account and a billing project. HTAN reads a parquet snapshot of the same tables without an account, and works offline once the snapshot is cached.
  • Synapse’s own clients download a file by its Synapse ID but know nothing of HTAN’s data model. HTAN finds the file from the metadata, then downloads it from Synapse or the CRDC General Commons and checks its md5.
  • GenomicDataCommons is the Bioconductor client for NCI’s Genomic Data Commons, with a similar query-then-download design. HTAN’s data are not in the GDC, so it does not reach them.

This vignette covers what HTAN is, how its data are organised and where they are stored, and what the package can and cannot do, and ends with a short tour of the package. Three companion vignettes go further:

The code in these vignettes runs against the real HTAN Release 7 metadata each time they are built (see How these vignettes are built).

Installation

Install the package from Bioconductor with BiocManager:

if (!requireNamespace("BiocManager", quietly = TRUE)) {
    install.packages("BiocManager")
}
BiocManager::install("HTAN")

Or install the development version from GitHub, for example before the package is available from Bioconductor:

BiocManager::install("seandavi/HTAN")

Getting started

Load the package and dplyr, which is the query language for everything that follows:

Open a connection to the Release 7 metadata snapshot. The first call downloads about 20 MB of parquet files from Hugging Face, checks each one against its sha256 checksum and caches it. Later calls read from the cache. You do not need an account for any of this.

con <- htan_con("r7")

htan_files() returns one row per HTAN data file, as a lazy table that runs in DuckDB until you call collect(). Here we count the single-cell RNA-seq Level 4 files by center and file extension:

htan_files(assay == "ScRNA-seq", level == 4, con = con) |>
    count(HTAN_Center, extension) |>
    arrange(desc(n)) |>
    collect()
#> # A tibble: 12 × 3
#>    HTAN_Center     extension     n
#>    <chr>           <chr>     <dbl>
#>  1 HTAN WUSTL      .rds        237
#>  2 HTAN CHOP       .rds        197
#>  3 HTAN MSK        .csv        191
#>  4 HTAN MSK        .txt         76
#>  5 HTAN DFCI       .h5ad        48
#>  6 HTAN HTAPP      .tsv         47
#>  7 HTAN BU         .csv         32
#>  8 HTAN MSK        .h5ad        15
#>  9 HTAN Vanderbilt .h5ad         6
#> 10 HTAN CHOP       .tsv          6
#> 11 HTAN CHOP       .h5ad         1
#> 12 HTAN Duke       .rds          1

htan_lineage() traces a processed file back to the raw files and the biospecimen it came from. We take one of participant HTA12_251’s files:

htan_files(assay == "ScRNA-seq", level == 4, participants = "HTA12_251",
    con = con) |>
    head(1) |>
    htan_lineage(con = con) |>
    select(related_file_id, depth, Component, HTAN_Assayed_Biospecimen_ID) |>
    arrange(depth) |>
    collect()
#> # A tibble: 13 × 4
#>    related_file_id depth Component        HTAN_Assayed_Biospecimen_ID
#>    <chr>           <int> <chr>            <chr>                      
#>  1 HTA12_251_1013     -3 ScATAC-seqLevel1 HTA12_251_3                
#>  2 HTA12_251_1015     -3 ScATAC-seqLevel1 HTA12_251_3                
#>  3 HTA12_251_1002     -3 ScRNA-seqLevel1  HTA12_251_3                
#>  4 HTA12_251_1000     -3 ScRNA-seqLevel1  HTA12_251_3                
#>  5 HTA12_251_1003     -3 ScRNA-seqLevel1  HTA12_251_3                
#>  6 HTA12_251_1001     -3 ScRNA-seqLevel1  HTA12_251_3                
#>  7 HTA12_251_1014     -3 ScATAC-seqLevel1 HTA12_251_3                
#>  8 HTA12_251_2002     -2 ScATAC-seqLevel2 HTA12_251_3                
#>  9 HTA12_251_2000     -2 ScRNA-seqLevel2  HTA12_251_3                
#> 10 HTA12_251_3003     -1 ScATAC-seqLevel3 HTA12_251_3                
#> 11 HTA12_251_3002     -1 ScATAC-seqLevel3 HTA12_251_3                
#> 12 HTA12_251_3001     -1 ScATAC-seqLevel3 HTA12_251_3                
#> 13 HTA12_251_4000      0 ScRNA-seqLevel4  HTA12_251_3

The last two steps are downloading a file and reading it. Level 2 images in the CRDC General Commons download anonymously, while processed Level 3 and 4 files are on Synapse and need a free personal access token (see Downloading files). read_htan() then reads the file, returning a Bioconductor object where it can.

That is the whole workflow: query, trace, download, read. The rest of this vignette explains what you are querying.

What HTAN is

The Human Tumor Atlas Network is a National Cancer Institute (NCI) Cancer Moonshot initiative, launched in September 2018, that builds three-dimensional atlases of the cellular, morphological and molecular features of human cancers (HTAN overview). The founding paper (Rozenblatt-Rosen et al., Cell 2020; doi:10.1016/j.cell.2020.03.053, PMID 32302568) frames the program around transitions: the points at which a tumour’s behaviour changes, such as

  • the progression of a precancerous lesion to invasive cancer,
  • local expansion and metastasis, and
  • the response of a tumour to therapy and the emergence of resistance.

Bulk sequencing of a single tumour sample averages over every cell in it and records one moment in time. HTAN’s premise is that interactions between tumour cells, immune cells, stroma and vasculature drive these transitions, and that seeing them takes measurements at single-cell resolution, in spatial context and over time. So HTAN centers combine single-cell and single-nucleus sequencing, spatial transcriptomics, multiplexed tissue imaging, and conventional bulk sequencing and pathology, on biospecimens with detailed clinical annotation. Many participants contribute several biospecimens: serial sections of one block, several regions of a resection, or samples taken before and after treatment.

Phase 1

Phase 1 had ten Research Centers, each building an atlas of one or more cancer types, and two NCI pilot projects, the Human Tumor Atlas Pilot Project (HTAPP) and the Pre-Cancer Atlas Pilot Project (PCAPP). A single Data Coordinating Center (DCC) set the data standards, ran ingestion and validation, and built the portal and the other routes to the data (HTAN overview; de Bruijn et al., Nature Methods 2025, doi:10.1038/s41592-025-02643-0). Four Trans-Network Projects (TNPs) compared technologies across centers. The HTAN manual lists every Phase 1 center with its identifier prefix (HTAN centers):

Prefix Center Focus
HTA1 Human Tumor Atlas Pilot Project (HTAPP) Pilot project
HTA2 Pre-Cancer Atlas Pilot Project (PCAPP) Pilot project
HTA3 Boston University Lung
HTA4 Children’s Hospital of Philadelphia Pediatric
HTA5 Dana-Farber Cancer Institute Multiple cancer types
HTA6 Duke University Breast
HTA7 Harvard Medical School Melanoma, colorectal cancer, clonal hematopoiesis
HTA8 Memorial Sloan Kettering Cancer Center Multiple cancer types
HTA9 Oregon Health & Science University Breast
HTA10 Stanford University Familial adenomatous polyposis
HTA11 Vanderbilt University Colorectal
HTA12 Washington University in St. Louis Multiple cancer types
HTA13 TNP: SARDANA Technology comparison
HTA14 TNP: Tissue MicroArray (TMA) Technology comparison
HTA15 TNP: SRRS Technology comparison
HTA16 TNP: CASI Technology comparison

Phase 1 data were released in seven numbered releases between May 2021 and November 2025 (data release history). Release 7, published on 2025-11-26, is the last Phase 1 release and the one this package targets. The Phase 1 data model is archived (ncihtan/data-models), so the release is effectively frozen. The DCC’s 2025 paper counts 8,425 biospecimens from 2,042 participants profiled with more than 20 assays. That paper predates Release 7, so the atlas overview recounts everything from the Release 7 tables themselves.

Phase 2

Phase 2 funds ten new atlases, five of pre-cancer and five of cancer, with identifier prefixes HTA200 to HTA209. Its first data release, on 2026-08-03, was 50 files from 11 participants of the prostate atlas (data release history). Phase 2 uses a new data model, aligned with the NCI Cancer Research Data Commons, that changes file formats, valid values and attributes, and marks biospecimen and data file identifiers with B and D (HTAN data model overview, identifiers). That model is still changing, and the ISB-CGC BigQuery tables for Phase 2 did not exist when this package was written. This package covers Phase 1 only. Phase 2 will be added once its tables settle.

How HTAN data are organised

Participants, biospecimens and files

Every HTAN record hangs from a three-level hierarchy:

  1. A participant is a research participant (a patient or donor), with clinical data: demographics, diagnosis, therapy, follow-up and more.
  2. A biospecimen is something taken from a participant (a biopsy, a resection, a blood draw) or derived from another biospecimen (a block, a section, a dissociated cell suspension, an extracted analyte).
  3. A data file is the output of an assay run on a biospecimen, or a file computed from other files.

Each level has an HTAN identifier that starts with the center prefix: HTA11_7862 is a participant at Vanderbilt, HTA11_7862_2000001011 is one of that participant’s biospecimens, and HTA11_7862_200000101134111 is a data file. The data model vignette covers the identifier grammar and its exceptions.

Data levels

Every assay’s files are grouped into levels, from raw instrument output to analysis-ready summaries. The HTAN manual defines them per assay (file standards, metadata standards). In outline:

Level Sequencing (scRNA-seq, bulk, scATAC-seq) Multiplexed imaging (CyCIF, CODEX, MIBI, H&E, …) 10x Visium
1 Raw reads: FASTQ, unaligned BAM Raw tiles before stitching and registration (rarely submitted) FASTQ
2 Aligned reads: BAM One assembled image, preferably a tiled, pyramidal OME-TIFF Aligned BAM
3 Derived molecular data: gene-by-cell count matrices, VCFs Segmentation masks, validated channel metadata, QC’d image Space Ranger output: counts, spot positions, tissue image
4 Sample-level summaries: annotated objects, embeddings, clusters A cell-by-feature table (marker intensities, centroids, morphology) Processed objects: clusters, embeddings, .h5ad or .rds

Other assays follow the same idea. RPPA has no Level 1; mass spectrometry runs from raw spectra (Level 1) to protein abundance (Level 4); and some newer assays, such as 10x Xenium, are submitted as a single experiment bundle instead of separate levels. Auxiliary files (for example Visium alignment images and QC reports) and “Other Assay” files have no level.

In practice most users start at Level 3 or 4: a count matrix or an annotated single-cell object, or a cell-by-marker table for imaging. Those are the files this package reads.

Access tiers

HTAN data are released in two tiers (data access). Open access covers all metadata (clinical, biospecimen and file-level), multiplexed and H&E images, and processed (Level 3 and 4) genomic data. Controlled access covers unprocessed genomic data (Level 1 and 2 sequencing: FASTQ and BAM files), which could identify a participant; you apply for it through dbGaP study phs002371.

The package records the tier of each file in the access column of htan_files(), with open files split by where they can be fetched from.

Where the data live, and why

HTAN data are spread across several NCI and partner systems, each chosen for one job:

System Holds Access
Synapse (Sage Bionetworks) Open Level 3 and 4 files, auxiliary files, submitted metadata Free account and personal access token
CRDC General Commons Controlled Level 1/2 sequencing; open Level 2 images dbGaP authorisation for controlled data; open images anonymously through GA4GH DRS
Imaging Data Commons (IDC) DICOM conversions of some HTAN slide images Anonymous
ISB-CGC BigQuery (isb-cgc-bq.HTAN, isb-cgc-bq.HTAN_versioned) All open metadata tables, plus some processed expression and cell tables Google Cloud account and a billing project
HTAN Data Portal Search, summaries and manifests for every tier Browser

Synapse is the DCC’s ingestion platform: centers upload files and metadata there, and the DCC validates and releases them. The CRDC General Commons is NCI’s long-term repository, and the only one of these systems that can hold dbGaP-controlled data. It also serves the open images, because image files are large and the CRDC is built for cloud-scale storage. IDC converts a subset of the slides to DICOM so they can be viewed in a browser alongside other NCI imaging collections. ISB-CGC loads every release’s metadata into BigQuery for SQL analysis in Google Cloud (HTAN BigQuery, ISB-CGC HTAN notebooks).

For an R user, this means that finding a file and fetching it are separate problems. The metadata tell you which files exist and how they relate; the file itself is on Synapse or the CRDC, behind different authentication.

What this package does, and what it doesn’t

HTAN is a client for the open-access data of HTAN Phase 1. It does five things:

  1. Query the metadata locally. htan_con() opens a DuckDB connection over a parquet snapshot of the ISB-CGC Release 7 metadata tables; htan_tables(), htan_tbl() and htan_columns() list, open and describe them; htan_files() gives one row per file with its assay, level, participants, biospecimens and access tier. Queries are dplyr code that dbplyr translates to SQL, so they run in DuckDB and only the result comes into R.
  2. Trace lineage. htan_lineage() walks the id_provenance table from a file to its ancestors (down to Level 1 and the biospecimen) or its descendants.
  3. Download open files. htan_download() fetches open Level 2 images anonymously from the CRDC General Commons, and Level 3/4 files from Synapse with a personal access token. It checks each file’s md5 and guards against accidentally large downloads.
  4. Read files into Bioconductor classes. read_htan() turns .h5ad, .rds (including Seurat objects), 10x .h5, Space Ranger output and imaging cell tables into SingleCellExperiment or SpatialExperiment objects.
  5. Assemble a MultiAssayExperiment. htan_experiment() combines objects from several files, links every cell or spot to its participant and attaches clinical data.

It does not:

  • download controlled-access data (it stops with a pointer to dbGaP and the CRDC tools);
  • cover HTAN Phase 2;
  • query the large processed tables in BigQuery (single-cell expression and imaging cell tables, about 2.4 TB), or BigQuery at all;
  • query IDC, CELLxGENE or the HTAN portal’s database;
  • analyse images (it returns image paths, which RBioFormats or cytomapper can read).

Level 4 files are heterogeneous: each center chose its own object classes, assay names and annotations. read_htan() is best effort, so check what it returns.

The metadata snapshot

What it is

ISB-CGC publishes HTAN’s metadata in two BigQuery datasets: HTAN, whose _current tables always point at the newest release, and HTAN_versioned, which keeps every release’s tables under names such as clinical_tier1_demographics_r7. The snapshot is an export of the 78 tables that make up Release 7, each pinned to its versioned copy, written as zstd parquet with a manifest of checksums. It is published as the Hugging Face dataset seandavis/htan, one git tag per release, so htan_con("r7") always reads the same bytes. htan_snapshot_info() reports which snapshot a connection is reading:

info <- htan_snapshot_info(con)
info[c("release", "phase", "source", "n_tables", "total_rows", "build_date")]
#> $release
#> [1] "r7"
#> 
#> $phase
#> [1] "1"
#> 
#> $source
#> [1] "isb-cgc-bq.HTAN_versioned"
#> 
#> $n_tables
#> [1] "78"
#> 
#> $total_rows
#> [1] "821773"
#> 
#> $build_date
#> [1] "2026-10-14T11:53:18Z"

The tables fall into two groups: clinical and biospecimen tables, and metadata tables (one or more per assay and level, plus id_provenance, gc_drs_map and the data-model schema):

htan_tables(con) |>
    count(category)
#> # A tibble: 2 × 2
#>   category                      n
#>   <chr>                     <int>
#> 1 clinical_biospecimen_data    16
#> 2 metadata                     62

A few tables were not refreshed in Release 7, so the snapshot takes them from the last release that had them:

htan_tables(con) |>
    filter(source_version != "r7") |>
    select(name, source_version, rows)
#> # A tibble: 6 × 3
#>   name                                        source_version  rows
#>   <chr>                                       <chr>          <dbl>
#> 1 imaging_level1_metadata                     r6_v2             16
#> 2 lipidomics_metadata                         r2_v2             84
#> 3 metabolomics_metadata                       r2_v2            176
#> 4 proteomics_metadata                         r2               392
#> 5 publication_manifest_metadata               r5                 1
#> 6 tissueOrOrganOfOrigin_to_wholeOrgan_mapping r4               332

How it relates to the authoritative sources

The snapshot is a copy of a copy. The DCC’s records in Synapse are the source of truth. ISB-CGC derives its BigQuery tables from them at each release, and the snapshot is an export of those tables at one release. Three things follow from that:

  • It can lag or differ. If the HTAN portal and the snapshot disagree, the portal is right. Fixes the DCC made after Release 7 reach the snapshot only if ISB-CGC republishes the r7 tables and the snapshot is rebuilt.
  • It is unofficial. The DCC does not host or endorse it. It redistributes open-access metadata, so HTAN’s terms of use still apply, and work that uses the data should cite HTAN’s publications, as the HTAN manual asks.
  • It holds metadata only. File contents stay on Synapse and the CRDC.

What you get in return is convenience: the snapshot needs no Google account or billing project, works offline once cached, and answers most questions in milliseconds. You can also browse it without R. The Hugging Face page has a data viewer and a SQL console, and DuckDB reads the files directly as hf://datasets/seandavis/htan@r7/<table>.parquet.

To use a mirror or a local build, set options(HTAN.base_url = ...). The package also ships a tiny fixture of the snapshot (all 78 tables cut down to six participants), which its examples and tests use:

fixture <- system.file("extdata", "snapshot", package = "HTAN")
con_small <- htan_con("r7", base_url = fixture)
htan_snapshot_info(con_small)[c("release", "n_tables", "total_rows")]
#> $release
#> [1] "r7"
#> 
#> $n_tables
#> [1] "78"
#> 
#> $total_rows
#> [1] "1023"
htan_disconnect(con_small)

A quick tour

Tables and columns

htan_tbl() opens any table lazily. Here we count participants by gender in the demographics table, with the counting done in DuckDB:

htan_tbl("clinical_tier1_demographics", con) |>
    count(Gender, sort = TRUE) |>
    collect()
#> # A tibble: 6 × 2
#>   Gender           n
#>   <chr>        <dbl>
#> 1 Female        1454
#> 2 Male           547
#> 3 female         418
#> 4 Not Reported   193
#> 5 male           183
#> 6 unknown         10

Note the same value spelled several ways. Centers submitted their own metadata, and the DCC’s validation did not normalise case, so clean values before you count or join on them:

htan_tbl("clinical_tier1_demographics", con) |>
    mutate(Gender = tolower(Gender)) |>
    count(Gender, sort = TRUE) |>
    collect()
#> # A tibble: 4 × 2
#>   Gender           n
#>   <chr>        <dbl>
#> 1 female        1872
#> 2 male           730
#> 3 not reported   193
#> 4 unknown         10

htan_columns() returns the column descriptions recorded in the BigQuery schema. It is the quickest way to learn what a field means:

htan_columns("id_provenance", con) |>
    select(column, description)
#> # A tibble: 12 × 2
#>    column                          description                                  
#>    <chr>                           <chr>                                        
#>  1 HTAN_Data_File_ID               Self-identifier for this data file - HTAN ID…
#>  2 Filename                        Name of a file                               
#>  3 entityId                        Synapse ID of entity                         
#>  4 Component                       Category of metadata (e.g. Diagnosis, Biospe…
#>  5 Data_Release                    Inclusion in HTAN Data Release e.g. Release …
#>  6 GC_Release                      Released to CRDC’s General Commons (GC) as p…
#>  7 HTAN_Center                     Name of HTAN Center e.g. HTAN HTAPP          
#>  8 HTAN_Assayed_Biospecimen_ID     HTAN ID of the biospecimen directly assayed …
#>  9 HTAN_Parent_Data_File_ID        HTAN Data File Identifier indicating the fil…
#> 10 HTAN_Originating_Biospecimen_ID HTAN ID of the biopsied or resected biospeci…
#> 11 HTAN_Participant_ID             HTAN ID associated with a patient based on H…
#> 12 Biospecimen_Path                Full Biospecimen ancestry path from HTAN_Ass…

Files

htan_files() combines every file-level table in the snapshot. Its columns include the Component (the assay and level, as HTAN names it), assay and level split out of it, the file extension, size and md5, the Synapse entityId, the General Commons drs_uri, the participants and biospecimens from id_provenance, and the access tier. Counting files by tier:

files <- htan_files(con = con)
files |>
    count(access) |>
    arrange(desc(n)) |>
    collect()
#> # A tibble: 3 × 2
#>   access            n
#>   <chr>         <dbl>
#> 1 open-synapse 154520
#> 2 controlled    42897
#> 3 open-gc       24271

There are 221,688 files in Release 7. The tiers are:

  • open-gc: open Level 2 images in the General Commons, downloadable anonymously;
  • open-synapse: open files on Synapse (Level 3/4, auxiliary and other files, and the images that were never copied to the General Commons), downloadable with a token;
  • controlled: Level 1/2 sequencing under dbGaP, which the package will not download.

Filters go straight into htan_files(). For example, every single-cell Level 4 file in AnnData format:

htan_files(assay == "ScRNA-seq", level == 4, extension == ".h5ad",
    con = con) |>
    select(HTAN_Data_File_ID, HTAN_Center, File_Size, n_participants) |>
    arrange(File_Size) |>
    collect()
#> # A tibble: 70 × 4
#>    HTAN_Data_File_ID HTAN_Center File_Size n_participants
#>    <chr>             <chr>           <dbl>          <dbl>
#>  1 HTA5_0000_1003255 HTAN DFCI    11599590              4
#>  2 HTA5_0000_1003254 HTAN DFCI    12396714              4
#>  3 HTA5_0000_1003271 HTAN DFCI    24735020              4
#>  4 HTA5_0000_1003281 HTAN DFCI    30191344              4
#>  5 HTA5_0000_1003295 HTAN DFCI    32403150              4
#>  6 HTA5_0000_1003261 HTAN DFCI    34842022              4
#>  7 HTA5_0000_1003274 HTAN DFCI    37313138              4
#>  8 HTA5_0000_1003284 HTAN DFCI    38056449              4
#>  9 HTA5_0000_1003243 HTAN DFCI    39081430              4
#> 10 HTA5_0000_1003257 HTAN DFCI    40003858              4
#> # ℹ 60 more rows

Some files, such as merged single-cell objects, come from several participants; their HTAN_Participant_ID is a comma-separated list. To find every file that involves a participant, use the participants argument instead of ==; it handles that case:

htan_files(participants = "HTA11_7862", con = con) |>
    count(Component, access) |>
    arrange(Component) |>
    collect()
#> # A tibble: 13 × 3
#>    Component                                      access           n
#>    <chr>                                          <chr>        <dbl>
#>  1 10xVisiumSpatialTranscriptomics-AuxiliaryFiles open-synapse     1
#>  2 10xVisiumSpatialTranscriptomics-RNA-seqLevel1  controlled       2
#>  3 10xVisiumSpatialTranscriptomics-RNA-seqLevel2  controlled       1
#>  4 10xVisiumSpatialTranscriptomics-RNA-seqLevel3  open-synapse     4
#>  5 10xVisiumSpatialTranscriptomics-RNA-seqLevel4  open-synapse     1
#>  6 BulkWESLevel1                                  controlled       4
#>  7 BulkWESLevel2                                  controlled       2
#>  8 BulkWESLevel3                                  open-synapse     1
#>  9 ImagingLevel2                                  open-synapse     3
#> 10 ScRNA-seqLevel1                                controlled       6
#> 11 ScRNA-seqLevel2                                controlled       3
#> 12 ScRNA-seqLevel3                                open-synapse     3
#> 13 ScRNA-seqLevel4                                open-synapse     4

This one participant, from the Vanderbilt colorectal atlas, has Visium spatial transcriptomics, single-cell RNA-seq, whole-exome sequencing and imaging. The analysis vignette analyses a Visium section from another Vanderbilt participant.

Lineage

htan_lineage() follows HTAN_Parent_Data_File_ID links in id_provenance. Depth 0 is the query file; negative depths are its ancestors:

htan_lineage("HTA11_7862_200000101134111", con = con) |>
    select(related_file_id, depth, Filename) |>
    arrange(depth, related_file_id) |>
    collect() |>
    mutate(Filename = basename(Filename))
#> # A tibble: 8 × 3
#>   related_file_id            depth Filename                            
#>   <chr>                      <int> <chr>                               
#> 1 HTA11_7862_200000101131111    -3 8270-AS-0001_S1_L005_R1_001.fastq.gz
#> 2 HTA11_7862_200000101131121    -3 8270-AS-0001_S1_L005_R2_001.fastq.gz
#> 3 HTA11_7862_200000101132111    -2 8270_AS_1_possorted_genome_bam.bam  
#> 4 HTA11_7862_200000101133111    -1 8270_AS_1_barcodes.tsv.gz           
#> 5 HTA11_7862_200000101133121    -1 8270_AS_1_features.tsv.gz           
#> 6 HTA11_7862_200000101133131    -1 8270_AS_1_matrix.mtx.gz             
#> 7 HTA11_7862_200000101133141    -1 8270_AS_1_tissue_positions_list.csv 
#> 8 HTA11_7862_200000101134111     0 8270_AS_1_unfiltered.h5ad

The Level 4 Visium object was computed from four Level 3 Space Ranger files, which came from a Level 2 alignment, which came from two Level 1 FASTQ files. The data model vignette explains how these links are recorded and where they get complicated.

Downloading files

htan_download() routes each file by its access tier, checks its md5, and returns a table of local paths. Open images in the General Commons download anonymously; this one is a 250 KB imaging mass cytometry image:

tiff <- htan_files(
    drs_uri == "dg.4DFC/6231a7d4-7e68-11ee-b51d-e7db3b9207b8", con = con)
tiff |>
    select(HTAN_Data_File_ID, Component, File_Size, access) |>
    collect()
#> # A tibble: 1 × 4
#>   HTAN_Data_File_ID Component     File_Size access 
#>   <chr>             <chr>             <dbl> <chr>  
#> 1 HTA12_15_1105     ImagingLevel2    254833 open-gc
dl <- htan_download(tiff, con = con)
dl$status
#> [1] "cached"
read_htan(dl) |> basename()
#> [1] "HTAN_HT166P1_S1H5_L4_ROI_001.ome.tiff"

read_htan() returns image paths unchanged; RBioFormats or cytomapper can read them.

Processed files are on Synapse. To fetch them:

  1. create a free account at https://www.synapse.org;
  2. make a personal access token (Account Settings, then Personal Access Tokens) with download permission;
  3. put it in the SYNAPSE_AUTH_TOKEN environment variable, for example in ~/.Renviron, and restart R.

This chunk is not run when the vignette is built, because it needs a token; the analysis vignette runs the same steps when one is set.

visium <- htan_files(HTAN_Data_File_ID == "HTA11_99999933430_8422134111",
    con = con)
dl <- htan_download(visium, con = con)
spe <- read_htan(dl)

Some HTAN files are tens of gigabytes. htan_download() refuses to start if the files total more than max_bytes (20 GB by default). It keeps every file it fetches in a download cache, so asking for a file again rechecks its md5 and serves it from the cache instead of downloading it. Pass dest to copy the files to a directory of your choice as well. Controlled files are refused with a classed error:

fastq <- htan_files(access == "controlled", con = con) |>
    arrange(HTAN_Data_File_ID) |>
    head(1)
tryCatch(
    htan_download(fastq, con = con),
    htan_error_controlled = function(e) cat(conditionMessage(e))
)
#> Controlled-access files cannot be downloaded by HTAN.
#> ✖ HTA10_0000_42410718832338308254033538547980
#> ℹ Level 1/2 sequencing is under dbGaP phs002371; request access, then use the CRDC gen3-client.
#> ℹ Drop them with `filter(access != "controlled")`.

Reading and assembling

read_htan() dispatches on the file extension:

File Returns
.h5ad SingleCellExperiment (via anndataR), or SpatialExperiment when there is a spatial embedding
.rds, .RData the object; Seurat objects become SingleCellExperiment
10x .h5 SingleCellExperiment (via TENxIO)
Space Ranger outs/ directory SpatialExperiment (via VisiumIO)
Imaging Level 4 .csv cell table SpatialExperiment, cells as columns
.tif, .ome.tiff, .svs the path

htan_experiment() then builds a MultiAssayExperiment from a named list of objects, using the file IDs to find each object’s participant and attaching that participant’s demographics and diagnosis as colData. The analysis vignette does this with real data.

How these vignettes are built

The vignettes run their code when the package is built. They read the Release 7 snapshot from Hugging Face with htan_con("r7"), about 20 MB that BiocFileCache downloads once and then reuses. The tables, the figures and most counts in the text are computed from the real metadata at build time; the few typed in by hand are file sizes and the published totals from the DCC’s 2025 paper. With the release pinned to r7, the numbers should not change between builds.

The analysis vignette also downloads a file from Synapse, which needs a personal access token. Where SYNAPSE_AUTH_TOKEN is set, as in the package’s own continuous integration, those steps run too. Without it, for example on the Bioconductor build machines, they are shown as code without output.

References

Session information

sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.5 LTS
#> 
#> Matrix products: default
#> BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0
#> 
#> locale:
#>  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
#>  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
#>  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
#>  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
#>  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
#> 
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] dplyr_1.2.1 HTAN_0.99.1
#> 
#> loaded via a namespace (and not attached):
#>  [1] bit_4.6.0           jsonlite_2.0.0      compiler_4.6.1     
#>  [4] filelock_1.0.3      tidyselect_1.2.1    blob_1.3.0         
#>  [7] yaml_2.3.12         fastmap_1.2.0       R6_2.6.1           
#> [10] generics_0.1.4      curl_8.1.0          httr2_1.3.0        
#> [13] knitr_1.52          tibble_3.3.1        DBI_1.3.0          
#> [16] pillar_1.11.1       rlang_1.3.0         utf8_1.2.6         
#> [19] cachem_1.1.0        xfun_0.61           bit64_4.8.6        
#> [22] otel_0.2.0          RSQLite_3.53.3      memoise_2.0.1      
#> [25] cli_3.6.6           withr_3.0.3         magrittr_2.0.5     
#> [28] digest_0.6.39       dbplyr_2.6.0        lifecycle_1.0.5    
#> [31] BiocFileCache_3.3.0 vctrs_0.7.3         evaluate_1.0.5     
#> [34] glue_1.8.1          duckdb_1.5.6        rmarkdown_2.32     
#> [37] purrr_1.2.2         tools_4.6.1         pkgconfig_2.0.3    
#> [40] htmltools_0.5.9