Skip to content

Commit 2ee24b2

Browse files
committed
regular maintenance
1 parent 02f7fe6 commit 2ee24b2

34 files changed

Lines changed: 152 additions & 91 deletions

R/annotation-gspace.R

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,15 @@ annotation_gspace_image <- function(raster, interpolate = FALSE, opacity = 1,
7777
.validate_gs_args("singleLogical", "flip.v", flip.v)
7878
.validate_gs_args("singleLogical", "flip.h", flip.h)
7979
.validate_gs_args("singleNumber", "opacity", opacity)
80-
80+
8181
if (inherits(raster, "GraphSpace")) {
82-
raster <- gs_image(raster)
83-
if (is.null(raster)) {
82+
if (!.has_image(raster)) {
8483
rlang::warn("The 'GraphSpace' object contains no image.")
8584
return(invisible(NULL))
8685
}
86+
raster <- gs_image(raster)
8787
}
88-
88+
8989
if (!inherits(raster, "raster")) {
9090
raster <- tryCatch({
9191
grDevices::as.raster(raster)

R/geom-edgespace.R

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,10 @@ geom_edgespace <- function(mapping = NULL, data = NULL,
146146
lineend = "butt", linejoin = "mitre",
147147
raster = FALSE, dpi = NULL, dev = "cairo", scale = 1) {
148148

149-
# Check custom params
150-
.validate_gs_args("singleLogical", "na.rm", na.rm)
151-
.validate_gs_args("singleNumber", "arrow_size", arrow_size)
152-
.validate_gs_args("singleNumber", "arrow_offset", arrow_offset)
153-
.validate_gs_args("singleString", "lineend", lineend)
154-
.validate_gs_args("singleString", "linejoin", linejoin)
149+
# Validate package-specific arguments;
150+
# All other arguments are validated elsewhere.
151+
.validate_gs_args("numeric_vec", "arrow_size", arrow_size)
152+
.validate_gs_args("numeric_vec", "arrow_offset", arrow_offset)
155153

156154
if (is.null(data)){
157155
data <- edgespace_handler()
@@ -251,7 +249,7 @@ edgespace_handler <- function() {
251249
rlang::warn(
252250
message = c(
253251
"x" = "`edgespace_handler()` found no edges in the input data.",
254-
"i" = "Input must be a 'GraphSpace', 'gs_edges', 'igraph', 'tidygraph', or 'ggraph' layout."
252+
"i" = "Input must be a 'GraphSpace', 'igraph', 'tbl_graph', or 'layout_ggraph'."
255253
)
256254
)
257255
data <- NULL
@@ -260,7 +258,7 @@ edgespace_handler <- function() {
260258
rlang::abort(
261259
message = c(
262260
"x" = "`edgespace_handler()` received an unsupported object type.",
263-
"i" = "Input must be a 'GraphSpace', 'gs_edges', 'igraph', 'tidygraph', or 'ggraph' layout."
261+
"i" = "Input must be a 'GraphSpace', 'igraph', 'tbl_graph', or 'layout_ggraph'."
264262
)
265263
)
266264
}
@@ -725,6 +723,7 @@ GeomEdgeSpace <- ggproto(
725723
# a tiny segment (0.01 npc) is used to anchor the arrowhead
726724
exy$xend <- exy$x + (edges$px * 0.01)
727725
exy$yend <- exy$y + (edges$py * 0.01)
726+
# grid::arrow(length = ...) is vectorized; it has been tested and validate
728727
arrow <- grid::arrow(angle = edges$arrowAngleStart,
729728
type = "open", ends = "first",
730729
length = grid::unit(edges$arrowSize1, size_unit))
@@ -736,6 +735,7 @@ GeomEdgeSpace <- ggproto(
736735
# a tiny segment (0.01 npc) is used to anchor the arrowhead
737736
exy$x <- exy$xend - (edges$px * 0.01)
738737
exy$y <- exy$yend - (edges$py * 0.01)
738+
# grid::arrow(length = ...) is vectorized; it has been tested and validated
739739
arrow <- grid::arrow(angle = edges$arrowAngleEnd,
740740
type = "open", ends = "last",
741741
length = grid::unit(edges$arrowSize2, size_unit))

R/geom-graphspace.R

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ geom_graphspace <- function(mapping = NULL, data,
182182
arrow_size = 1, arrow_offset = 0.01,
183183
raster = FALSE, dpi = NULL, dev = "cairo", scale = 1) {
184184

185+
# Validate package-specific arguments;
186+
# All other arguments are validated elsewhere.
187+
.validate_gs_args("numeric_vec", "arrow_size", arrow_size)
188+
.validate_gs_args("numeric_vec", "arrow_offset", arrow_offset)
189+
185190
if (missing(data) || is.null(data)){
186191
rlang::warn(
187192
message = c(

R/geom-nodespace.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ nodespace_handler <- function(mapping = NULL) {
253253
rlang::abort(
254254
message = c(
255255
"x" = "`nodespace_handler()` received an unsupported object type.",
256-
"i" = "Input must be a 'GraphSpace', 'gs_nodes', 'igraph', 'tidygraph', or 'ggraph' layout."
256+
"i" = "Input must be a 'GraphSpace', 'igraph', 'tbl_graph', or 'layout_ggraph'."
257257
)
258258
)
259259
}

R/gspace-classes.R

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ setValidity("GraphSpace", function(object) {
9191
}
9292

9393
# graph <-> nodes consistency
94+
# Note: do not assume that @nodes rows and @graph vertices share the same order,
95+
# as igraph accessors are independent. Downstream code relies on validated
96+
# index values rather than positional order
9497
if (!inherits(object@graph, "igraph")) {
9598
errors <- c(errors, "'@graph' slot must be an igraph object.")
9699
} else {

R/gspace-coercion.R

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ as.GraphSpace.default <- function(x, ...) {
3636
)
3737

3838
if (!is.null(y)) {
39+
rlang::inform(paste0(
40+
"No native 'as.GraphSpace' method for class '", class(x)[1], "'; ",
41+
"converted via tidygraph::as_tbl_graph(). Verify the resulting graph ",
42+
"structure if this wasn't the intended input."
43+
))
3944
return(GraphSpace(y, ...))
4045
}
4146

@@ -137,7 +142,7 @@ as.GraphSpace.Seurat <- function(x,
137142
}
138143

139144
# Remove unnamed columns occasionally returned by some methods
140-
coords[, !nzchar(colnames(coords))] <- NULL
145+
coords <- coords[, nzchar(colnames(coords)), drop = FALSE]
141146

142147
if (nrow(coords) == 0L || ncol(coords) < 2L){
143148
rlang::abort(
@@ -170,8 +175,20 @@ as.GraphSpace.Seurat <- function(x,
170175
if(inherits(metadata, "data.frame") && ncol(metadata) > 0){
171176
cids <- setdiff(colnames(metadata), colnames(coords))
172177
if (length(cids) > 0){
173-
metadata <- metadata[rownames(coords), cids, drop = FALSE]
174-
coords <- cbind(coords, metadata)
178+
if (!any(rownames(coords) %in% rownames(metadata))) {
179+
rlang::warn(c(
180+
"None of the coordinate row names match the Seurat object's cell identifiers.",
181+
"i" = "Skipping metadata merge; the resulting GraphSpace will not include x[[]] columns."
182+
))
183+
} else {
184+
if (!all(rownames(coords) %in% rownames(metadata))) {
185+
rlang::warn(
186+
"Some coordinate row names do not match Seurat cell identifiers; corresponding metadata will be NA."
187+
)
188+
}
189+
metadata <- metadata[rownames(coords), cids, drop = FALSE]
190+
coords <- cbind(coords, metadata)
191+
}
175192
}
176193
}
177194

@@ -181,6 +198,11 @@ as.GraphSpace.Seurat <- function(x,
181198

182199
# Add fdata
183200
fdata <- SeuratObject::LayerData(x, layer = layer)
201+
if (is.null(fdata)) {
202+
rlang::abort(c("x" = "LayerData() returned NULL.",
203+
"i" = sprintf("Layer '%s' may not exist.",
204+
layer %||% "default")))
205+
}
184206
fdata <- Matrix::t(fdata)
185207
gs_fdata(gs) <- fdata
186208

R/gspace-features.R

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -130,25 +130,33 @@ gs_add_features <- function(x, data) {
130130
matched_idx <- match(node_ids, rownames(data))
131131
missing_count <- sum(is.na(matched_idx))
132132
if (missing_count == 0) {
133-
133+
134134
# safe: matched_idx has no NAs here
135135
data <- data[matched_idx, , drop = FALSE]
136-
136+
137137
} else {
138-
139-
rlang::warn(sprintf(
140-
"%d node(s) have no feature data and will be set to NA.",
141-
missing_count))
142138

143-
result <- Matrix::Matrix(
144-
NA_real_,
145-
nrow = length(node_ids),
146-
ncol = ncol(data),
147-
dimnames = list(node_ids, colnames(data))
148-
)
149-
present <- !is.na(matched_idx)
150-
result[present, ] <- data[matched_idx[present], , drop = FALSE]
151-
data <- result
139+
rlang::warn(sprintf(
140+
"%d node(s) have no feature data and will be set to NA.",
141+
missing_count))
142+
143+
# 'result' is always dense (Matrix::Matrix(NA_real_, ...)); 'data' may
144+
# be sparse (e.g. dgCMatrix) at this point. Assigning a sparse-derived
145+
# row subset into a dense row-subset target, as below, has been
146+
# verified empirically: correct values (including stored structural
147+
# zeros, not coerced to NA) for both partial node coverage (this
148+
# branch) and shuffled/reordered row names matched via 'matched_idx'.
149+
# Not a risk needing further guarding -- Matrix's S4 dispatch handles
150+
# this correctly.
151+
result <- Matrix::Matrix(
152+
NA_real_,
153+
nrow = length(node_ids),
154+
ncol = ncol(data),
155+
dimnames = list(node_ids, colnames(data))
156+
)
157+
present <- !is.na(matched_idx)
158+
result[present, ] <- data[matched_idx[present], , drop = FALSE]
159+
data <- result
152160
}
153161

154162
# Load fdata slot

R/gspace-generics.R

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11

2-
setGeneric("GraphSpace", function(g, ...) standardGeneric("GraphSpace"))
2+
setGeneric("GraphSpace", function(g, ...)
3+
standardGeneric("GraphSpace"),
4+
package = "RGraphSpace"
5+
)
36

47
setGeneric("plotGraphSpace", function(gs, ...)
58
standardGeneric("plotGraphSpace"),
69
package = "RGraphSpace"
710
)
811

9-
setGeneric("getGraphSpace", function(gs, what = "summary")
12+
setGeneric("getGraphSpace", function(gs, ...)
1013
standardGeneric("getGraphSpace"),
1114
package = "RGraphSpace"
1215
)

R/gspace-ggplot-constructor.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ ggplot_add.inject_nodespace <- function(object, plot, ...) {
184184
return(plot)
185185
}
186186

187+
# Note: @data/@layers/@scales require ggplot2 >= 4.0 (S7 plot objects).
188+
# This requirement is intentional and enforced in DESCRIPTION.
187189
for(i in seq_along(plot@layers)){
188190

189191
layer <- plot@layers[[i]]

R/gspace-methods.R

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -166,19 +166,20 @@ setMethod("GraphSpace", signature(g = "ANY"),
166166
error = function(e) NULL
167167
)
168168
g <- attr(g, "graph")
169+
} else if (inherits(g, "tbl_graph")) {
170+
g <- tidygraph::as.igraph(g)
169171
}
170172

171-
if (inherits(g, "igraph")) {
172-
class(g) <- "igraph"
173-
} else {
173+
if (!inherits(g, "igraph")) {
174174
rlang::abort(
175175
message = c(
176176
"x" = "Input 'g' must inherit from the 'igraph' class.",
177-
"i" = paste("Received an object of class:", paste(class(g), collapse = "/")),
178-
"*" = "Did you mean to use `tidygraph::as_tbl_graph()`?"
177+
"i" = "Input must be an 'igraph', 'tbl_graph', or 'layout_ggraph'."
179178
)
180179
)
181180
}
181+
class(g) <- "igraph"
182+
182183
if(!is.null(layout)){
183184
.validate_gs_args("numeric_mtx", "layout", layout)
184185
if (ncol(layout) != 2) {
@@ -232,6 +233,9 @@ setMethod("GraphSpace", signature(g = "data.frame"),
232233

233234
# Initialize a graph using 'coord' as vertices, with no edges
234235
g <- make_empty_graph(n = nrow(coord), directed = FALSE)
236+
237+
# If 'coord' has no row names (a common case for a plain data.frame),
238+
# sequential names will be later assigned in the validation functions
235239
if(!is.null(rownames(coord))){
236240
V(g)$name <- rownames(coord)
237241
}
@@ -266,12 +270,12 @@ setMethod("GraphSpace", signature(g = "data.frame"),
266270
#' @param xlab The title for the 'x' axis of a 2D-image space.
267271
#' @param ylab The title for the 'y' axis of a 2D-image space.
268272
#' @param font.size A single numeric value passed to ggplot themes.
269-
#' @param bg.color A single color for background.
273+
#' @param bg.colour A single color for background.
270274
#' @param add.labels A logical value indicating whether to plot vertex labels.
271275
#' @param node.labels A vector of vertex names to be highlighted in the graph
272276
#' space. This argument overrides 'add.labels'.
273277
#' @param label.size A size argument passed to \code{\link[ggplot2]{geom_text}}.
274-
#' @param label.color A color passed to \code{\link[ggplot2]{geom_text}}.
278+
#' @param label.colour A color passed to \code{\link[ggplot2]{geom_text}}.
275279
#' @param add.image A logical value indicating whether to add a background
276280
#' image, when one is available (see \code{\link{GraphSpace}}).
277281
#' @param raster A logical value indicating whether to rasterize the main plot.
@@ -319,9 +323,9 @@ setMethod("GraphSpace", signature(g = "data.frame"),
319323
setMethod("plotGraphSpace", "GraphSpace",
320324
function(gs, theme = "th0", xlab = "Graph coordinates 1",
321325
ylab = "Graph coordinates 2", font.size = 1,
322-
bg.color = "grey95", add.labels = FALSE,
326+
bg.colour = "grey95", add.labels = FALSE,
323327
node.labels = NULL, label.size = 3,
324-
label.color = "grey20", add.image = TRUE,
328+
label.colour = "grey20", add.image = TRUE,
325329
raster = FALSE, dpi = 300, dev = "cairo_png") {
326330

327331
gs <- updateGraphSpace(gs)
@@ -330,10 +334,10 @@ setMethod("plotGraphSpace", "GraphSpace",
330334
.validate_gs_args("singleString", "xlab", xlab)
331335
.validate_gs_args("singleString", "ylab", ylab)
332336
.validate_gs_args("singleNumber", "font.size", font.size)
333-
.validate_gs_colors("singleColor", "bg.color", bg.color)
337+
.validate_gs_colors("singleColor", "bg.colour", bg.colour)
334338
.validate_gs_args("singleLogical", "add.labels", add.labels)
335339
.validate_gs_args("singleNumber", "label.size", label.size)
336-
.validate_gs_colors("singleColor", "label.color", label.color)
340+
.validate_gs_colors("singleColor", "label.colour", label.colour)
337341
.validate_gs_args("singleLogical", "add.image", add.image)
338342
.validate_gs_args("singleLogical", "raster", raster)
339343
.validate_gs_args("singleInteger", "dpi", dpi)
@@ -362,7 +366,7 @@ setMethod("plotGraphSpace", "GraphSpace",
362366
ggi <- ggi + theme_gspace_coords(theme = theme,
363367
is_norm = pars$is.normalized, xlab = xlab, ylab = ylab,
364368
txt_size = font.size, leg_size = font.size,
365-
bg_color = bg.color)
369+
bg_colour = bg.colour)
366370
}
367371
}
368372

@@ -372,7 +376,7 @@ setMethod("plotGraphSpace", "GraphSpace",
372376
#--- add node labels
373377
if (!is.null(node.labels)){
374378
ggp <- .add_labels1(ggp, nodes, node.labels,
375-
label.size, label.color)
379+
label.size, label.colour)
376380
} else if(add.labels){
377381
ggp <- .add_labels2(ggp, nodes)
378382
}
@@ -381,7 +385,7 @@ setMethod("plotGraphSpace", "GraphSpace",
381385
ggp <- ggp + theme_gspace_coords(theme = theme,
382386
is_norm = pars$is.normalized, xlab = xlab, ylab = ylab,
383387
txt_size = font.size, leg_size = font.size,
384-
bg_color = bg.color)
388+
bg_colour = bg.colour)
385389

386390
if(raster){
387391
ggp <- ggrastr::rasterize(ggp, layers = "GraphSpace",
@@ -440,7 +444,7 @@ plot.GraphSpace <- function(x, ...) {
440444
#-------------------------------------------------------------------------------
441445
#' @title Accessors for fetching slots from a GraphSpace object
442446
#'
443-
#' @description \code{getGraphSpace} retrives information from
447+
#' @description \code{getGraphSpace} retrieves information from
444448
#' individual slots available in a GraphSpace object.
445449
#'
446450
#' @param gs A preprocessed \linkS4class{GraphSpace} class object
@@ -458,7 +462,7 @@ plot.GraphSpace <- function(x, ...) {
458462
#' # Create a new GraphSpace object
459463
#' gs <- GraphSpace(gtoy1)
460464
#'
461-
#' # Get the 'summary' slot in gs
465+
#' # Get the 'graph' slot in gs
462466
#' getGraphSpace(gs, what = 'graph')
463467
#'
464468
#' @import methods
@@ -835,8 +839,7 @@ setMethod("gs_edge_attr<-", "GraphSpace", function(x, name, ..., value) {
835839
x@graph <- .validate_igraph(g)
836840
nodes <- .get_nodes(x@graph)
837841
if (x@pars$is.normalized) {
838-
nodes$x <- x@nodes$x
839-
nodes$y <- x@nodes$y
842+
nodes[x@nodes$name, c("x","y")] <- x@nodes[, c("x","y")]
840843
}
841844
x@nodes <- nodes
842845
return(x)

0 commit comments

Comments
 (0)