---
title: "Snake Plots"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Snake Plots}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

Snake plots display data as horizontal bands in a serpentine layout — each
row reverses direction and connects to the next through a U-turn arc. This
compact layout lets you compare many items at once while preserving
adjacency information such as inter-item correlations.

The package ships with three datasets from an experience sampling study of
university students (Neubauer & Schmiedek, 2024), rescaled to a 1--5 Likert
scale, and 10 built-in color palettes via `snake_palettes`:

```{r load}
library(snakeplot)

labs5 <- c("1" = "Not at all", "2" = "Slightly", "3" = "Moderate",
           "4" = "Quite",      "5" = "Extremely")
```

## Daily EMA — value distribution ticks

When you have beep-level data, `var` and `day` auto-pivot into one band
per day. Ticks are positioned within proportional zones by response level:

```{r daily_value, fig.height = 8}
survey_snake(ema_beeps, var = "angry", day = "day",
             colors = snake_palettes$sunset, level_labels = labs5,
             title = "Anger — 14 days, value distribution")
```

## Daily EMA — distribution bars

The same daily data with `tick_shape = "bar"` shows how response
distributions shift across days. Use `bar_reverse = TRUE` to start
from the highest level:

```{r daily_bars, fig.height = 8}
survey_snake(ema_beeps, var = "happy", day = "day",
             tick_shape = "bar", bar_reverse = TRUE,
             colors = snake_palettes$sunset, level_labels = labs5,
             title = "Happiness — 14 days, distribution bars")
```

## Activity timelines

`activity_snake()` shows daily event timelines — rug ticks or duration
blocks on a dark ribbon:

```{r activity, fig.height = 6}
set.seed(42)
days <- c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
d <- data.frame(
  day      = rep(days, each = 40),
  start    = round(runif(280, 360, 1400)),
  duration = 0
)
activity_snake(d)
```

Pass character timestamps directly — they are parsed automatically:

```{r flex_activity, fig.height = 6}
set.seed(42)
dates <- seq(as.POSIXct("2024-03-11"), as.POSIXct("2024-03-17"),
             by = "day")
events <- data.frame(
  timestamp = format(
    rep(dates, each = 30) + round(runif(210, 6*3600, 22*3600)),
    "%Y-%m-%d %H:%M:%S"
  ),
  stringsAsFactors = FALSE
)
activity_snake(events, title = "From character timestamps — 7 days")
```

Duration blocks show event length as filled rectangles:

```{r activity_blocks, fig.height = 6}
set.seed(42)
days <- c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
d2 <- data.frame(
  day      = rep(days, each = 8),
  start    = round(runif(56, 360, 1200)),
  duration = round(runif(56, 15, 120))
)
activity_snake(d2, event_color = "#e09480", band_color = "#3d2518",
               title = "Weekly activity — duration blocks")
```

With `flow = "natural"`, all bands read 6AM→12AM left-to-right — no
alternating. Compare: the default boustrophedon flips morning events
between left and right on alternate rows, while natural keeps them
consistently on the left:

```{r activity_natural, fig.height = 6}
set.seed(1)
d_morning <- data.frame(
  day      = rep(days, each = 15),
  start    = round(runif(105, 360, 720)),
  duration = 0
)
activity_snake(d_morning, flow = "natural",
               title = "Morning events — flow='natural' (6AM always left)")
```

## Line snake

`line_snake()` draws a continuous intensity line winding through bands:

```{r line_snake}
set.seed(42)
hours <- seq(0, 1440, by = 10)
d_line <- data.frame(
  day   = rep(c("Mon", "Tue", "Wed", "Thu", "Fri"), each = length(hours)),
  time  = rep(hours, 5),
  value = sin(rep(hours, 5) / 1440 * 4 * pi) * 50 + 50 +
          rnorm(5 * length(hours), 0, 8)
)
line_snake(d_line, fill_color = "#e74c3c")
```

## Timeline snake

`timeline_snake()` takes a 3-column data.frame (role, start, end) and
auto-generates monthly blocks, transition labels, and band year labels:

```{r timeline_snake}
career <- data.frame(
  role  = c("Intern", "Junior Dev", "Mid Dev",
            "Senior Dev", "Tech Lead", "Architect"),
  start = c("2015-01", "2015-07", "2017-01",
            "2019-07", "2022-07", "2024-01"),
  end   = c("2015-06", "2016-12", "2019-06",
            "2022-06", "2023-12", "2024-12")
)
timeline_snake(career,
               title = "Software Engineer — Career Path (2015-2024)")
```

## Tick lines with correlation arcs

Individual responses as colored tick marks, with inter-item Pearson *r*
displayed at each U-turn arc:

```{r corr, fig.height = 7}
survey_snake(ema_emotions, tick_shape = "line",
             arc_fill = "correlation", sort_by = "mean",
             colors = snake_palettes$berry, level_labels = labs5,
             title = "Emotions — correlations at U-turns")
```

## Dot plot with dark bands

Use `band_palette` for darker band shading. Dots with jitter show
individual responses:

```{r dots_dark, fig.height = 7}
survey_snake(ema_emotions, tick_shape = "dot", sort_by = "mean",
             colors = snake_palettes$viridis, level_labels = labs5,
             band_palette = c("#1a1228", "#1a2a42"),
             title = "Emotions — dots on dark bands")
```

## Mean and median markers

A diamond shows the item mean; a dashed line shows the median:

```{r markers, fig.height = 7}
survey_snake(ema_emotions, tick_shape = "bar", sort_by = "mean",
             show_mean = TRUE, show_median = TRUE,
             colors = snake_palettes$sunset, level_labels = labs5,
             title = "Emotions — mean (diamond) and median (dashed)")
```

## Faceted multi-construct

When column names share a prefix (e.g., `Emo_`, `Mot_`), `facet = TRUE`
auto-groups them into panels. Prefixes are stripped from labels:

```{r facet, fig.width = 9, fig.height = 11}
survey_snake(student_survey, facet = TRUE, facet_ncol = 2L,
             tick_shape = "bar", sort_by = "mean",
             colors = snake_palettes$earth, level_labels = labs5)
```

## Survey sequence

`survey_sequence()` renders 100% stacked horizontal bars in a
serpentine layout:

```{r survey_seq}
survey_sequence(ema_emotions, colors = snake_palettes$earth)
```

Matrix with row/col names — labels and levels are inferred automatically:

```{r flex_survey, fig.height = 6}
m <- matrix(c(50, 120, 80, 30,
              40,  90, 110, 60,
              70, 100,  70, 50,
              80,  85,  95, 40,
              30, 110,  90, 70,
              60,  75, 105, 55,
              45, 130,  65, 35), nrow = 7, byrow = TRUE)
rownames(m) <- c("Satisfaction", "Engagement", "Motivation",
                  "Belonging", "Autonomy", "Competence", "Wellbeing")
colnames(m) <- c("Low", "Medium", "High", "Very High")
survey_sequence(m, title = "Labels from matrix dimnames",
                colors = snake_palettes$sunset)
```

## Sequential distribution

`sequential_dist()` is a monochrome variant of `survey_sequence()`:

```{r seq_dist}
sequential_dist(ema_emotions)
```

## Sequence snake

`sequence_snake()` displays a state sequence as colored blocks flowing
through the serpentine layout — each block is one time point colored by
its state:

```{r sequence_snake}
set.seed(42)
verbs <- c("Read", "Write", "Discuss", "Listen",
           "Search", "Plan", "Code", "Review")
seq75 <- character(0)
while (length(seq75) < 75) {
  seq75 <- c(seq75, rep(sample(verbs, 1), sample(1:4, 1)))
}
seq75 <- seq75[seq_len(75)]
sequence_snake(seq75, title = "75-step learning sequence")
```

Pass a data.frame directly — the first character/factor column is
auto-detected:

```{r flex_df}
set.seed(1)
logs <- data.frame(
  id     = 1:80,
  action = sample(c("Read", "Write", "Discuss", "Search", "Code",
                     "Plan", "Review", "Listen"), 80, replace = TRUE)
)
sequence_snake(logs, rows = 5,
               title = "From a data.frame — column auto-detected")
```

## Built-in palettes

10 palettes are available via `snake_palettes` or `snake_palette()`:

```{r palette_names}
names(snake_palettes)
```

Use any palette by name:

```r
survey_snake(ema_emotions, colors = snake_palettes$earth, tick_shape = "bar")
snake_palette("sunset", n = 5)  # interpolate to 5 colors
```
