---
title: "Advanced Circumplex Visualization"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Advanced Circumplex Visualization}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7,
  fig.height = 5,
  out.width = "100%"
)
set.seed(12345)
library(ggplot2)
```

```{r setup}
library(circumplex)
```

## Beyond the built-in plots

The `ssm_plot_circle()`, `ssm_plot_curve()`, and `ssm_plot_contrast()`
functions cover the most common circumplex figures, but they each produce a
finished plot with a fixed set of layers. Sometimes you want more control: to
overlay individual respondents on a group profile, to annotate a specific
region of the circle, to restyle the points, or to place several circumplex
panels side by side.

To make that possible, `circumplex` exposes the building blocks that the
built-in plots are themselves made of. These are ordinary
[`ggplot2`](https://ggplot2.tidyverse.org/) components, so you compose them with
`+` and combine them freely with any other `ggplot2` layers, scales, and themes:

- `ggcircumplex()` draws the empty circular **canvas** (amplitude rings,
  displacement spokes, and scale labels).
- `geom_ssm_point()` and `geom_ssm_arc()` are polar-native **layers** that place
  profile points and their confidence regions in the circle, taking amplitude
  and displacement directly as aesthetics.
- `scale_x_circumplex()` is a **scale** for the angle axis of linear circumplex
  plots (such as the score-by-angle curve).

This vignette works through each of these and then combines them.

## The circular canvas

`ggcircumplex()` returns a `ggplot2` object containing just the circular
backdrop, with no data drawn on it yet. By default it uses octant scales
labeled by their angular position in degrees:

```{r canvas-default}
ggcircumplex()
```

You can label the scales however you like. Passing a character vector labels the
spokes in the order of the angles:

```{r canvas-labels}
ggcircumplex(octants(), labels = PANO())
```

If you are working with one of the instruments bundled with the package, you can
pass it directly and the scale angles and abbreviations are taken from the
instrument:

```{r canvas-instrument}
ggcircumplex(instrument = csip)
```

The `amax` argument sets the amplitude represented by the outer ring; it also
determines the amplitude gridline labels. It matters because it is the shared
reference that the data layers below must agree with, as we will see next.

## Placing SSM results in the circle

Let's estimate a Structural Summary Method (SSM) profile for two measures and
draw it on the canvas ourselves, rather than calling `ssm_plot_circle()`.

```{r analyze}
results <- ssm_analyze(
  jz2017,
  scales = PANO(),
  measures = c("NARPD", "ASPD")
)
results$results[, c("Label", "a_est", "d_est", "a_lci", "a_uci")]
```

`geom_ssm_point()` places a point for each profile at its amplitude
(`a_est`) and displacement (`d_est`), and `geom_ssm_arc()` draws the wedge
spanning each profile's amplitude confidence interval radially and its
displacement confidence interval angularly. Both take the SSM parameters
directly as aesthetics and handle the conversion into circular coordinates
internally, including wrap-around when a displacement interval crosses the
0/360 degree boundary.

The one rule to remember is that **`amax` must be the same** for the canvas and
for every data layer, so that amplitudes map onto the same radius. Here we set
it once and reuse it:

```{r results-plot}
amax <- 1

ggcircumplex(octants(), labels = PANO(), amax = amax) +
  geom_ssm_arc(
    data = results$results,
    mapping = aes(
      amplitude_min = a_lci, amplitude_max = a_uci,
      displacement_min = d_lci, displacement_max = d_uci,
      fill = Label
    ),
    amax = amax, alpha = 0.4, color = NA
  ) +
  geom_ssm_point(
    data = results$results,
    mapping = aes(amplitude = a_est, displacement = d_est, fill = Label),
    amax = amax
  )
```

Each arc displays two separate confidence intervals for one profile at once:
its radial extent is the amplitude interval and its angular extent is the
displacement interval. It is a convenient way to show both intervals together,
not a single joint confidence region with its own coverage level, and not a
hypothesis test. The angular extent in particular is a range of plausible
*directions*: because zero degrees is an arbitrary reference direction rather
than a null value, it should not be read as a significance test the way a
confidence interval for a linear parameter (such as elevation) can be.
Displacement is only worth interpreting at all when the amplitude interval is
clearly above zero and the model fits reasonably well (see the "Introduction to
SSM Analysis" vignette and `?ssm_analyze`).

## Composing custom layers

Because the canvas and geoms are ordinary `ggplot2` objects, you can add
anything else to them. A common request is to show where individual respondents
fall relative to a summary. We can compute each person's own amplitude and
displacement with `ssm_score()` and draw them as a faint cloud behind a
group-level point.

```{r individuals, warning = FALSE}
# Per-person SSM parameters for a subset of the sample. A respondent whose
# scores are flat has no displacement and is returned as NA (with a warning),
# so we keep only the well-defined profiles.
people <- ssm_score(
  jz2017[1:100, ],
  scales = PANO(),
  append = FALSE
)
people <- people[!is.na(people$Disp), ]

# Group-level profile for the same subset
group <- ssm_analyze(jz2017[1:100, ], scales = PANO())

amax <- 3

ggcircumplex(octants(), labels = PANO(), amax = amax) +
  geom_ssm_point(
    data = people,
    mapping = aes(amplitude = Ampl, displacement = Disp),
    amax = amax, fill = "grey70", size = 1.5, alpha = 0.6
  ) +
  geom_ssm_point(
    data = group$results,
    mapping = aes(amplitude = a_est, displacement = d_est),
    amax = amax, fill = "#0072B2", size = 4
  )
```

The individual points spread around the circle while the group summary sits near
their center of mass, a picture that none of the built-in functions produce
directly. Any other `ggplot2` layer --- text annotations, additional geoms,
faceting --- can be added the same way.

## The angle axis for linear plots

Not every circumplex figure is circular. The score-by-angle curve drawn by
`ssm_plot_curve()` is a linear plot whose x-axis runs through the scale angles.
`scale_x_circumplex()` labels that axis consistently with the circular canvas:
by default with the angle in degrees, or with custom labels or an instrument's
abbreviations.

```{r curve-axis}
angles <- octants()
curve <- data.frame(
  angle = angles,
  score = 1 + 0.8 * cos((angles - 135) * pi / 180)
)

ggplot(curve, aes(x = angle, y = score)) +
  geom_line() +
  geom_point(size = 2) +
  scale_x_circumplex(angles, labels = PANO()) +
  labs(x = "Scale", y = "Score") +
  theme_bw()
```

Passing the same `labels` (or the same `instrument`) to both `ggcircumplex()`
and `scale_x_circumplex()` guarantees that a circular figure and a linear one
label their scales identically.

## Relationship to the built-in plots

The built-in plotting functions are implemented on exactly these components:
`ssm_plot_circle()` is `ggcircumplex()` plus `geom_ssm_arc()` and
`geom_ssm_point()`, and `ssm_plot_curve()` uses `scale_x_circumplex()` for its
angle axis. So you can always start from a built-in plot and add to it, or
rebuild it from the pieces when you need finer control. Whichever route you
take, the coordinates are computed the same way, so the results line up.

## References

* Gurtman, M. B. (1992). Construct validity of interpersonal personality
  measures: The interpersonal circumplex as a nomological net. _Journal of
  Personality and Social Psychology, 63_(1), 105--118.

* Wright, A. G. C., Pincus, A. L., Conroy, D. E., & Hilsenroth, M. J. (2009).
  Integrating methods to optimize circumplex description and comparison of
  groups. _Journal of Personality Assessment, 91_(4), 311--322.

* Zimmermann, J., & Wright, A. G. C. (2017). Beyond description in interpersonal
  construct validation: Methodological advances in the circumplex Structural
  Summary Approach. _Assessment, 24_(1), 3--23.
