Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: autograph
Title: Automatic Plotting and Theming of Many Graphs
Version: 1.2.0
Version: 1.2.1
Description: Visual exploration and presentation of networks should not be difficult.
This package includes functions for plotting networks and network-related metrics with sensible and pretty defaults.
It includes 'ggplot2'-based plot methods for many popular network package classes.
Expand Down
14 changes: 14 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# autograph 1.2.1

## Layouts

- Fixed "valence" layout returning a poor layout for some random starts
- The nodes now start on a circle, so one run resembles the next
- The repulsion force between two close nodes is now bounded
- Each step is now capped and cools over the iterations

## Tests

- Fixed the tutorial test failing on a deprecation warning that the tutorial code does not raise itself
- Fixed the "valence" layout test depending on the random seed

# autograph 1.2.0

## Package
Expand Down
22 changes: 18 additions & 4 deletions R/layout_valence.R
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ layout_valence <- function(.data, times = 500, center = NULL, circular = FALSE,
rep(1, manynet::net_ties(graph))
weights[is.na(weights)] <- 1

coords <- matrix(stats::runif(n * 2, min = -1, max = 1), ncol = 2)
# The nodes start on a circle rather than at random points, so that the
# layout is stable from one run to the next. A random start can place two
# nodes on top of each other, which the repulsion force then throws apart.
# A small jitter breaks the symmetry of the circle.
angle <- 2 * pi * seq_len(n) / n
coords <- cbind(cos(angle), sin(angle)) +
matrix(stats::runif(n * 2, min = -0.01, max = 0.01), ncol = 2)
Comment on lines +48 to +50

for (i in 1:times) {
delta <- matrix(0, nrow = n, ncol = 2)
Expand All @@ -52,7 +58,10 @@ layout_valence <- function(.data, times = 500, center = NULL, circular = FALSE,
vec <- coords[k, ] - coords[j, ]
dist <- sqrt(sum(vec^2)) + 1e-4
dir <- vec / dist
force <- repulsion_coef / dist^2
# The distance is floored, since two nodes that start close together
# would otherwise repel each other with a force large enough to throw
# the whole layout apart, which it never recovers from.
force <- repulsion_coef / max(dist, 0.1)^2

delta[j, ] <- delta[j, ] - force * dir
delta[k, ] <- delta[k, ] + force * dir
Expand All @@ -75,8 +84,13 @@ layout_valence <- function(.data, times = 500, center = NULL, circular = FALSE,
delta[t_id, ] <- delta[t_id, ] - force * dir
}

# Position update with damping
coords <- coords + 0.1 * delta
# Position update with damping, a capped step, and cooling.
# The cap keeps one large force from moving a node further than the layout
# is wide, and the cooling lets the layout settle over the iterations.
step <- sqrt(rowSums(delta^2))
limit <- ifelse(step > 1, 1 / step, 1)
temp <- 1 - (i - 1) / times
coords <- coords + 0.1 * temp * delta * limit
}
coords <- as.data.frame(coords)
names(coords) <- c("x", "y")
Expand Down
19 changes: 19 additions & 0 deletions cran-comments.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
## Resubmission

This is a resubmission of 1.2.0, which failed the incoming checks with a test error
on Windows and on Debian. Both are fixed here.

* `layout_valence()` started its nodes at random points, and a start that placed two
nodes close together gave a force large enough to spoil the layout. The nodes now
start on a circle, the force is bounded, and the test sets a seed.
* On Windows, the tutorial test failed on a deprecation warning that the tutorial code
does not raise itself: `netrics::tie_by_closeness()` (0.4.1) calls
`manynet::to_ties()`, which manynet deprecates in 2.3.0. netrics 1.0.0, to be
submitted, calls the current function. The test now fails only if the tutorial calls
a deprecated function itself, so it passes with either netrics version.

The full test suite passes with each of these three pairs: manynet 2.2.3 with
netrics 0.4.0, manynet 2.3.1 with netrics 0.4.1 (the pair that failed on Windows),
and manynet 2.3.0 with netrics 1.0.0. manynet 2.3.1 and netrics 1.0.0 are to be
submitted; this version does not require either of them.

## Test environments

* local R installation, aarch64-apple-darwin20, R 4.5.1
Expand Down
19 changes: 19 additions & 0 deletions tests/testthat/helper-tutorials.R
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,25 @@ check_tute_functions <- function(path, skip = "ergm\\(|grapht\\("){
if (!grepl("deprecate|defunct|moved", msg, ignore.case = TRUE)) {
w <- NULL
}

# Only fail if the tutorial calls the deprecated function itself. A
# dependency that calls a deprecated function of its own dependency
# raises the same warning, and no edit to this tutorial can silence it.
if (!is.null(w)) {
code <- paste(deparse(exprs[[i]]), collapse = " ")
# The name a deprecation warning reports, in either the base R form
# ("'to_ties' is deprecated") or the {lifecycle} form
# ("`to_ties()` was deprecated in manynet 2.3.0").
hits <- regmatches(msg, gregexpr(
"[`'\"][^`'\"]+[`'\"][^[:alpha:]]*(is|was|has been)[[:space:]]+(deprecated|defunct|moved)",
msg))[[1]]
named <- gsub("^[`'\"]([^`'\"]+)[`'\"].*$", "\\1", hits)
named <- gsub("\\(\\)$", "", named)
if (length(named) > 0 &&
!any(vapply(named, grepl, logical(1), x = code, fixed = TRUE))) {
w <- NULL
}
Comment on lines +97 to +109
}
}

# Now test what happened
Expand Down
1 change: 1 addition & 0 deletions tests/testthat/test-layout_valence.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
test_that("valence layout works", {
set.seed(123)
edges <- data.frame(from = c("A", "B"),
to = c("B", "C"),
weight = c(3, 3),
Expand Down
Loading