--- title: "Graph gallery: multiscale GRIP" output: rmarkdown::html_vignette: toc: true vignette: > %\VignetteIndexEntry{Graph gallery: multiscale GRIP} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- This gallery demonstrates multiscale GRIP on six graph families. For the recommended embedding workflow, see [the SGD metric-MDS gallery](gallery.html). This gallery complements the [function guide](function-guide.html) and [synthetic graph examples](synthetic-graph-families.html). ```{r setup, include=FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.retina = 2, fig.width = 11, fig.height = 4.2 ) ``` This article is a guide to the synthetic graph families shipped with `grip`. The package no longer provides only a few toy generators for smoke tests. It now includes a broad collection of geometry-rich benchmark families covering: - lifted lattices, - recursive and fractal families, - irregular manifolds, - porous 3D families, - and intrinsically weighted trees. For many of these families, the package stores both: - a target geometry used to induce edge lengths, and - a weighted graph bundle that can be passed directly to `grip(metric = "edge_length")`. As a workflow guide, use `grip()` on the purely topological versions of these families when you want an unweighted baseline, and use `grip(metric = "edge_length")` on the weighted bundles when the induced geometry is part of the problem. Advanced GKK/LGKK scoring can be layered onto smaller weighted examples later, but that is not the main purpose of this article. ```{r} library(grip) ``` ```{r view-helpers, include=FALSE} source(system.file('scripts','vignette-views.R',package='grip'),local=TRUE) ``` The views rotate and zoom. Reference and fitted coordinates are displayed without rotation or scale fitting. The original 2D tree fit is preserved and shown in the z = 0 plane of a 3D viewer. ## Family classes at a glance The table below lists a representative subset of the larger family collection. | Family class | Representative helper | Why it matters | |:--|:--|:--| | Lifted lattices | `mesh.surface.graph()` | Plain topology, nontrivial metric geometry | | Wrapped surfaces | `torus.surface.graph()` | Closed periodic surface geometry | | Recursive fractals | `vicsek.surface.graph()` | Self-similar bottlenecks and holes | | Irregular manifolds | `irregular.annulus.surface.graph()` | Non-lattice surface geometry with boundary | | Porous 3D families | `cube.channel.network.surface.graph()` | Volumetric geodesic detours | | Intrinsic trees | `kary.tree.weighted.graph()` | Geometry from edge lengths rather than ambient space | This article shows one representative example from each class. The interactive family browser described in `Interactive Exploration with gripui` exposes a much larger catalog. ## Lifted lattices The simplest geometry-rich family keeps the graph topology of a rectangular mesh but induces edge lengths from a curved embedding in `R^3`. ```{r mesh-family} mesh.graph <- mesh.surface.graph( 5, 5, surface = "saddle", amplitude = 0.8 ) mesh.coords <- grip(metric = "edge_length", mesh.graph$edges, n = mesh.graph$n, edge.weights = mesh.graph$edge_weights, dim = 3, preset = "mesh", seed = 1 ) mesh.summary <- data.frame( family = mesh.graph$family, surface = mesh.graph$surface, n = mesh.graph$n, m = nrow(mesh.graph$edges), weight_scale = mesh.graph$weight_scale ) knitr::kable(mesh.summary, digits = 3) ``` ```{r mesh-interactive} documentation.view(list(`Weighted GRIP`=mesh.coords, `Reference geometry`=mesh.graph$coords_surface, `Parameter grid`=cbind(mesh.graph$coords_param,z=0)), edges=mesh.graph$edges, aligned=TRUE, description="Drag to rotate; scroll to zoom; select a geometry.") ``` The useful design pattern here is that the topology stays simple while the metric geometry becomes nontrivial. ## Wrapped surfaces Wrapped lattices extend the same idea to periodic topologies such as a torus. ```{r torus-family} torus.graph <- torus.surface.graph( 5, 6, surface = "pinched", minor.radius = 0.33, amplitude = 0.18, twist = 0.18 ) torus.coords <- grip(metric = "edge_length", torus.graph$edges, n = torus.graph$n, edge.weights = torus.graph$edge_weights, dim = 3, preset = "torus", seed = 2 ) knitr::kable( data.frame( family = torus.graph$family, surface = torus.graph$surface, n = torus.graph$n, m = nrow(torus.graph$edges) ) ) ``` ```{r torus-interactive} documentation.view(list(`Weighted GRIP`=torus.coords, `Reference geometry`=torus.graph$coords_surface), edges=torus.graph$edges, aligned=TRUE, description="Drag to rotate; scroll to zoom; select a geometry.") ``` These wrapped families are especially useful when ordinary planar intuition is misleading and a 3D layout is the natural target. ## Recursive and fractal families The package now includes recursive square-mask families such as the Vicsek fractal and Sierpinski carpet variants, all of which can be lifted into curved surface geometries. ```{r vicsek-family} vicsek.graph <- vicsek.surface.graph( level = 2, surface = "ripple", amplitude = 0.55 ) vicsek.coords <- grip(metric = "edge_length", vicsek.graph$edges, n = vicsek.graph$n, edge.weights = vicsek.graph$edge_weights, dim = 3, preset = "carpet", seed = 3 ) ``` ```{r vicsek-interactive} documentation.view(list(`Weighted GRIP`=vicsek.coords, `Reference geometry`=vicsek.graph$coords_surface), edges=vicsek.graph$edges, aligned=TRUE, description="Drag to rotate; scroll to zoom; select a geometry.") ``` Recursive families are useful because they create holes, bottlenecks, and multi-scale detours that are hard to capture with simpler lattices. ## Irregular manifolds Not all surface families in `grip` are based on regular grids. The package also includes irregular triangulated manifolds with boundary and closed irregular surfaces. ```{r annulus-family} annulus.graph <- irregular.annulus.surface.graph( rings = 5, outer.count = 24, inner.radius = 0.42, surface = "folded", amplitude = 0.2 ) annulus.coords <- grip(metric = "edge_length", annulus.graph$edges, n = annulus.graph$n, edge.weights = annulus.graph$edge_weights, dim = 3, preset = "irregular", seed = 4 ) ``` ```{r annulus-interactive} documentation.view(list(`Weighted GRIP`=annulus.coords, `Reference geometry`=annulus.graph$coords_surface), edges=annulus.graph$edges, aligned=TRUE, description="Drag to rotate; scroll to zoom; select a geometry.") ``` These families are important because they reduce lattice bias and produce more variable local geometry than mesh-like constructions. ## Porous 3D families The cubical branch introduces graphs that are genuinely volumetric rather than surface-like. Channel networks and related porous families create 3D geodesic detours that are hard to flatten cleanly. ```{r cube-family} cube.graph <- cube.channel.network.surface.graph( side = 5, level = 1, surface = "twisted", twist = 0.2 ) cube.coords <- grip(metric = "edge_length", cube.graph$edges, n = cube.graph$n, edge.weights = cube.graph$edge_weights, dim = 3, preset = "irregular", seed = 5 ) knitr::kable( data.frame( family = cube.graph$family, n = cube.graph$n, m = nrow(cube.graph$edges) ) ) ``` ```{r cube-interactive} documentation.view(list(`Weighted GRIP`=cube.coords, `Reference geometry`=cube.graph$coords_surface), edges=cube.graph$edges, aligned=TRUE, description="Drag to rotate; scroll to zoom; select a geometry.") ``` This family class is especially useful for testing whether a method can preserve large-scale volumetric structure without collapsing tunnels and channels. ## Intrinsic weighted trees Some family geometries are intrinsic rather than ambient. The weighted tree helpers preserve the exact tree topology while assigning edge lengths directly from branch-depth and branch-position rules. ```{r tree-family} tree.graph <- kary.tree.weighted.graph( k = 2, depth = 4, depth.rule = "geometric", depth.decay = 0.82, branch.rule = "linear", branch.spread = 0.25 ) tree.coords <- grip(metric = "edge_length", tree.graph$edges, n = tree.graph$n, edge.weights = tree.graph$edge_weights, dim = 2, preset = "tree", seed = 6 ) knitr::kable( head(tree.graph$edge_table[, c( "parent", "child", "child_depth", "branch_index", "edge_weight" )]), digits = 3 ) ``` ```{r tree-interactive} documentation.view(list(`Weighted GRIP (2D fit)`=cbind(tree.coords,z=0)), edges=tree.graph$edges, aligned=TRUE, description="Drag to rotate; scroll to zoom; select a geometry.") ``` These tree families are useful because they separate intrinsic weighted geometry from any arbitrary 3D embedding choice. ## Why this family library matters The family collection now serves three roles: - it gives users concrete examples of what the package can represent, - it supports regression testing and benchmark design, - and it makes it possible to study layout behavior under controlled geometric variation rather than only on a handful of fixed toy graphs. ## Learn more - `Getting Started with grip` introduces the main layout APIs. - `Weighted Graph Layouts with grip` explains how to use these family bundles with the weighted sister API. - `Interactive Exploration with gripui` shows how to browse the larger family registry through `run.gripui.family()`.