@@ -73,3 +73,94 @@ h5group_to_matrix <- function(x) {
7373 dims = rev(shape )
7474 )
7575}
76+
77+ # ' Subset function with automatic layer repair for Seurat v5 objects
78+ # '
79+ # ' This function handles corrupted layers in Seurat v5 assays that can cause
80+ # ' "incorrect number of dimensions" errors during subsetting.
81+ # '
82+ # ' Strategy:
83+ # ' 1. Evaluate subset normally
84+ # ' 2. Check for corrupted layers proactively
85+ # ' 3. Repair any corrupted layers before subsetting
86+ # ' 4. Perform the subset operation
87+ # ' 5. If subset still fails, re-throw the error
88+ # '
89+ # ' Example: subset_seurat(obj, EFS %in% c("EFS_L", "EFS_S"), nCount_RNA > 1000)
90+ # ' @param object Seurat object to subset
91+ # ' @param ... Arguments passed to `subset()`
92+ # ' @return Subsetted Seurat object with repaired layers if needed
93+ # ' @keywords internal
94+ subset_seurat <- function (object , ... ) {
95+ # Try subsetting first
96+ result <- tryCatch({
97+ subset(object , ... )
98+ }, error = function (e ) {
99+ if (grepl(" incorrect number of dimensions" , e $ message )) {
100+ warning(" Subsetting failed due to corrupted layers. Attempting to repair..." , call. = FALSE )
101+
102+ # Scan and repair assays with multiple layers
103+ for (assay_name in names(object @ assays )) {
104+ assay <- object @ assays [[assay_name ]]
105+
106+ # Check if it's a v5 assay with layers
107+ if (inherits(assay , " Assay5" ) && length(assay @ layers ) > 1 ) {
108+ cat(sprintf(" Scanning assay '%s' with %d layers...\n " , assay_name , length(assay @ layers )))
109+
110+ # Identify intact and corrupted layers
111+ intact_layers <- list ()
112+ corrupted_layers <- character ()
113+
114+ for (layer_name in names(assay @ layers )) {
115+ layer <- assay @ layers [[layer_name ]]
116+ if (is.matrix(layer ) || inherits(layer , " dgCMatrix" )) {
117+ intact_layers [[layer_name ]] <- layer
118+ } else {
119+ corrupted_layers <- c(corrupted_layers , layer_name )
120+ }
121+ }
122+
123+ # If all layers are corrupted, remove the assay
124+ if (length(intact_layers ) == 0 ) {
125+ warning(sprintf(" All layers in assay '%s' are corrupted. Removing assay." , assay_name ), call. = FALSE )
126+ object @ assays [[assay_name ]] <- NULL
127+ } else {
128+ # Restore corrupted layers based on intact ones
129+ if (length(corrupted_layers ) > 0 ) {
130+ # Get dimensions from first intact layer
131+ template_layer <- intact_layers [[1 ]]
132+ n_features <- nrow(template_layer )
133+ n_cells <- ncol(template_layer )
134+
135+ for (layer_name in corrupted_layers ) {
136+ corrupted_data <- assay @ layers [[layer_name ]]
137+
138+ # Check if it's a 1D vector with correct number of features
139+ if (is.vector(corrupted_data ) && length(corrupted_data ) == n_features ) {
140+ # Restore as single-column sparse matrix
141+ warning(sprintf(" Restoring corrupted layer '%s' in assay '%s' (1D vector -> sparse matrix)" ,
142+ layer_name , assay_name ), call. = FALSE )
143+ object @ assays [[assay_name ]]@ layers [[layer_name ]] <-
144+ Matrix :: Matrix(corrupted_data , nrow = n_features , ncol = 1 , sparse = TRUE )
145+ } else {
146+ # Cannot restore, remove it
147+ warning(sprintf(" Cannot restore layer '%s' in assay '%s' (incompatible dimensions). Removing." ,
148+ layer_name , assay_name ), call. = FALSE )
149+ object @ assays [[assay_name ]]@ layers [[layer_name ]] <- NULL
150+ }
151+ }
152+ }
153+ }
154+ }
155+ }
156+
157+ # Try subsetting again after repairs
158+ subset(object , ... )
159+ } else {
160+ # Re-throw other errors
161+ stop(e )
162+ }
163+ })
164+
165+ return (result )
166+ }
0 commit comments