Skip to contents

When what = "hierarchy" (default), renders the layered bass-ackwards hierarchy as a ggplot2 diagram. A factor is a summary variable standing in for a group of items that move together. Factors appear as labelled boxes arranged in levels. Level 1 sits at the top and level k at the bottom by default. Set direction = "horizontal" for a left-to-right layout. Between-level edges below cut_show are hidden. Two aesthetics carry the edge information, each explained by its own legend: sign (positive/negative) is shown by sign_by (edge colour by default) and magnitude (|r|) by magnitude_by (line thickness by default). No aesthetic is ever mapped without a matching legend.

Usage

# S3 method for class 'ackwards'
autoplot(
  object,
  what = c("hierarchy", "fit"),
  sign_by = c("color", "linetype", "both", "none"),
  magnitude_by = c("linewidth", "none"),
  cut_show = NULL,
  color_pos = "#2166AC",
  color_neg = "#D6604D",
  color_edge = "black",
  colour_pos = NULL,
  colour_neg = NULL,
  colour_edge = NULL,
  node_width = 0.8,
  node_height = 0.4,
  min_sep = 1,
  order = NULL,
  show_items = FALSE,
  n_items = 5,
  item_cut = 0.3,
  show_skip = NULL,
  curvature = 0.2,
  color_pruned = "grey80",
  colour_pruned = NULL,
  show_r = FALSE,
  r_digits = 2L,
  r_label_size = 2.5,
  mono = FALSE,
  edge_linewidth = NULL,
  cut_strong = NULL,
  direction = c("vertical", "horizontal"),
  show_level_labels = TRUE,
  level_label_size = 3,
  node_labels = NULL,
  primary_only = FALSE,
  drop_pruned = FALSE,
  compress_levels = FALSE,
  show_secondary = FALSE,
  show_arrows = TRUE,
  legend = TRUE,
  ...
)

# S3 method for class 'ackwards'
plot(x, ...)

Arguments

object

An ackwards object.

what

One of "hierarchy" (default) or "fit". Controls which visualisation is produced. All other parameters are ignored when what = "fit".

sign_by

How edge sign (positive vs negative correlation) is encoded. There are four choices. The default "color" draws positive edges in color_pos and negative edges in color_neg. Option "linetype" draws positive as solid and negative as dashed. Option "both" uses colour and linetype, with negative drawn as a distinct double-dash so it reads clearly in greyscale. Option "none" does not encode sign and draws all edges color_edge and solid. Whichever channel is used gets a "Direction" legend. Colour is the default because it reads sign at a glance and leaves linetype free. Switch to "linetype" or "both" for greyscale or colour-blind-safe figures.

magnitude_by

How edge magnitude (|r|) is encoded. One of "linewidth" (the default, where thicker = stronger, with a |r| legend) or "none" (constant width). A numeric edge_linewidth also forces constant width at that value.

cut_show

Edges with |r| < cut_show are not drawn. Defaults to the value used when the object was created (x$meta$cut_show, typically 0.3).

color_pos, colour_pos

Colour for positive edges when sign_by uses colour. Default "#2166AC" (blue). colour_pos is an accepted British alias.

color_neg, colour_neg

Colour for negative edges when sign_by uses colour. Default "#D6604D" (red). colour_neg is an accepted British alias.

color_edge, colour_edge

Single colour for all edges when sign_by does not use colour ("linetype" or "none"). Default "black". colour_edge is an accepted British alias.

node_width

Width of factor boxes in layout units. Either a single value applied to every box (default 0.8), or a named numeric vector keyed by factor ID (e.g. c(m5f1 = 1.6)) giving a per-box width. Boxes not named fall back to the 0.8 default. Use a per-box width to fit a long manual node_labels string. Names matching no factor ID warn.

node_height

Height of factor boxes in layout units. Either a single value applied to every box (default 0.4), or a named numeric vector keyed by factor ID for a per-box height (unnamed boxes fall back to 0.4). This helps with multi-line manual labels. Names matching no factor ID warn.

min_sep

Minimum horizontal separation between nodes, passed to ba_layout(). Default 1.0.

order

Optional manual left-to-right ordering of the deepest (k_max) level, passed to ba_layout(). Supply a character vector of that level's factor IDs, or a named list keyed by the level number. That fixes the leaf order, and every upper factor re-centres above its primary children. Use it to untangle a figure by hand. NULL (default) uses the automatic ordering.

show_items

When TRUE, lists the salient observed items beneath each deepest-level (k_max) factor box, so a publication figure shows what each most-granular factor is made of. Items are the top n_items by loading (the correlation between an item and a factor), taken in absolute value at or above item_cut. The extraction is the same as in top_items(). Variable labels are shown when the fit carried them, else the item IDs. Listed below the boxes in a vertical layout, and to their right in a horizontal one. Default FALSE.

n_items

Maximum number of items listed per deepest-level factor when show_items = TRUE. NULL lists every item meeting item_cut. Default 5.

item_cut

Absolute-loading threshold for show_items: only items with |loading| >= item_cut are listed. Default 0.3.

show_skip

Whether to draw skip-level (non-adjacent) edges. NULL (default) auto-detects: TRUE when the object was run with pairs = "all", FALSE otherwise. Ignored when drop_pruned = TRUE.

curvature

Curvature of skip-level edge arcs. Passed to ggplot2::geom_curve(). Positive values curve right. Default 0.2. Ignored when drop_pruned = TRUE.

color_pruned, colour_pruned

Fill colour for nodes flagged as pruned or redundant (a factor that persists across levels without changing). Default "grey80". Only applied when the object carries pruning annotations (x$prune is non-NULL) and drop_pruned = FALSE (pruned nodes are omitted entirely when drop_pruned = TRUE). colour_pruned is an accepted British alias.

show_r

Whether to label each drawn edge with its correlation coefficient. Default FALSE. When TRUE, labels are formatted in APA style (leading zero stripped, e.g. .23, -.30) and placed beside each edge using a white-background label that clears the arrowhead.

r_digits

Number of decimal places for edge labels when show_r = TRUE. Default 2L.

r_label_size

Font size for edge correlation labels when show_r = TRUE. Passed to ggplot2::geom_label() as size. Default 2.5.

mono

Monochrome convenience wrapper. When TRUE, equivalent to sign_by = "linetype" with black edges (it overrides sign_by and the colour arguments). magnitude_by still applies. Default FALSE.

edge_linewidth

NULL (default) uses magnitude_by to decide edge width. A numeric value forces every edge to that constant width (implying magnitude_by = "none") and drops the |r| legend. Forbes figures use uniform thin lines (about 0.5 to 0.6).

cut_strong

Deprecated in M35 and ignored (with a warning). Edge magnitude is now shown by magnitude_by (linewidth) and sign by sign_by, because the old strong/weak linetype split double-encoded magnitude. Retained only so existing calls do not error.

direction

Layout orientation. "vertical" (default) stacks levels top-to-bottom, with level 1 at top. "horizontal" lays them out left-to-right, with level 1 at left, which suits wide slides or posters. Level-axis labels move to the bottom margin under "horizontal".

show_level_labels

Whether to draw level axis labels ("1 factor", "2 factors", ...) to the left of the diagram. Default TRUE. Sometimes the object carries pruning annotations (x$prune non-NULL) and drop_pruned = FALSE. Then a level whose factors are all pruned has its axis label rendered in italic to denote its status. The italic matches the grey node fill. Partially-pruned levels keep a plain label.

level_label_size

Font size for level axis labels. Default 3.

node_labels

A named character vector mapping factor IDs (e.g. "m5f1") to custom display strings (e.g. "General"). Unspecified factors keep any label attached with set_factor_labels(), falling back to the default m{k}f{j} ID. Entries here override a stored factor label for that node, so this argument is a per-call last word over the persistent labels. A warning is issued for names that match no factor ID in the object. Default NULL.

primary_only

When TRUE, only primary-parent edges (is_primary == TRUE) are drawn. Because skip-level edges are never primary, this also suppresses skip arcs. Ignored when drop_pruned = TRUE. Default FALSE.

drop_pruned

When TRUE, activates the Forbes (2023) pruned-view rendering path. Pruned nodes are removed from the diagram entirely. Each retained node is connected to its single strongest kept ancestor by a straight arrow, even across level gaps. This requires the object to carry pruning annotations (piped through prune()), and errors if not. Overrides show_skip, curvature, and primary_only. Default FALSE.

compress_levels

When TRUE under drop_pruned = TRUE, closes vertical gaps left by pruned levels so retained levels are evenly spaced. Level axis labels (d) still show the original level numbers. Ignored when drop_pruned = FALSE. Default FALSE.

show_secondary

When TRUE under drop_pruned = TRUE, also draws the between-level correlation edges the single-strongest-ancestor primary view hides: every kept cross-level factor pair with |r| >= cut_show that is not already a primary edge. This includes cross-branch second parents and same-lineage skip arcs (a direct skip-level r is a distinct, non-transitive fact, not implied by the primary path). Secondary edges render in a channel deliberately distinct from the primary edges. They are dimmed (reduced opacity) and thinner, with plain line ends. They still inherit the sign encoding (sign_by), so the sign colour or linetype is never confused with the secondary channel. By construction each node's secondaries are weaker than its primary edge, so a secondary edge never appears while that node's primary is below cut_show. Ignored when drop_pruned = FALSE. Default FALSE.

show_arrows

When FALSE, edges are drawn with plain line ends instead of closed arrowheads (arrow = NULL). Applies to both straight and curved edge layers. Default TRUE. Forbes (2023) figures use plain line ends.

legend

When FALSE, suppresses all plot legends (legend.position = "none"). Useful when color_pos == color_neg (e.g. both "black") to remove an otherwise redundant Direction key. Default TRUE.

...

Ignored.

x

An ackwards object.

Value

A ggplot object.

Details

When what = "fit", renders a two-panel line plot of per-level fit indices. CFI and TLI go in the top panel, RMSEA and SRMR in the bottom panel. Horizontal reference lines mark the conventional Hu & Bentler (1999) thresholds. The anchor level (k = 1, saturated and always fits perfectly) is excluded. This needs the EFA (exploratory factor analysis) or ESEM (exploratory structural equation modeling) engine. It returns an informative empty plot for PCA (principal component analysis), which has no model-fit indices.

Requires the ggplot2 package.

Saving plots

autoplot() returns a standard ggplot object, so save it with ggplot2::ggsave():


  p <- autoplot(x)
  ggplot2::ggsave("hierarchy.png", p, width = 8, height = 6, dpi = 300)

ggsave() is not re-exported by ackwards, because that would move ggplot2 from Suggests into Imports. Call it from ggplot2 directly. For a wide slide or poster, pair it with direction = "horizontal".

See also

ba_layout(), plot.ackwards()

Examples

# \donttest{
if (requireNamespace("ggplot2", quietly = TRUE)) {
  # sim16 has a known 1 -> 2 -> 4 hierarchy (continuous; pearson basis)
  x <- ackwards(sim16, k_max = 5)
  autoplot(x)
  autoplot(x, color_pos = "steelblue")

  # Encode sign by linetype instead of colour, or by both
  autoplot(x, sign_by = "linetype")
  autoplot(x, sign_by = "both")

  # Left-to-right layout (wide slides / posters)
  autoplot(x, direction = "horizontal")

  # List the top items under each deepest-level factor
  autoplot(x, show_items = TRUE, n_items = 4)

  # Per-level fit index chart (EFA or ESEM only)
  x_efa <- ackwards(sim16, k_max = 5, engine = "efa")
  autoplot(x_efa, what = "fit")

  # Monochrome with correlation labels (for greyscale figures)
  autoplot(x, mono = TRUE, show_r = TRUE)

  # Custom node labels for the 5-factor level
  autoplot(x, node_labels = c(m5f1 = "Factor A", m5f2 = "Factor B"))

  # Widen two boxes to fit long manual labels (per-box sizing)
  autoplot(x,
    node_labels = c(m5f1 = "Conscientiousness"),
    node_width = c(m5f1 = 1.8)
  )

  # Primary links only -- clean hierarchy tree
  autoplot(x, primary_only = TRUE)

  # Manually order the deepest level to untangle the figure by hand
  ids5 <- paste0("m5f", c(2, 1, 3, 5, 4))
  autoplot(x, order = ids5)

  # Forbes pruned view: omit redundant nodes, straight spanning arrows
  xp <- ackwards(sim16, k_max = 5) |> prune("redundant")
  autoplot(xp, drop_pruned = TRUE)
  autoplot(xp, drop_pruned = TRUE, show_r = TRUE)
  autoplot(xp, drop_pruned = TRUE, compress_levels = TRUE)

  # Add the secondary between-level correlations the primary view hides
  # (dimmed + thinner, drawn beneath the primary edges)
  autoplot(xp, drop_pruned = TRUE, show_secondary = TRUE)

  # Plain line ends without arrowheads
  autoplot(x, show_arrows = FALSE)

  # Uniform edge width (no |r| scaling)
  autoplot(x, edge_linewidth = 0.5)

  # Suppress legend
  autoplot(x, legend = FALSE)

  # Forbes (2023) publication style: black lines, uniform width, no arrowheads
  autoplot(xp,
    drop_pruned = TRUE,
    color_pos = "black", color_neg = "black",
    edge_linewidth = 0.6, show_arrows = FALSE, legend = FALSE
  )
}
#> Warning: `min_sep` (1) is less than the widest box (1.8); adjacent boxes may overlap.
#>  Redundancy pruning (direct criterion, |r| ≥ 0.9) flagged 7 nodes.
#>  Nodes are retained in the object; inspect with `x$prune$nodes` and
#>   `x$prune$chains`.

# }