@@ -506,13 +506,17 @@ GetResidual <- function(
506506# ' passed in it should be co-indexed with \code{`bin.size`}
507507# ' @param segmentation.type Which segmentations to load (cell or nucleus) when bin.size includes "polygons".
508508# ' Defaults to "cell".
509+ # ' @param compact Whether to store segmentations in \emph{only} the \code{sf.data} slot
510+ # ' in the corresponding Segmentation object (default TRUE) to save memory and processing time.
511+ # ' If FALSE, segmentations are also stored in \code{\link[sp]{sp}} format in addition to the \code{sf.data} slot.
509512# ' @param image.name Name of the tissue image to be plotted. Defaults to tissue_lowres_image.png
510513# ' @param ... Arguments passed to \code{\link{Read10X_h5}}
511514# '
512515# ' @return A \code{Seurat} object
513516# '
514517# ' @importFrom png readPNG
515518# ' @importFrom jsonlite fromJSON
519+ # ' @importFrom SeuratObject DefaultBoundary<-
516520# '
517521# ' @export
518522# ' @concept preprocessing
@@ -536,6 +540,7 @@ Load10X_Spatial <- function (
536540 image = NULL ,
537541 image.name = " tissue_lowres_image.png" ,
538542 segmentation.type = NULL ,
543+ compact = TRUE ,
539544 ...
540545) {
541546 # if more than one directory is passed in
@@ -669,6 +674,11 @@ Load10X_Spatial <- function (
669674
670675 # read segmentation data if requested
671676 if (load.segmentations ) {
677+ # Check for required packages, stop with clear message if missing
678+ if (! requireNamespace(" sf" , quietly = TRUE )) {
679+ stop(" The 'sf' package must be installed to load segmentation data." )
680+ }
681+
672682 segmentation.assay.name <- paste0(assay , " .Polygons" )
673683 seg.data.dir <- file.path(data.dir , " segmented_outputs" )
674684
@@ -710,49 +720,22 @@ Load10X_Spatial <- function (
710720 image.dir = file.path(seg.data.dir , " spatial" ),
711721 data.dir = data.dir ,
712722 image.name = image.name ,
713- segmentation.type = segmentation.type
714- )
715-
716- # Holds the segmentation object
717- segmentation_obj <- visium.segmentation @ boundaries $ segmentation
718-
719- # Get sf data
720- sf_data <- visium.segmentation @ boundaries $ segmentation @ sf.data
721-
722- # Set the attribute-geometry relationship to constant
723- # See https://r-spatial.github.io/sf/reference/sf.html#details
724- st_agr(sf_data ) <- " constant"
725-
726- # Create a dataframe from sf data to hold centroids
727- centroids_obj <- visium.segmentation @ boundaries $ centroids
728- centroid_coords <- sf :: st_coordinates(sf :: st_centroid(sf_data ))
729- centroids_df <- data.frame (
730- x = centroid_coords [, " X" ],
731- y = centroid_coords [, " Y" ],
732- row.names = sf_data $ barcodes
723+ segmentation.type = segmentation.type ,
724+ compact = compact
733725 )
734726
735- # Create centroids object
736- centroids <- CreateCentroids(centroids_df ,
737- nsides = Inf ,
738- radius = NULL ,
739- theta = 0 )
740-
741- # Add centroids to the Visium object
742- visium.segmentation @ boundaries $ centroids <- centroids
743-
744727 # Create a new Seurat object with the raw counts
745728 segmentation.object <- CreateSeuratObject(
746729 segmentation.counts ,
747730 assay = segmentation.assay.name
748731 )
749-
750- # Make sure the list of cell names between segmentations & raw counts matches exactly
732+
733+ common_cells <- unique(Cells( visium.segmentation )[Cells( visium.segmentation ) %in% Cells( segmentation.object )])
751734 visium.segmentation <- subset(
752735 x = visium.segmentation ,
753- cells = intersect(Cells( segmentation.object ), Cells( visium.segmentation ))
736+ cells = common_cells
754737 )
755-
738+
756739 # Set the default boundary type to centroids for plotting
757740 DefaultBoundary(object = visium.segmentation ) <- " centroids"
758741
@@ -1426,23 +1409,31 @@ Read10X_Image <- function(
14261409
14271410 # Create an `sp` compatible `FOV` instance.
14281411 fov <- CreateFOV(
1429- coordinates [, c(" imagerow " , " imagecol " )],
1412+ coordinates [, c(" imagecol " , " imagerow " )],
14301413 type = " centroids" ,
14311414 radius = scale.factors [[" spot" ]],
14321415 assay = assay ,
14331416 key = key
14341417 )
14351418
1436- # Build the final `VisiumV2` instance, essentially just adding `image` and
1437- # `scale.factors` to the `fov`.
1419+ # ### NOTE ####
1420+ # The Visium coordinate system takes the origin to be in the top-left corner,
1421+ # where the x-axis is horizontal and associated with the image column.
1422+ # We mark this with the coords_x_orientation flag.
1423+ # Older Visium objects in Seurat have a different system (x-axis vertical, etc),
1424+ # which is updated after checking whether the flag is set (SeuratObject::UpdateSeuratObject).
1425+ # ##############
1426+
1427+ # Build the final `VisiumV2` instance
14381428 visium.v2 <- new(
14391429 Class = " VisiumV2" ,
14401430 boundaries = fov @ boundaries ,
14411431 molecules = fov @ molecules ,
14421432 assay = fov @ assay ,
14431433 key = fov @ key ,
14441434 image = image ,
1445- scale.factors = scale.factors
1435+ scale.factors = scale.factors ,
1436+ coords_x_orientation = " horizontal"
14461437 )
14471438
14481439 return (visium.v2 )
@@ -1548,6 +1539,7 @@ Read10X_ScaleFactors <- function(filename) {
15481539# ' @param assay Name of assay to associate segmentations to
15491540# ' @param slice Name of the slice to associate the segmentations to
15501541# ' @param segmentation.type Which segmentations to load, cell or nucleus. If using nucleus the full matrix from cells is still used
1542+ # ' @param compact Whether to store segmentations in only the \code{sf.data} slot; see \code{\link{Load10X_Spatial}} for details
15511543# '
15521544# '
15531545# ' @return A VisiumV2 object with segmentations
@@ -1560,27 +1552,30 @@ Read10X_Segmentations <- function (image.dir,
15601552 image.name = " tissue_lowres_image.png" ,
15611553 assay = " Spatial.Polygons" ,
15621554 slice = " slice1.polygons" ,
1563- segmentation.type = " cell" ) {
1564-
1565- image <- png :: readPNG(source = file.path(image.dir , image.name ))
1566-
1567- scale.factors <- Read10X_ScaleFactors(filename = file.path(image.dir ,
1568- " scalefactors_json.json" ))
1569- key <- Key(slice , quiet = TRUE )
1555+ segmentation.type = " cell" ,
1556+ compact = TRUE ) {
15701557
1571- # Pass proper scale.factor based on whether image is lowres or hires
1572- # We assume if not lowres it is hires - image has been validated above
1573- scale.factor <- if (grepl(" lowres" , image.name )) " lowres" else " hires"
15741558
1575- sf.data <- Read10X_HD_GeoJson(data.dir = data.dir ,
1576- image.dir = image.dir ,
1559+ sf.obj <- Read10X_HD_GeoJson(data.dir = data.dir ,
15771560 segmentation.type = segmentation.type )
1561+
1562+ # Create a Segmentation object; populate it based on the coordinates from the sf object
1563+ segmentations <- CreateSegmentation(sf.obj , compact = compact )
15781564
1579- # Create a Segmentation object based on sf, populate sf.data and polygons
1580- segmentation <- CreateSegmentation(sf.data )
1565+ # Create a Centroids object; populate it based on the centroids from the sf object
1566+ centroids <- CreateCentroids(sf.obj ,
1567+ nsides = Inf ,
1568+ radius = NULL ,
1569+ theta = 0 )
15811570
1582- # Named list with segmentation
1583- boundaries <- list (segmentation = segmentation )
1571+ # Named list with segmentations and centroids
1572+ boundaries <- list (segmentations = segmentations , centroids = centroids )
1573+
1574+ # Get image, scale factors, key
1575+ image <- png :: readPNG(source = file.path(image.dir , image.name ))
1576+ scale.factors <- Read10X_ScaleFactors(filename = file.path(image.dir ,
1577+ " scalefactors_json.json" ))
1578+ key <- Key(slice , quiet = TRUE )
15841579
15851580 # Build VisiumV2 object
15861581 visium.v2 <- new(
@@ -1589,11 +1584,13 @@ Read10X_Segmentations <- function (image.dir,
15891584 assay = assay ,
15901585 key = key ,
15911586 image = image ,
1592- scale.factors = scale.factors
1587+ scale.factors = scale.factors ,
1588+ coords_x_orientation = " horizontal"
15931589 )
15941590
15951591 return (visium.v2 )
15961592}
1593+
15971594# ' Format 10X Genomics GeoJson cell IDs
15981595# '
15991596# ' @param ids Vector of cell IDs to format
@@ -1619,25 +1616,24 @@ Format10X_GeoJson_CellID <- function(ids, prefix = "cellid_", suffix = "-1", dig
16191616# ' Load 10X Genomics GeoJson
16201617# '
16211618# ' @param data.dir Path to the directory containing matrix data
1622- # ' @param image.dir Path to the directory with spatial GeoJSON data
16231619# ' @param segmentation.type Which segmentations to load, cell or nucleus. If using nucleus the full matrix from cells is still used
16241620# '
1625- # ' @return A FOV
1621+ # ' @return An \code{sf} object containing polygon segmentations from the GeoJSON provided by 10x, formatted for downstream coordinate retrieval
16261622# '
16271623# ' @export
16281624# ' @concept preprocessing
16291625# '
1630- Read10X_HD_GeoJson <- function (data.dir , image.dir , segmentation.type = " cell" ) {
1631- segmentation_polygons <- read_sf(file.path(data.dir ," segmented_outputs" , paste0(segmentation.type , " _segmentations.geojson" )))
1626+ Read10X_HD_GeoJson <- function (data.dir , segmentation.type = " cell" ) {
1627+ segmentation_polygons <- sf :: read_sf(file.path(data.dir ," segmented_outputs" , paste0(segmentation.type , " _segmentations.geojson" )))
16321628
16331629 # Restructure sf geometry for downstream compatibility
1634- segmentation_polygons $ geometry <- lapply(
1630+ segmentation_polygons $ geometry <- sf :: st_sfc( lapply(
16351631 segmentation_polygons $ geometry ,
16361632 function (geom ) {
16371633 coords <- geom [[1 ]]
1638- st_polygon(list (coords ))
1634+ sf :: st_polygon(list (coords ))
16391635 }
1640- ) % > % st_sfc( crs = st_crs(NA ))
1636+ ), crs = sf :: st_crs(NA ))
16411637
16421638 segmentation_polygons $ barcodes <- Format10X_GeoJson_CellID(segmentation_polygons $ cell_id )
16431639 segmentation_polygons
@@ -3747,7 +3743,7 @@ RunMoransI <- function(data, pos, verbose = TRUE) {
37473743# '
37483744# ' @examples
37493745# ' data("pbmc_small")
3750- # ' counts = as.matrix(x = GetAssayData(object = pbmc_small, assay = "RNA", slot = "counts"))
3746+ # ' counts = as.matrix(x = GetAssayData(object = pbmc_small, assay = "RNA", layer = "counts"))
37513747# ' downsampled = SampleUMI(data = counts)
37523748# ' head(x = downsampled)
37533749# '
0 commit comments