{ "cells": [ { "cell_type": "markdown", "id": "45940777-2ceb-4970-96a7-88cdc1a303ee", "metadata": {}, "source": [ "# Label cell types using Seurat Label Transfer\n", "\n", "To build our reference, we would like to start with labels that originate from published cell type references. \n", "\n", "One of the approaches for this cell type labeling is Seurat, which labels cells by integration with a reference dataset. \n", "\n", "Label transfer using Seurat is described [on their website](https://satijalab.org/seurat/articles/integration_mapping), and was introduced in this publication: \n", "\n", "Stuart, T. et al. Comprehensive Integration of Single-Cell Data. Cell 177, 1888–1902.e21 (2019)\n", "\n", "Here, we'll load in our cells in batches, and assign cell types based on the PBMC reference dataset provided by the Satija lab as part of their 2021 publication in Cell (described below)." ] }, { "cell_type": "markdown", "id": "578488b5-52e9-4696-aa42-9c2944b77b1b", "metadata": {}, "source": [ "## Load libraries\n", "\n", "`dplyr`: Data frame manipulation tools \n", "`H5weaver`: A package for reading .h5 files generated by AIFI \n", "`hise`: The HISE SDK \n", "`parallel`: Parallelization of processes in R \n", "`purrr`: Functional programing tools \n", "`Seurat`: Single-cell data analysis tools \n", "`SeuratObject`: Data structures for Seurat\n", "\n", "We also set the `timeout` option to be high so that R waits for us to download the large reference dataset from Zenodo, below" ] }, { "cell_type": "code", "execution_count": 1, "id": "84c8862c-7ddd-4ef1-b5fb-27bdd8c948f6", "metadata": { "tags": [] }, "outputs": [], "source": [ "quiet_library <- function(...) { suppressPackageStartupMessages(library(...)) }\n", "\n", "quiet_library(dplyr)\n", "quiet_library(H5weaver)\n", "quiet_library(hise)\n", "quiet_library(parallel)\n", "quiet_library(purrr)\n", "quiet_library(Seurat)\n", "quiet_library(SeuratObject)\n", "\n", "options(timeout = 10000)" ] }, { "cell_type": "markdown", "id": "31328a06-0d11-4f06-b369-97cb326b610e", "metadata": {}, "source": [ "## Prepare Seurat PBMC reference" ] }, { "cell_type": "markdown", "id": "05c93485-4e86-4137-98f3-21b46999a767", "metadata": {}, "source": [ "To use Seurat to label our cells, we'll utilize the PBMC reference provided by the Satija Lab for PBMCs generated using Seurat V5. This reference is derived from data in this publication from the Satija lab:\n", "\n", "Hao, Y. and Hao, S. et al. Integrated analysis of multimodal single-cell data. Cell 184, 3573–3587.e29 (2021)\n", "\n", "The version of record for this reference dataset is provided in a Zenodo repository at this accession: \n", "https://zenodo.org/records/7779017\n", "\n", "Additional information about the cell type labels in this reference is available [on the Azimuth website](https://azimuth.hubmapconsortium.org/references/#Human%20-%20PBMC).\n", "\n", "We'll download the reference from Zenodo for label transfer:" ] }, { "cell_type": "code", "execution_count": 2, "id": "a2237f65-92a1-4167-b6d3-1d2c2feea463", "metadata": {}, "outputs": [], "source": [ "if(!dir.exists(\"reference\")) {\n", " dir.create(\"reference\")\n", "}\n", "download.file(\n", " \"https://zenodo.org/records/7779017/files/pbmc_multimodal_2023.rds?download=1\",\n", " \"reference/pbmc_multimodal_2023.rds\"\n", ")" ] }, { "cell_type": "code", "execution_count": 3, "id": "310a3425-2e9c-4d09-92d7-d37aa3133f1c", "metadata": {}, "outputs": [], "source": [ "reference <- readRDS(\"reference/pbmc_multimodal_2023.rds\")" ] }, { "cell_type": "markdown", "id": "352f9dd8-7653-4b8d-82cc-ec7fc32e1b8f", "metadata": {}, "source": [ "Between Level 2 (L2) and Level 3 (L3) labels provided by the Satija lab, we like to add an additional level that we call L2.5, which separates the Treg Naive and Memory cells based on L3, and assigns a CD8 TEMRA cell label to cells with the L3 labels CD8 TEM_4 and CD8 TEM_5. All other cell types use their L2 assignments." ] }, { "cell_type": "code", "execution_count": 4, "id": "414d81e9-23a1-4293-a12d-4557273eeb84", "metadata": { "tags": [] }, "outputs": [], "source": [ "l3 <- as.character(reference@meta.data$celltype.l3)\n", "l2 <- as.character(reference@meta.data$celltype.l2)\n", "l2.5 <- l2\n", "l2.5[l3 == \"Treg Naive\"] <- \"Treg Naive\"\n", "l2.5[l3 == \"Treg Memory\"] <- \"Treg Memory\"\n", "l2.5[l3 %in% c(\"CD8 TEM_4\", \"CD8 TEM_5\")] <- \"CD8 TEMRA\"\n", "\n", "reference <- AddMetaData(reference, metadata = l2.5, col.name = \"celltype.l2.5\")" ] }, { "cell_type": "markdown", "id": "5d96208b-30c8-4516-9093-ff0fd724f0c3", "metadata": {}, "source": [ "## Retreive sample metadata\n", "\n", "In an earlier step, we assembled and stored sample metadata in HISE. We'll pull this file, and use it to retrieve file for our labeling process." ] }, { "cell_type": "code", "execution_count": 5, "id": "41889435-89c3-419d-845b-848514fe977f", "metadata": {}, "outputs": [], "source": [ "sample_meta_uuid <- \"2da66a1a-17cc-498b-9129-6858cf639caf\"" ] }, { "cell_type": "code", "execution_count": 6, "id": "086448e5-5aad-443e-af11-8d7e86a90b8b", "metadata": {}, "outputs": [], "source": [ "res <- cacheFiles(list(sample_meta_uuid))\n", "sample_meta_file <- list.files(\n", " paste0(\"cache/\", sample_meta_uuid), \n", " pattern = \".csv\",\n", " full.names = TRUE\n", ")" ] }, { "cell_type": "code", "execution_count": 7, "id": "ec100df3-b875-46b0-95f4-0798c488cd6f", "metadata": {}, "outputs": [], "source": [ "hise_meta <- read.csv(sample_meta_file)" ] }, { "cell_type": "markdown", "id": "c163a8af-555c-4728-b00f-c6620abf7619", "metadata": {}, "source": [ "## Cache input files\n", "\n", "Next, we'll use the hise package to cache all of the input files. With this many files, there are occasional problems with transfer, so we'll also add a check for existing files in our function, and run a second pass to make sure we have everything we want to label." ] }, { "cell_type": "code", "execution_count": null, "id": "ed9e672c-fe7d-4494-81d8-56a68184a835", "metadata": {}, "outputs": [], "source": [ "# Helper function with cache path check\n", "cache_file <- function(h5_uuid) {\n", " cache_dir <- paste0(\"cache/\",h5_uuid)\n", " if(!dir.exists(cache_dir)) {\n", " res <- cacheFiles(list(h5_uuid))\n", " }\n", "}\n", "\n", "# Walk file UUIDs to cache\n", "file_ids <- hise_meta$file.id\n", "walk(file_ids, cache_file)" ] }, { "cell_type": "markdown", "id": "a6ae6965-7ab7-4a4f-ad0f-1d0016c800a3", "metadata": {}, "source": [ "Run a second pass to make sure we have everything" ] }, { "cell_type": "code", "execution_count": null, "id": "cd55c1db-da54-43a1-9889-efefd793f42e", "metadata": {}, "outputs": [], "source": [ "walk(file_ids, cache_file)" ] }, { "cell_type": "markdown", "id": "7abde79c-a9aa-429f-ab51-e210c885e1e2", "metadata": {}, "source": [ "## Divide data into chunks for parallel processing\n", "\n", "For labeling, we'll take files in batches of up to 10 files. We'll label those files, then output the results for each sample in the batch." ] }, { "cell_type": "code", "execution_count": 8, "id": "a9bf4fd0-6c9e-4944-8925-36684ace10ae", "metadata": { "tags": [] }, "outputs": [], "source": [ "hise_meta <- hise_meta %>% \n", " arrange(file.batchID)" ] }, { "cell_type": "code", "execution_count": 9, "id": "2421afd7-2be3-4e9c-8985-1a6f1d6e2554", "metadata": {}, "outputs": [], "source": [ "b <- rep(1:11, each = 10)[1:nrow(hise_meta)]\n", "df_chunk_list <- split(hise_meta, b)" ] }, { "cell_type": "code", "execution_count": 10, "id": "6f607a41-e4da-478a-994e-09eba3989e1b", "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "