---
title: "Customizing the Hierarchy Diagram"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Customizing the Hierarchy Diagram}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

<!-- Generated by vignettes/precompute.R; DO NOT EDIT BY HAND.
     Edit ackwards-visualization.Rmd.orig and re-run `Rscript vignettes/precompute.R`.
     Freshness is enforced by tools/check-vignette-freshness.R. -->
<!-- precompute-stamp: source=ackwards-visualization.Rmd.orig md5=9eff46d85cbd201ae74b723c52005e9b -->



`autoplot.ackwards()` exposes a large number of arguments for controlling the
appearance of the hierarchy diagram. This vignette is a visual reference: each
section demonstrates one group of arguments with rendered figures so you can
see the effect before writing any code.

All options shown here are **presentation-only** — they do not change which
factors were extracted or how the between-level correlations were computed.
Options that change *which nodes appear* (`drop_pruned`, `compress_levels`) are
specific to the Forbes pruning extension and are covered in
`vignette("ackwards-forbes")`.

## Setup


``` r
library(ackwards)

bfi <- na.omit(bfi25)
x <- ackwards(bfi, k_max = 5, cor = "polychoric")
```

The default diagram for reference:


``` r
autoplot(x)
```

![plot of chunk base](assets/ackwards-visualization-base-1.png)

Factors are labeled `m{k}f{j}` (level k, factor j). Two edge aesthetics carry
the between-level correlations, and each one comes with its own legend: arrow
**thickness** encodes the magnitude |r|, and edge **color** encodes the
direction (blue = positive, red–orange = negative). Level labels on the left
count factors per level.

Primary-parent edges are always positive after sign alignment; a red (negative)
edge is therefore a genuine *secondary* relationship, not an artifact.

## Encoding sign and magnitude

You choose which aesthetic carries which piece of information. `sign_by` picks
the channel for direction and `magnitude_by` picks the channel for |r|. No
aesthetic is ever mapped without a matching legend.

### `sign_by` — how direction is shown

`sign_by = "color"` (the default) uses `color_pos`/`color_neg`. `"linetype"`
draws positive edges solid and negative edges dashed, freeing color for a
single-hue figure. `"both"` uses color *and* linetype together — negatives get a
distinct double-dash so they still read in greyscale — and merges the two into a
single "Direction" legend. `"none"` drops sign encoding entirely.


``` r
autoplot(x, sign_by = "linetype")
```

![plot of chunk sign-by](assets/ackwards-visualization-sign-by-1.png)

``` r
autoplot(x, sign_by = "both")
```

![plot of chunk sign-by](assets/ackwards-visualization-sign-by-2.png)

### `magnitude_by` — how |r| is shown

By default `magnitude_by = "linewidth"` maps |r| to arrow thickness with a `|r|`
legend. Set `magnitude_by = "none"` for uniform-width edges (see also
`edge_linewidth`, below, to pin a specific width).


``` r
autoplot(x, magnitude_by = "none")
```

![plot of chunk magnitude-by](assets/ackwards-visualization-magnitude-by-1.png)

## Filtering edges

### `cut_show` — minimum |r| to display

Edges below `cut_show` are hidden entirely. Raising it produces a sparser
diagram that emphasises only the strongest connections.


``` r
# Default cut_show = 0.3 (already shown above)
autoplot(x, cut_show = 0.5)
```

![plot of chunk cut-show](assets/ackwards-visualization-cut-show-1.png)

## Edge colors

### `color_pos` / `color_neg` — custom direction colors

The default blue/red palette can be replaced with any colors recognised by R.
British spellings (`colour_pos`, `colour_neg`) are accepted as aliases.


``` r
autoplot(x, color_pos = "darkorchid", color_neg = "darkorange")
```

![plot of chunk colours](assets/ackwards-visualization-colours-1.png)

When sign is *not* encoded by color (`sign_by = "linetype"` or `"none"`), all
edges take the single `color_edge` (default black) — the basis for the Forbes
(2023) publication style (see the worked example at the end of this vignette).

## Monochrome mode

### `mono = TRUE` — a black-and-white convenience wrapper

`mono = TRUE` is shorthand for `sign_by = "linetype"` with black edges: solid
lines are positive correlations, dashed lines are negative. `magnitude_by` still
applies, so `linewidth` continues to encode |r|.


``` r
autoplot(x, mono = TRUE)
```

![plot of chunk mono](assets/ackwards-visualization-mono-1.png)

`mono` suits black-and-white figures where the reader must distinguish positive
from negative edges. To label the edges with their exact values as well, add
`show_r = TRUE` (documented next).

## Correlation labels

### `show_r` / `r_digits` — annotate edges with r values

`show_r = TRUE` draws the rounded (signed) correlation at each edge midpoint.
`r_digits` controls the number of decimal places (default 2).


``` r
autoplot(x, show_r = TRUE)
```

![plot of chunk show-r](assets/ackwards-visualization-show-r-1.png)


``` r
autoplot(x, show_r = TRUE, r_digits = 1)
```

![plot of chunk show-r-digits](assets/ackwards-visualization-show-r-digits-1.png)

## Node labels

### `node_labels` — rename individual factors

`node_labels` is a named character vector mapping factor IDs to display strings.
Unspecified factors keep any name attached with `set_factor_labels()`, falling
back to their `m{k}f{j}` labels. If you have already labelled the object with
`set_factor_labels()` (see `vignette("ackwards-interpret")`), those names appear
on the diagram automatically and `node_labels` is only needed to override a
particular node for this one plot.


``` r
autoplot(x, node_labels = c(
  m5f1 = "Neuro.",
  m5f2 = "Extra.",
  m5f3 = "Consc.",
  m5f4 = "Agree.",
  m5f5 = "Open."
))
```

![plot of chunk node-labels](assets/ackwards-visualization-node-labels-1.png)

Multi-line labels are supported via `\n`:


``` r
autoplot(x, node_labels = c(
  m5f1 = "Neuro-\nticism",
  m5f2 = "Extra-\nversion"
))
```

![plot of chunk node-labels-multiline](assets/ackwards-visualization-node-labels-multiline-1.png)

### `node_width` / `node_height` — size individual boxes to fit a label

A long substantive name may not fit the default box. `node_width` and
`node_height` each accept a **named vector** keyed by factor ID, sizing those
boxes individually; boxes you do not name keep the default. Increase `min_sep`
to make room when a box grows wider than the spacing between siblings.


``` r
autoplot(x,
  node_labels = c(m5f1 = "Neuroticism", m5f3 = "Conscientiousness"),
  node_width = c(m5f1 = 1.8, m5f3 = 2.2),
  min_sep = 2.4
)
```

![plot of chunk node-size](assets/ackwards-visualization-node-size-1.png)

### `label_template()` — generate the scaffold

Typing out every factor ID is tedious for large objects. `label_template()`
generates the full named vector in canonical diagram order and prints a
copy-pasteable `c(...)` literal you can edit and pass back to `node_labels`. It
also offers the Forbes (2023) letter convention (`"A1"`, `"B1"`, `"B2"`, …) as a
built-in style:


``` r
autoplot(x, node_labels = label_template(x, style = "forbes"))
```

![plot of chunk label-template-forbes](assets/ackwards-visualization-label-template-forbes-1.png)

For the full naming workflow — reading factors, the sign convention, and choosing
labels across the hierarchy — see `vignette("ackwards-interpret")`.

## Item content

### `show_items` — list the items under the deepest-level factors

For a publication figure it helps to show *what* each most-granular factor is
made of. `show_items = TRUE` lists the salient items beneath each deepest-level
(`k_max`) box: the top `n_items` by `|loading|` at or above `item_cut`, using the
same extraction as `top_items()` (variable labels appear when the data carried
them into the fit; here `na.omit()` stripped `bfi25`'s label attributes, so the
item IDs are shown — see `vignette("ackwards-interpret")` on keeping labels).


``` r
autoplot(x, show_items = TRUE, n_items = 4)
```

![plot of chunk show-items](assets/ackwards-visualization-show-items-1.png)

## Structural simplifications

### `primary_only = TRUE` — show only primary-parent edges

Setting `primary_only = TRUE` keeps only the single strongest edge per factor
(its primary parent), producing a clean tree. Because skip-level edges are
never primary, this also suppresses curved arcs when `pairs = "all"` was used.


``` r
autoplot(x, primary_only = TRUE)
```

![plot of chunk primary-only](assets/ackwards-visualization-primary-only-1.png)

### `order` — arrange the deepest level by hand

The layout orders factors automatically to minimise edge crossings, but you may
want a specific left-to-right arrangement — to match a paper, or to untangle a
figure. `order` fixes the order of the **deepest** (`k_max`) level; supply that
level's factor IDs in the desired order. Every factor above stays centred over
its primary children, so fixing the leaf order rearranges the whole tree
coherently — any arrangement of the hierarchy is reachable this way.


``` r
# Reverse the deepest level's left-to-right order
deepest <- paste0("m5f", 5:1)
autoplot(x, order = deepest)
```

![plot of chunk manual-order](assets/ackwards-visualization-manual-order-1.png)

### `drop_pruned` + `show_secondary` — the pruned view and its hidden correlations

Pruning (see `vignette("ackwards-forbes")`) flags redundant factors;
`drop_pruned = TRUE` then renders the reduced hierarchy, joining each retained
factor to its single strongest surviving ancestor. That primary view hides every
*other* between-level correlation. `show_secondary = TRUE` adds them back — each
kept cross-level pair with `|r| >= cut_show` that is not a primary edge — drawn
dimmed and thinner beneath the primary arrows, so the sign colors stay intact.
These are a factor's weaker second parents *and* direct skip-level correlations
the primary path would otherwise obscure (a skip-level |r| is its own fact:
correlation is not transitive, so it need not equal the product along the path).


``` r
xp <- prune(x, "redundant")
#> ℹ Redundancy pruning (direct criterion, |r| ≥ 0.9) flagged 6 nodes.
#> ℹ Nodes are retained in the object; inspect with `x$prune$nodes` and
#>   `x$prune$chains`.
autoplot(xp, drop_pruned = TRUE) # primary view: one ancestor per factor
```

![plot of chunk drop-pruned-secondary](assets/ackwards-visualization-drop-pruned-secondary-1.png)

``` r
autoplot(xp, drop_pruned = TRUE, show_secondary = TRUE) # + secondary correlations
```

![plot of chunk drop-pruned-secondary](assets/ackwards-visualization-drop-pruned-secondary-2.png)

## Level labels

### `show_level_labels` / `level_label_size`

Level labels ("1 factor", "2 factors", …) are shown by default on the left
margin. They can be hidden or resized.


``` r
autoplot(x, show_level_labels = FALSE)
```

![plot of chunk level-labels-off](assets/ackwards-visualization-level-labels-off-1.png)


``` r
autoplot(x, show_level_labels = TRUE, level_label_size = 4)
```

![plot of chunk level-labels-size](assets/ackwards-visualization-level-labels-size-1.png)

## Arrowheads

### `show_arrows = FALSE` — plain line ends

By default, edges end with closed arrowheads. Setting `show_arrows = FALSE`
draws plain line ends. This applies to both straight edges and curved skip-level
arcs.


``` r
autoplot(x, show_arrows = FALSE)
```

![plot of chunk no-arrows](assets/ackwards-visualization-no-arrows-1.png)

## Edge width

### `edge_linewidth` — uniform vs. |r|-scaled width

By default, edge width is proportional to |r| (via `magnitude_by`). A numeric
`edge_linewidth` draws every edge at that constant width and removes the `|r|`
legend — like `magnitude_by = "none"`, but at a width you choose.


``` r
autoplot(x, edge_linewidth = 0.7)
```

![plot of chunk edge-linewidth](assets/ackwards-visualization-edge-linewidth-1.png)

## Layout orientation

### `direction = "horizontal"` — left-to-right layout

By default levels stack top-to-bottom (level 1 at top). `direction =
"horizontal"` lays them out left-to-right (level 1 at left), which fits wide
slides and posters; the level labels move to the bottom margin.


``` r
autoplot(x, direction = "horizontal")
```

![plot of chunk direction](assets/ackwards-visualization-direction-1.png)

## Legend

### `legend = FALSE` — suppress all guides

`legend = FALSE` removes all legends from the plot. Most useful when the diagram
is self-explanatory or the legend duplicates information conveyed by labels.


``` r
autoplot(x, legend = FALSE)
```

![plot of chunk no-legend](assets/ackwards-visualization-no-legend-1.png)

## Worked example: publication-ready figure

The following call reproduces the visual style of Forbes (2023): black lines of
uniform weight, plain line ends, correlation labels, and no legend. Setting both
direction colors to black yields a single-hue figure, and `legend = FALSE`
suppresses the now-redundant key.


``` r
autoplot(x,
  color_pos      = "black",
  color_neg      = "black",
  edge_linewidth = 0.6,
  show_arrows    = FALSE,
  show_r         = TRUE,
  legend         = FALSE
)
```

![plot of chunk pub-figure](assets/ackwards-visualization-pub-figure-1.png)

Combining with `node_labels` names the factors for the final figure:


``` r
autoplot(x,
  color_pos = "black",
  color_neg = "black",
  edge_linewidth = 0.6,
  show_arrows = FALSE,
  show_r = TRUE,
  legend = FALSE,
  node_labels = c(
    m5f1 = "Neuro.",
    m5f2 = "Extra.",
    m5f3 = "Consc.",
    m5f4 = "Agree.",
    m5f5 = "Open."
  )
)
```

![plot of chunk pub-figure-labeled](assets/ackwards-visualization-pub-figure-labeled-1.png)

For the pruned-factor variant of this figure (nodes omitted, spanning arrows)
see `vignette("ackwards-forbes")`.

## Saving plots

`autoplot()` returns an ordinary `ggplot` object, so save it with
`ggplot2::ggsave()`:


``` r
p <- autoplot(x, direction = "horizontal")
ggplot2::ggsave("hierarchy.png", p, width = 9, height = 5, dpi = 300)
```

`ackwards` does not re-export `ggsave()` — that would move `ggplot2` from
Suggests into Imports — so call it from `ggplot2` directly.

---

## Diagnostic scree / criteria plot: `autoplot.suggest_k()`

`suggest_k()` also has its own `autoplot()` method, producing a multi-panel
scree / parallel-analysis / VSS diagnostic. It is documented in depth in
`vignette("ackwards-suggest-k")`; here we only note that the same `autoplot()`
generic covers it.


``` r
sk <- suggest_k(bfi, seed = 42)
#> ℹ Running parallel analysis (20 iterations, PC + FA)...
#> ✔ Running parallel analysis (20 iterations, PC + FA)... [168ms]
#> 
#> ℹ Running MAP and VSS...
#> ✔ Running MAP and VSS... [61ms]
#> 
#> ℹ Running Comparison Data (CD)...
#> ✔ Running Comparison Data (CD)... [6.8s]
#> 
autoplot(sk)
```

![plot of chunk suggest_k_plot](assets/ackwards-visualization-suggest_k_plot-1.png)

## References

Forbes, M. K. (2023). Improving hierarchical models of individual differences:
An extension of Goldberg's bass-ackward method. *Psychological Methods*.
https://doi.org/10.1037/met0000546
