Tracing and Diagnosing Layouts

Installed figures use static projections. To enable 3D rotation and layout selection, render with options(grip.vignette.interactive = TRUE) and ivue and rgl installed.

Why trace a layout?

Most graph-layout functions return only the final coordinate matrix. That is enough for plotting, but it hides the most useful diagnostic information:

The trace.grip() API makes those questions visible through the same metric choice as grip():

library(grip)
source(system.file('scripts','vignette-views.R',package='grip'),local=TRUE)

A first combinatorial trace

The example below traces a planar recursive triangle. Its nested holes make the multiscale construction visible. Using trace = "level" keeps the vignette readable by recording the coarse initialization, the start of each new level, and the final layout.

mesh.edges <- edges.sierpinski.triangle(4)

mesh.trace <- trace.grip(
  mesh.edges,
  n = max(mesh.edges),
  dim = 2,
  preset = "carpet",
  rounds = 48,
  final.rounds = 96,
  trace = "level",
  diagnostics = "light",
  seed = 1
)

knitr::kable(mesh.trace$meta)
frame phase level_index misf_level round_in_level active_vertices
1 init 1 2 0 28
2 level_start 2 1 0 37
3 level_start 3 0 0 123
4 final 3 0 96 123
knitr::kable(mesh.trace$diagnostics[, c(
  "frame",
  "edge.length.cv",
  "median.edge.length",
  "sampled.nonedge.sep.ratio"
)], digits = 3)
frame edge.length.cv median.edge.length sampled.nonedge.sep.ratio
1 NA NA NA
2 NA NA NA
3 0.352 32.119 0.668
4 0.213 28.611 1.507
Frame 4 of 4 — final — 123 active vertices

With interactive rendering enabled, each recorded stage has an ivue viewer showing its active vertices and edges. Drag to rotate or scroll to zoom. Original planar coordinates are retained at z = 0; each viewer fits its own bounds, so apparent size across stages is not a measure of expansion. By default, a planar stage selector shows the same recorded vertices and edges with common bounds across stages.

The two most useful tables are:

Level traces versus round traces

When you need more detail, trace = "round" records intermediate refinement rounds within each active level.

mesh.trace.round <- trace.grip(
  mesh.edges,
  n = max(mesh.edges),
  dim = 2,
  preset = "carpet",
  rounds = 6,
  final.rounds = 8,
  trace = "round",
  trace.every = 4,
  diagnostics = "light",
  seed = 1
)

data.frame(
  trace_mode = c("level", "round"),
  n.frames = c(length(mesh.trace$frames), length(mesh.trace.round$frames))
)
#>   trace_mode n.frames
#> 1      level        4
#> 2      round        8

Use:

Read changes over the trace

Early frames contain only the active coarse vertices. Read changes in the score together with the stage and active graph; adjacent frames may not score identical vertex sets. Level traces show insertion stages; round traces show more of the refinement within each stage. They are different sampling schedules.

For a weighted graph, use trace.grip(metric='edge_length', ...) with its lengths. The weighted guide explains this metric. Detailed construction animations and their reproduction commands are described in the asset guide.

Trace objects are analysis objects

A trace object is more than a list of pictures. It can support:

The most useful components are:

Practical guidance

Where to go next

For an API map, see Finding your way around grip. For reproducible bundles and reference scoring, see Graph examples. These guides and the interactive-explorer walkthrough are installed vignettes.