Skip to contents

SpatialMap Structure

Schematic

SpatialMap Schematic ## R internal schematic

To view a SpatialMap (SM) object in R, let’s load one and print the output of str()

sm_tonsil <- load_sm_data("tonsil")
str(sm_tonsil)
#> Formal class 'SpatialMap' [package "SpatialMap"] with 8 slots
#>   ..@ regions        :List of 2
#>   .. ..$ TonsilA:Formal class 'Region' [package "SpatialMap"] with 16 slots
#>   .. .. .. ..@ Data           : num [1:16, 1:5810] 25.4 616.5 96.7 25.4 192.5 ...
#>   .. .. .. .. ..- attr(*, "dimnames")=List of 2
#>   .. .. .. .. .. ..$ : chr [1:16] "CD3e" "CD21" "CD68" "Actin" ...
#>   .. .. .. .. .. ..$ : chr [1:5810] "TonsilA.125182" "TonsilA.125238" "TonsilA.125254" "TonsilA.125325" ...
#>   .. .. .. ..@ NormalizedData : NULL
#>   .. .. .. ..@ ScaledData     : NULL
#>   .. .. .. ..@ bgData         : num [1:16, 1:5810] 2242 2328.1 67.1 1433.4 195.4 ...
#>   .. .. .. .. ..- attr(*, "dimnames")=List of 2
#>   .. .. .. .. .. ..$ : chr [1:16] "DAPI_ch1_cyc7" "DAPI_ch1_cyc8" "Blank_ch2_cyc8" "Blank_ch3_cyc8" ...
#>   .. .. .. .. .. ..$ : chr [1:5810] "TonsilA.125182" "TonsilA.125238" "TonsilA.125254" "TonsilA.125325" ...
#>   .. .. .. ..@ coordinates    :'data.frame': 5810 obs. of  14 variables:
#>   .. .. .. .. ..$ study_id      : num [1:5810] 266 266 266 266 266 266 266 266 266 266 ...
#>   .. .. .. .. ..$ acquisition_id: chr [1:5810] "EnableShare_c001_v001_r001_reg001" "EnableShare_c001_v001_r001_reg001" "EnableShare_c001_v001_r001_reg001" "EnableShare_c001_v001_r001_reg001" ...
#>   .. .. .. .. ..$ cell_id       : num [1:5810] 125182 125238 125254 125325 125326 ...
#>   .. .. .. .. ..$ region        : num [1:5810] 1 1 1 1 1 1 1 1 1 1 ...
#>   .. .. .. .. ..$ tile_num      : num [1:5810] 1 1 1 1 1 1 1 1 1 1 ...
#>   .. .. .. .. ..$ x             : num [1:5810] 891 935 34 18 997 ...
#>   .. .. .. .. ..$ y             : num [1:5810] 1996 1993 1991 1985 1986 ...
#>   .. .. .. .. ..$ z             : num [1:5810] 0 0 0 0 0 0 0 0 0 0 ...
#>   .. .. .. .. ..$ x_tile        : num [1:5810] 891 935 34 18 997 ...
#>   .. .. .. .. ..$ y_tile        : num [1:5810] 1996 1993 1991 1985 1986 ...
#>   .. .. .. .. ..$ size          : num [1:5810] 484 763 357 417 520 651 358 528 370 193 ...
...

A bit complex! To abstract the getting and setting of different data types, the SM package provides simple methods to retrieve data in the most common ways. The general framework for this type of object and methods is described in detail in Hadley Wickam’s excellent book on object-oriented programming in R, particularly the section on S4 classes. This approach simplifies the organization of code, and minimizes the unnecessary duplication of data in memory.

Getting and Setting

Here is a demonstration of many “get” methods for SM objects.

SpatialMap-level data

Retrieving Regions and Analyses


## S4 Methods

# Get a Region by name (returns a Region)
getRegion(sm_tonsil, "TonsilA")
#> Region object
#> ID: TonsilA
#> + 5,810 cells
#> + 16 features

# Get multiple Regions, or named subset of them (returns a list)
getRegions(sm_tonsil)
#> $TonsilA
#> Region object
#> ID: TonsilA
#> + 5,810 cells
#> + 16 features
#> 
#> $TonsilB
#> Region object
#> ID: TonsilB
#> + 10,694 cells
#> + 16 features
getRegions(sm_tonsil, c("TonsilA", "TonsilB"))
#> $TonsilA
#> Region object
#> ID: TonsilA
#> + 5,810 cells
#> + 16 features
#> 
#> $TonsilB
#> Region object
#> ID: TonsilB
#> + 10,694 cells
#> + 16 features

# List Region IDs
Regions(sm_tonsil)
#> [1] "TonsilA" "TonsilB"

## Base R Methods

# Get Regions by indexing
sm_tonsil[[1]]
#> Region object
#> ID: TonsilA
#> + 5,810 cells
#> + 16 features
sm_tonsil[["TonsilA"]]
#> Region object
#> ID: TonsilA
#> + 5,810 cells
#> + 16 features
sm_tonsil$TonsilA
#> Region object
#> ID: TonsilA
#> + 5,810 cells
#> + 16 features

# Subset SpatialMaps by indexing
sm_tonsil[1:2]
#> SpatialMap object 
#> Active analysis:  regions 
#> +  16,504 total cells 
#> +  16 features 
#> +  2 Regions: 
#>   - TonsilA
#>   - TonsilB
sm_tonsil[c("TonsilA", "TonsilB")]
#> SpatialMap object 
#> Active analysis:  regions 
#> +  16,504 total cells 
#> +  16 features 
#> +  2 Regions: 
#>   - TonsilA
#>   - TonsilB

Equivalent methods are available to access combined single-cell Analyses


sm_tonsil <- createAnalysis(sm_tonsil)
#> New analysis created.
#>  2 Regions
#>  16504 cells
#>  16 common features
#> 
#> Added Analysis `combined` to SpatialMap project 'SpatialMap Project'.
#> Setting as active Analysis
#> 

# List Analyses
Analyses(sm_tonsil)
#> [1] "combined"

# Get an Analysis
getAnalysis(sm_tonsil, "combined")
#> Analysis object
#> ID: combined
#> + 16,504 cells
#> + 16 common features
#> + 2 Regions:
#>   - TonsilA
#>   - TonsilB

Retrieving other SM slots

SM data slots can also be accessed with SM methods. To see SM slots, and their allowed data types, use the getSlots function.

To pull up a list of SM slots in an interactive IDE (RStudio), use the @ accessor.


getSlots("SpatialMap")
#>           regions          analyses     activeRegions    activeAnalysis 
#>            "list"             "ANY"             "ANY"             "ANY" 
#>   projectMetadata       projectName    projectSummary          settings 
#>      "data.frame" "characterOrNull" "characterOrNull"            "list"

sm_tonsil@settings
#> $cores
#> [1] 1
#> 
#> $parallel
#> [1] "future"
#> 
#> $future.initialized
#> [1] FALSE
#> 
#> $show.progress
#> [1] FALSE
#> 
#> $Rstudio
#> [1] TRUE
#> 
...
settings(sm_tonsil)
#>                      cores                   parallel 
#>                        "1"                   "future" 
#>         future.initialized              show.progress 
#>                    "FALSE"                    "FALSE" 
#>                    Rstudio                python.path 
#>                     "TRUE"                     "none" 
#>         python.environment              python.method 
#>            "spatialmap_py"               "reticulate" 
#>                   platform               local.images 
#>                     "unix"                    "FALSE" 
#>                 filtration              normalization 
#>                     "soft"                      "log" 
#>              max_cell.size              min_cell.size 
#>                     "1600"                      "100" 
#>             max_signal.sum             min_signal.sum 
...

projectMetadata(sm_tonsil)
#>             color width n_channels height           projection_visualizer_uuid
#> TonsilA grayscale  9408          4   9072 96e6af5a-f612-4f97-a294-c580dcd41915
#> TonsilB grayscale  9408          4   9072 f0b41218-209e-4946-9a1d-1fb7fb3e7a0d
#>         sample_label n_levels assay_id n_cycles
#> TonsilA  EnableShare        5        1        8
#> TonsilB EnableShare2        5        1        8
#>                   base_image_visualizer_uuid experiment_label axes
#> TonsilA 728d42b7-77ea-4319-a48a-7f7340bf182d      enableshare TCYX
#> TonsilB 2007da53-7ede-492e-84b6-f2d2ab32a09d     enableshare2 TCYX
#>                                    assay_metadata assay_description
#> TonsilA {"image_mpp": 0.377, "num_amp_cycles": 0}                  
#> TonsilB {"image_mpp": 0.377, "num_amp_cycles": 0}                  
#>         experiment_id visual_quality assay_name region_display_label
#> TonsilA           164           true      CODEX          EnableShare
#> TonsilB           355           true      CODEX         EnableShare2
...
activeRegions(sm_tonsil)
#> [1] "TonsilA" "TonsilB"
activeAnalysis(sm_tonsil)
#> [1] "combined"

Setting new values for SM slots

To update these slots, we can use “setter” methods


## Project metadata is a data frame
pm <- projectMetadata(sm_tonsil)
pm$RandomData <- LETTERS[c(5, 16)]

projectMetadata(sm_tonsil) <- pm

activeRegions(sm_tonsil) <- c("TonsilA", "TonsilB")

activeAnalysis(sm_tonsil) <- "regions"
activeAnalysis(sm_tonsil)
#> [1] "regions"

Remember that updating activeRegions and activeAnalysis will change the behavior of almost all SM functions!

Region-level data

Most SpatialMap functions are designed to operate on SM objects, even if they actually affect data in individual Regions. As an example, we will look at cellMetadata.


## cellMetadata is stored on an individual Region level
head(sm_tonsil$TonsilA@cellMetadata)
#>                cell_id        cell.id anno316_some_categories anno916_Leiden_v1
#> TonsilA.125182  125182 TonsilA.125182                     yay         Cluster 2
#> TonsilA.125238  125238 TonsilA.125238                     nay         Cluster 2
#> TonsilA.125254  125254 TonsilA.125254                     yay         Cluster 1
#> TonsilA.125325  125325 TonsilA.125325                     yay         Cluster 1
#> TonsilA.125326  125326 TonsilA.125326                     nay         Cluster 6
#> TonsilA.125608  125608 TonsilA.125608                     nay         Cluster 1
#>                anno248_test_subset_annotation_324
#> TonsilA.125182                                  p
#> TonsilA.125238                                  u
#> TonsilA.125254                                  t
#> TonsilA.125325                                  t
#> TonsilA.125326                                  b
#> TonsilA.125608                                  y
#>                anno1189_uqc_test10_letters_qc_assoc anno1149_uqc_test10_letters
...

## the Getter function works well for an individual Region
cm1 <- cellMetadata(sm_tonsil$TonsilA)
head(cm1)
#>                cell_id        cell.id anno316_some_categories anno916_Leiden_v1
#> TonsilA.125182  125182 TonsilA.125182                     yay         Cluster 2
#> TonsilA.125238  125238 TonsilA.125238                     nay         Cluster 2
#> TonsilA.125254  125254 TonsilA.125254                     yay         Cluster 1
#> TonsilA.125325  125325 TonsilA.125325                     yay         Cluster 1
#> TonsilA.125326  125326 TonsilA.125326                     nay         Cluster 6
#> TonsilA.125608  125608 TonsilA.125608                     nay         Cluster 1
#>                anno248_test_subset_annotation_324
#> TonsilA.125182                                  p
#> TonsilA.125238                                  u
#> TonsilA.125254                                  t
#> TonsilA.125325                                  t
#> TonsilA.125326                                  b
#> TonsilA.125608                                  y
#>                anno1189_uqc_test10_letters_qc_assoc anno1149_uqc_test10_letters
...
dim(cm1)
#> [1] 5810   38

## And for the whole SM object
cm.all <- cellMetadata(sm_tonsil)

## The SM function combines all Region@cellMetadata slots into one data.frame
dim(cm.all)
#> [1] 16504    38

Similar rules apply to most of the Region slots. There are slightly different rules based on whether output from multiple Regions is concatenated (as in the cellMetadata) case, intersected (in the case of the features() getter, only features in common for all Regions will be returned), or listed (the output is not combined, but instead returned as a list per Region)


activeAnalysis(sm_tonsil) <- "regions"

## Concatenate
Data(sm_tonsil, "Data") %>% med()
#> Matrix dim 16 x 16504
#>        TonsilA.125182 TonsilA.125238 TonsilA.125254 TonsilA.125325
#> CD3e           25.430         32.674         47.148         43.724
#> CD21          616.531        264.544        295.633        342.288
#> CD68           96.736        115.676        400.171        376.578
#> Actin          25.351         30.097         68.339         75.369
#> CD45RO        192.475        159.933        597.997        558.926
#> HisH3p         54.665         55.067         53.076         62.578
#>        TonsilA.125326 TonsilA.125608
#> CD3e           26.698         27.512
#> CD21          217.321        241.673
#> CD68          206.606        233.141
#> Actin          32.975         46.071
#> CD45RO        293.971        205.307
#> HisH3p         59.348         57.280
cellMetadata(sm_tonsil) %>% med()
#> Data Frame dim 16504 x 38
#>                cell_id        cell.id anno316_some_categories anno916_Leiden_v1
#> TonsilA.125182  125182 TonsilA.125182                     yay         Cluster 2
#> TonsilA.125238  125238 TonsilA.125238                     nay         Cluster 2
#> TonsilA.125254  125254 TonsilA.125254                     yay         Cluster 1
#> TonsilA.125325  125325 TonsilA.125325                     yay         Cluster 1
#> TonsilA.125326  125326 TonsilA.125326                     nay         Cluster 6
#> TonsilA.125608  125608 TonsilA.125608                     nay         Cluster 1
#>                anno248_test_subset_annotation_324
#> TonsilA.125182                                  p
#> TonsilA.125238                                  u
#> TonsilA.125254                                  t
#> TonsilA.125325                                  t
#> TonsilA.125326                                  b
#> TonsilA.125608                                  y
#>                anno1189_uqc_test10_letters_qc_assoc
...
cells(sm_tonsil) %>% med()
#> Character vector,  length:  16504
#> [1] "TonsilA.125182" "TonsilA.125238" "TonsilA.125254" "TonsilA.125325"
#> [5] "TonsilA.125326" "TonsilA.125608"

## Intersect
bgFeatures(sm_tonsil)
#>  [1] "DAPI_ch1_cyc7"  "DAPI_ch1_cyc8"  "Blank_ch2_cyc8" "Blank_ch3_cyc8"
#>  [5] "Blank_ch4_cyc8" "DAPI_ch1_cyc1"  "Blank_ch2_cyc1" "Blank_ch3_cyc1"
#>  [9] "Blank_ch4_cyc1" "DAPI_ch1_cyc2"  "DAPI_ch1_cyc3"  "Empty_ch2_cyc3"
#> [13] "DAPI_ch1_cyc4"  "DAPI_ch1_cyc5"  "DAPI_ch1_cyc6"  "Empty_ch2_cyc6"
features(sm_tonsil)
#>  [1] "CD3e"       "CD21"       "CD68"       "Actin"      "CD45RO"    
#>  [6] "HisH3p"     "PanCK"      "Ki67"       "CD11c"      "ECad"      
#> [11] "CD4"        "CD31"       "Podoplanin" "CD107a"     "CD20"      
#> [16] "CD8"

## List per Region
embeddings(sm_tonsil, "spatial")
#> $TonsilA
#>                   x    y
#> TonsilA.125182  891 1996
#> TonsilA.125238  935 1993
#> TonsilA.125254   34 1991
#> TonsilA.125325   18 1985
#> TonsilA.125326  997 1986
#> TonsilA.125608   13 1964
#> TonsilA.125729  879 1956
#> TonsilA.125925    9 1938
#> TonsilA.126062 1736 1928
#> TonsilA.126166 1750 1919
#> TonsilA.126199  955 1917
#> TonsilA.126219  902 1921
#> TonsilA.126569  963 1889
...

Representations(sm_tonsil, "spatial")
#> $TonsilA
#> Representation object 'spatial' 
#>  Dimensions: 'x', 'y' 
#>  5810 cells 
#> 
#> $TonsilB
#> Representation object 'spatial' 
#>  Dimensions: 'x', 'y' 
#>  10694 cells

In the future, additional methods will be added to summon images and masks. The infrastructure for retrieving these files from Enable DB is under construction.

Behind the scenes, most SpatialMap functions work using these methods. .smapply for instance, first dispatches on the activeAnalysis, iterating, grouping, or combining samples (with a Formal Analysis). Then it runs a function to perform some computation. Then it updates the appropriate data slots, replaces the old Regions with the modified ones, and returns a modified SpatialMap.

Scroll to top