Diff of /R/metadata.R [000000] .. [413088]

Switch to unified view

a b/R/metadata.R
1
#' @importClassesFrom data.table data.table
2
3
####
4
# Objects and Classes ####
5
####
6
7
### $ methods ####
8
9
#' @method $ vrMetadata
10
#'
11
"$.vrMetadata" <- function(x, i, ...) {
12
  return(NULL)
13
}
14
15
#' @method $<- vrMetadata
16
#'
17
#' @importFrom methods new slot
18
"$<-.vrMetadata" <- function(x, i, ..., value) {
19
20
  # molecule metadata
21
  mol.metadata <- methods::slot(x, "molecule")
22
  if(nrow(mol.metadata) > 0)
23
    mol.metadata[[i]] <- value
24
25
  # cell metadata
26
  cell.metadata <- methods::slot(x, "cell")
27
  if(nrow(cell.metadata) > 0)
28
    cell.metadata[[i]] <- value
29
30
  # spot metadata
31
  spot.metadata <- methods::slot(x, "spot")
32
  if(nrow(spot.metadata) > 0)
33
    spot.metadata[[i]] <- value
34
35
  # ROI metadata
36
  roi.metadata <- methods::slot(x, "ROI")
37
  if(nrow(roi.metadata) > 0)
38
    roi.metadata[[i]] <- value
39
40
  # ROI metadata
41
  tile.metadata <- methods::slot(x, "tile")
42
  if(nrow(tile.metadata) > 0)
43
    tile.metadata[[i]] <- value
44
45
  return(methods::new("vrMetadata", molecule = mol.metadata, cell = cell.metadata, spot = spot.metadata, ROI = roi.metadata, tile = tile.metadata))
46
}
47
48
#' @method $<- vrMetadata
49
#'
50
#' @importFrom methods new slot
51
#'
52
"[[<-.vrMetadata" <- function(x, i, ..., value) {
53
54
  # molecule metadata
55
  mol.metadata <- methods::slot(x, "molecule")
56
  if(nrow(mol.metadata) > 0)
57
    mol.metadata[[i]] <- value
58
59
  # cell metadata
60
  cell.metadata <- methods::slot(x, "cell")
61
  if(nrow(cell.metadata) > 0)
62
    cell.metadata[[i]] <- value
63
64
  # spot metadata
65
  spot.metadata <- methods::slot(x, "spot")
66
  if(nrow(spot.metadata) > 0)
67
    spot.metadata[[i]] <- value
68
69
  # ROI metadata
70
  roi.metadata <- methods::slot(x, "ROI")
71
  if(nrow(roi.metadata) > 0)
72
    roi.metadata[[i]] <- value
73
74
  # ROI metadata
75
  tile.metadata <- methods::slot(x, "tile")
76
  if(nrow(tile.metadata) > 0)
77
    tile.metadata[[i]] <- value
78
79
  return(methods::new("vrMetadata", molecule = mol.metadata, cell = cell.metadata, spot = spot.metadata, ROI = roi.metadata, tile = tile.metadata))
80
}
81
82
####
83
# Methods ####
84
####
85
86
vrSpatialPointsvrMetadata <- function(object, assay = NULL) {
87
  
88
  # get spatial points
89
  points <- unlist(lapply(methods::slotNames(object), function(x) {
90
    if(x %in% c("cell", "spot", "ROI")){
91
      mdata <- slot(object, name = x)
92
      if(nrow(mdata) > 0){
93
        if(!is.null(rownames(mdata))){
94
          sp <- rownames(mdata)
95
        } else {
96
          sp <- as.vector(mdata$id)
97
        }
98
        if(!is.null(assay))
99
          sp <- sp[grepl(paste(paste0(assay, "$"), collapse = "|"), sp)]
100
        return(sp)  
101
      }
102
    } else {
103
      mdata <- slot(object, name = x)
104
      if(nrow(mdata) > 0){
105
        if(inherits(mdata, "data.table")){
106
          if(!is.null(assay))
107
            sp <- subset(mdata, subset = assay_id %in% assay)
108
          return(sp[["id"]])
109
        } else {
110
          sp <- as.vector(mdata$id)
111
          if(!is.null(assay))
112
            sp <- sp[grepl(paste(paste0(assay, "$"), collapse = "|"), sp)]
113
          return(sp)
114
        }
115
      }
116
    }
117
  }))
118
  
119
  # return points
120
  return(points)
121
}
122
123
#' @param assay assay name (exp: Assay1) or assay class (exp: Visium, Xenium), see \link{SampleMetadata}. 
124
#' if NULL, the default assay will be used, see \link{vrMainAssay}.
125
#'
126
#' @rdname vrSpatialPoints
127
#' @order 3
128
#'
129
#' @importFrom methods slotNames
130
#'
131
#' @export
132
setMethod("vrSpatialPoints", "vrMetadata", vrSpatialPointsvrMetadata)
133
134
subsetvrMetadata <- function(x, subset, samples = NULL, assays = NULL, spatialpoints = NULL) {
135
  
136
  # start 
137
  object <- x
138
  
139
  if (!missing(x = subset)) {
140
    subset <- enquo(arg = subset)
141
  }
142
  
143
  # subset all metadata types
144
  if(!is.null(samples)){
145
    if(nrow(object@molecule) > 0){
146
      mol.metadata <- subset_metadata(object@molecule, samples = samples)
147
    } else {
148
      mol.metadata <- data.table::data.table()
149
    }
150
    cell.metadata <- subset_metadata(object@cell, samples = samples)
151
    spot.metadata <- subset_metadata(object@spot, samples = samples)
152
    roi.metadata <- subset_metadata(object@ROI, samples = samples)
153
    if(nrow(object@tile) > 0){
154
      tile.metadata <- subset_metadata(object@tile, samples = samples)
155
    } else {
156
      tile.metadata <- data.table::data.table()
157
    }
158
  } else if(!is.null(assays)){
159
    assay_names <- unique(lapply(slotToList(object), function(x) {
160
      if(inherits(x, "data.table")){
161
        return(unique(as.vector(x$assay_id)))
162
      } else {
163
        if(!is.null(rownames(x))){
164
          return(unique(stringr::str_extract(rownames(x), "Assay[0-9]+")))
165
        } else {
166
          return(unique(stringr::str_extract(as.vector(x$id), "Assay[0-9]+"))) 
167
        }
168
      }
169
    }))
170
    assay_names <- unique(do.call(c,assay_names))
171
    if(all(assays %in% assay_names)){
172
      if(nrow(object@molecule) > 0) {
173
        mol.metadata <- subset_metadata(object@molecule, assays = assays)
174
      } else {
175
        mol.metadata <- data.table::data.table()
176
      }
177
      cell.metadata <- subset_metadata(object@cell, assays = assays)
178
      spot.metadata <- subset_metadata(object@spot, assays = assays)
179
      roi.metadata <- subset_metadata(object@ROI, assays = assays)
180
      if(nrow(object@tile) > 0) {
181
        tile.metadata <- object@tile[assay_id %in% assays, ]
182
      } else {
183
        tile.metadata <- data.table::data.table()
184
      }
185
    } else {
186
      if(nrow(object@molecule) > 0) {
187
        mol.metadata <- subset_metadata(object@molecule, assaytypes = assays)
188
      } else {
189
        mol.metadata <- data.table::data.table()
190
      }
191
      cell.metadata <- subset_metadata(object@cell, assaytypes = assays)
192
      spot.metadata <- subset_metadata(object@spot, assaytypes = assays)
193
      roi.metadata <- subset_metadata(object@ROI, assaytypes = assays)
194
      if(nrow(object@tile) > 0) {
195
        tile.metadata <- subset_metadata(object@tile, assaytypes = assays)
196
      } else {
197
        tile.metadata <- data.table::data.table()
198
      }
199
    }
200
  } else if(!is.null(spatialpoints)){
201
    if(nrow(object@molecule) > 0){
202
      mol.metadata <- subset_metadata(object@molecule, spatialpoints = spatialpoints)
203
    } else {
204
      mol.metadata <- data.table::data.table()
205
    }
206
    cell.metadata <- subset_metadata(object@cell, spatialpoints = spatialpoints)
207
    spot.metadata <- subset_metadata(object@spot, spatialpoints = spatialpoints)
208
    roi.metadata <- subset_metadata(object@ROI, spatialpoints = spatialpoints)
209
    if(nrow(object@tile) > 0){
210
      tile.metadata <- subset_metadata(object@tile, spatialpoints = spatialpoints)
211
    } else {
212
      tile.metadata <- data.table::data.table()
213
    }
214
  } else {
215
    stop("No assay, sample or spatial points were provided!")
216
  }
217
  
218
  # return new metadata
219
  methods::new("vrMetadata",
220
               molecule = mol.metadata,
221
               cell = cell.metadata,
222
               spot = spot.metadata,
223
               ROI = roi.metadata,
224
               tile = tile.metadata)
225
}
226
227
#' Subsetting vrMetadata objects
228
#'
229
#' Given a vrMetadata object, subset the object given one of the attributes
230
#'
231
#' @param x a vrMetadata object
232
#' @param subset the subset statement
233
#' @param samples the set of samples to subset the object
234
#' @param assays assay name (exp: Assay1) or assay class (exp: Visium, Xenium), see \code{SampleMetadata(object)}
235
#' @param spatialpoints the set of spatial points to subset the object
236
#'
237
#' @method subset vrMetadata
238
#' @order 3
239
#'
240
#' @importFrom rlang enquo
241
#' @importFrom stringr str_extract
242
#' @importFrom data.table setkey
243
setMethod("subset", "vrMetadata", subsetvrMetadata)
244
245
#' subset_sampleMetadata
246
#'
247
#' Subseting sample metadata
248
#'
249
#' @param metadata sample metadata of a VoltRon object
250
#' @param samples the set of samples to subset the object
251
#' @param assay assay name (exp: Assay1) or assay class (exp: Visium, Xenium), see \link{SampleMetadata}. 
252
#' if NULL, the default assay will be used, see \link{vrMainAssay}.
253
#'
254
#' @noRd
255
subset_sampleMetadata <- function(metadata, samples = NULL, assays = NULL) {
256
257
  # subseting on samples, layers and assays
258
  if(!is.null(samples)){
259
    if(all(samples %in% metadata$Sample)){
260
      metadata <- metadata[metadata$Sample %in% samples,]
261
    } else {
262
      stop("Some samples with the names '", paste(samples, collapse = ", "), "' are not found in the object")
263
    }
264
  } else if(!is.null(assays)) {
265
    if(all(assays %in% rownames(metadata))){
266
      metadata <- metadata[assays,]
267
    } else if(all(assays %in% metadata$Assay)){
268
      metadata <- metadata[metadata$Assay %in% assays,]
269
    } else {
270
      stop("Some assay with the names or types '", paste(assays, collapse = ", "), "' are not found in the object")
271
    }
272
  }
273
  metadata
274
}
275
276
mergevrMetadata <- function(x, y) {
277
278
  # start 
279
  object <- x
280
  object_list <- y
281
  
282
  # combine all elements
283
  if(!is.list(object_list))
284
    object_list <- list(object_list)
285
  object_list <- c(object, object_list)
286
287
  # check if all are VoltRon
288
  if(!all(lapply(object_list, class) == "vrMetadata"))
289
    stop("All arguements have to be of vrMetadata class")
290
291
  # choose objects
292
  obj1 <- object_list[[1]]
293
  obj2 <- object_list[[2]]
294
295
  # initial combination
296
  if(length(object_list) > 2){
297
    combined.metadata <- mergevrMetadata(obj1, obj2)
298
    for(i in 3:(length(object_list))){
299
      combined.metadata <- mergevrMetadata(combined.metadata, object_list[[i]])
300
    }
301
  } else {
302
    updateobjects <- updateMetadataAssay(obj1, obj2)
303
    obj1 <- updateobjects$object1
304
    obj2 <- updateobjects$object2
305
    mol.metadata <- rbind_metadata(methods::slot(obj1, "molecule"), methods::slot(obj2, "molecule"))
306
    cell.metadata <- rbind_metadata(methods::slot(obj1, "cell"), methods::slot(obj2, "cell"))
307
    spot.metadata <- rbind_metadata(methods::slot(obj1, "spot"), methods::slot(obj2, "spot"))
308
    roi.metadata <- rbind_metadata(methods::slot(obj1, "ROI"), methods::slot(obj2, "ROI"))
309
    tile.metadata <- rbind_metadata(methods::slot(obj1, "tile"), methods::slot(obj2, "tile"))
310
    combined.metadata <- methods::new("vrMetadata", 
311
                                      molecule = mol.metadata, 
312
                                      cell = cell.metadata, 
313
                                      spot = spot.metadata, 
314
                                      ROI = roi.metadata, 
315
                                      tile = tile.metadata)
316
  }
317
318
  # return combined object
319
  return(combined.metadata)
320
}
321
322
#' Merging vrMetadata objects
323
#'
324
#' Given a vrMetadata object, and a list of vrMetadata objects, merge all.
325
#'
326
#' @param x a vrMetadata object
327
#' @param y a single or a list of vrMetadata objects
328
#'
329
#' @method merge vrMetadata
330
#'
331
#' @importFrom dplyr bind_rows
332
#' @importFrom methods slot
333
#' @export
334
setMethod("merge", "vrMetadata", mergevrMetadata)
335
336
#' rbind_metadata
337
#'
338
#' @param metadata1 metadata1
339
#' @param metadata2 metadata2
340
#'
341
#' @method merge vrMetadata
342
#'
343
#' @importFrom dplyr bind_rows
344
#' @noRd
345
#'
346
rbind_metadata <- function(metadata1, metadata2){
347
  flag1 <- FALSE
348
  flag2 <- FALSE
349
  if(!inherits(metadata1, "DataFrame")){
350
    flag1 <- TRUE
351
  }
352
  if(!inherits(metadata2, "DataFrame")){
353
    flag2 <- TRUE
354
  }
355
  if(flag1 && flag2){
356
    return(dplyr::bind_rows(metadata1,metadata2))
357
  } else {
358
    if(flag1)
359
      metadata1 <- S4Vectors::DataFrame(metadata1)
360
    if(flag2)
361
      metadata2 <- S4Vectors::DataFrame(metadata2)
362
    return(rbind(metadata1, metadata2))
363
  }
364
}
365
366
#' subset_metadata
367
#'
368
#' @param metadata metadata
369
#' @param samples the set of samples to subset the object
370
#' @param assays assay name (exp: Assay1), see \code{SampleMetadata(object)}
371
#' @param assaytypes assay class (exp: Visium, Xenium), see \code{SampleMetadata(object)}
372
#' @param spatialpoints the set of spatial points to subset the object
373
#'
374
#' @noRd
375
subset_metadata <- function(metadata, assays = NULL, assaytypes = NULL, samples = NULL, spatialpoints = NULL){
376
  
377
  if(inherits(metadata, "data.table")){
378
    if(nrow(metadata) > 0){
379
      if(!is.null(assays)){
380
        metadata <- subset(metadata, subset = assay_id %in% assays)
381
      } else if(!is.null(assaytypes)){
382
        metadata <- subset(metadata, subset = Assay %in% assaytypes)
383
      } else if(!is.null(samples)){
384
        metadata <- subset(metadata, subset = Sample %in% samples)
385
      } else if(!is.null(spatialpoints)){
386
        metadata <- subset(metadata, subset = id %in% spatialpoints)
387
      } else {
388
        stop("No assay, sample or spatial points were provided!")
389
      }  
390
    } else {
391
      metadata <- data.table::data.table()
392
    }
393
  } else if(inherits(metadata, "DataFrame")){
394
    if(!is.null(assays)){
395
      if("assay_id" %in% colnames(metadata)){
396
        cur_column <- as.vector(metadata$assay_id)
397
        metadata <- metadata[cur_column %in% assays,]
398
      } else {
399
        cur_column <- as.vector(metadata$id)
400
        metadata <- metadata[stringr::str_extract(cur_column, "Assay[0-9]+") %in% assays, ]
401
      }
402
    } else if(!is.null(assaytypes)){
403
      cur_column <- as.vector(metadata$Assay)
404
      metadata <- metadata[cur_column %in% assaytypes,]
405
    } else if(!is.null(samples)){
406
      cur_column <- as.vector(metadata$Sample)
407
      metadata <- metadata[cur_column %in% samples,]
408
    } else if(!is.null(spatialpoints)){
409
      cur_column <- as.vector(metadata$id)
410
      metadata <- metadata[cur_column %in% spatialpoints,]
411
    } else {
412
      stop("No assay, sample or spatial points were provided!")
413
    }  
414
  } else {
415
    if(nrow(metadata) > 0){
416
      if(!is.null(assays)){
417
        if(!is.null(rownames(metadata))){
418
          metadata <- metadata[stringr::str_extract(rownames(metadata), "Assay[0-9]+") %in% assays, ]
419
        } else {
420
          if("assay_id" %in% colnames(metadata)){
421
            metadata <- subset(metadata, subset = assay_id %in% assays)
422
          } else {
423
            metadata <- metadata[stringr::str_extract(metadata$id, "Assay[0-9]+") %in% assays, ]
424
          }
425
        }
426
      } else if(!is.null(assaytypes)){
427
        metadata <- subset(metadata, subset = Assay %in% assaytypes)
428
      } else if(!is.null(samples)){
429
        metadata <- subset(metadata, subset = Sample %in% samples)
430
      } else if(!is.null(spatialpoints)){
431
        if(!is.null(rownames(metadata))){
432
          metadata <- metadata[rownames(metadata) %in% spatialpoints,]
433
        } else {
434
          metadata <- metadata[metadata$id %in% spatialpoints,]
435
        }
436
      } else {
437
        stop("No assay, sample or spatial points were provided!")
438
      }  
439
    }
440
  }
441
  metadata
442
}
443
444
#' merge.sampleMetadata
445
#'
446
#' Merging sample.metadata from two VoltRon objects
447
#'
448
#' @param metadata_list a list of sample metadata of a VoltRon object
449
#'
450
#' @noRd
451
#'
452
merge_sampleMetadata <- function(metadata_list) {
453
454
  sample_names <- NULL
455
  sample.metadata <- do.call(rbind, metadata_list)
456
  rownames(sample.metadata) <- paste0("Assay", seq_len(nrow(sample.metadata)))
457
458
  # change sample names if provided
459
  if(!is.null(sample_names)){
460
461
    # check the number sample names
462
    if(!length(sample_names) %in% c(1,nrow(sample.metadata))){
463
      stop("Please provide only one sample name or of length of object list!")
464
    } else {
465
      sample.metadata$Sample <- sample_names
466
      section_ids <- rep(NA,nrow(sample.metadata))
467
      uniq_names <- unique(sample.metadata$Sample)
468
      for(i in seq_len(length(uniq_names))){
469
        cur_ind <- which(sample.metadata$Sample == uniq_names[i])
470
        section_ids[cur_ind] <- seq_len(length(cur_ind))
471
      }
472
      sample.metadata$Layer <- paste0("Section", section_ids)
473
    }
474
  }
475
  sample.metadata
476
}
477
478
### Assay Methods ####
479
480
addAssayvrMetadata <- function(object, metadata = NULL, assay, assay_name, sample = "Sample1", layer = "Section1"){
481
482
  # get metadata and other info
483
  assay.type <- vrAssayTypes(assay)
484
  object_metadata <- methods::slot(object, name = assay.type)
485
  data <- vrData(assay, norm = FALSE)
486
487
  # add new assay
488
  assay_ids <- vrAssayNames(object)
489
  assay_ids <- as.numeric(gsub("Assay", "", assay_ids))
490
  assay_id <- paste0("Assay", max(assay_ids)+1)
491
492
  # metadata
493
  if(inherits(metadata, "data.table")){
494
495
    if(!is.null(metadata)){
496
497
      if(nrow(data) > 0){
498
        assay_metadata <- data.table::data.table(metadata[, "id", with=FALSE], assay_id = assay_id, Count = Matrix::colSums(data),
499
                                                 Assay = assay_name, Layer = layer, Sample = sample,
500
                                                 metadata[, colnames(metadata)[!colnames(metadata) %in% c("id", "assay_id", "Count", "Assay", "Layer", "Sample")], with=FALSE])
501
      } else{
502
        assay_metadata <- data.table::data.table(metadata[, "id", with=FALSE], assay_id = assay_id,
503
                                                 Assay = assay_name, Layer = layer, Sample = sample,
504
                                                 metadata[, colnames(metadata)[!colnames(metadata) %in% c("id", "assay_id", "Count", "Assay", "Layer", "Sample")], with=FALSE])
505
      }
506
507
    }
508
  } else {
509
510
    # get original names
511
    entityID_nopostfix <- stringr::str_replace(vrSpatialPoints(assay), pattern = "_Assay[0-9]+", "")
512
    entityID <- stringr::str_replace(entityID_nopostfix, pattern = "$", paste0("_", assay_id))
513
514
    # if original metadata has rownames
515
    if(!"id" %in% colnames(object_metadata)){
516
      rownames_metadata <- stringr::str_replace(rownames(metadata), pattern = "_Assay[0-9]+", "")
517
      
518
      # initiate metadata
519
      if(nrow(data) > 0){
520
        assay_metadata <- data.frame(Count = Matrix::colSums(data), row.names = entityID)
521
      } else {
522
        assay_metadata <- data.frame(row.names = entityID)
523
      }
524
525
      # add metadata
526
      if(!is.null(metadata)){
527
        if(length(setdiff(rownames_metadata, entityID_nopostfix)) > 0){
528
          stop("Some spatial points in the metadata does not match with the assay!")
529
        } else{
530
          assay_metadata <- dplyr::bind_cols(assay_metadata,
531
                                             metadata[,!colnames(metadata) %in% c("Count", "Assay", "Layer", "Sample"), drop = FALSE])
532
        }
533
      }
534
      
535
      # complete assay_metadata
536
      assay_metadata <- dplyr::bind_cols(data.frame(Assay = rep(assay_name, length(entityID)),
537
                                                    Layer = rep(layer, length(entityID)),
538
                                                    Sample = rep(sample, length(entityID))),
539
                                         assay_metadata)
540
    } else {
541
      metadata_id <- stringr::str_replace(as.vector(metadata$id), pattern = "_Assay[0-9]+", "")
542
      
543
      # initiate metadata
544
      if(nrow(data) > 0){
545
        assay_metadata <- data.frame(id = entityID, Count = Matrix::colSums(data), assay_id = assay_id)
546
      } else {
547
        assay_metadata <- data.frame(id = entityID, assay_id = assay_id)
548
      }
549
      
550
      # check rownames
551
      if(!is.null(rownames(object_metadata))){
552
        rownames(assay_metadata) <- assay_metadata$id
553
      }
554
      
555
      # add metadata
556
      if(!is.null(metadata)){
557
        if(length(setdiff(metadata_id, entityID_nopostfix)) > 0){
558
          stop("Some spatial points in the metadata does not match with the assay!")
559
        } else{
560
          assay_metadata <- dplyr::bind_cols(assay_metadata,
561
                                             data.frame(Assay = rep(assay_name, length(entityID)),
562
                                                        Layer = rep(layer, length(entityID)),
563
                                                        Sample = rep(sample, length(entityID))),
564
                                             metadata[,!colnames(metadata) %in% c("id", "Count", "assay_id", "Assay", "Layer", "Sample"), drop = FALSE])
565
        }
566
      } else {
567
        assay_metadata <- dplyr::bind_cols(assay_metadata,
568
                                           data.frame(Assay = rep(assay_name, length(entityID)),
569
                                                      Layer = rep(layer, length(entityID)),
570
                                                      Sample = rep(sample, length(entityID))))
571
      }
572
    }
573
  }
574
575
  # add to the main metadata
576
  if(inherits(object_metadata, "DataFrame")){
577
    object_metadata <- rbind(object_metadata, assay_metadata)
578
  } else {
579
    object_metadata <- dplyr::bind_rows(object_metadata, assay_metadata)
580
  }
581
  methods::slot(object, name = assay.type) <- object_metadata
582
583
  # return
584
  return(object)
585
}
586
587
#' @rdname addAssay
588
#' @method addAssay vrMetadata
589
#'
590
#' @importFrom dplyr bind_rows bind_cols
591
#' @importFrom methods slot slot<-
592
#' @importFrom stringr str_replace
593
#' @importFrom data.table data.table
594
#' @importFrom Matrix colSums
595
#'
596
#' @export
597
setMethod("addAssay", "vrMetadata", addAssayvrMetadata)
598
599
vrAssayNamesvrMetadata <- function(object){
600
  
601
  # get assay names from metadata
602
  assay_names <- NULL
603
  for(sl in methods::slotNames(object)){
604
    cur_metadata <- slot(object, name = sl)
605
    if(sl %in% c("molecule", "tile")){
606
      cur_names <- cur_metadata$assay_id
607
    } else {
608
      if("assay_id" %in% colnames(cur_metadata)){
609
        cur_names <- as.vector(cur_metadata$assay_id)
610
      } else if(!is.null(rownames(cur_metadata))){
611
        cur_names <- stringr::str_extract(rownames(cur_metadata), "Assay[0-9]+")
612
      } else{
613
        cur_names <- stringr::str_extract(as.vector(cur_metadata$id), "Assay[0-9]+")
614
      }
615
    }
616
    assay_names <- c(assay_names, unique(cur_names))
617
  }
618
  assay_names
619
}
620
621
#' @rdname vrAssayNames
622
#' @order 3
623
#' @importFrom methods slotNames
624
#' @export
625
setMethod("vrAssayNames", "vrMetadata", vrAssayNamesvrMetadata)
626
627
#' updateMetadataAssay
628
#'
629
#' Updating assay names for merge
630
#'
631
#' @param object1 vrMetadata object
632
#' @param object2 vrMetadata object
633
#'
634
#' @importFrom stringr str_extract
635
#' @importFrom methods new
636
#'
637
#' @noRd
638
updateMetadataAssay <- function(object1, object2){
639
640
  # get assay types
641
  object_list <- slotToList(object1)
642
  assaytype <- unlist(lapply(object_list, function(obj) {
643
    if(inherits(obj, "data.table")){
644
      unique(obj$assay_id)
645
    } else if(inherits(obj, c("HDF5DataFrame", "ZarrDataFrame", "DataFrame"))){
646
      if("assay_id" %in% colnames(obj)){
647
        unique(as.vector(obj$assay_id))
648
      } else {
649
        unique(stringr::str_extract(as.vector(obj$id), "Assay[0-9]+$"))
650
      }
651
    } else {
652
      unique(stringr::str_extract(rownames(obj), "Assay[0-9]+$"))
653
    }
654
  }))
655
  assaytype <- assaytype[order(nchar(assaytype), assaytype)]
656
657
  # replace assay names
658
  replacement <- paste0("Assay", seq_len(length(assaytype)))
659
  object1 <- lapply(object_list, function(obj) {
660
    if(nrow(obj) > 0){
661
      
662
      if(inherits(obj, "data.table")){
663
        
664
        # change assay id
665
        temp <- obj$assay_id
666
        for(i in seq_len(length(assaytype)))
667
          temp[grepl(assaytype[i], obj$assay_id)] <- replacement[i]
668
        obj$assay_id <- temp
669
        return(obj)
670
        
671
      } else if(inherits(obj, c("HDF5DataFrame", "ZarrDataFrame", "DataFrame"))){
672
        
673
        # change assay id
674
        if("assay_id" %in% colnames(obj)){
675
          temp <- as.vector(obj$assay_id)
676
          for(i in seq_len(length(assaytype)))
677
            temp[grepl(assaytype[i], obj$assay_id)] <- replacement[i]
678
          obj$assay_id <- temp
679
        }
680
        
681
        # change id
682
        temp <- as.vector(obj$id)
683
        for(i in seq_len(length(assaytype))){
684
          temp[grepl(paste0(assaytype[i],"$"), obj$id)] <- 
685
            gsub(paste0(assaytype[i],"$"), replacement[i],
686
                 obj$id[grepl(paste0(assaytype[i],"$"),  obj$id)])
687
        }
688
        obj$id <- temp
689
        
690
        return(obj)
691
      } else {
692
        
693
        # change rownames
694
        temp <- rownames(obj)
695
        for(i in seq_len(length(assaytype)))
696
          temp[grepl(paste0(assaytype[i],"$"), rownames(obj))] <- 
697
            gsub(paste0(assaytype[i],"$"), replacement[i],
698
                 rownames(obj)[grepl(paste0(assaytype[i],"$"), rownames(obj))])
699
        rownames(obj) <- temp
700
        
701
        # change assay id
702
        if("assay_id" %in% colnames(obj)){
703
          temp <- obj$assay_id
704
          for(i in seq_len(length(assaytype)))
705
            temp[grepl(assaytype[i], obj$assay_id)] <- replacement[i]
706
          obj$assay_id <- temp
707
        }
708
        return(obj)
709
      }
710
    } else {
711
      return(obj)
712
    }
713
  })
714
  object1 <- methods::new("vrMetadata", 
715
                          molecule = object1$molecule, 
716
                          cell = object1$cell, 
717
                          spot = object1$spot, 
718
                          ROI = object1$ROI, 
719
                          tile = object1$tile)
720
721
  # get assay types
722
  object_list <- slotToList(object2)
723
  assaytype <- unlist(lapply(object_list, function(obj) {
724
    if(inherits(obj, "data.table")){
725
      unique(obj$assay_id)
726
    } else if(inherits(obj, c("HDF5DataFrame", "ZarrDataFrame", "DataFrame"))){
727
      if("assay_id" %in% colnames(obj)){
728
        unique(as.vector(obj$assay_id))
729
      } else {
730
        unique(stringr::str_extract(as.vector(obj$id), "Assay[0-9]+$"))
731
      }
732
    } else {
733
      unique(stringr::str_extract(rownames(obj), "Assay[0-9]+$"))
734
    }
735
  }))
736
  assaytype <- assaytype[order(nchar(assaytype), assaytype)]
737
738
  # replace assay names
739
  replacement <- paste0("Assay", (length(replacement)+1):(length(replacement) + length(assaytype)))
740
  object2 <- lapply(object_list, function(obj) {
741
    if(nrow(obj) > 0){
742
      if(inherits(obj, "data.table")){
743
        
744
        # change assay id
745
        temp <- obj$assay_id
746
        for(i in seq_len(length(assaytype)))
747
          temp[grepl(assaytype[i], obj$assay_id)] <- replacement[i]
748
        obj$assay_id <- temp
749
        
750
        return(obj)
751
      } else if(inherits(obj, c("HDF5DataFrame", "ZarrDataFrame", "DataFrame"))){
752
        
753
        # change assay id
754
        if("assay_id" %in% colnames(obj)){
755
          temp <- as.vector(obj$assay_id)
756
          for(i in seq_len(length(assaytype)))
757
            temp[grepl(assaytype[i], obj$assay_id)] <- replacement[i]
758
          obj$assay_id <- temp
759
        }
760
        
761
        # change id
762
        temp <- as.vector(obj$id)
763
        for(i in seq_len(length(assaytype))){
764
          temp[grepl(paste0(assaytype[i],"$"), obj$id)] <- 
765
            gsub(paste0(assaytype[i],"$"), replacement[i], 
766
                 obj$id[grepl(paste0(assaytype[i],"$"), obj$id)])
767
        }
768
        obj$id <- temp
769
        
770
        return(obj)
771
      } else {
772
        
773
        # change row names
774
        temp <- rownames(obj)
775
        for(i in seq_len(length(assaytype)))
776
          temp[grepl(paste0(assaytype[i],"$"), rownames(obj))] <- 
777
            gsub(paste0(assaytype[i],"$"), replacement[i],
778
                 rownames(obj)[grepl(paste0(assaytype[i],"$"), rownames(obj))])
779
        rownames(obj) <- temp
780
        
781
        # change id
782
        temp <- obj$id
783
        for(i in seq_len(length(assaytype))){
784
          temp[grepl(paste0(assaytype[i],"$"), obj$id)] <- 
785
            gsub(paste0(assaytype[i],"$"), replacement[i], 
786
                 obj$id[grepl(paste0(assaytype[i],"$"), obj$id)])
787
        }
788
        obj$id <- temp
789
        
790
        # change assay id
791
        if("assay_id" %in% colnames(obj)){
792
          temp <- obj$assay_id
793
          for(i in seq_len(length(assaytype)))
794
            temp[grepl(assaytype[i], obj$assay_id)] <- replacement[i]
795
          obj$assay_id <- temp
796
        }
797
        obj
798
      }
799
    } else {
800
      return(obj)
801
    }
802
  })
803
  object2 <- methods::new("vrMetadata", 
804
                          molecule = object2$molecule, 
805
                          cell = object2$cell, 
806
                          spot = object2$spot, 
807
                          ROI = object2$ROI, 
808
                          tile = object2$tile)
809
810
  # return
811
  return(list(object1 = object1, object2 = object2))
812
}
813
814
changeSampleNamesvrMetadata <- function(object, sample_metadata_table){
815
816
  # get old and new samples
817
  old.samples <- sample_metadata_table$Sample
818
  new.samples <- sample_metadata_table$NewSample
819
820
  # check all types in the vrMetadata object
821
  new_object <- object
822
  all_types <- methods::slotNames(object)
823
  for(type in all_types){
824
    metadata <- methods::slot(object, name = type)
825
    new_metadata <-  methods::slot(new_object, name = type)
826
    if(nrow(new_metadata) > 0){
827
828
      # change samples
829
      for(i in seq_len(length(old.samples)))
830
        new_metadata$Sample[new_metadata$Sample==old.samples[i]] <- new.samples[i]
831
832
      # change layers
833
      for(i in seq_len(nrow(sample_metadata_table))){
834
        new_metadata$Layer[grepl(paste0(sample_metadata_table$AssayID[i], "$"), rownames(new_metadata))] <- sample_metadata_table[sample_metadata_table$AssayID[i], "NewLayer"]
835
      }
836
837
      # rewrite metadata type
838
      methods::slot(new_object, name = type) <- new_metadata
839
    }
840
  }
841
842
  # return
843
  return(new_object)
844
}
845
846
#' changeSampleNames.vrMetadata
847
#'
848
#' Change the sample names of the vrMetadata object and reorient layers if needed
849
#' This functions requires the new and old sample and layer names passed from \code{changeSampleNames.VoltRon}
850
#'
851
#' @param sample_metadata_table the sample metadata with old and new layers and samples passed from \code{changeSampleNames.VoltRon}
852
#' 
853
#' @rdname changeSampleNames
854
#' @method changeSampleNames vrMetadata
855
#'
856
#' @importFrom methods slot slot<- slotNames
857
#'
858
#' @noRd
859
setMethod("changeSampleNames", "vrMetadata", changeSampleNamesvrMetadata)
860
861
### Sample Methods ####
862
863
vrSampleNamesvrMetadata <- function(object){
864
  
865
  # get assay names from metadata
866
  sample_names <- NULL
867
  for(sl in methods::slotNames(object)){
868
    cur_metadata <- slot(object, name = sl)
869
    sample_names <- c(sample_names, unique(cur_metadata$Sample))
870
  }
871
  
872
  # return
873
  sample_names
874
}
875
876
#' @rdname vrSampleNames
877
#' @method vrSampleNames vrMetadata
878
#'
879
#' @importFrom methods slotNames
880
#' @export
881
setMethod("vrSampleNames", "vrMetadata", vrSampleNamesvrMetadata)
882
883
####
884
# Functions ####
885
####
886
887
#' setVRMetadata
888
#'
889
#' @param molecule molecule data frame
890
#' @param cell cell data frame
891
#' @param spot spot data frame
892
#' @param ROI ROI data frame
893
#' @param tile tile data frame
894
#'
895
#' @importFrom methods new
896
#'
897
#' @noRd
898
setVRMetadata <- function(metadata, data, entityID, main.assay, assay.type, sample_name, layer_name, version){
899
  
900
  if(is.null(metadata)){
901
902
    # set metadata
903
    vr_metadata <- list(molecule = data.table::data.table(),
904
                        cell = data.frame(),
905
                        spot = data.frame(),
906
                        ROI = data.frame(),
907
                        tile = data.table::data.table())
908
909
    # create entity IDs using Assay index, make it colnames
910
    entityID <- stringr::str_replace(entityID, pattern = "$", paste0("_Assay1"))
911
912
    # create metadata
913
    # slot(vr_metadata, name = assay.type) <-
914
    if(version == "v1"){
915
      vr_metadata[[assay.type]] <- 
916
        data.frame(Count = Matrix::colSums(data),
917
                   assay_id = "Assay1",
918
                   Assay = main.assay,
919
                   Layer = layer_name,
920
                   Sample = sample_name,
921
                   row.names = entityID) 
922
    } else if (version == "v2"){
923
      vr_metadata[[assay.type]] <- 
924
        data.frame(id = entityID,
925
                   Count = Matrix::colSums(data),
926
                   assay_id = "Assay1",
927
                   Assay = main.assay,
928
                   Layer = layer_name,
929
                   Sample = sample_name,
930
                   row.names = entityID) 
931
    }
932
933
  } else {
934
    if(any(is(metadata) %in% c("data.table", "data.frame", "matrix"))){
935
      vr_metadata <- list(molecule = data.table::data.table(),
936
                          cell = data.frame(),
937
                          spot = data.frame(),
938
                          ROI = data.frame(),
939
                          tile = data.table::data.table())
940
941
      # if metadata is a data.table
942
      if(inherits(metadata, "data.table")){
943
944
        # if there are no id column, insert entityID
945
        if(!"id" %in% colnames(metadata)){
946
          metadata$id <- entityID  
947
        }
948
        
949
        # check ID names
950
        if(length(setdiff(metadata$id, entityID)) > 0){
951
          stop("Entity IDs are not matching")
952
        } else {
953
954
          # entity IDs
955
          metadata <- subset(metadata, subset = entityID %in% id)
956
957
          # create entity IDs using Assay index, make it colnames
958
          set.seed(nrow(metadata$id))
959
          entityID <- paste0(metadata$id, "_", ids::random_id(bytes = 3, use_openssl = FALSE))
960
961
          if(nrow(data) > 0){
962
            suppressWarnings({
963
              vr_metadata[[assay.type]] <-
964
                data.table::data.table(id = entityID,
965
                                       assay_id = "Assay1",
966
                                       Count = Matrix::colSums(data),
967
                                       Assay = main.assay,
968
                                       Layer = layer_name,
969
                                       Sample = sample_name,
970
                                       metadata[,-"id"])
971
            })
972
          } else{
973
            suppressWarnings({
974
              vr_metadata[[assay.type]] <-
975
                  data.table::data.table(id = entityID,
976
                                         assay_id = "Assay1",
977
                                         Assay = main.assay,
978
                                         Layer = layer_name,
979
                                         Sample = sample_name, 
980
                                         metadata[,-"id"])
981
            })
982
          }
983
        }
984
985
      # if metadata is a regular data.frame
986
      } else if(inherits(metadata, "data.frame")){
987
988
        # check row names
989
        if(length(setdiff(rownames(metadata), entityID)) > 0){
990
          stop("Entity IDs are not matching")
991
        } else {
992
993
          # entity IDs
994
          if(version == "v1") {
995
            metadata <- metadata[entityID,] 
996
          } else if(version == "v2") {
997
            
998
            # if there are no id column, insert entityID
999
            if(!"id" %in% colnames(metadata)){
1000
              metadata$id <- entityID  
1001
            }
1002
            metadata <- metadata[match(entityID, metadata$id),]
1003
          }
1004
1005
          # create entity IDs using Assay index, make it colnames
1006
          entityID <- stringr::str_replace(entityID, pattern = "$", paste0("_Assay1"))
1007
1008
          # create metadata for version 1
1009
          if(version == "v1"){
1010
            if(nrow(data) > 0){
1011
              vr_metadata[[assay.type]] <-
1012
                data.frame(Count = Matrix::colSums(data),
1013
                           assay_id = "Assay1",
1014
                           Assay = main.assay,
1015
                           Layer = layer_name,
1016
                           Sample = sample_name,
1017
                           metadata, 
1018
                           row.names = entityID)
1019
            } else{
1020
              vr_metadata[[assay.type]] <-
1021
                data.frame(assay_id = "Assay1",
1022
                           Assay = main.assay,
1023
                           Layer = layer_name,
1024
                           Sample = sample_name,
1025
                           metadata,
1026
                           row.names = entityID)
1027
            } 
1028
          
1029
          # create metadata for version 2
1030
          } else if(version == "v2"){
1031
            if(nrow(data) > 0){
1032
              vr_metadata[[assay.type]] <-
1033
                data.frame(id = entityID,
1034
                           Count = Matrix::colSums(data),
1035
                           assay_id = "Assay1",
1036
                           Assay = main.assay,
1037
                           Layer = layer_name,
1038
                           Sample = sample_name,
1039
                           metadata, 
1040
                           row.names = entityID)
1041
            } else{
1042
              vr_metadata[[assay.type]] <-
1043
                data.frame(id = entityID,
1044
                           Assay = main.assay,
1045
                           assay_id = "Assay1",
1046
                           Layer = layer_name,
1047
                           Sample = sample_name,
1048
                           metadata,
1049
                           row.names = entityID)
1050
            }
1051
          }
1052
          
1053
        }
1054
      }
1055
    }
1056
  }
1057
  
1058
  return(
1059
    list(
1060
      entityID = entityID,
1061
      vr_metadata =  methods::new("vrMetadata", 
1062
                                 molecule = vr_metadata$molecule, 
1063
                                 cell = vr_metadata$cell, 
1064
                                 spot = vr_metadata$spot, 
1065
                                 ROI = vr_metadata$ROI, 
1066
                                 tile = vr_metadata$tile)
1067
    )
1068
  )
1069
}
1070
1071
#' setVRSampleMetadata
1072
#'
1073
#' @param samples a list of vrSample object
1074
#'
1075
#' @noRd
1076
setVRSampleMetadata <- function(samples){
1077
1078
  # imput missing sample names
1079
  # sample_name_ind <- sapply(names(samples), is.null)
1080
  sample_name_ind <- vapply(names(samples), is.null, logical(1))
1081
  if(length(sample_name_ind) > 0){
1082
    names_samples <- names(samples)
1083
    if(any(sample_name_ind)){
1084
      null_samples_ind <- which(sample_name_ind)
1085
      names_samples[null_samples_ind] <- paste0("Sample", null_samples_ind)
1086
    }
1087
  } else {
1088
    names_samples <- paste0("Sample", seq_len(length(samples)))
1089
  }
1090
1091
  # get sample metadata
1092
  sample_list <- names(samples)
1093
  sample.metadata <- NULL
1094
  for(i in seq_len(length(sample_list))){
1095
    layer_list <- samples[[sample_list[i]]]@layer
1096
    layer_data <- NULL
1097
    for(j in seq_len(length(layer_list))){
1098
      assay_list <- layer_list[[j]]@assay
1099
      layer_data <- rbind(layer_data, cbind(names(assay_list), names(layer_list)[j]))
1100
    }
1101
    sample.metadata <- rbind(sample.metadata, cbind(layer_data, sample_list[i]))
1102
  }
1103
  sample.metadata <- data.frame(sample.metadata, row.names = paste0("Assay", seq_len(nrow(sample.metadata))))
1104
  colnames(sample.metadata) <- c("Assay", "Layer", "Sample")
1105
1106
  sample.metadata
1107
}