Skip to content

Commit 36d54ec

Browse files
authored
Merge branch 'devel' into pseudobulkDGE_compatable
2 parents 0e32c65 + 1de5729 commit 36d54ec

File tree

11 files changed

+276
-12
lines changed

11 files changed

+276
-12
lines changed

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
Package: spatialLIBD
22
Title: spatialLIBD: an R/Bioconductor package to visualize spatially-resolved
33
transcriptomics data
4-
Version: 1.19.12
5-
Date: 2025-04-03
4+
Version: 1.21.2
5+
Date: 2025-04-24
66
Authors@R:
77
c(
88
person("Leonardo", "Collado-Torres", role = c("aut", "cre"),

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export(vis_gene)
4545
export(vis_gene_p)
4646
export(vis_grid_clus)
4747
export(vis_grid_gene)
48+
export(vis_image)
4849
import(ExperimentHub)
4950
import(MatrixGenerics)
5051
import(SingleCellExperiment)

NEWS.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
# spatialLIBD 1.21.2
2+
3+
NEW FEATURES
4+
5+
* @lahuuki added the `vis_image()` for plotting just the histology image. See
6+
<https://github.com/LieberInstitute/spatialLIBD/pull/107> for details.
7+
8+
# spatialLIBD 1.21.1
9+
10+
SIGNIFICANT USER-VISIBLE CHANGES
11+
12+
* The documentation of `registration_pseudobulk()` has been expanded to further
13+
explain the `logcounts()` assay. That is, to highlight that this assay
14+
contains log2 CPM values computed with `edgeR::cpm()` and not log2 library-size
15+
normalized counts (as computed with `scuttle::logNormCounts()`).
16+
See <https://support.bioconductor.org/p/9161754> and
17+
<https://github.com/LieberInstitute/spatialLIBD/issues/106> by @kinnaryshah
18+
for more details.
19+
120
# spatialLIBD 1.19.12
221

322
NEW FEATURES

R/registration_pseudobulk.R

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@
2828
#' mitochondrial, used to calculate pseudo bulked mitochondrial expression rate
2929
#' `expr_chrM` and `pseudo_expr_chrM` .
3030
#'
31-
#' @return A pseudo-bulked [SingleCellExperiment-class][SingleCellExperiment::SingleCellExperiment-class] object.
31+
#' @return A pseudo-bulked [SingleCellExperiment-class][SingleCellExperiment::SingleCellExperiment-class] object. The `logcounts()` assay are `log2-CPM`
32+
#' values calculated with `edgeR::cpm(log = TRUE)`. See
33+
#' <https://github.com/LieberInstitute/spatialLIBD/issues/106> and
34+
#' <https://support.bioconductor.org/p/9161754> for more details about the
35+
#' math behind `scuttle::logNormFactors()`, `edgeR::cpm()`, and their
36+
#' differences.
3237
#' @importFrom SingleCellExperiment logcounts
3338
#' @importFrom scuttle aggregateAcrossCells
3439
#' @importFrom edgeR filterByExpr calcNormFactors
@@ -76,7 +81,8 @@ registration_pseudobulk <-
7681
stopifnot(var_registration %in% colnames(colData(sce)))
7782
stopifnot(var_sample_id %in% colnames(colData(sce)))
7883
stopifnot(all(
79-
!c("registration_sample_id", "registration_variable") %in% colnames(colData(sce))
84+
!c("registration_sample_id", "registration_variable") %in%
85+
colnames(colData(sce))
8086
))
8187

8288
## Avoid any incorrect inputs that are otherwise hard to detect
@@ -110,7 +116,10 @@ registration_pseudobulk <-
110116
"var_registration \"%s\" contains non-syntatic variables: %s\nconverting to %s",
111117
var_registration,
112118
paste(uniq_var_regis[!syntatic], collapse = ", "),
113-
paste(make.names(uniq_var_regis[!syntatic]), collapse = ", ")
119+
paste(
120+
make.names(uniq_var_regis[!syntatic]),
121+
collapse = ", "
122+
)
114123
),
115124
call. = FALSE
116125
)
@@ -167,7 +176,9 @@ registration_pseudobulk <-
167176
if (is.factor(sce_pseudo$registration_variable)) {
168177
## Drop unused var_registration levels if we had to drop some due
169178
## to min_ncells
170-
sce_pseudo$registration_variable <- droplevels(sce_pseudo$registration_variable)
179+
sce_pseudo$registration_variable <- droplevels(
180+
sce_pseudo$registration_variable
181+
)
171182
}
172183

173184
## compute pseudo QC metrics
@@ -195,7 +206,8 @@ registration_pseudobulk <-
195206
## Compute the logcounts
196207
message(Sys.time(), " normalize expression")
197208
logcounts(sce_pseudo) <-
198-
edgeR::cpm(edgeR::calcNormFactors(sce_pseudo),
209+
edgeR::cpm(
210+
edgeR::calcNormFactors(sce_pseudo),
199211
log = TRUE,
200212
prior.count = 1
201213
)

R/vis_image.R

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#' Sample image visualization
2+
#'
3+
#' This function visualizes the histology image for selected sample. Matches
4+
#' crop and settings of [vis_clus()] and [vis_gene()].
5+
#'
6+
#' @inheritParams vis_clus
7+
#' @param title_suffix A `character(1)` passed to [paste()][base::paste] to
8+
#' modify the title of the plot following the `sampleid`.
9+
#'
10+
#' @return A [ggplot2][ggplot2::ggplot] object.
11+
#' @family Spatial cluster visualization functions
12+
#' @export
13+
#' @importFrom SpatialExperiment spatialCoords
14+
#' @details This function subsets `spe` to the given sample and prepares the
15+
#' data and title for [vis_clus_p()].
16+
#'
17+
#' @examples
18+
#'
19+
#' if (enough_ram()) {
20+
#' ## Obtain the necessary data
21+
#' if (!exists("spe")) spe <- fetch_data("spe")
22+
#'
23+
#' ## Print the "lowres" image for sample 151673
24+
#' p1 <- vis_image(
25+
#' spe = spe,
26+
#' sampleid = "151673"
27+
#' )
28+
#' print(p1)
29+
#'
30+
#' ## Without auto-cropping the image
31+
#' p2 <- vis_image(
32+
#' spe = spe,
33+
#' sampleid = "151673",
34+
#' auto_crop = FALSE
35+
#' )
36+
#' print(p2)
37+
#' }
38+
vis_image <- function(
39+
spe,
40+
sampleid = unique(spe$sample_id)[1],
41+
image_id = "lowres",
42+
auto_crop = TRUE,
43+
is_stitched = FALSE,
44+
title_suffix = NULL
45+
) {
46+
# Verify existence and legitimacy of 'sampleid'
47+
if (
48+
!("sample_id" %in% colnames(colData(spe))) ||
49+
!(sampleid %in% spe$sample_id)
50+
) {
51+
stop(
52+
paste(
53+
"'spe$sample_id' must exist and contain the ID",
54+
sampleid
55+
),
56+
call. = FALSE
57+
)
58+
}
59+
60+
# Check validity of spatial coordinates
61+
if (
62+
!setequal(
63+
c("pxl_col_in_fullres", "pxl_row_in_fullres"),
64+
colnames(spatialCoords(spe))
65+
)
66+
) {
67+
stop(
68+
"Abnormal spatial coordinates: should have 'pxl_row_in_fullres' and 'pxl_col_in_fullres' columns.",
69+
call. = FALSE
70+
)
71+
}
72+
73+
spe_sub <- spe[, spe$sample_id == sampleid]
74+
75+
if (is_stitched) {
76+
# Frame limits are poorly defined for stitched data
77+
auto_crop <- FALSE
78+
}
79+
80+
d <- as.data.frame(
81+
cbind(colData(spe_sub), SpatialExperiment::spatialCoords(spe_sub)),
82+
optional = TRUE
83+
)
84+
85+
pxl_row_in_fullres <- pxl_col_in_fullres <- key <- NULL
86+
87+
img <- SpatialExperiment::imgRaster(
88+
spe,
89+
sample_id = sampleid,
90+
image_id = image_id
91+
)
92+
93+
## Crop the image if needed
94+
if (auto_crop) {
95+
frame_lims <-
96+
frame_limits(spe, sampleid = sampleid, image_id = image_id)
97+
img <-
98+
img[
99+
frame_lims$y_min:frame_lims$y_max,
100+
frame_lims$x_min:frame_lims$x_max
101+
]
102+
adjust <-
103+
list(x = frame_lims$x_min, y = frame_lims$y_min)
104+
} else {
105+
adjust <- list(x = 0, y = 0)
106+
}
107+
108+
title <- paste(sampleid, title_suffix)
109+
110+
grob <- grid::rasterGrob(
111+
img,
112+
width = grid::unit(1, "npc"),
113+
height = grid::unit(1, "npc")
114+
)
115+
116+
p <- ggplot() +
117+
geom_spatial(
118+
data = tibble::tibble(grob = list(grob)),
119+
aes(grob = grob),
120+
x = 0.5,
121+
y = 0.5
122+
) +
123+
xlim(0, ncol(img)) +
124+
ylim(nrow(img), 0) +
125+
xlab("") +
126+
ylab("") +
127+
labs(fill = NULL) +
128+
ggtitle(title) +
129+
theme_set(theme_bw(base_size = 20)) +
130+
theme(
131+
panel.grid.major = element_blank(),
132+
panel.grid.minor = element_blank(),
133+
panel.background = element_blank(),
134+
axis.line = element_blank(),
135+
axis.text = element_blank(),
136+
axis.ticks = element_blank(),
137+
legend.box.spacing = unit(0, "pt")
138+
)
139+
return(p)
140+
}

man/frame_limits.Rd

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/registration_pseudobulk.Rd

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/vis_clus.Rd

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/vis_clus_p.Rd

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/vis_grid_clus.Rd

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)