@@ -14,10 +14,15 @@ SpatialPlot <- function(object, ...) {
1414# ' @rdname SpatialPlot
1515SpatialPlot.Seurat <- function (object , image = NULL , ... ) {
1616 first_image <- Seurat :: Images(object )[1 ]
17+ if (is.null(first_image )) {
18+ stop(" [SpatialPlot] No images found in the Seurat object. Is this an object with spatial data? " )
19+ }
1720 image <- image %|| % first_image
1821 stype <- class(object @ images [[first_image ]])
1922 if (" VisiumV2" %in% stype ) {
2023 SpatialPlot.Seurat.VisiumV2(object , image = image , ... )
24+ } else if (" SlideSeq" %in% stype ) {
25+ SpatialPlot.Seurat.SlideSeq(object , image = NULL , ... )
2126 }
2227}
2328
@@ -27,24 +32,22 @@ SpatialPlot.Seurat <- function(object, image = NULL, ...) {
2732SpatialPlot.Seurat.VisiumV2 <- function (
2833 object , image = NULL , masks = NULL , shapes = NULL , points = NULL , ext = NULL ,
2934 image_scale = NULL , crop = TRUE , group_by = NULL , features = NULL , layer = " data" ,
30- layers = NULL , flip_y = TRUE , theme = " plotthis:: theme_box" , theme_args = list (),
35+ layers = NULL , flip_y = TRUE , theme = " theme_box" , theme_args = list (),
3136 label = FALSE , label_size = 4 , label_fg = " white" , label_bg = " black" , label_bg_r = 0.1 ,
3237 label_repel = FALSE , label_repulsion = 20 , label_pt_size = 1 , label_pt_color = " black" ,
3338 label_segment_color = " black" , label_insitu = FALSE ,
3439 palette = NULL , palette_reverse = FALSE , palcolor = NULL ,
3540 highlight = NULL , highlight_alpha = 1 , highlight_size = 1 , highlight_color = " black" , highlight_stroke = 0.8 ,
3641 legend.position = " right" , legend.direction = " vertical" ,
42+ title = NULL , subtitle = NULL , xlab = NULL , ylab = NULL ,
3743 facet_scales = " fixed" , facet_nrow = NULL , facet_ncol = NULL , facet_byrow = TRUE ,
3844 ...
3945
4046) {
41-
42- ggplot <- if (getOption(" plotthis.gglogger.enabled" , FALSE )) {
43- gglogger :: ggplot
44- } else {
45- ggplot2 :: ggplot
46- }
4747 stopifnot(" [SpatialPlot] Either 'group_by' or 'features' should be provided, not both." = is.null(group_by ) || is.null(features ))
48+ if (theme %in% c(" theme_box" , " theme_this" , " theme_blank" )) {
49+ theme <- utils :: getFromNamespace(theme , " plotthis" )
50+ }
4851
4952 points <- points %|| % TRUE
5053
@@ -70,6 +73,7 @@ SpatialPlot.Seurat.VisiumV2 <- function(
7073 ext_unscaled <- NULL
7174 if (crop ) {
7275 points_data <- Seurat :: GetTissueCoordinates(object )
76+ points_data <- points_data [, colnames(points_data )[! is.na(colnames(points_data ))], drop = FALSE ]
7377 points_data $ .y <- points_data $ x
7478 points_data $ x <- points_data $ y
7579 points_data $ y <- points_data $ .y
@@ -108,6 +112,7 @@ SpatialPlot.Seurat.VisiumV2 <- function(
108112 if (crop ) {
109113 # attach metadata for highlighting selection
110114 points_args $ data <- object @ meta.data [rownames(points_data ), , drop = FALSE ]
115+ points_args $ data <- points_args $ data [, colnames(points_args $ data )[! is.na(colnames(points_args $ data ))], drop = FALSE ]
111116 points_args $ data <- cbind(points_args $ data , points_data )
112117 points_args $ data $ x <- points_args $ data $ x * scale_factor
113118 points_args $ data $ y <- points_args $ data $ y * scale_factor
@@ -126,19 +131,193 @@ SpatialPlot.Seurat.VisiumV2 <- function(
126131 if (! is.null(group_by )) {
127132 points_args $ data [[group_by ]] <- object @ meta.data [[group_by ]]
128133 points_args $ color_by <- group_by
134+ points_args $ label <- points_args $ label %|| % label
135+ points_args $ label_size <- points_args $ label_size %|| % label_size
136+ points_args $ label_fg <- points_args $ label_fg %|| % label_fg
137+ points_args $ label_bg <- points_args $ label_bg %|| % label_bg
138+ points_args $ label_bg_r <- points_args $ label_bg_r %|| % label_bg_r
139+ points_args $ label_repel <- points_args $ label_repel %|| % label_repel
140+ points_args $ label_repulsion <- points_args $ label_repulsion %|| % label_repulsion
141+ points_args $ label_pt_size <- points_args $ label_pt_size %|| % label_pt_size
142+ points_args $ label_pt_color <- points_args $ label_pt_color %|| % label_pt_color
143+ points_args $ label_segment_color <- points_args $ label_segment_color %|| % label_segment_color
144+ points_args $ label_insitu <- points_args $ label_insitu %|| % label_insitu
145+ } else if (! is.null(features )) {
146+ cells_by_image <- utils :: getFromNamespace(" CellsByImage" , " Seurat" )
147+ cells <- unique(cells_by_image(object , images = if (isFALSE(image )) NULL else image , unlist = TRUE ))
148+ featdata <- Seurat :: FetchData(
149+ object = object ,
150+ vars = features ,
151+ cells = cells ,
152+ layer = layer ,
153+ clean = FALSE
154+ )
155+ features <- colnames(featdata )
156+ points_args $ data [, features ] <- featdata
157+ points_args $ color_by <- colnames(featdata )
129158 points_args $ legend.position <- legend.position
130159 points_args $ legend.direction <- legend.direction
131- points_args $ label <- label
132- points_args $ label_size <- label_size
133- points_args $ label_fg <- label_fg
134- points_args $ label_bg <- label_bg
135- points_args $ label_bg_r <- label_bg_r
136- points_args $ label_repel <- label_repel
137- points_args $ label_repulsion <- label_repulsion
138- points_args $ label_pt_size <- label_pt_size
139- points_args $ label_pt_color <- label_pt_color
140- points_args $ label_segment_color <- label_segment_color
141- points_args $ label_insitu <- label_insitu
160+ if (length(features ) == 1 ) {
161+ points_args $ color_name <- points_args $ color_name %|| % features
162+ } else {
163+ points_args $ color_name <- points_args $ color_name %|| % " feature"
164+ facet_by <- " .facet_var"
165+ }
166+ }
167+ points_args $ highlight <- points_args $ highlight %|| % highlight
168+ points_args $ highlight_alpha <- points_args $ highlight_alpha %|| % highlight_alpha
169+ points_args $ highlight_size <- points_args $ highlight_size %|| % highlight_size
170+ points_args $ highlight_color <- points_args $ highlight_color %|| % highlight_color
171+ points_args $ highlight_stroke <- points_args $ highlight_stroke %|| % highlight_stroke
172+ points_args $ palette <- points_args $ palette %|| % palette
173+ points_args $ palette_reverse <- points_args $ palette_reverse %|| % palette_reverse
174+ points_args $ palcolor <- points_args $ palcolor %|| % palcolor
175+ points_args $ legend.position <- legend.position
176+ points_args $ legend.direction <- legend.direction
177+ points_args $ flip_y <- flip_y
178+ points_args $ return_layer <- TRUE
179+ player <- do.call(SpatialPointsPlot , points_args )
180+ scales_reused <- intersect(scales_used , attr(player , " scales" ))
181+ if (" fill" %in% scales_reused ) {
182+ players <- c(players , list (ggnewscale :: new_scale_fill()))
183+ }
184+ players <- c(players , list (player ))
185+ scales_used <- unique(c(scales_used , attr(player , " scales" )))
186+ }
187+ if (element == " masks" && ! is.null(masks )) {
188+ stop(" [SpatialPlot] 'masks' is not supported for Seurat Visium V2 objects." )
189+ }
190+ if (element == " shapes" && ! is.null(shapes )) {
191+ stop(" [SpatialPlot] 'shapes' is not supported for Seurat Visium V2 objects." )
192+ }
193+ }
194+
195+ if (! is.null(ext_unscaled )) {
196+ ext <- ext %|| % ext_unscaled * scale_factor
197+ }
198+
199+ p <- utils :: getFromNamespace(" .wrap_spatial_layers" , " plotthis" )(
200+ layers = players ,
201+ ext = ext ,
202+ flip_y = flip_y ,
203+ legend.position = legend.position ,
204+ legend.direction = legend.direction ,
205+ title = title ,
206+ subtitle = subtitle ,
207+ xlab = xlab ,
208+ ylab = ylab ,
209+ theme = theme ,
210+ theme_args = theme_args
211+ )
212+
213+ if (! is.null(facet_by )) {
214+ p <- utils :: getFromNamespace(" facet_plot" , " plotthis" )(
215+ p , facet_by , facet_scales , facet_nrow , facet_ncol , facet_byrow ,
216+ legend.position = legend.position , legend.direction = legend.direction
217+ )
218+ }
219+
220+ p
221+ }
222+
223+ # ' @keywords internal
224+ # ' @rdname SpatialPlot
225+ SpatialPlot.Seurat.SlideSeq <- function (
226+ object , image = NULL , masks = NULL , shapes = NULL , points = NULL , ext = NULL ,
227+ image_scale = NULL , crop = TRUE , group_by = NULL , features = NULL , layer = " data" ,
228+ layers = NULL , flip_y = TRUE , theme = " theme_box" , theme_args = list (),
229+ label = FALSE , label_size = 4 , label_fg = " white" , label_bg = " black" , label_bg_r = 0.1 ,
230+ label_repel = FALSE , label_repulsion = 20 , label_pt_size = 1 , label_pt_color = " black" ,
231+ label_segment_color = " black" , label_insitu = FALSE ,
232+ palette = NULL , palette_reverse = FALSE , palcolor = NULL ,
233+ highlight = NULL , highlight_alpha = 1 , highlight_size = 1 , highlight_color = " black" , highlight_stroke = 0.8 ,
234+ legend.position = " right" , legend.direction = " vertical" ,
235+ title = NULL , subtitle = NULL , xlab = NULL , ylab = NULL ,
236+ facet_scales = " fixed" , facet_nrow = NULL , facet_ncol = NULL , facet_byrow = TRUE ,
237+ ...
238+
239+ ) {
240+ stopifnot(" [SpatialPlot] Either 'group_by' or 'features' should be provided, not both." = is.null(group_by ) || is.null(features ))
241+ if (theme %in% c(" theme_box" , " theme_this" , " theme_blank" )) {
242+ theme <- utils :: getFromNamespace(theme , " plotthis" )
243+ }
244+
245+ points <- points %|| % TRUE
246+
247+ layers <- intersect(
248+ layers %|| % c(" image" , " masks" , " shapes" , " points" ),
249+ c(
250+ if (! is.null(image ) && ! isFALSE(image )) " image" ,
251+ if (! is.null(masks ) && ! isFALSE(masks )) " masks" ,
252+ if (! is.null(shapes ) && ! isFALSE(shapes )) " shapes" ,
253+ if (! is.null(points ) && ! isFALSE(points )) " points"
254+ )
255+ )
256+ stopifnot(' Either "image", "masks", "shapes", or "points" must be provided.' = any(layers %in% c(" image" , " masks" , " shapes" , " points" )))
257+
258+ players <- list ()
259+ scales_used <- c()
260+ args <- rlang :: dots_list(... )
261+ scale_factor <- 1
262+ facet_by <- NULL
263+ ext_unscaled <- NULL
264+ if (crop ) {
265+ points_data <- Seurat :: GetTissueCoordinates(object )
266+ points_data <- points_data [, colnames(points_data )[! is.na(colnames(points_data ))], drop = FALSE ]
267+ points_data $ .y <- points_data $ x
268+ points_data $ x <- points_data $ y
269+ points_data $ y <- points_data $ .y
270+ points_data $ .y <- NULL
271+ padding <- 0.05
272+ delta_x <- diff(range(points_data $ x , na.rm = TRUE )) * padding
273+ delta_y <- diff(range(points_data $ y , na.rm = TRUE )) * padding
274+ ext_unscaled <- c(
275+ min(points_data $ x , na.rm = TRUE ) - delta_x ,
276+ max(points_data $ x , na.rm = TRUE ) + delta_x ,
277+ min(points_data $ y , na.rm = TRUE ) - delta_y ,
278+ max(points_data $ y , na.rm = TRUE ) + delta_y
279+ )
280+ }
281+ for (element in layers ) {
282+ if (element == " image" && ! is.null(image )) {
283+ stop(" [SpatialPlot] 'image' is not supported for Seurat SlideSeq objects." )
284+ }
285+ if (element == " points" && ! is.null(points )) {
286+ points_args <- args [startsWith(names(args ), " points_" )]
287+ names(points_args ) <- sub(" ^points_" , " " , names(points_args ))
288+ if (crop ) {
289+ # attach metadata for highlighting selection
290+ points_args $ data <- object @ meta.data [rownames(points_data ), , drop = FALSE ]
291+ points_args $ data <- cbind(points_args $ data , points_data )
292+ points_args $ data $ x <- points_args $ data $ x * scale_factor
293+ points_args $ data $ y <- points_args $ data $ y * scale_factor
294+ points_args $ ext <- ext %|| % (ext_unscaled * scale_factor )
295+ } else {
296+ points_args $ data <- Seurat :: GetTissueCoordinates(object , image = if (isFALSE(image )) NULL else image )
297+ points_args $ data <- points_args $ data [, colnames(points_args $ data )[! is.na(colnames(points_args $ data ))], drop = FALSE ]
298+ points_args $ data $ .y <- points_args $ data $ x * scale_factor
299+ points_args $ data $ x <- points_args $ data $ y * scale_factor
300+ points_args $ data $ y <- points_args $ data $ .y
301+ points_args $ data $ .y <- NULL
302+ points_args $ data <- cbind(
303+ object @ meta.data [rownames(points_args $ data ), , drop = FALSE ],
304+ points_args $ data
305+ )
306+ }
307+ if (! is.null(group_by )) {
308+ points_args $ data [[group_by ]] <- object @ meta.data [[group_by ]]
309+ points_args $ color_by <- group_by
310+ points_args $ label <- points_args $ label %|| % label
311+ points_args $ label_size <- points_args $ label_size %|| % label_size
312+ points_args $ label_fg <- points_args $ label_fg %|| % label_fg
313+ points_args $ label_bg <- points_args $ label_bg %|| % label_bg
314+ points_args $ label_bg_r <- points_args $ label_bg_r %|| % label_bg_r
315+ points_args $ label_repel <- points_args $ label_repel %|| % label_repel
316+ points_args $ label_repulsion <- points_args $ label_repulsion %|| % label_repulsion
317+ points_args $ label_pt_size <- points_args $ label_pt_size %|| % label_pt_size
318+ points_args $ label_pt_color <- points_args $ label_pt_color %|| % label_pt_color
319+ points_args $ label_segment_color <- points_args $ label_segment_color %|| % label_segment_color
320+ points_args $ label_insitu <- points_args $ label_insitu %|| % label_insitu
142321 } else if (! is.null(features )) {
143322 cells_by_image <- utils :: getFromNamespace(" CellsByImage" , " Seurat" )
144323 cells <- unique(cells_by_image(object , images = if (isFALSE(image )) NULL else image , unlist = TRUE ))
@@ -161,14 +340,16 @@ SpatialPlot.Seurat.VisiumV2 <- function(
161340 facet_by <- " .facet_var"
162341 }
163342 }
164- points_args $ highlight <- highlight
165- points_args $ highlight_alpha <- highlight_alpha
166- points_args $ highlight_size <- highlight_size
167- points_args $ highlight_color <- highlight_color
168- points_args $ highlight_stroke <- highlight_stroke
343+ points_args $ highlight <- points_args $ highlight % || % highlight
344+ points_args $ highlight_alpha <- points_args $ highlight_alpha % || % highlight_alpha
345+ points_args $ highlight_size <- points_args $ highlight_size % || % highlight_size
346+ points_args $ highlight_color <- points_args $ highlight_color % || % highlight_color
347+ points_args $ highlight_stroke <- points_args $ highlight_stroke % || % highlight_stroke
169348 points_args $ palette <- points_args $ palette %|| % palette
170349 points_args $ palette_reverse <- points_args $ palette_reverse %|| % palette_reverse
171350 points_args $ palcolor <- points_args $ palcolor %|| % palcolor
351+ points_args $ legend.position <- legend.position
352+ points_args $ legend.direction <- legend.direction
172353 points_args $ flip_y <- flip_y
173354 points_args $ return_layer <- TRUE
174355 player <- do.call(SpatialPointsPlot , points_args )
@@ -187,23 +368,26 @@ SpatialPlot.Seurat.VisiumV2 <- function(
187368 }
188369 }
189370
190- xlim <- ylim <- NULL
191371 if (! is.null(ext_unscaled )) {
192372 ext <- ext %|| % ext_unscaled * scale_factor
193373 }
194- if (! is.null(ext )) {
195- xlim <- c(ext [1 ], ext [2 ])
196- ylim <- c(- ext [4 ], - ext [3 ])
197- }
198374
199- p <- ggplot() +
200- players +
201- ggplot2 :: coord_sf(expand = 0 , xlim = xlim , ylim = ylim ) +
202- do.call(plotthis ::: process_theme(theme ), theme_args ) +
203- ggplot2 :: scale_y_continuous(labels = abs )
375+ p <- utils :: getFromNamespace(" .wrap_spatial_layers" , " plotthis" )(
376+ layers = players ,
377+ ext = ext ,
378+ flip_y = flip_y ,
379+ legend.position = legend.position ,
380+ legend.direction = legend.direction ,
381+ title = title ,
382+ subtitle = subtitle ,
383+ xlab = xlab ,
384+ ylab = ylab ,
385+ theme = theme ,
386+ theme_args = theme_args
387+ )
204388
205389 if (! is.null(facet_by )) {
206- p <- plotthis ::: facet_plot(
390+ p <- utils :: getFromNamespace( " facet_plot" , " plotthis " ) (
207391 p , facet_by , facet_scales , facet_nrow , facet_ncol , facet_byrow ,
208392 legend.position = legend.position , legend.direction = legend.direction
209393 )
@@ -212,7 +396,6 @@ SpatialPlot.Seurat.VisiumV2 <- function(
212396 p
213397}
214398
215-
216399# ' Plot features for spatial data
217400# '
218401# ' The features can include expression, dimension reduction components, metadata, etc
0 commit comments