Minkowski Parameter Neighborhood
Brian Muchmore
2026-07-14
Source:vignettes/articles/Minkowski-Parameter-Neighborhood.Rmd
Minkowski-Parameter-Neighborhood.RmdThis vignette assumes you have already read the main example
workflow. Here we focus on a local parameter neighbourhood rather than a
set of named metrics. The question is whether a small sweep around
Minkowski p = 0.5 carries coherent structure.
The parameter sweep creates a local family of related distances. The graph tier then handles what it is responsible for: retaining and normalizing graph structure.
Setup
Use the same balanced subset as the main workflow.
set.seed(1)
label_col <- data_cell_cycle$Cell_cycle
rows_by_label <- split(seq_len(nrow(data_cell_cycle)), label_col)
workflow_rows <- unlist(lapply(rows_by_label, head, 20), use.names = FALSE)
workflow_features <- seq_len(500)
cell_cycle <- as.matrix(data_cell_cycle[workflow_rows, -1, drop = FALSE][, workflow_features])
storage.mode(cell_cycle) <- "double"
cell_cycle_labels <- label_col[workflow_rows]
rownames(cell_cycle) <- sprintf("%s_%02d", cell_cycle_labels, seq_along(cell_cycle_labels))
cell_cycle_groups <- setNames(cell_cycle_labels, rownames(cell_cycle))
cell_cycle_palette <- c(G1 = "#0017FF", G2M = "#000000", S = "#FF0017")
dim(cell_cycle)
#> [1] 60 500
table(cell_cycle_labels)
#> cell_cycle_labels
#> G1 G2M S
#> 20 20 20Build the Parameter Sweep
Create ten Minkowski functions with p values near
0.5.
cell_cycle_minkowski_params <- seq(0.45, 0.54, length.out = 10)
cell_cycle_minkowski_funcs <- precise_func_fact(
func = "minkowski",
params = cell_cycle_minkowski_params
)
names(cell_cycle_minkowski_funcs)
#> [1] "minkowski_0.45" "minkowski_0.46" "minkowski_0.47" "minkowski_0.48"
#> [5] "minkowski_0.49" "minkowski_0.5" "minkowski_0.51" "minkowski_0.52"
#> [9] "minkowski_0.53" "minkowski_0.54"
cell_cycle_minkowski_dists <- precise_dist(
cell_cycle,
dist_funcs = cell_cycle_minkowski_funcs,
suffix = "cell_minkowski_",
file = NULL,
parallel = FALSE,
verbose = FALSE
)
cell_cycle_minkowski_dists[, c("distance", "metric", "type")]
#> # A tibble: 10 × 3
#> distance metric type
#> <chr> <chr> <chr>
#> 1 cell_minkowski_minkowski_0.45 NA distance
#> 2 cell_minkowski_minkowski_0.46 NA distance
#> 3 cell_minkowski_minkowski_0.47 NA distance
#> 4 cell_minkowski_minkowski_0.48 NA distance
#> 5 cell_minkowski_minkowski_0.49 NA distance
#> 6 cell_minkowski_minkowski_0.5 NA distance
#> 7 cell_minkowski_minkowski_0.51 NA distance
#> 8 cell_minkowski_minkowski_0.52 NA distance
#> 9 cell_minkowski_minkowski_0.53 NA distance
#> 10 cell_minkowski_minkowski_0.54 NA distanceNormalize Graph Structure
Laplacian normalization is graph normalization:
D^(-1/2) W D^(-1/2). So this workflow first builds graph
matrices from each distance, then normalizes those graph matrices.
cell_cycle_minkowski_distances <- precise_transform(
cell_cycle_minkowski_dists,
to = "distance",
normalize = "range01",
diagonal = 0
)
cell_cycle_minkowski_graphs <- precise_graph(
cell_cycle_minkowski_distances,
methods = "knn",
params = list(
knn = list(k = 15)
),
parallel = FALSE,
verbose = FALSE
)
cell_cycle_minkowski_laplacian <- precise_graph(
cell_cycle_minkowski_graphs,
methods = "laplacian",
parallel = FALSE,
verbose = FALSE
)
cell_cycle_minkowski_laplacian[, c("distance", "graph_method", "input", "input_type")]
#> # A tibble: 10 × 4
#> distance graph_method input input_type
#> <chr> <chr> <chr> <chr>
#> 1 cell_minkowski_minkowski_0.45__knn__laplacian laplacian cell_m… similarity
#> 2 cell_minkowski_minkowski_0.46__knn__laplacian laplacian cell_m… similarity
#> 3 cell_minkowski_minkowski_0.47__knn__laplacian laplacian cell_m… similarity
#> 4 cell_minkowski_minkowski_0.48__knn__laplacian laplacian cell_m… similarity
#> 5 cell_minkowski_minkowski_0.49__knn__laplacian laplacian cell_m… similarity
#> 6 cell_minkowski_minkowski_0.5__knn__laplacian laplacian cell_m… similarity
#> 7 cell_minkowski_minkowski_0.51__knn__laplacian laplacian cell_m… similarity
#> 8 cell_minkowski_minkowski_0.52__knn__laplacian laplacian cell_m… similarity
#> 9 cell_minkowski_minkowski_0.53__knn__laplacian laplacian cell_m… similarity
#> 10 cell_minkowski_minkowski_0.54__knn__laplacian laplacian cell_m… similarityFuse and Inspect
Now fuse the normalized graph matrices. This is the graph-before-fusion spine, but with a parameter sweep rather than a set of named metrics:
precise_dist() -> precise_transform() -> precise_graph() -> precise_graph() -> precise_fusion()
cell_cycle_minkowski_fused <- precise_fusion(
cell_cycle_minkowski_laplacian,
methods = "mean",
verbose = FALSE
)
cell_cycle_minkowski_fused[, c("method", "type", "inputs")]
#> # A tibble: 1 × 3
#> method type inputs
#> <chr> <chr> <list>
#> 1 mean similarity <chr [10]>Finally, render the fused graph with a three-dimensional DRL layout. The point of this view is to rotate the object, inspect the edges, and ask whether the structure survives a different route through the workflow.
cell_cycle_minkowski_viz <- precise_viz(
cell_cycle_minkowski_fused,
views = "graph_layout",
params = list(
graph_layout = list(
layout = "drl",
dimensions = 3,
engine = "threejs",
render = "graph",
seed = 1,
color = cell_cycle_groups,
colors = cell_cycle_palette,
show_labels = FALSE,
size = 1
)
),
verbose = FALSE
)
cell_cycle_minkowski_viz$panel[[1]]