Closed iago-pssjd closed 2 months ago
Reproducible example with R 4.0.5 (and probably newer). I use library checkout to a sane and compatible installation of libraries before geomnet
being archived (therefore ggplot2 3.3.3, ggrepel 0.9.0, geomnet 0.3.1):
(GeomTextRepel
used in https://github.com/sctyner/geomnet/blob/master/R/geom-net.r)
library(checkpoint)
checkpoint("2021-01-01")
options(checkpoint.mranUrl="https://packagemanager.posit.co/")
install.packages('ggplot2')
install.packages('ggrepel')
install.packages('geomnet')
library(dplyr)
library(geomnet)
data(theme_elements)
# data step
TEnet <- fortify(as.edgedf(theme_elements$edges[,c("parent", "child")]), theme_elements$vertices)
# create a degree variable for use later
TEnet <- TEnet %>%
group_by(from_id) %>%
mutate(degree = sqrt(10 * n() + 1))
# plot
ggplot(data = TEnet,
aes(from_id = from_id, to_id = to_id)) +
geom_net(layout.alg = "fruchtermanreingold",
aes(fontsize = degree), directed = TRUE,
labelon = TRUE, size = 1, labelcolour = 'black',
ecolour = "grey70", arrowsize = 0.5,
linewidth = 0.5, repel = TRUE) +
theme_net() +
xlim(c(-0.05, 1.05))
Error in `$<-.data.frame`(`*tmp*`, "point.size", value = numeric(0)) :
replacement has 0 rows, data has 53
rlang::last_trace()
<error/rlang_error>
Can't show last error because no error was recorded yet
Backtrace:
█
1. └─rlang::last_trace()
2. └─rlang::last_error()
traceback()
23: stop(sprintf(ngettext(N, "replacement has %d row, data has %d",
"replacement has %d rows, data has %d"), N, nrows), domain = NA)
22: `$<-.data.frame`(`*tmp*`, "point.size", value = numeric(0))
21: `$<-`(`*tmp*`, "point.size", value = numeric(0))
20: makeContent.textrepeltree(x)
19: makeContent(x)
18: drawGTree(x)
17: recordGraphics(drawGTree(x), list(x = x), getNamespace("grid"))
16: grid.draw.gTree(x$children[[i]], recording = FALSE)
15: grid.draw(x$children[[i]], recording = FALSE)
14: drawGTree(x)
13: recordGraphics(drawGTree(x), list(x = x), getNamespace("grid"))
12: grid.draw.gTree(x$children[[i]], recording = FALSE)
11: grid.draw(x$children[[i]], recording = FALSE)
10: drawGTree(x)
9: recordGraphics(drawGTree(x), list(x = x), getNamespace("grid"))
8: grid.draw.gTree(x$children[[i]], recording = FALSE)
7: grid.draw(x$children[[i]], recording = FALSE)
6: drawGTree(x)
5: recordGraphics(drawGTree(x), list(x = x), getNamespace("grid"))
4: grid.draw.gTree(gtable)
3: grid.draw(gtable)
2: print.ggplot(x)
1: (function (x, ...)
UseMethod("print"))(x)
When you encounter an error, consider using rlang::last_trace()
to help reveal which lines of code are related to the error. Could you share the traceback?
Keep also in mind that changes introduced in 'ggplot2' updates have made changes in extensions like 'ggrepel' necessary, so newer versions of 'ggplot2' can fail with older versions of extensions and vice versa. Kamil's suggestion is a very good one! In the tidyverse blog posts have been published for the major updates to 'ggplot2' describing the changes required in extensions.
@slowkow @aphalo Thanks for your answers.
I added to the reprex the tracebacks.
I checked mainly the NEWS for ggrepel
, since it seems an issue depending only on this package because of two reasons: on one hand, with ggplot2
release fixed (with both either 3.3.3 and 3.4.3), I got geomnet
working or not depending on ggrepel
release; on the other hand; it just fails with GeomTextRepel
, but not with GeomText
.
However I also checked ggplot2
last NEWS, but I couldn't detect any hint to this issue.
Is there some reason that you must use old (unsupported) versions?
With the latest versions, I don't get the same error you do. I get an error with geomnet code:
#library(checkpoint)
#checkpoint("2021-01-01")
#options(checkpoint.mranUrl="https://packagemanager.posit.co/")
# install.packages('geomnet')
devtools::install_github("sctyner/geomnet")
#> Skipping install of 'geomnet' from a github remote, the SHA1 (030537d5) has not changed since last install.
#> Use `force = TRUE` to force installation
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
library(geomnet)
#> Loading required package: ggplot2
data(theme_elements)
# data step
TEnet <- fortify(as.edgedf(theme_elements$edges[,c("parent", "child")]), theme_elements$vertices)
#> Using parent as the from node column and child as the to node column.
#> If this is not correct, rewrite dat so that the first 2 columns are from and to node, respectively.
#> Joining edge and node information by from_id and name respectively.
# create a degree variable for use later
TEnet <- TEnet %>%
group_by(from_id) %>%
mutate(degree = sqrt(10 * n() + 1))
# plot
ggplot(data = TEnet,
aes(from_id = from_id, to_id = to_id)) +
geom_net(layout.alg = "fruchtermanreingold",
aes(fontsize = degree), directed = TRUE,
labelon = TRUE, size = 1, labelcolour = 'black',
ecolour = "grey70", arrowsize = 0.5,
linewidth = 0.5, repel = TRUE) +
theme_net() +
xlim(c(-0.05, 1.05))
#> Error in `geom_net()`:
#> ! Problem while computing stat.
#> ℹ Error occurred in the 1st layer.
#> Caused by error:
#> ! The first two columns of `x` must be of the same type.
#> Backtrace:
#> ▆
#> 1. ├─base::tryCatch(...)
#> 2. │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#> 3. │ ├─base (local) tryCatchOne(...)
#> 4. │ │ └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#> 5. │ └─base (local) tryCatchList(expr, names[-nh], parentenv, handlers[-nh])
#> 6. │ └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> 7. │ └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#> 8. ├─base::withCallingHandlers(...)
#> 9. ├─base::saveRDS(...)
#> 10. ├─base::do.call(...)
#> 11. ├─base (local) `<fn>`(...)
#> 12. ├─global `<fn>`(input = base::quote("used-aidi_reprex.R"))
#> 13. │ └─rmarkdown::render(input, quiet = TRUE, envir = globalenv(), encoding = "UTF-8")
#> 14. │ └─knitr::knit(knit_input, knit_output, envir = envir, quiet = quiet)
#> 15. │ └─knitr:::process_file(text, output)
#> 16. │ ├─xfun:::handle_error(...)
#> 17. │ ├─base::withCallingHandlers(...)
#> 18. │ └─knitr:::process_group(group)
#> 19. │ └─knitr:::call_block(x)
#> 20. │ └─knitr:::block_exec(params)
#> 21. │ └─knitr:::eng_r(options)
#> 22. │ ├─knitr:::in_input_dir(...)
#> 23. │ │ └─knitr:::in_dir(input_dir(), expr)
#> 24. │ └─knitr (local) evaluate(...)
#> 25. │ └─evaluate::evaluate(...)
#> 26. │ └─evaluate:::evaluate_call(...)
#> 27. │ ├─evaluate (local) handle(...)
#> 28. │ │ └─base::try(f, silent = TRUE)
#> 29. │ │ └─base::tryCatch(...)
#> 30. │ │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#> 31. │ │ └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> 32. │ │ └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#> 33. │ ├─base::withCallingHandlers(...)
#> 34. │ ├─base::withVisible(value_fun(ev$value, ev$visible))
#> 35. │ └─knitr (local) value_fun(ev$value, ev$visible)
#> 36. │ └─knitr (local) fun(x, options = options)
#> 37. │ ├─base::withVisible(knit_print(x, ...))
#> 38. │ ├─knitr::knit_print(x, ...)
#> 39. │ └─knitr:::knit_print.default(x, ...)
#> 40. │ └─evaluate (local) normal_print(x)
#> 41. │ ├─base::print(x)
#> 42. │ └─ggplot2:::print.ggplot(x)
#> 43. │ ├─ggplot2::ggplot_build(x)
#> 44. │ └─ggplot2:::ggplot_build.ggplot(x)
#> 45. │ └─ggplot2:::by_layer(...)
#> 46. │ ├─rlang::try_fetch(...)
#> 47. │ │ ├─base::tryCatch(...)
#> 48. │ │ │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#> 49. │ │ │ └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> 50. │ │ │ └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#> 51. │ │ └─base::withCallingHandlers(...)
#> 52. │ └─ggplot2 (local) f(l = layers[[i]], d = data[[i]])
#> 53. │ └─l$compute_statistic(d, layout)
#> 54. │ └─ggplot2 (local) compute_statistic(..., self = self)
#> 55. │ └─self$stat$compute_layer(data, self$computed_stat_params, layout)
#> 56. │ └─geomnet (local) compute_layer(..., self = self)
#> 57. │ └─self$compute_panel(...)
#> 58. │ └─geomnet (local) compute_panel(..., self = self)
#> 59. │ └─self$compute_network(...)
#> 60. │ └─geomnet (local) compute_network(...)
#> 61. │ ├─network::as.network(na.omit(edges[, 1:2]), matrix.type = "edgelist")
#> 62. │ └─network::as.network.data.frame(na.omit(edges[, 1:2]), matrix.type = "edgelist")
#> 63. │ └─network:::.validate_edge_df(...)
#> 64. │ └─base::stop(...)
#> 65. └─base::.handleSimpleError(...)
#> 66. └─rlang (local) h(simpleError(msg, call))
#> 67. └─handlers[[1L]](cnd)
#> 68. └─cli::cli_abort(...)
#> 69. └─rlang::abort(...)
Created on 2024-08-06 with reprex v2.0.2
Have you considered using ggnet2 or ggnetwork or ggraph or any other packages?
For example, ggnet2 seems to work just fine (after removing NA
from your network):
library(dplyr)
library(geomnet)
data(theme_elements)
# data step
TEnet <- fortify(as.edgedf(theme_elements$edges[,c("parent", "child")]), theme_elements$vertices)
#> Using parent as the from node column and child as the to node column.
#> If this is not correct, rewrite dat so that the first 2 columns are from and to node, respectively.
#> Joining edge and node information by from_id and name respectively.
# create a degree variable for use later
TEnet <- TEnet %>%
group_by(from_id) %>%
mutate(degree = sqrt(10 * n() + 1))
# install.packages("GGally")
library(GGally)
#> Registered S3 method overwritten by 'GGally':
#> method from
#> +.gg ggplot2
ix <- !is.na(TEnet[,2])
net <- TEnet[ix,]
net[[1]] <- as.character(net[[1]])
net[[2]] <- as.character(net[[2]])
net <- network::network(net, loops = TRUE)
ggnet2(net) +
geom_text(aes(label = label))
#> Warning in ggnet2(net): ggnet2 does not know how to handle self-loops
Created on 2024-08-06 with reprex v2.0.2
@slowkow
Is there some reason that you must use old (unsupported) versions?
I was looking for the version (release/commit) either of ggplot2 or ggrepel from which geomnet stopped working. And to test geomnet with a version of ggrepel working, I need a ggplot2 release compatible with ggrepel release.
With the latest versions, I don't get the same error you do. I get an error with geomnet code:
Indeed, those errors are part of the cause geomnet becoming archived. Try
remotes::install_github("iago-pssjd/geomnet@archivedCRANissues")
Have you considered using ggnet2 or ggnetwork or ggraph or any other packages?
No, my goal was not to use such code or an equivalent one, but got geomnet again on CRAN after solving all the issues.
Debugging makeContent.textrepeltree(x)
(see line numbered 20 in traceback shown above), I have just found that the issue occurs when
(line added in commit cc34e6d) where the data.frame x$data
does not contain a variable point.size
.
Do you have any suggestion on changes I should do on https://github.com/sctyner/geomnet/blob/master/R/geom-net.r to solve this issue? Or is it fixable on your side?
I'm not sure. Maybe the GeomTextRepel$draw_panel()
function needs to check for the presence of a point.size
column and then add the column if it is missing?
I believe I solved the issue adding this column as NA, so I close. Thanks!
Current situation. I thought I had solved the issue, however I did not have installed the most recent version of ggrepel, but a commit previous to 0.9.0.
Now, with commit 8d16037, the reproducible example "sometimes works, most doesn't"... and I was not able to find till now the rule to describe how to reproduce when it works.
But, in general, the error it produces is
library(dplyr)
library(geomnet)
data(theme_elements)
# data step
TEnet <- fortify(as.edgedf(theme_elements$edges[,c("parent", "child")]), theme_elements$vertices)
# create a degree variable for use later
TEnet <- TEnet %>%
group_by(from_id) %>%
mutate(degree = sqrt(10 * n() + 1))
# plot
ggplot(data = TEnet,
aes(from_id = from_id, to_id = to_id)) +
geom_net(layout.alg = "fruchtermanreingold",
aes(fontsize = degree), directed = TRUE,
labelon = TRUE, size = 1, labelcolour = 'black',
ecolour = "grey70", arrowsize = 0.5,
linewidth = 0.5, repel = TRUE) +
theme_net() +
xlim(c(-0.05, 1.05))
Error in check.length(gparname) :
'gpar' element 'lwd' must not be length 0
> traceback()
34: stop(gettextf("'gpar' element '%s' must not be length 0", gparname),
domain = NA)
33: check.length(gparname)
32: numnotnull("lwd")
31: validGP(list(...))
30: gpar(col = scales::alpha(row$segment.colour %||% row$colour,
row$segment.alpha %||% row$alpha), lwd = row$segment.size *
.pt, lty = row$segment.linetype %||% 1)
29: gTree(x1 = x1, y1 = y1, x2 = x2, y2 = y2, curvature = curvature,
angle = angle, ncp = ncp, shape = shape, square = square,
squareShape = squareShape, inflect = inflect, arrow = arrow,
open = open, debug = debug, name = name, gp = gp, vp = vp,
cl = "curve")
28: curveGrob(x1 = int[1], y1 = int[2], x2 = point_int[1], y2 = point_int[2],
default.units = "native", curvature = segment.curvature,
angle = segment.angle, ncp = segment.ncp, gp = segment.gp,
name = sprintf("segmentrepelgrob%s", i), arrow = arrow)
27: makeTextRepelGrobs(i, x$lab[i], x = unit(repel$x[i], "native"),
y = unit(repel$y[i], "native"), x.orig = row$x, y.orig = row$y,
rot = row$angle, box.padding = x$box.padding, point.size = point_size[i],
point.padding = x$point.padding, segment.curvature = row$segment.curvature,
segment.angle = row$segment.angle, segment.ncp = row$segment.ncp,
text.gp = gpar(col = scales::alpha(row$colour, row$alpha),
fontsize = row$size * .pt, fontfamily = row$family, fontface = row$fontface,
lineheight = row$lineheight), segment.gp = gpar(col = scales::alpha(row$segment.colour %||%
row$colour, row$segment.alpha %||% row$alpha), lwd = row$segment.size *
.pt, lty = row$segment.linetype %||% 1), arrow = x$arrow,
min.segment.length = x$min.segment.length, hjust = row$hjust,
vjust = row$vjust)
26: FUN(X[[i]], ...)
25: lapply(seq_along(valid_strings), function(i) {
row <- x$data[i, , drop = FALSE]
makeTextRepelGrobs(i, x$lab[i], x = unit(repel$x[i], "native"),
y = unit(repel$y[i], "native"), x.orig = row$x, y.orig = row$y,
rot = row$angle, box.padding = x$box.padding, point.size = point_size[i],
point.padding = x$point.padding, segment.curvature = row$segment.curvature,
segment.angle = row$segment.angle, segment.ncp = row$segment.ncp,
text.gp = gpar(col = scales::alpha(row$colour, row$alpha),
fontsize = row$size * .pt, fontfamily = row$family,
fontface = row$fontface, lineheight = row$lineheight),
segment.gp = gpar(col = scales::alpha(row$segment.colour %||%
row$colour, row$segment.alpha %||% row$alpha), lwd = row$segment.size *
.pt, lty = row$segment.linetype %||% 1), arrow = x$arrow,
min.segment.length = x$min.segment.length, hjust = row$hjust,
vjust = row$vjust)
})
24: makeContent.textrepeltree(x)
23: makeContent(x)
22: drawGTree(x)
21: recordGraphics(drawGTree(x), list(x = x), getNamespace("grid"))
20: grid.draw.gTree(x$children[[i]], recording = FALSE)
19: grid.draw(x$children[[i]], recording = FALSE)
18: drawGTree(x)
17: recordGraphics(drawGTree(x), list(x = x), getNamespace("grid"))
16: grid.draw.gTree(x$children[[i]], recording = FALSE)
15: grid.draw(x$children[[i]], recording = FALSE)
14: drawGTree(x)
13: recordGraphics(drawGTree(x), list(x = x), getNamespace("grid"))
12: grid.draw.gTree(x$children[[i]], recording = FALSE)
11: grid.draw(x$children[[i]], recording = FALSE)
10: drawGTree(x)
9: recordGraphics(drawGTree(x), list(x = x), getNamespace("grid"))
8: grid.draw.gTree(x$children[[i]], recording = FALSE)
7: grid.draw(x$children[[i]], recording = FALSE)
6: drawGTree(x)
5: recordGraphics(drawGTree(x), list(x = x), getNamespace("grid"))
4: grid.draw.gTree(gtable)
3: grid.draw(gtable)
2: print.ggplot(x)
1: (function (x, ...)
UseMethod("print"))(x)
You need to share what is inside the geom_net()
function.
Currently
geom_net <- function (
mapping = NULL, data = NULL, stat = "net", position = "identity", show.legend = NA, na.rm = FALSE, inherit.aes = TRUE,
layout.alg="kamadakawai", layout.par=list(), directed = FALSE, fiteach=FALSE, selfloops = FALSE, singletons = TRUE,
alpha = 0.25, ecolour=NULL, ealpha=NULL, arrow=NULL, arrowgap=0.01, arrowsize=1,
labelon=FALSE, labelcolour=NULL, labelgeom = 'text', repel = FALSE,
vertices=NULL, ...) {
##browser()
ggplot2::layer(
geom = GeomNet, mapping = mapping, data = data, stat = stat,
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
params = list(na.rm = na.rm, layout.alg=layout.alg, layout.par=layout.par, fiteach=fiteach, labelon=labelon, labelgeom=labelgeom,
ecolour = ecolour, ealpha=ealpha, arrow=arrow, arrowgap=arrowgap, directed=directed, repel=repel,
arrowsize=arrowsize, singletons=singletons,
labelcolour=labelcolour, vertices=vertices, selfloops = selfloops,
...)
)
}
and
GeomNet <- ggplot2::ggproto("GeomNet", ggplot2::Geom,
required_aes = c("x", "y"),
default_aes = ggplot2::aes(width = 0.75, linetype = "solid", fontsize=5, label = NULL,
shape = 19, colour = "grey40", arrowsize = 1,
size = 4, fill = NA, alpha = NA, stroke = 0.5,
linewidth=1, angle=0, vjust=0, hjust=0.5, curvature = 0),
draw_key = function(data, params, size) {
# #browser()
draw_arrow <- NULL
if (params$directed) {
if (any(data$curvature != 0)){
draw_arrow <- arrow(length = unit(params$arrowsize*5,"points"), type="open")
}
else{
draw_arrow <- arrow(length = unit(params$arrowsize*5,"points"), type="closed")
}
}
with(data, grobTree(
grid::pointsGrob(x = c(.15, .85), y = c(.85, .15),
pch = data$shape, size = unit(data$size, "points"),
gp = grid::gpar(col = alpha(data$colour, data$alpha),
fill = alpha(data$fill, data$alpha),
fontsize = data$size * .pt + data$stroke * .stroke/2,
lwd = data$stroke * .stroke/2)
),
grid::segmentsGrob(x0 = .15, y0 = .85 ,
x1 = ifelse(is.null(draw_arrow), .85, .82),
y1 = ifelse(is.null(draw_arrow), .15, .18),
gp = grid::gpar(
col = alpha(data$colour, data$alpha),
fill = alpha(data$colour, data$alpha),
lwd = data$linewidth,
lty = data$linetype,
lineend="butt"),
arrow = draw_arrow
)
))
},
setup_data = function(data, params, mapping) {
# cat("setup_data geom_net\n")
##BROWSER()
data$from <- as.character(data$from)
data$to <- as.character(data$to)
selfie <- (data$from == data$to) & (params$selfloops == TRUE)
# maximum radius is at the moment hard coded to 0.05
data$ymax = max(with(data, pmax(y, yend) + 2*0.05*selfie))
data$xmax = with(data, pmax(x, xend) + 2*0.05*selfie)
data$from <- factor(data$from)
data$to <- factor(data$to)
data
},
draw_panel = function(data, panel_scales, coord, ecolour=NULL, ealpha=NULL, arrow=NULL, arrowgap=0.01,
directed=FALSE, arrowsize=1, repel = FALSE, singletons = TRUE,
labelon=FALSE, labelgeom='text', labelcolour=NULL, selfloops = FALSE) {
# browser()
# data$self <- as.character(data$to) == as.character(data$from)
edges <- data.frame(
x = data$x,
xend = data$xend,
y = data$y,
yend = data$yend,
weight = data$weight,
colour = ecolour %||% ifelse(data$.samegroup, data$colour, "grey40"),
linewidth = data$linewidth %||% (data$size / 4),
nodesize = data$size,
alpha = ealpha %||% data$alpha,
linetype=data$linetype,
stroke = data$stroke,
selfie = data$.selfie,
stringsAsFactors = FALSE
)
selfy <- subset(edges, selfie == TRUE)
edges <- subset(edges, selfie != TRUE) # what are we going to do with self references?
edges <- subset(edges, !is.na(xend))
# if (singletons) {
vertices <- data.frame(
x = data$x,
y = data$y,
colour = data$colour,
shape = data$shape,
size = data$size,
fill = NA,
alpha = data$alpha,
stroke = 0.5,
stringsAsFactors = FALSE
)
vertices <- unique(vertices)
# } else {
# vertices <- data.frame(
# from = data$from,
# to = data$to,
# x = data$x,
# y = data$y,
# colour = data$colour,
# shape = data$shape,
# size = data$size,
# fill = NA,
# alpha = data$alpha,
# stroke = 0.5,
# stringsAsFactors = FALSE
# )
# all_singletons <- vertices$from[vertices$from == vertices$to]
# true_singletons <- all_singletons[!all_singletons %in% vertices$to[vertices$from != vertices$to]]
# vertices <- vertices[!vertices$from %in% true_singletons,]
# vertices <- vertices[,-c(1,2)]
# vertices <- unique(vertices)
# }
if (directed) {
if (any(data$curvature != 0)) {
if (is.null(arrow)) arrow = arrow(length = unit(data$arrowsize*10,"points"), type="open")
} else {
if (is.null(arrow)) arrow = arrow(length = unit(data$arrowsize*10,"points"), type="closed")
}
arrowgap <- with(edges, arrowgap/sqrt((xend-x)^2+(yend-y)^2))
edges <- transform(
edges,
xend = x + (1-arrowgap)*(xend-x),
yend = y + (1-arrowgap)*(yend-y),
x = x + arrowgap*(xend-x),
y = y + arrowgap*(yend-y)
)
} else arrow=NULL
#
if (any(data$curvature != 0)){
edges_draw <- GeomCurve$draw_panel(edges, panel_scales,
coord, arrow=arrow, curvature=data$curvature[1], angle=90)
}
else {edges_draw <- GeomSegment$draw_panel(edges, panel_scales, coord, arrow, lineend = "round")}
#
selfies_draw <- NULL
if ((nrow(selfy) > 0) & selfloops) {
selfy$radius <- min(0.04, 1/sqrt(nrow(vertices)))
selfy <- transform(selfy,
x = x + (radius + nodesize/(100*.pt) + linewidth/100)/sqrt(2),
y = y + (radius + nodesize/(100*.pt) + linewidth/100)/sqrt(2),
linewidth = linewidth*.pt,
fill = NA
)
selfies_draw <- GeomCircle$draw_panel(selfy, panel_scales, coord)
}
selfies_arrows <- NULL
if ((nrow(selfy) > 0) & selfloops & directed) {
#
selfy_arrows <- transform (
selfy,
xend = x - 0.5* arrowsize*.pt/100,
yend = y-0.04 - linewidth/100,
y = y-0.04 - linewidth/100
)
selfies_arrows <- GeomSegment$draw_panel(selfy_arrows, panel_scales, coord,
arrow=arrow)
}
label_grob <- NULL
if (labelon | !is.null(data$label)) {
# if (singletons){
labels <- data.frame(
x = data$x,
y = data$y,
label = data$label %||% data$from,
colour = labelcolour %||% data$colour,
shape = data$shape,
size = data$fontsize,
angle = data$angle,
alpha = data$alpha,
hjust = data$hjust,
fill = data$colour,
vjust = data$vjust,
stringsAsFactors = FALSE
)
labels <- unique(labels)
# } else {
# labels <- data.frame(
# from = data$from,
# to = data$to,
# x = data$x,
# y = data$y,
# label = data$label %||% data$from,
# colour = labelcolour %||% data$colour,
# shape = data$shape,
# size = data$fontsize,
# angle = data$angle,
# alpha = data$alpha,
# hjust = data$hjust,
# fill = data$colour,
# vjust = data$vjust,
# stringsAsFactors = FALSE
# )
# labels <- labels[!labels$from %in% true_singletons,]
# labels <- labels[,-c(1,2)]
# labels <- unique(labels)
# }
# if (labelgeom=='label'){
# label_grob <- GeomLabel$draw_panel(labels, panel_scales, coord)
# }
# else {label_grob <- GeomText$draw_panel(labels, panel_scales, coord)}
# }
if (labelgeom=='label'){
if(repel){
label_grob <- ggrepel::GeomLabelRepel$draw_panel(labels, panel_scales, coord)
} else {label_grob <- ggplot2::GeomLabel$draw_panel(labels, panel_scales, coord)}
} else {
if(repel){
labels$point.size <- 1
labels$bg.colour <- NA
labels$bg.r <- 0.1
label_grob <- ggrepel::GeomTextRepel$draw_panel(labels, panel_scales, coord)
} else{label_grob <- ggplot2::GeomText$draw_panel(labels, panel_scales, coord)}
}
}
ggplot2:::ggname("geom_net", grobTree(
edges_draw,
selfies_draw,
selfies_arrows,
GeomPoint$draw_panel(vertices, panel_scales, coord),
label_grob
))
}
)
I added the lines
to solve other issues I detected due to new variables you added to ggrepel, although if this should be done in other way, please let me know.
At some point between 1a267f4 and 8d16037 some variables in makeContent.textrepeltree
, when grobs
is defined through
grobs <- lapply(seq_along(valid_strings), function(i) {
change their definition, I mean, for example for segment.gp
, row$segment.colour
or row$segment.size
are used instead of x$segment.colour
and x$segment.size
respectively, where row <- x$data[i, , drop = FALSE]
.
Variables which were saved at x
are not there anymore and are supposed to be at x$data
, assumption which I suspect is the cause of the last error reported:
Error in check.length(gparname) :
'gpar' element 'lwd' must not be length 0
What is the reason for this change and how should we deal with it? (I will try to investigate too)
Thanks!
If you want to use the lower-level functions, then you will need to study the ggrepel code and re-create all of the same columns in your package to match the ones that are used internally in the ggrepel code. If that internal ggrepel code changes, then your code will break.
I didn't really expect other packages would be calling ggrepel::GeomTextRepel$draw_panel()
, because I think of it as an internal function. My expectation was that users would be using geom_text_repel()
instead (which eventually calls that internal function with all the right parameters).
Do you think there is a way to modify ggrepel code so that you can use the internal draw_panel()
function and not worry about the way variables are named in ggrepel? If there is, maybe that would be a nice modification for other packages that depend on ggrepel.
I believe I fixed the issue, so I will close it for the moment. I had to add to the data passed to ggrepel::GeomTextRepel$draw_panel
(labels
) (many of) the new variables you added in
https://github.com/slowkow/ggrepel/blob/0f34805b28abc239cc96fc497e7461910c15086a/R/geom-text-repel.R#L238-L243
Thanks!
@iago-pssjd With your solution, the geomnet code will break again when ggrepel changes one of those variables.
I think it might be possible to find another solution, where geomnet does not need to be aware of all these variables, so it will be more robust to future changes in the ggrepel code. This would probably involve changing the ggrepel draw_panel()
function in some way, but I will leave that to you to explore if you wish. For example, maybe the draw_panel()
function could check for missing columns and add them if they are missing.
For now, I'm glad you found a path forward. Good luck!
@slowkow That's a good point.
I have just detected that instead of adding each variable in a separate step ggrepel::GeomTextRepel$default_aes
is a list with the names and defaults of default_aes
and this coul be used either
geomnet
ggrepel::GeomTextRepel$draw_panel()
ggrepel:::makeContent.textrepeltree
Sorry for lack of specificity on title.
Summary
I am trying to update an archived package which calls to
ggrepel
. Although it passes all the tests, certain example working either withggplot2::GeomText$draw_panel(labels, panel_scales, coord)
orggplot2::GeomTextRepel$draw_panel(labels, panel_scales, coord)
(or with label instead of text), it works with theggplot2
version, but it gives an error with theggrepel
option.First, I am working with current R 4.4.1 and
ggplot2
release 3.4.3 on Debian 12.I see that until commit 1a267f4 (2018-10-30) (and/or CRAN release 0.8.2), it works. After commit f4ebe30 (2019-01-02), it does not print labels and it produces
Same until commit 306c074 (2019-04-30). From commit b8352c1 (2019-05-01) to commit e02dfdf (2019-11-03) I cannot even install the package. Then, with commit 8d16037 (2019-11-03) I can install again, the used code print no labels and then, when printing the produced plot, I get the error
where
labels
is adata.frame
with 53 rows (see below); and this is the same as for most recent versions of bothggplot2
andggrepel
(from CRAN release 0.9.0) installed.I tried using
ggplot2::GeomTextRepel$draw_panel(labels, panel_scales, coord, max.overlaps = Inf)
with the same result.May you give me some hint on how should I proceed?
Thanks a lot!
The objects passed to `GeomTextRepel`: