############################################################################### # SUBSCRIPT_03d: asignacion de tipos celulares en funcion de SCtype #https://github.com/IanevskiAleksandr/sc-type/blob/master/README.md # ScType: Fully-automated and ultra-fast cell-type identification using specific marker combinations from single-cell transcriptomic data # Article: [https://doi.org/10.1038/s41467-022-28803-w] # ScType a computational method for automated selection of marker genes based merely on scRNA-seq data. The open-source portal (http://sctype.app) provides an interactive web-implementation of the method. # ############################################################################### #vaciar memorias graphics.off() gc(full = TRUE) #***Define raiz de rutas*** raiz <- "D:/INVESTIGACION/PROYECTOS/ELKARTEK-2024-2026/ANALISIS/CCRCC" #***Define raiz de rutas*** #esto define la muestra y los bins sample_in<-"muestra-277T" bins<-"square_016um" #elejimos aqui si 8um o 16um sample_in_bins<-paste0(sample_in,"_",bins) #REQUIERE HABER EJECUTADO EL SCRIPT 2 dir_bundle_in <- file.path(raiz, "SUB-BUNDLES", sample_in_bins) #bundle_in <- file.path(dir_bundle_in, "S2-bundle_markers_annot_scores.rds") bundle_in <- file.path(dir_bundle_in, "S2-bundle.rds") stopifnot(file.exists(bundle_in)) ##esto define donde va a estar la salida de datos #tipo CRRCC/SUB_OUTPUTS/muestra277t_square_016um sample_out<-paste0(sample_in, "_", bins) dir_sample_out <-file.path(raiz, "SUB-OUTPUTS", sample_out) dir.create(dir_sample_out, showWarnings = FALSE, recursive = TRUE) stopifnot(file.exists(dir_sample_out)) #esto define donde va a estar la salida para el bundle #tipo CCRCC/SUB_BUNDLES/muestra277T_squre_016um dir_bundle_out <- file.path(raiz, "SUB-BUNDLES", sample_out) dir.create(dir_bundle_out, showWarnings = FALSE, recursive = TRUE) stopifnot(file.exists(dir_bundle_out)) # ----------------------------------------------------------------------------- # 0) CARGA DEL BUNDLE DEL SUBSCRIPT_02 # ----------------------------------------------------------------------------- bundle_step02 <- readRDS(bundle_in) # Objetos principales del bundle visium <- bundle_step02$visium #visium2 <- bundle_step02$visium2 # puede ser NULL config <- bundle_step02$config # dims_use: robusto (algunas versiones lo guardan fuera de config) dims_use <- if (!is.null(bundle_step02$dims_use)) bundle_step02$dims_use else config$dims_use # ----------------------------------------------------------------------------- # Carga de librerias # ----------------------------------------------------------------------------- #install.packages("openxlsx") # load libraries and functions lapply(c("dplyr","Seurat","HGNChelper","openxlsx"), library, character.only = T) raizsctype <- "D:/INVESTIGACION/PROYECTOS/ELKARTEK-2024-2026/ANALISIS" #bajarme los scripts de RCtype sctype_dir <- file.path( raizsctype, "R/SCytpe" ) ####################################################################### ####################################################################### ####################################################################### #*** esto solo la primera vez ####################################################################### ####################################################################### ####################################################################### dir.create(sctype_dir, showWarnings = FALSE, recursive = TRUE) stopifnot(dir.exists(sctype_dir)) #***solo la primera vez, luego ignorar*** download.file( "https://raw.githubusercontent.com/IanevskiAleksandr/sc-type/master/R/gene_sets_prepare.R", destfile = file.path(sctype_dir, "gene_sets_prepare.R"), mode = "wb" ) download.file( "https://raw.githubusercontent.com/IanevskiAleksandr/sc-type/master/R/sctype_score_.R", destfile = file.path(sctype_dir, "sctype_score_.R"), mode = "wb" ) #recordar poner la direccion raw.gitxxx.... y no algo que contenga blob en la ruta, porque entonces se descarga un html download.file( "https://raw.githubusercontent.com/IanevskiAleksandr/sc-type/master/ScTypeDB_short.xlsx", destfile = file.path(sctype_dir, "ScTypeDB_short.xlsx"), mode = "wb" ) download.file( "https://raw.githubusercontent.com/IanevskiAleksandr/sc-type/master/ScTypeDB_full.xlsx", destfile = file.path(sctype_dir, "ScTypeDB_full.xlsx"), mode = "wb" ) download.file( "https://raw.githubusercontent.com/IanevskiAleksandr/sc-type/master/exampleData.RDS", destfile = file.path(sctype_dir, "exampleData.RDS"), mode = "wb" ) download.file( "https://raw.githubusercontent.com/IanevskiAleksandr/sc-type/master/R/auto_detect_tissue_type.R", destfile = file.path(sctype_dir, "auto_detect_tissue_type.R"), mode = "wb" ) download.file( "https://raw.githubusercontent.com/IanevskiAleksandr/sc-type/master/R/sctype_wrapper.R", destfile = file.path(sctype_dir, "sctype_wrapper.R"), mode = "wb" ) #***solo la primera vez, luego ignorar*** ####################################################################### ####################################################################### ####################################################################### ####################################################################### #RUN EVERY TIME #---------------------------------------------------------------------- source(file.path(sctype_dir, "gene_sets_prepare.R")) #Hace tres cosas clave: #Lee el archivo .R #Ejecuta todo su contenido, línea por línea #Inserta los objetos creados en el entorno actual (normalmente el global environment) source(file.path(sctype_dir, "sctype_score_.R")) #Define típicamente: #gene_sets_prepare() #objetos con CellMarker + PanglaoDB #funciones auxiliares para preparar markers #"Ahora R sabe cómo construir los gene sets de SCType" #sctype_score_.R Define:sctype_score() #lógica de scoring por clúster / tipo celular #Ahora R sabe cómo calcular scores y asignar tipos celulares" source(file.path(sctype_dir, "sctype_wrapper.R")) #ejemplos e la pag web https://github.com/IanevskiAleksandr/sc-type/tree/master/R # get cell-type-specific gene sets from our in-built database (DB) # gs_list <- gene_sets_prepare(file.path(sctype_dir, "ScTypeDB_short.xlsx"), "Immune system") # e.g. Immune system, Liver, Pancreas, Kidney, Eye, Brain # # # load example (scaled/normalized) scRNA-seq matrix # scRNAseqData <- readRDS(file.path(sctype_dir, "ScTypeDB_short.xlsx"),exampleData.RDS'); # # # assign cell types # es.max <- sctype_score(scRNAseqData = scRNAseqData, scaled = TRUE, gs = gs_list$gs_positive, gs2 = gs_list$gs_negative) ############################################################### # ASIGANCION DE FIRMAS (USANDO visium 16µm) ############################################################### db_short_local <- file.path(sctype_dir, "ScTypeDB_short.xlsx") db_full_local <- file.path(sctype_dir, "ScTypeDB_full.xlsx") wrapper_local <- file.path(sctype_dir, "sctype_wrapper.R") autotiss_local <- file.path(sctype_dir, "auto_detect_tissue_type.R") exdata_local <- file.path(sctype_dir, "exampleData.RDS") stopifnot(exists("gene_sets_prepare"), exists("sctype_score"), exists("run_sctype")) #------------------------------------------------------------ # 4) Selección de DB y tissue #------------------------------------------------------------ # DB recomendada: # - short: más compacta (a veces menos ruido) # - full : más completa (a veces más falsos positivos) db_path <- db_full_local # cambia a db_short_local si prefieres # educated guess para tu caso (ccRCC): tissue <- "Kidney" # alternativa: "Immune system" si quieres focalizar en inmunes #En la base oficial (SCTypeDB), los tissueType relevantes para ccRCC suelen ser: #"Kidney", "Immune system", "Endothelial" (en algunas versiones), #"Stromal" / "Mesenchymal" (limitado, depende versión DB) #No hay: "Cancer", "Tumor", "Renal cancer" #------------------------------------------------------------ # 5) Asegurar clusters en tu visium # SCType asigna "por cluster": necesita una columna de cluster en metadata #------------------------------------------------------------ cluster_col <- "seurat_clusters" if (!cluster_col %in% colnames(visium@meta.data)) { # Si no existe, intenta usar Idents; si tampoco, habría que clusterizar antes. if (length(levels(Idents(visium))) > 1) { visium$seurat_clusters <- as.character(Idents(visium)) } else { stop("No encuentro clusters (seurat_clusters/Idents). Primero clusteriza el objeto visium.") } } #------------------------------------------------------------ # 6) Preparar gene sets (markers) para ese tejido #------------------------------------------------------------ gs_list <- gene_sets_prepare(db_path, tissue) # Sanity checks stopifnot(is.list(gs_list), "gs_positive" %in% names(gs_list)) # gs_negative puede estar vacío en algunos tejidos if (!"gs_negative" %in% names(gs_list)) gs_list$gs_negative <- NULL #------------------------------------------------------------ # 7) Extraer matriz de expresión "scaled" desde tu Seurat (visium) # SCType funciona mejor con datos escalados (scaled = TRUE) # Para objetos grandes (Visium HD) reducimos a genes relevantes (markers) #------------------------------------------------------------ assays_avail <- Seurat::Assays(visium) # debe ser character #Assays(visium) (sin Seurat::) NO estaba llamando a la función de Seurat, sino a otra función llamada Assays() #(probablemente de SummarizedExperiment o por colisión de namespaces). assay_use <- if ("SCT" %in% assays_avail) "SCT" else "RNA" # Asegura que hay scale.data; si no existe, lo creamos (solo features relevantes) DefaultAssay(visium) <- assay_use # Genes relevantes: unión de markers (+ y -) genes_pos <- unique(unlist(gs_list$gs_positive, use.names = FALSE)) genes_neg <- if (!is.null(gs_list$gs_negative)) unique(unlist(gs_list$gs_negative, use.names = FALSE)) else character(0) genes_markers <- unique(c(genes_pos, genes_neg)) genes_markers <- genes_markers[genes_markers %in% rownames(visium)] if (length(genes_markers) < 50) { warning("Muy pocos genes marcadores intersectan con tu objeto. Revisa símbolos (HGNC) o tissue/db.") } # Si no hay scale.data (o está vacío), escalar SOLO genes_markers para ahorrar RAM scale_has_data <- FALSE if (assay_use == "SCT") { # En SCT, scale.data suele existir; si está vacío, lo escalamos igual scale_has_data <- nrow(GetAssayData(visium, slot = "scale.data")) > 0 } else { scale_has_data <- nrow(GetAssayData(visium, slot = "scale.data")) > 0 } if (!scale_has_data) { message("No hay scale.data. Ejecutando ScaleData() solo para genes marcadores (ahorra memoria)...") visium <- ScaleData(visium, features = genes_markers, verbose = FALSE) } # Extraer matriz escalada (solo genes_markers) sc_mat_scaled <- GetAssayData(visium, slot = "scale.data") sc_mat_scaled <- as.matrix(sc_mat_scaled[intersect(rownames(sc_mat_scaled), genes_markers), , drop = FALSE]) #------------------------------------------------------------ # 8) Ejecutar SCType (sctype_score) como en el tutorial #------------------------------------------------------------ es.max <- sctype_score( scRNAseqData = sc_mat_scaled, scaled = TRUE, gs = gs_list$gs_positive, gs2 = gs_list$gs_negative ) # es.max: matriz (celltype x cells). Ahora agregamos por cluster como en tutorial. clusters <- as.character(visium@meta.data[[cluster_col]]) names(clusters) <- colnames(sc_mat_scaled) #------------------------------------------------------------ # 9) Resumen por cluster: top tipos + scores + regla "Unknown" # (misma lógica del tutorial: score bajo -> Unknown) #------------------------------------------------------------ cL_results <- do.call( "rbind", lapply(sort(unique(clusters)), function(cl) { cells_in_cl <- names(clusters)[clusters == cl] # Suma por tipo celular sobre las celdas/spots del cluster es.max.cl <- sort(rowSums(es.max[, cells_in_cl, drop = FALSE]), decreasing = TRUE) head( data.frame( cluster = cl, type = names(es.max.cl), scores = as.numeric(es.max.cl), ncells = length(cells_in_cl), stringsAsFactors = FALSE ), 10 ) }) ) sctype_scores <- cL_results %>% group_by(cluster) %>% slice_max(order_by = scores, n = 1, with_ties = FALSE) %>% ungroup() # Regla de baja confianza del tutorial: # si score < ncells/4 => Unknown sctype_scores$type[as.numeric(sctype_scores$scores) < (sctype_scores$ncells / 4)] <- "Unknown" #------------------------------------------------------------ # 10) Escribir anotación en metadata (por spot) #------------------------------------------------------------ visium$sctype_classification <- NA_character_ for (cl in sctype_scores$cluster) { cl_type <- sctype_scores$type[sctype_scores$cluster == cl][1] visium$sctype_classification[clusters == cl] <- cl_type } visium$sctype_classification <- factor(visium$sctype_classification) #------------------------------------------------------------ # 11) Outputs: tablas + objeto + plots #------------------------------------------------------------ # Guardar tablas write.xlsx( list( top1_per_cluster = as.data.frame(sctype_scores), top10_per_cluster = as.data.frame(cL_results) ), file = file.path(dir_sample_out, paste0(sample_in_bins, "_KIDNEY_SCType_scores.xlsx")) ) # Guardar objeto (bundle intermedio) bundle_sctype <- list( visium = visium, sctype = list( tissue = tissue, db_path = db_path, assay_use = assay_use, cluster_col = cluster_col, sctype_scores = sctype_scores, top10 = cL_results ), config = config ) saveRDS(bundle_sctype, file.path(dir_bundle_out, paste0(sample_in_bins, "_KIDNEY_bundle_sctype.rds"))) # Plots (si tienes imágenes/UMAP ya calculados) p_umap <- DimPlot(visium, group.by = "sctype_classification", label = TRUE, repel = TRUE) + ggplot2::ggtitle(paste0(sample_in_bins, " - SCType (", tissue, ")")) ggplot2::ggsave( filename = file.path(dir_sample_out, paste0(sample_in_bins, "_KIDNEY_SCType_DimPlot.png")), plot = p_umap, width = 9, height = 7, dpi = 200 ) # Spatial plot (si el objeto tiene imagen espacial) # Nota: para evitar bordes negros en spots, usa stroke = NA (como ya sabes) p_spatial <- SpatialDimPlot( visium, group.by = "sctype_classification", pt.size.factor = 4, image.alpha = 0.4, stroke = NA ) + ggplot2::ggtitle(paste0(sample_in_bins, " - SCType (", tissue, ")")) ggplot2::ggsave( filename = file.path(dir_sample_out, paste0(sample_in_bins, "_KIDNEY_SCType_SpatialDimPlot.png")), plot = p_spatial, width = 9, height = 7, dpi = 200 ) p_spatial_big <- p_spatial + guides( fill = guide_legend(override.aes = list(size = legend_size, alpha = 1)), colour = guide_legend(override.aes = list(size = legend_size, alpha = 1)) ) + theme( legend.key.size = unit(1.2 * legend_mult, "lines") # hace "la cajita" más grande ) legend_size <- 6 # tamaño del punto en la leyenda legend_mult <- 1.2 # multiplicador del tamaño de la caja print(p_spatial_big) + theme_void() # Resumen por consola print(sctype_scores[, c("cluster","type","scores","ncells")]) message("SCType terminado. Outputs en: ", dir_sample_out) ###################################################### #AHORA PARA INMUNE ###################################################### #------------------------------------------------------------ # 4) Selección de DB y tissue #------------------------------------------------------------ # DB recomendada: # - short: más compacta (a veces menos ruido) # - full : más completa (a veces más falsos positivos) db_path <- db_full_local # cambia a db_short_local si prefieres # educated guess para tu caso (ccRCC): tissue <- "Immune system" #En la base oficial (SCTypeDB), los tissueType relevantes para ccRCC suelen ser: #"Kidney", "Immune system", "Endothelial" (en algunas versiones), #"Stromal" / "Mesenchymal" (limitado, depende versión DB) #No hay: "Cancer", "Tumor", "Renal cancer" #------------------------------------------------------------ # 5) Asegurar clusters en tu visium # SCType asigna "por cluster": necesita una columna de cluster en metadata #------------------------------------------------------------ cluster_col <- "seurat_clusters" if (!cluster_col %in% colnames(visium@meta.data)) { # Si no existe, intenta usar Idents; si tampoco, habría que clusterizar antes. if (length(levels(Idents(visium))) > 1) { visium$seurat_clusters <- as.character(Idents(visium)) } else { stop("No encuentro clusters (seurat_clusters/Idents). Primero clusteriza el objeto visium.") } } #------------------------------------------------------------ # 6) Preparar gene sets (markers) para ese tejido #------------------------------------------------------------ gs_list <- gene_sets_prepare(db_path, tissue) # Sanity checks stopifnot(is.list(gs_list), "gs_positive" %in% names(gs_list)) # gs_negative puede estar vacío en algunos tejidos if (!"gs_negative" %in% names(gs_list)) gs_list$gs_negative <- NULL #------------------------------------------------------------ # 7) Extraer matriz de expresión "scaled" desde tu Seurat (visium) # SCType funciona mejor con datos escalados (scaled = TRUE) # Para objetos grandes (Visium HD) reducimos a genes relevantes (markers) #------------------------------------------------------------ assays_avail <- Seurat::Assays(visium) # debe ser character #Assays(visium) (sin Seurat::) NO estaba llamando a la función de Seurat, sino a otra función llamada Assays() #(probablemente de SummarizedExperiment o por colisión de namespaces). assay_use <- if ("SCT" %in% assays_avail) "SCT" else "RNA" # Asegura que hay scale.data; si no existe, lo creamos (solo features relevantes) DefaultAssay(visium) <- assay_use # Genes relevantes: unión de markers (+ y -) genes_pos <- unique(unlist(gs_list$gs_positive, use.names = FALSE)) genes_neg <- if (!is.null(gs_list$gs_negative)) unique(unlist(gs_list$gs_negative, use.names = FALSE)) else character(0) genes_markers <- unique(c(genes_pos, genes_neg)) genes_markers <- genes_markers[genes_markers %in% rownames(visium)] if (length(genes_markers) < 50) { warning("Muy pocos genes marcadores intersectan con tu objeto. Revisa símbolos (HGNC) o tissue/db.") } # Si no hay scale.data (o está vacío), escalar SOLO genes_markers para ahorrar RAM scale_has_data <- FALSE if (assay_use == "SCT") { # En SCT, scale.data suele existir; si está vacío, lo escalamos igual scale_has_data <- nrow(GetAssayData(visium, slot = "scale.data")) > 0 } else { scale_has_data <- nrow(GetAssayData(visium, slot = "scale.data")) > 0 } if (!scale_has_data) { message("No hay scale.data. Ejecutando ScaleData() solo para genes marcadores (ahorra memoria)...") visium <- ScaleData(visium, features = genes_markers, verbose = FALSE) } # Extraer matriz escalada (solo genes_markers) sc_mat_scaled <- GetAssayData(visium, slot = "scale.data") sc_mat_scaled <- as.matrix(sc_mat_scaled[intersect(rownames(sc_mat_scaled), genes_markers), , drop = FALSE]) #------------------------------------------------------------ # 8) Ejecutar SCType (sctype_score) como en el tutorial #------------------------------------------------------------ es.max <- sctype_score( scRNAseqData = sc_mat_scaled, scaled = TRUE, gs = gs_list$gs_positive, gs2 = gs_list$gs_negative ) # es.max: matriz (celltype x cells). Ahora agregamos por cluster como en tutorial. clusters <- as.character(visium@meta.data[[cluster_col]]) names(clusters) <- colnames(sc_mat_scaled) #------------------------------------------------------------ # 9) Resumen por cluster: top tipos + scores + regla "Unknown" # (misma lógica del tutorial: score bajo -> Unknown) #------------------------------------------------------------ cL_results <- do.call( "rbind", lapply(sort(unique(clusters)), function(cl) { cells_in_cl <- names(clusters)[clusters == cl] # Suma por tipo celular sobre las celdas/spots del cluster es.max.cl <- sort(rowSums(es.max[, cells_in_cl, drop = FALSE]), decreasing = TRUE) head( data.frame( cluster = cl, type = names(es.max.cl), scores = as.numeric(es.max.cl), ncells = length(cells_in_cl), stringsAsFactors = FALSE ), 10 ) }) ) sctype_scores <- cL_results %>% group_by(cluster) %>% slice_max(order_by = scores, n = 1, with_ties = FALSE) %>% ungroup() # Regla de baja confianza del tutorial: # si score < ncells/4 => Unknown sctype_scores$type[as.numeric(sctype_scores$scores) < (sctype_scores$ncells / 4)] <- "Unknown" #------------------------------------------------------------ # 10) Escribir anotación en metadata (por spot) #------------------------------------------------------------ visium$sctype_classification <- NA_character_ for (cl in sctype_scores$cluster) { cl_type <- sctype_scores$type[sctype_scores$cluster == cl][1] visium$sctype_classification[clusters == cl] <- cl_type } visium$sctype_classification <- factor(visium$sctype_classification) #------------------------------------------------------------ # 11) Outputs: tablas + objeto + plots #------------------------------------------------------------ # Guardar tablas write.xlsx( list( top1_per_cluster = as.data.frame(sctype_scores), top10_per_cluster = as.data.frame(cL_results) ), file = file.path(dir_sample_out, paste0(sample_in_bins, "_IMMUNE_SCType_scores.xlsx")) ) # Guardar objeto (bundle intermedio) bundle_sctype <- list( visium = visium, sctype = list( tissue = tissue, db_path = db_path, assay_use = assay_use, cluster_col = cluster_col, sctype_scores = sctype_scores, top10 = cL_results ), config = config ) saveRDS(bundle_sctype, file.path(dir_bundle_out, paste0(sample_in_bins, "_IMMUNE_bundle_sctype.rds"))) # Plots (si tienes imágenes/UMAP ya calculados) p_umap <- DimPlot(visium, group.by = "sctype_classification", label = TRUE, repel = TRUE) + ggplot2::ggtitle(paste0(sample_in_bins, " - SCType (", tissue, ")")) ggplot2::ggsave( filename = file.path(dir_sample_out, paste0(sample_in_bins, "_IMMUNE_SCType_DimPlot.png")), plot = p_umap, width = 9, height = 7, dpi = 200 ) # Spatial plot (si el objeto tiene imagen espacial) # Nota: para evitar bordes negros en spots, usa stroke = NA (como ya sabes) p_spatial <- SpatialDimPlot( visium, group.by = "sctype_classification", pt.size.factor = 4, image.alpha = 0.4, stroke = NA ) + ggplot2::ggtitle(paste0(sample_in_bins, " - SCType (", tissue, ")")) ggplot2::ggsave( filename = file.path(dir_sample_out, paste0(sample_in_bins, "_IMMUNE_SCType_SpatialDimPlot.png")), plot = p_spatial, width = 9, height = 7, dpi = 200 ) p_spatial_big <- p_spatial + guides( fill = guide_legend(override.aes = list(size = legend_size, alpha = 1)), colour = guide_legend(override.aes = list(size = legend_size, alpha = 1)) ) + theme( legend.key.size = unit(1.2 * legend_mult, "lines") # hace "la cajita" más grande ) legend_size <- 6 # tamaño del punto en la leyenda legend_mult <- 1.2 # multiplicador del tamaño de la caja print(p_spatial_big) + theme_void() # Resumen por consola print(sctype_scores[, c("cluster","type","scores","ncells")]) message("SCType terminado. Outputs en: ", dir_sample_out)