15  Sigma.js: high-level API

library(rtemis.draw)

Attaching package: 'rtemis.draw'
The following object is masked from 'package:graphics':

    Axis

Network plots use Sigma.js for rendering and graphology for layout and community detection. draw_network() accepts a square weight matrix or an edge-list data frame. The graph model is also used in rtemis.live.

Like the other draw_* functions, network plots automatically follow your system’s light/dark setting. Communities are detected with the Louvain algorithm and the default layout is ForceAtlas2. Both run in the browser, with reproducible layouts for a given graph and configuration.

15.1 A collaboration network

We will use a synthetic network of 150 researchers in five teams. Each node is a researcher; each edge is a collaboration, weighted by the number of joint projects. Researchers collaborate more often within their team, with a few connections between teams. These are simulated data, not observations.

The fixed seed reproduces the same network using only base R. The identifiers A01 through E30 indicate team membership. A connecting chain ensures that no researcher is isolated.

set.seed(42)
team <- rep(LETTERS[1:5], each = 30)
id <- sprintf("%s%02d", team, rep(seq_len(30), 5))
n <- length(id)

# Collaborations are more likely within a team than between teams.
same_team <- outer(team, team, "==")
weights <- matrix(0, n, n, dimnames = list(id, id))
linked <- matrix(runif(n * n), n) < ifelse(same_team, 0.12, 0.002)
linked <- linked & upper.tri(weights)

# A chain connects every researcher, including adjacent teams.
linked[cbind(seq_len(n - 1), 2:n)] <- TRUE
within_team <- linked & same_team
between_teams <- linked & !same_team
weights[within_team] <- sample(3:8, sum(within_team), replace = TRUE)
weights[between_teams] <- sample(1:2, sum(between_teams), replace = TRUE)
weights <- weights + t(weights)

15.2 From a weight matrix

Entry [i, j] gives the edge weight between researchers i and j; zero means no connection. Node identifiers come from the matrix dimnames. Edge thickness represents weight, and node size defaults to weighted degree: here, the sum of joint-project counts across a researcher’s collaborations.

Small nodes and translucent edges keep the overview readable. Hover a node to see its identifier and highlight its neighbors; scroll to zoom and drag to pan. show_labels = FALSE hides persistent labels while retaining hover details.

network <- draw_network(
  weights,
  node_size = 5,
  edge_scale = 2,
  edge_opacity = 0.35,
  show_labels = FALSE,
  title = "Research collaborations",
  height = 600
)
network

By default every nonzero edge is drawn. threshold keeps edges whose absolute weight is at least the specified value. In this example, requiring three joint projects removes the weaker connections between teams while retaining all 150 researchers:

draw_network(
  weights,
  threshold = 3,
  node_size = 5,
  edge_scale = 2,
  edge_opacity = 0.35,
  show_labels = FALSE,
  title = "Collaborations with at least three joint projects",
  height = 600
)

Correlation matrices work the same way: absolute correlations determine edge thickness, signs determine edge color, and threshold filters by absolute correlation. Diagonal entries are omitted unless self_loops = TRUE.

15.3 Communities and layout

Set color_by_group = TRUE to color nodes by their detected Louvain community. These communities are inferred from the connections, rather than assigned from the team labels. resolution tunes the community sizes; higher values favor more, smaller communities. blend_edges blends the colors of an edge’s endpoints.

draw_network(
  weights,
  color_by_group = TRUE,
  blend_edges = TRUE,
  resolution = 1,
  node_size = 5,
  edge_scale = 2,
  edge_opacity = 0.35,
  show_labels = FALSE,
  title = "Communities in the collaboration network",
  height = 600
)

Four layouts are available: "force" (ForceAtlas2, the default), "circular", "circlepack", and "random". The circular layout orders nodes around the ring by detected community. It makes the many connections within communities and the few bridges between them easy to compare:

draw_network(
  weights,
  layout = "circular",
  color_by_group = TRUE,
  blend_edges = TRUE,
  node_size = 4,
  edge_scale = 1.5,
  edge_opacity = 0.3,
  show_labels = FALSE,
  title = "Connections within and between communities",
  height = 600
)

15.4 From an edge list

An edge-list data frame has one row per connection. source and target name the endpoints, with optional weight and sign columns. For this undirected network, use the upper triangle of the matrix so each connection appears once:

endpoints <- which(upper.tri(weights) & weights > 0, arr.ind = TRUE)
edges <- data.frame(
  source = rownames(weights)[endpoints[, 1]],
  target = colnames(weights)[endpoints[, 2]],
  weight = weights[endpoints],
  sign = 1
)
nodes <- data.frame(id = id, label = id, group = team)

The optional nodes table supplies identifiers, display labels, size values (value), and group metadata. Nodes referenced by an edge but absent from the table are added automatically. Here the team is retained as metadata; color_by_group still colors the communities detected from the connections.

draw_network(
  edges,
  nodes = nodes,
  color_by_group = TRUE,
  blend_edges = TRUE,
  node_size = 5,
  edge_scale = 2,
  edge_opacity = 0.35,
  show_labels = FALSE,
  title = "Research collaborations from an edge list",
  height = 600
)

For directed relationships, such as citations, set directed = TRUE. A collaboration is mutual, so this example remains undirected.

15.5 Styling

node_size sets the base radius in screen pixels; edge_scale maps normalized weight to stroke width. The *_opacity arguments control transparency. Set scale_by_degree = FALSE to give all nodes the same size.

palette supplies community colors when color_by_group = TRUE. Otherwise, node_color supplies a single node color. With blend_edges = FALSE (the default), positive_color and negative_color distinguish signed edges. All collaborations here have positive weights:

draw_network(
  weights,
  node_color = rtemis_colors[["blue"]],
  positive_color = rtemis_colors[["teal"]],
  node_size = 4,
  scale_by_degree = FALSE,
  edge_scale = 2,
  edge_opacity = 0.35,
  show_labels = FALSE,
  title = "Collaborations with equal-sized nodes",
  height = 600
)

Use show_labels = TRUE to display node labels as space permits. Hover details include degree and, when community coloring is enabled, the detected community.

15.6 Export a network

Save the first network as editable SVG using its returned widget:

save_drawing(
  network,
  file.path(tempdir(), "research-collaborations.svg"),
  width = 900,
  height = 650
)

This requires Node.js. The export uses the initial layout and theme; subsequent browser zoom and hover states are not part of the saved R object.

15.7 Lower-level API

draw_network() builds the graph and a SigmaOption render spec internally. For explicit node and edge construction, see the same network in the Sigma.js low-level S7 API chapter.

© 2026 E.D. Gennatas