diff --git a/R/plot.R b/R/plot.R index 95fa53c49ff..4e10254f7ec 100644 --- a/R/plot.R +++ b/R/plot.R @@ -99,7 +99,9 @@ plot.igraph <- function(x, ################################################################ ## Visual parameters params <- i.parse.plot.params(graph, list(...)) - vertex.size <- 1 / 200 * params("vertex", "size") + + vertex.size <- params("vertex", "size") + vertex.size.scaling <- params("vertex", "size.scaling") label.family <- params("vertex", "label.family") label.font <- params("vertex", "label.font") label.cex <- params("vertex", "label.cex") @@ -140,6 +142,7 @@ plot.igraph <- function(x, ylab <- params("plot", "ylab") palette <- params("plot", "palette") + if (!is.null(palette)) { old_palette <- palette(palette) on.exit(palette(old_palette), add = TRUE) @@ -150,12 +153,13 @@ plot.igraph <- function(x, ################################################################ ## create the plot - maxv <- max(vertex.size) - if (vc > 0 && rescale) { - # norm layout to (-1, 1) + if (rescale) { layout <- norm_coords(layout, -1, 1, -1, 1) - xlim <- c(xlim[1] - margin[2] - maxv, xlim[2] + margin[4] + maxv) - ylim <- c(ylim[1] - margin[1] - maxv, ylim[2] + margin[3] + maxv) + fact <- (1 - vertex.size.scaling) + maxv <- 1 / 200 * max(vertex.size) + + xlim <- c(xlim[1] - margin[2] - fact * maxv, xlim[2] + margin[4] + fact * maxv) + ylim <- c(ylim[1] - margin[1] - fact * maxv, ylim[2] + margin[3] + fact * maxv) } if (!add) { plot(0, 0, @@ -165,6 +169,49 @@ plot.igraph <- function(x, ) } + ################################################################ + ## Rescaling vertices and updating params + if (vertex.size.scaling) { + newdots <- list(...) + + # vertex.size + vertex.size <- i.rescale.vertex(vertex.size, + minmax.relative.size = + params("vertex", "relative.size") + ) + newdots$vertex.size <- vertex.size + + # vertex.size2: Notice that in this case we need to ajust the scale + # in two ways: (1) On the relative size of the axes, and (2) on the + # relative size of vertex.size/vertex.size2 + + scalefactor <- parusr <- par("usr") + scalefactor <- (parusr[2] - parusr[1]) / (parusr[4] - parusr[3]) + if ("vertex.size2" %in% names(newdots)) { # If the user provided -vertex.size2- + + scalefactor <- scalefactor * ( + max(params("vertex", "size2"), na.rm = TRUE) / max(params("vertex", "size"), na.rm = TRUE)) + + newdots$vertex.size2 <- i.rescale.vertex( + params("vertex", "size2"), + parusr[3:4] * scalefactor, + params("vertex", "relative.size") + ) + } else { # Otherwise use -vertex.size- + newdots$vertex.size2 <- i.rescale.vertex( + params("vertex", "size"), + parusr[3:4] * scalefactor, + params("vertex", "relative.size") + ) + } + + params <- i.parse.plot.params(graph, newdots) + } else { + params <- i.parse.plot.params( + graph, + list(vertex.size = 1 / 200 * vertex.size, vertex.size2 = 1 / 200 * params("vertex", "size2")) + ) + } ################################################################ ## Mark vertex groups if (!is.list(mark.groups) && is.numeric(mark.groups)) { @@ -778,7 +825,20 @@ rglplot.igraph <- function(x, ...) { label.degree <- params("vertex", "label.degree") label.dist <- params("vertex", "label.dist") vertex.color <- params("vertex", "color") - vertex.size <- (1 / 200) * params("vertex", "size") + + vertex.size <- params("vertex", "size") + vertex.size.scaling <- params("vertex", "size.scaling") + + # Rescaling vertex size + if (vertex.size.scaling) { + vertex.size <- i.rescale.vertex( + vertex.size, rgl::par3d("scale")[1:2] * c(-1, 1), + params("vertex", "relative.size") + ) + } else { + vertex.size <- (1 / 200) * params("vertex", "size") + } + loop.angle <- params("edge", "loop.angle") loop.angle2 <- params("edge", "loop.angle2") diff --git a/R/plot.common.R b/R/plot.common.R index 6590ca69937..754e9560aba 100644 --- a/R/plot.common.R +++ b/R/plot.common.R @@ -83,7 +83,7 @@ #' order have about the same size of vertices for a given value for all three #' plotting commands. It does not need to be an integer number. #' The default value is 15. This is big enough to place short labels on -#' vertices.} +#' vertices. If `size.scaling` is `TRUE`, `relative.size` is used to scale the size appropriately.} #' \item{size2}{The \dQuote{other} size of the vertex, for some #' vertex shapes. For the various rectangle shapes this gives the height of the #' vertices, whereas `size` gives the width. It is ignored by shapes for @@ -209,7 +209,21 @@ #' labels, see the `color` vertex parameter discussed earlier for the #' possible values. #' -#' The default value is `black`. } } +#' The default value is `black`.} +#' +#' \item{size.scaling}{Switches between absolute vertex sizing (FALSE,default) and relative (TRUE). +#' If FALSE, `vertex.size` and `vertex.size2` are used as is. IF TRUE, +#' `relative.size` is used to scale both appropriately with `relative.size`} +#' +#' \item{relative.size}{ +#' The relative size of the smallest and largest vertices as percentage of +#' the plotting region. When all vertices have the same size, then by default +#' the relative size observed in the plot will be equal to +#' \code{relative.size[2]}. +#' The default value is \code{c(.01,.025)} (1\% and 2.5\% respectively). +#' +#' Only used if `size.scaling` is TRUE`. +#' }} #' #' Edge parameters require to add the \sQuote{\code{edge.}} prefix when used as #' arguments or set by [igraph_options()]. The edge parameters: @@ -417,11 +431,19 @@ #' vertex.size = 10, #' vertex.color = "green" #' ) +#' +#' # use relative scaling instead of absolute +#' g <- make_famous_graph("Zachary") +#' igraph_options(plot.layout = layout_nicely) +#' plot(g, vertex.size = degree(g)) +#' plot(g, vertex.size = degree(g), size.scaling = TRUE) +#' plot(g, vertex.size = degree(g), size.scaling = TRUE, relative.size = c(0.05, 0.1)) #' } #' @name plot.common #' @rdname plot.common NULL + #' Optimal edge curvature when plotting graphs #' #' @description @@ -1380,7 +1402,9 @@ i.vertex.default <- list( pie.angle = 45, pie.density = -1, pie.lty = 1, - raster = .igraph.logo.raster + raster = .igraph.logo.raster, + size.scaling = FALSE, + relative.size = c(0.01, 0.025) ) i.edge.default <- list( @@ -1418,6 +1442,33 @@ i.plot.default <- list( i.default.values <- new.env() i.default.values[["vertex"]] <- i.vertex.default + +i.default.values[["edge"]] <- i.edge.default +i.default.values[["plot"]] <- i.plot.default + +# Rescale vertex size +# +# Rescale the size of the vertex according to the device dimmensions +# By default uses x1 and x2. +# +# @param size Numeric vector with relative sizes. +# @param plot.reg.coords Coordinates of the device. +# @param minmax.relative.size Relative minimum and maximun sizes in terms of +# percent of the device scale. +# +# To use the default values (calling par()), it should be done after calling +# the device and specifying its dimmensions. +i.rescale.vertex <- function(size, plot.reg.coords = par("usr")[1:2], + minmax.relative.size) { + # Adjusting + ran <- range(size, na.rm = TRUE) + scal <- (plot.reg.coords[2] - plot.reg.coords[1]) * minmax.relative.size + size <- (size - ran[1] + 1e-15) / (ran[2] - ran[1] + 1e-15) * + (scal[2] - scal[1]) + scal[1] + + return(size) +} + i.default.values[["edge"]] <- i.edge.default i.default.values[["plot"]] <- i.plot.default diff --git a/R/plot.shapes.R b/R/plot.shapes.R index 4581ed964b1..685dd7a9585 100644 --- a/R/plot.shapes.R +++ b/R/plot.shapes.R @@ -261,7 +261,7 @@ add.vertex.shape <- function(shape, clip = shape_noclip, plot = shape_noplot, pa #' if (length(vertex.color) != 1 && !is.null(v)) { #' vertex.color <- vertex.color[v] #' } -#' vertex.size <- 1 / 200 * params("vertex", "size") +#' vertex.size <- params("vertex", "size") #' if (length(vertex.size) != 1 && !is.null(v)) { #' vertex.size <- vertex.size[v] #' } @@ -289,7 +289,7 @@ add.vertex.shape <- function(shape, clip = shape_noclip, plot = shape_noplot, pa #' if (length(vertex.color) != 1 && !is.null(v)) { #' vertex.color <- vertex.color[v] #' } -#' vertex.size <- 1 / 200 * params("vertex", "size") +#' vertex.size <- params("vertex", "size") #' if (length(vertex.size) != 1 && !is.null(v)) { #' vertex.size <- vertex.size[v] #' } @@ -401,7 +401,7 @@ add_shape <- function(shape, clip = shape_noclip, return(coords) } - vertex.size <- 1 / 200 * params("vertex", "size") + vertex.size <- params("vertex", "size") if (end == "from") { phi <- atan2(coords[, 4] - coords[, 2], coords[, 3] - coords[, 1]) @@ -463,7 +463,8 @@ add_shape <- function(shape, clip = shape_noclip, if (length(vertex.frame.width) != 1 && !is.null(v)) { vertex.frame.width <- vertex.frame.width[v] } - vertex.size <- 1 / 200 * params("vertex", "size") + vertex.size <- params("vertex", "size") + if (length(vertex.size) != 1 && !is.null(v)) { vertex.size <- vertex.size[v] } @@ -499,7 +500,7 @@ add_shape <- function(shape, clip = shape_noclip, return(coords) } - vertex.size <- 1 / 200 * params("vertex", "size") + vertex.size <- params("vertex", "size") square.shift <- function(x0, y0, x1, y1, vsize) { m <- (y0 - y1) / (x0 - x1) @@ -578,7 +579,8 @@ add_shape <- function(shape, clip = shape_noclip, if (length(vertex.frame.width) != 1 && !is.null(v)) { vertex.frame.width <- vertex.frame.width[v] } - vertex.size <- 1 / 200 * params("vertex", "size") + vertex.size <- params("vertex", "size") + if (length(vertex.size) != 1 && !is.null(v)) { vertex.size <- vertex.size[v] } @@ -614,7 +616,7 @@ add_shape <- function(shape, clip = shape_noclip, return(coords) } - vertex.size <- 1 / 200 * params("vertex", "size") + vertex.size <- params("vertex", "size") square.shift <- function(x0, y0, x1, y1, vsize) { l <- cbind( @@ -676,8 +678,8 @@ add_shape <- function(shape, clip = shape_noclip, return(coords) } - vertex.size <- 1 / 200 * params("vertex", "size") - vertex.size2 <- 1 / 200 * params("vertex", "size2") + vertex.size <- params("vertex", "size") + vertex.size2 <- params("vertex", "size2") rec.shift <- function(x0, y0, x1, y1, vsize, vsize2) { m <- (y0 - y1) / (x0 - x1) @@ -766,12 +768,13 @@ add_shape <- function(shape, clip = shape_noclip, if (length(vertex.frame.width) != 1 && !is.null(v)) { vertex.frame.width <- vertex.frame.width[v] } - vertex.size <- 1 / 200 * params("vertex", "size") + vertex.size <- params("vertex", "size") if (length(vertex.size) != 1 && !is.null(v)) { vertex.size <- vertex.size[v] } vertex.size <- rep(vertex.size, length.out = nrow(coords)) - vertex.size2 <- 1 / 200 * params("vertex", "size2") + vertex.size2 <- params("vertex", "size2") + if (length(vertex.size2) != 1 && !is.null(v)) { vertex.size2 <- vertex.size2[v] } @@ -807,8 +810,8 @@ add_shape <- function(shape, clip = shape_noclip, return(coords) } - vertex.size <- 1 / 200 * params("vertex", "size") - vertex.size2 <- 1 / 200 * params("vertex", "size2") + vertex.size <- params("vertex", "size") + vertex.size2 <- params("vertex", "size2") rec.shift <- function(x0, y0, x1, y1, vsize, vsize2) { l <- cbind( @@ -880,8 +883,8 @@ add_shape <- function(shape, clip = shape_noclip, return(coords) } - vertex.size <- 1 / 200 * params("vertex", "size") - vertex.size2 <- 1 / 200 * params("vertex", "size2") + vertex.size <- params("vertex", "size") + vertex.size2 <- params("vertex", "size2") rec.shift <- function(x0, y0, x1, y1, vsize, vsize2) { l <- cbind(x1 - vsize, y1, x1 + vsize, y1) @@ -989,7 +992,7 @@ mypie <- function(x, y, values, radius, edges = 200, col = NULL, angle = 45, return(coords) } - vertex.size <- 1 / 200 * params("vertex", "size") + vertex.size <- params("vertex", "size") if (end == "from") { phi <- atan2(coords[, 4] - coords[, 2], coords[, 3] - coords[, 1]) @@ -1049,7 +1052,7 @@ mypie <- function(x, y, values, radius, edges = 200, col = NULL, angle = 45, } vertex.color <- getparam("color") vertex.frame.color <- getparam("frame.color") - vertex.size <- rep(1 / 200 * getparam("size"), length.out = nrow(coords)) + vertex.size <- rep(getparam("size"), length = nrow(coords)) vertex.pie <- getparam("pie") vertex.pie.color <- getparam("pie.color") vertex.pie.angle <- getparam("pie.angle") @@ -1090,8 +1093,9 @@ mypie <- function(x, y, values, radius, edges = 200, col = NULL, angle = 45, } p } - vertex.color <- rep(getparam("color"), length.out = nrow(coords)) - vertex.size <- rep(1 / 200 * getparam("size"), length.out = nrow(coords)) + + vertex.color <- rep(getparam("color"), length = nrow(coords)) + vertex.size <- rep(getparam("size"), length = nrow(coords)) ## Need to create a separate image for every different vertex color allcols <- unique(vertex.color) @@ -1131,8 +1135,8 @@ mypie <- function(x, y, values, radius, edges = 200, col = NULL, angle = 45, p } - size <- rep(1 / 200 * getparam("size"), length.out = nrow(coords)) - size2 <- rep(1 / 200 * getparam("size2"), length.out = nrow(coords)) + size <- rep(getparam("size"), length = nrow(coords)) + size2 <- rep(getparam("size2"), length = nrow(coords)) raster <- getparam("raster") for (i in seq_len(nrow(coords))) { diff --git a/R/tkplot.R b/R/tkplot.R index f44cb1f8fc6..23420196e05 100644 --- a/R/tkplot.R +++ b/R/tkplot.R @@ -340,6 +340,12 @@ tkplot <- function(graph, canvas.width = 450, canvas.height = 450, ...) { label.dist <- params("vertex", "label.dist") vertex.color <- .tkplot.convert.color(params("vertex", "color")) vertex.size <- params("vertex", "size") + + # Adjusting size + vertex.size <- i.rescale.vertex( + vertex.size, c(-canvas.width, canvas.height)/2, + params("vertex", "relative.size")) + vertex.frame.color <- .tkplot.convert.color(params("vertex", "frame.color")) edge.color <- .tkplot.convert.color(params("edge", "color")) diff --git a/man/plot.common.Rd b/man/plot.common.Rd index 9890d261991..a68c65571a3 100644 --- a/man/plot.common.Rd +++ b/man/plot.common.Rd @@ -92,7 +92,7 @@ latter case each vertex sizes may differ. This vertex sizes are scaled in order have about the same size of vertices for a given value for all three plotting commands. It does not need to be an integer number. The default value is 15. This is big enough to place short labels on -vertices.} +vertices. If \code{size.scaling} is \code{TRUE}, \code{relative.size} is used to scale the size appropriately.} \item{size2}{The \dQuote{other} size of the vertex, for some vertex shapes. For the various rectangle shapes this gives the height of the vertices, whereas \code{size} gives the width. It is ignored by shapes for @@ -218,7 +218,21 @@ The default value is \code{-pi/4}. } labels, see the \code{color} vertex parameter discussed earlier for the possible values. -The default value is \code{black}. } } +The default value is \code{black}.} + +\item{size.scaling}{Switches between absolute vertex sizing (FALSE,default) and relative (TRUE). +If FALSE, \code{vertex.size} and \code{vertex.size2} are used as is. IF TRUE, +\code{relative.size} is used to scale both appropriately with \code{relative.size}} + +\item{relative.size}{ +The relative size of the smallest and largest vertices as percentage of +the plotting region. When all vertices have the same size, then by default +the relative size observed in the plot will be equal to +\code{relative.size[2]}. +The default value is \code{c(.01,.025)} (1\\% and 2.5\\% respectively). + +Only used if \code{size.scaling} is TRUE`. +}} Edge parameters require to add the \sQuote{\code{edge.}} prefix when used as arguments or set by \code{\link[=igraph_options]{igraph_options()}}. The edge parameters: @@ -424,6 +438,13 @@ tkplot(make_tree(50, 2, mode = "undirected"), vertex.size = 10, vertex.color = "green" ) + +# use relative scaling instead of absolute +g <- make_famous_graph("Zachary") +igraph_options(plot.layout = layout_nicely) +plot(g, vertex.size = degree(g)) +plot(g, vertex.size = degree(g), size.scaling = TRUE) +plot(g, vertex.size = degree(g), size.scaling = TRUE, relative.size = c(0.05, 0.1)) } } \seealso{ diff --git a/man/rglplot.Rd b/man/rglplot.Rd index 3a078863649..67b89564b94 100644 --- a/man/rglplot.Rd +++ b/man/rglplot.Rd @@ -31,7 +31,7 @@ arguments. g <- make_lattice(c(5, 5, 5)) coords <- layout_with_fr(g, dim = 3) -\dontshow{if (interactive() && rlang::is_installed("rgl")) withAutoprint(\{ # examplesIf} +\dontshow{if (interactive() && rlang::is_installed("rgl")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} rglplot(g, layout = coords) \dontshow{\}) # examplesIf} } diff --git a/man/shapes.Rd b/man/shapes.Rd index 22b10927f37..c479b2fdf5d 100644 --- a/man/shapes.Rd +++ b/man/shapes.Rd @@ -146,7 +146,7 @@ mytriangle <- function(coords, v = NULL, params) { if (length(vertex.color) != 1 && !is.null(v)) { vertex.color <- vertex.color[v] } - vertex.size <- 1 / 200 * params("vertex", "size") + vertex.size <- params("vertex", "size") if (length(vertex.size) != 1 && !is.null(v)) { vertex.size <- vertex.size[v] } @@ -174,7 +174,7 @@ mystar <- function(coords, v = NULL, params) { if (length(vertex.color) != 1 && !is.null(v)) { vertex.color <- vertex.color[v] } - vertex.size <- 1 / 200 * params("vertex", "size") + vertex.size <- params("vertex", "size") if (length(vertex.size) != 1 && !is.null(v)) { vertex.size <- vertex.size[v] } diff --git a/man/vertex.shape.pie.Rd b/man/vertex.shape.pie.Rd index 41f29019379..e77eb73e9ec 100644 --- a/man/vertex.shape.pie.Rd +++ b/man/vertex.shape.pie.Rd @@ -31,7 +31,7 @@ slices.} } g <- make_ring(10) values <- lapply(1:10, function(x) sample(1:10, 3)) -\dontshow{if (interactive()) withAutoprint(\{ # examplesIf} +\dontshow{if (interactive()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} plot(g, vertex.shape = "pie", vertex.pie = values, vertex.pie.color = list(heat.colors(5)), diff --git a/tests/testthat/_snaps/plot/basic-graph-layout-1.svg b/tests/testthat/_snaps/plot/basic-graph-layout-1.svg index d8d1dc241fa..cbb18228d35 100644 --- a/tests/testthat/_snaps/plot/basic-graph-layout-1.svg +++ b/tests/testthat/_snaps/plot/basic-graph-layout-1.svg @@ -25,7 +25,7 @@ - + diff --git a/tests/testthat/_snaps/plot/basic-graph-layout-2.svg b/tests/testthat/_snaps/plot/basic-graph-layout-2.svg index f0808d3e4c3..46111bdeb72 100644 --- a/tests/testthat/_snaps/plot/basic-graph-layout-2.svg +++ b/tests/testthat/_snaps/plot/basic-graph-layout-2.svg @@ -25,7 +25,7 @@ - + diff --git a/tests/testthat/_snaps/plot/basic-graph-spheres.svg b/tests/testthat/_snaps/plot/basic-graph-spheres.svg index f35282245e1..0d0423a8260 100644 --- a/tests/testthat/_snaps/plot/basic-graph-spheres.svg +++ b/tests/testthat/_snaps/plot/basic-graph-spheres.svg @@ -25,7 +25,6 @@ - diff --git a/tests/testthat/_snaps/plot/loop-graph.svg b/tests/testthat/_snaps/plot/loop-graph.svg index 91cf9f3730a..245c8ffb98f 100644 --- a/tests/testthat/_snaps/plot/loop-graph.svg +++ b/tests/testthat/_snaps/plot/loop-graph.svg @@ -25,8 +25,8 @@ - -green + +green red diff --git a/tests/testthat/_snaps/plot/rectangle-edges.svg b/tests/testthat/_snaps/plot/rectangle-edges.svg index 9687c3c7ce9..b37ed4d6b42 100644 --- a/tests/testthat/_snaps/plot/rectangle-edges.svg +++ b/tests/testthat/_snaps/plot/rectangle-edges.svg @@ -25,27 +25,27 @@ - - - + + + - - + + - - - - + + + + - - + + - - - - - - + + + + + + 1 diff --git a/tests/testthat/test-plot.R b/tests/testthat/test-plot.R index 0874cc09d3a..82cc2e908d1 100644 --- a/tests/testthat/test-plot.R +++ b/tests/testthat/test-plot.R @@ -121,6 +121,7 @@ test_that("Edges stop at outside of rectangle node", { ) plot(g, vertex.size = 30, + vertex.size2 = 30, vertex.color = rgb(0.1, 0.7, 0.8, 0.1), vertex.shape = "rectangle", layout = layout