Title: Serpentine Plots for Long Timeline, Sequential and Survey Data
Version: 0.3.0
Description: Visualize long timelines, extended sequences and temporally chained survey responses and experience sampling data using intuitive serpentine (snake) plots. Supports distribution bars, tick-mark plots, inter-item correlation arcs, faceted multi-construct panels, and daily time-of-day positioning for ecological momentary assessment data.
License: MIT + file LICENSE
Depends: R (≥ 3.5.0)
Imports: graphics, grDevices, stats
LazyData: true
URL: https://github.com/mohsaqr/snakeplot
BugReports: https://github.com/mohsaqr/snakeplot/issues
Encoding: UTF-8
RoxygenNote: 7.3.3
Config/testthat/edition: 3
Suggests: testthat (≥ 3.0.0), knitr, rmarkdown
VignetteBuilder: knitr
NeedsCompilation: no
Packaged: 2026-03-11 14:44:23 UTC; mohammedsaqr
Author: Mohammed Saqr [aut, cre, cph], Sonsoles Lopez-Pernas [aut]
Maintainer: Mohammed Saqr <saqr@saqr.me>
Repository: CRAN
Date/Publication: 2026-03-16 19:30:03 UTC

snakeplot: Serpentine Plots for Long Timeline, Sequential and Survey Data

Description

Visualize long timelines, extended sequences and temporally chained survey responses and experience sampling data using intuitive serpentine (snake) plots. Supports distribution bars, tick-mark plots, inter-item correlation arcs, faceted multi-construct panels, and daily time-of-day positioning for ecological momentary assessment data.

Author(s)

Maintainer: Mohammed Saqr saqr@saqr.me [copyright holder]

Authors:

See Also

Useful links:


Activity Snake Plot

Description

A daily activity timeline where each band is one day and colored ticks or blocks on a dark ribbon represent events. The serpentine (boustrophedon) layout connects days via U-turn arcs.

Usage

activity_snake(
  data,
  band_height = 28,
  band_gap = 18,
  day_start = 360,
  day_end = 1440,
  plot_width = 500,
  band_color = "#3d3d4a",
  event_color = "#d4a843",
  arc_color = "#2a2a3a",
  band_opacity = 0.9,
  arc_opacity = 0.85,
  event_opacity = 0.85,
  tick_width = 1.5,
  show_grid = TRUE,
  show_total = TRUE,
  show_count = FALSE,
  show_hour_labels = TRUE,
  show_arc_labels = TRUE,
  shadow = TRUE,
  grid_color = "rgba(255,255,255,0.25)",
  label_color = "#cccccc",
  label_size = 0.85,
  label_align = "left",
  orientation = c("horizontal", "vertical"),
  start_from = c("left", "right"),
  flow = c("snake", "natural"),
  day_format = NULL,
  legend = NULL,
  title = NULL,
  margin = c(top = 30, right = 10, bottom = 50, left = 80),
  background = "white"
)

Arguments

data

Input in one of three formats. (1) POSIXct vector: a bare vector of timestamps, producing rug ticks grouped by day. (2) Numeric format: a data.frame with columns day (character/factor day label), start (numeric minutes from midnight, 0–1440), duration (numeric minutes; 0 = rug tick), and optionally label (character event label). (3) Timestamp format: a data.frame with POSIXct column timestamp (or start), optionally end (POSIXct; if present, duration is computed), duration (numeric minutes; used when end is absent), and label (character event label).

band_height

Numeric. Height of each day band in plot units (default 28).

band_gap

Numeric. Vertical gap between bands (default 18).

day_start

Numeric. Start of the time window in minutes from midnight (default 360 = 6AM).

day_end

Numeric. End of the time window in minutes from midnight (default 1440 = midnight).

plot_width

Numeric. Width of the band area in plot units (default 500).

band_color

Character or character vector. Band ribbon color(s). If a vector, colors cycle per day (default "#3d3d4a").

event_color

Character or character vector. Event tick/block color(s). If a vector, colors cycle per day (default "#d4a843").

arc_color

Character. Overnight arc color (default "#2a2a3a").

band_opacity

Numeric 0-1 (default 0.90).

arc_opacity

Numeric 0-1 (default 0.85).

event_opacity

Numeric 0-1 (default 0.85).

tick_width

Numeric. Minimum event width in plot units (default 1.5). Use 1.0 for thin rug style.

show_grid

Logical. Show hour gridlines (default TRUE).

show_total

Logical. Show total duration after day label (default TRUE).

show_count

Logical. Show event count in parentheses after day label (default FALSE).

show_hour_labels

Logical. Show hour labels at bottom (default TRUE).

show_arc_labels

Logical. Show "12AM" at arc tips (default TRUE).

shadow

Logical. Draw drop shadows (default TRUE).

grid_color

Character. Gridline color (default "rgba(255,255,255,0.25)").

label_color

Character. Day label color (default "#cccccc").

label_size

Numeric. Label font size multiplier (default 0.85).

label_align

Character. Label alignment: "left" (default), "right", or "direction" (follows band reading direction).

orientation

Character: "horizontal" (default) or "vertical". Controls whether the snake runs left-right or top-bottom.

start_from

Character: "left" (default) or "right". Which side the first band starts from.

flow

Character, "snake" (default) or "natural". "snake" uses alternating boustrophedon direction; "natural" reads all bands in the same direction.

day_format

Optional strftime format for day labels when start is POSIXct (e.g., "%a" for "Mon", "%Y-%m-%d" for dates). NULL = auto-detect ("%a" for 7 or fewer days, "%Y-%m-%d" otherwise).

legend

List of legend items, each with label and color. NULL for no legend.

title

Optional plot title.

margin

Named numeric vector with top, right, bottom, left margins.

background

Background color (default "white").

Value

Invisible snake_layout object (for downstream use).

Examples

# Weekly rug-style activity plot
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)

# Duration blocks
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")


EMA Beep-Level Data (Daily Emotions)

Description

All 11 474 experience-sampling beeps from a 14-day study of 321 university students. Each row is one beep with the participant's emotion ratings and a timestamp. Use with the var/day/timestamp interface of survey_snake for daily snake plots.

Usage

ema_beeps

Format

A data.frame with 11 474 rows and 5 columns.

Details

id

Character. Anonymised participant identifier.

day

Integer 1–14. Study day.

start_time

POSIXct. Timestamp of the beep.

happy

Integer 1–5. Self-reported happiness (rescaled from original 1–7).

angry

Integer 1–5. Self-reported anger (rescaled from original 1–7).

Source

Neubauer, A. B., & Schmiedek, F. (2024). Approaching academic adjustment on multiple time scales. Zeitschrift fuer Erziehungswissenschaft, 27(1), 147–168. doi:10.1007/s11618-023-01182-8

Data: https://osf.io/bhq3p | Codebook: https://osf.io/csfwg | Code: https://osf.io/84kdr/files | License: CC-BY 4.0

Examples

# Anger over 14 days, ticks by time-of-day
survey_snake(ema_beeps, var = "angry", day = "day",
             timestamp = "start_time")

# Happiness over 14 days, distribution bars
survey_snake(ema_beeps, var = "happy", day = "day",
             tick_shape = "bar")

EMA Emotion Ratings (Person-Level)

Description

Person-level mean emotion ratings (rounded to integers) from a 14-day experience sampling study of 280 university students. Ten emotion items rescaled to a 1–5 Likert scale (original study used 1–7; rescaled via linear transformation for simplicity). Ready to pass directly to survey_snake.

Usage

ema_emotions

Format

A data.frame with 280 rows and 10 columns (integers 1–5): Happy, Afraid, Sad, Balanced, Exhausted, Cheerful, Worried, Lively, Angry, Relaxed.

Source

Neubauer, A. B., & Schmiedek, F. (2024). Approaching academic adjustment on multiple time scales. Zeitschrift fuer Erziehungswissenschaft, 27(1), 147–168. doi:10.1007/s11618-023-01182-8

Data: https://osf.io/bhq3p | Codebook: https://osf.io/csfwg | Code: https://osf.io/84kdr/files | License: CC-BY 4.0

Examples

survey_snake(ema_emotions, tick_shape = "bar", sort_by = "mean")

Faceted Snake Plot

Description

Splits data by a grouping variable and draws side-by-side snake panels. Works with activity_snake, survey_snake, survey_sequence, sequential_dist, or line_snake.

Usage

facet_snake(data, facet_var, FUN = activity_snake, ncol = NULL, ...)

Arguments

data

Data to plot (passed to FUN).

facet_var

Character. Column name in data to facet by.

FUN

Function to call for each panel. Default activity_snake.

ncol

Integer. Number of columns in the facet grid. Default: number of facet levels (all in one row).

...

Additional arguments passed to FUN.

Value

Invisible list of results from each panel call.

Examples

set.seed(42)
d <- data.frame(
  group    = rep(c("A", "B"), each = 70),
  day      = rep(rep(c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"),
                 each = 10), 2),
  start    = round(runif(140, 360, 1400)),
  duration = 0
)
facet_snake(d, "group")


Line Snake Plot (Experimental)

Description

A continuous intensity line winding through a serpentine layout. Each band represents a time segment (e.g., a day); the line's vertical position within the band encodes a continuous value (e.g., foot traffic, CPU usage). The line smoothly curves through U-turn arcs between bands.

Usage

line_snake(
  data,
  band_height = 40,
  band_gap = 18,
  day_start = 0,
  day_end = 1440,
  plot_width = 500,
  line_color = "#e74c3c",
  line_width = 1.5,
  fill_color = NULL,
  fill_opacity = 0.3,
  band_color = "#2d2d3d",
  arc_color = "#1a1a2e",
  band_opacity = 0.9,
  arc_opacity = 0.85,
  show_grid = TRUE,
  shadow = TRUE,
  label_color = "#cccccc",
  label_size = 0.85,
  orientation = c("horizontal", "vertical"),
  start_from = c("left", "right"),
  flow = c("snake", "natural"),
  title = NULL,
  margin = c(top = 30, right = 10, bottom = 50, left = 80),
  background = "white"
)

Arguments

data

A data.frame with columns:

time

Numeric (minutes from midnight) or POSIXct timestamps.

value

Numeric intensity value.

day

(Optional) Day labels. Auto-detected from timestamps if absent.

Alternatively, a numeric vector (interpreted as evenly-spaced values for a single band).

band_height

Numeric (default 40).

band_gap

Numeric (default 18).

day_start

Numeric, minutes from midnight (default 0).

day_end

Numeric, minutes from midnight (default 1440).

plot_width

Numeric (default 500).

line_color

Character (default "#e74c3c").

line_width

Numeric (default 1.5).

fill_color

Optional fill color below the line (default NULL = no fill).

fill_opacity

Numeric 0-1 (default 0.3).

band_color

Character (default "#2d2d3d").

arc_color

Character (default "#1a1a2e").

band_opacity

Numeric (default 0.90).

arc_opacity

Numeric (default 0.85).

show_grid

Logical (default TRUE).

shadow

Logical (default TRUE).

label_color

Character (default "#cccccc").

label_size

Numeric (default 0.85).

orientation

Character, "horizontal" or "vertical" (default "horizontal").

start_from

Character, "left" or "right" (default "left").

flow

Character, "snake" (default) or "natural". "snake" uses alternating boustrophedon direction; "natural" reads all bands in the same direction.

title

Optional title.

margin

Named numeric vector.

background

Background color.

Value

Invisible snake_layout object.

Examples

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


Multi-Sequence Snake Plot

Description

Displays many sequences simultaneously in a serpentine layout. Time points are packed as blocks within each band (like sequence_snake), with multiple time points flowing through bands and arcs.

Usage

multi_snake(
  sequences,
  type = c("index", "distribution"),
  states = NULL,
  colors = NULL,
  sort_by = c("none", "first", "last", "freq", "entropy"),
  rows = NULL,
  band_height = 28,
  band_gap = 18,
  plot_width = 500,
  margin = c(top = 30, right = 10, bottom = 50, left = 80),
  flow = c("snake", "natural"),
  show_labels = TRUE,
  show_legend = TRUE,
  show_percent = TRUE,
  border_color = NA,
  title = NULL,
  background = "white",
  shadow = TRUE,
  legend_text_size = 0.8,
  tick_opacity = 0.85
)

Arguments

sequences

Matrix or data.frame where rows are sequences and columns are time points. Each cell contains a state label.

type

Character, "index" (default) or "distribution".

states

Character vector of unique states in desired legend order. If NULL, derived from the data.

colors

Named or unnamed character vector of colors. If NULL, a built-in qualitative palette is used.

sort_by

Character controlling sequence order in index mode: "none" (default), "first" (sort by first state), "last" (sort by last state), "freq" (sort by most frequent state), or "entropy" (sort by Shannon entropy).

rows

Integer, number of serpentine rows. If NULL, auto-calculated (~10 blocks per band).

band_height

Numeric, height of each band in pixels (default 28).

band_gap

Numeric, gap between bands (default 18).

plot_width

Numeric, width of each band (default 500).

margin

Named numeric vector with top, right, bottom, left margins.

flow

Character, "snake" (default) or "natural". "snake" uses alternating boustrophedon direction; "natural" reads all bands in the same direction.

show_labels

Logical, show time-point range per row (default TRUE).

show_legend

Logical, draw color legend (default TRUE).

show_percent

Logical, show percentage labels inside distribution bars (default TRUE). Only used when type = "distribution".

border_color

Color for thin borders between blocks, or NA for no borders (default NA).

title

Optional character string for plot title.

background

Background color (default "white").

shadow

Logical, draw drop shadows (default TRUE).

legend_text_size

Numeric, legend text size (default 0.8).

tick_opacity

Numeric 0-1, opacity of ticks in index mode (default 0.85).

Details

Two display modes are supported:

"index"

Each block contains thin colored ticks stacked side by side — one tick per sequence, colored by state at that time point. Like TraMineR's seqiplot() folded into a serpentine.

"distribution"

Each block is a stacked proportional bar showing what fraction of sequences is in each state at that time point. Like TraMineR's seqdplot().

Value

Invisible NULL. Called for its side effect of producing a plot.

Examples

set.seed(42)
states <- c("Active", "Passive", "Absent")
seqs <- matrix(sample(states, 500, replace = TRUE), nrow = 50, ncol = 10)
multi_snake(seqs, type = "index")
multi_snake(seqs, type = "distribution")


Sequence Index Snake Plot

Description

Displays a state sequence as colored blocks flowing through a serpentine (boustrophedon) layout. Each block represents one time point colored by its state. Blocks flow continuously through both bands AND arcs, wrapping a long sequence into a compact multi-row display.

Usage

sequence_snake(
  sequence,
  states = NULL,
  colors = NULL,
  rows = NULL,
  band_height = 28,
  band_gap = 18,
  plot_width = 500,
  margin = c(top = 30, right = 10, bottom = 50, left = 80),
  orientation = "horizontal",
  start_from = "left",
  flow = c("natural", "snake"),
  show_labels = TRUE,
  show_legend = TRUE,
  show_numbers = FALSE,
  show_state = FALSE,
  state_size = 0.35,
  show_ticks = FALSE,
  tick_labels = NULL,
  transition_labels = NULL,
  transition_pos = NULL,
  tick_color = "#333333",
  tick_length = 5,
  tick_size = 0.4,
  style = c("block", "rug"),
  band_color = "#3d3d4a",
  rug_opacity = 0.9,
  jitter = 0,
  border_color = NA,
  block_labels = NULL,
  band_labels = NULL,
  title = NULL,
  background = "white",
  shadow = TRUE,
  text_size = 0.5,
  legend_text_size = 0.8
)

Arguments

sequence

Input in flexible formats:

  • Vector: character, integer, or factor vector of states.

  • Data.frame: first character/factor column is used.

  • Comma-separated string: "A,B,C,A" is split automatically.

  • List: unlisted to a vector.

NA values are dropped with a warning.

states

Character vector of unique states in desired order. If NULL, derived from unique(sequence).

colors

Named character vector of colors keyed by state, or an unnamed vector recycled to match states. If NULL, a built-in qualitative palette is used.

rows

Integer, number of serpentine rows. If NULL, auto-calculated targeting approximately 10 blocks per band.

band_height

Numeric, height of each band in pixels (default 28).

band_gap

Numeric, gap between bands (default 18).

plot_width

Numeric, width of each band (default 500).

margin

Named numeric vector with top, right, bottom, left margins.

orientation

Character, "horizontal" (default) or "vertical".

start_from

Character, "left" (default) or "right".

flow

Character, "natural" (default) or "snake". "natural" reads all bands left-to-right; "snake" uses alternating boustrophedon direction. Default "natural".

show_labels

Logical, show position range labels per row (default TRUE).

show_legend

Logical, draw color legend (default TRUE).

show_numbers

Logical, print small position numbers inside blocks (default FALSE).

show_state

Logical, print the state name inside each block (default FALSE).

state_size

Numeric, text size for state labels (default 0.35).

show_ticks

Logical, draw ruler-style tick marks at block boundaries outside the bands (default FALSE).

tick_labels

Character vector of labels for evenly spaced ruler marks within each band (e.g., month.abb for monthly ticks). Implies show_ticks = TRUE.

transition_labels

Character vector of date labels for state transition points (e.g., c("Oct 2017", "Apr 2019")). One label per transition (length = number of state changes).

transition_pos

Numeric vector of fractional block positions for transition labels (e.g., c(6.5, 24.3)). When provided, labels are placed at exact interpolated positions along the serpentine path rather than at state-change boundaries.

tick_color

Color for tick marks (default "#333333").

tick_length

Numeric, length of tick marks in pixels (default 5).

tick_size

Numeric, text size for tick labels (default 0.4).

style

Character, "block" (default) or "rug". "block" fills the full band height with colored blocks. "rug" draws thin colored tick marks on a dark ribbon, similar to activity_snake.

band_color

Character, band ribbon color for rug mode (default "#3d3d4a").

rug_opacity

Numeric 0-1, opacity of rug tick marks (default 0.9).

jitter

Numeric 0-1, vertical jitter as fraction of band height (default 0). When > 0, tick marks scatter vertically across the band instead of sitting at a fixed position.

border_color

Color for thin borders between blocks, or NA for no borders (default NA).

block_labels

Optional character vector of labels to display inside each block (same length as sequence). Overrides show_numbers.

band_labels

Character vector of labels to display centered below each band (e.g., year labels). Length must equal rows.

title

Optional character string for plot title.

background

Background color (default "white").

shadow

Logical, draw drop shadows (default TRUE).

text_size

Numeric, text size multiplier for block labels (default 0.5).

legend_text_size

Numeric, legend text size (default 0.8).

Value

Invisible NULL. Called for its side effect of producing a plot.

Examples

set.seed(42)
verbs <- c("Read", "Write", "Discuss", "Listen",
           "Search", "Plan", "Code", "Review")
seq75 <- sample(verbs, 75, replace = TRUE)
sequence_snake(seq75)

# Custom colors
cols <- c(Read = "#E41A1C", Write = "#377EB8", Discuss = "#4DAF4A",
          Listen = "#984EA3", Search = "#FF7F00", Plan = "#A6D854",
          Code = "#A65628", Review = "#F781BF")
sequence_snake(seq75, colors = cols, rows = 5)


Sequential Distribution Plot

Description

Like survey_sequence but uses a sequential (monochrome) palette instead of diverging colors. Suitable for ordinal scales without a natural midpoint (e.g., "Never" to "Always").

Usage

sequential_dist(
  counts,
  labels = NULL,
  levels = NULL,
  hue = 210,
  band_height = 28,
  band_gap = 14,
  plot_width = 500,
  colors = NULL,
  show_percent = TRUE,
  min_segment = 34,
  arc_style = c("gradient", "neutral"),
  arc_opacity = 0.85,
  sort_by = c("none", "mean", "net"),
  shadow = TRUE,
  show_legend = TRUE,
  label_color = "#333333",
  label_size = 0.85,
  label_align = "left",
  reverse_rtl = FALSE,
  start_from = c("left", "right"),
  flow = c("snake", "natural"),
  title = NULL,
  margin = c(top = 30, right = 10, bottom = 55, left = 100),
  background = "white"
)

Arguments

counts

Numeric matrix of response counts (rows=items, cols=levels).

labels

Character vector of item labels.

levels

Character vector of level labels.

hue

Numeric 0-360. Base hue for the sequential palette (default 210 = blue).

band_height

Numeric (default 28).

band_gap

Numeric (default 14).

plot_width

Numeric (default 500).

colors

Character vector of segment colors. Default: diverging palette.

show_percent

Logical. Show percentages inside segments (default TRUE).

min_segment

Numeric. Hide label if segment narrower than this (default 34).

arc_style

Character: "gradient" or "neutral" (default "gradient").

arc_opacity

Numeric 0-1 (default 0.5).

sort_by

Character: "none", "mean", "net" (default "none").

shadow

Logical (default TRUE).

show_legend

Logical (default TRUE).

label_color

Character (default "#333333").

label_size

Numeric (default 0.85).

label_align

Character. Label alignment: "left" (default), "right", or "direction" (follows band reading direction).

reverse_rtl

Logical. Reverse segment order on right-to-left bands so the visual reading direction mirrors the data order (default FALSE).

start_from

Character: "left" (default) or "right". Which side the first band starts from.

flow

Character, "snake" (default) or "natural". "snake" uses alternating boustrophedon direction; "natural" reads all bands in the same direction.

title

Optional title.

margin

Named numeric vector.

background

Background color.

Value

Invisible snake_layout object.

Examples

counts <- matrix(c(
  15, 25, 60, 80, 45,
  10, 20, 50, 90, 55,
  20, 30, 65, 70, 40
), nrow = 3, byrow = TRUE)
labels <- c("Behavior A", "Behavior B", "Behavior C")
levs <- c("Never", "Rarely", "Sometimes", "Often", "Always")
sequential_dist(counts, labels, levs, hue = 160)


Get a Snake Plot Palette

Description

Returns a color palette interpolated to n colors.

Usage

snake_palette(name = "classic", n = 7L)

Arguments

name

Character, palette name (see snake_palettes).

n

Integer, number of colors to return (default 7).

Value

Character vector of n hex color strings.

Examples

snake_palette("ocean", 5)
snake_palette("earth", 7)
snake_palette("blues", 3)


Built-in Color Palettes

Description

A named list of 10 color palettes for snake plots. Each palette contains 7 anchor colors that can be interpolated to any length with snake_palette.

Usage

snake_palettes

Format

A named list of 10 character vectors, each with 7 hex color strings.

Details

classic

Diverging red-to-blue. Clean Likert default.

earth

Diverging brown-to-teal. Natural, understated.

ocean

Diverging coral-to-navy. Warm/cool contrast.

sunset

Diverging orange-to-indigo. Vivid but balanced.

berry

Diverging rose-to-green. High contrast.

blues

Sequential light-to-dark blue.

greens

Sequential light-to-dark green.

grays

Sequential light-to-dark gray.

warm

Sequential cream-to-dark red.

viridis

Sequential yellow-green-blue-purple (viridis-inspired).

Examples

snake_palettes$ocean
survey_snake(ema_emotions, colors = snake_palettes$earth,
             tick_shape = "bar", sort_by = "mean")


Student Survey (Cross-Sectional, Multi-Construct)

Description

Person-level mean scores (rounded to integers) from a 14-day experience sampling study of 280 university students. Contains 34 items across four construct groups, rescaled to a 1–5 Likert scale (original 1–7). Column name prefixes enable automatic faceting with survey_snake(student_survey, facet = TRUE).

Usage

student_survey

Format

A data.frame with 280 rows and 34 integer columns (values 1–5).

Details

Emo_

10 emotion items: Happy, Afraid, Sad, Balanced, Exhausted, Cheerful, Worried, Lively, Angry, Relaxed.

Mot_

8 study motivation items: Disappointed, FeltBad, Important, Interesting, Compulsory, Proving, Understanding, Enjoyment.

Reg_

5 emotion regulation items: SeeGood, FocusGood, Suppression, ChangedFeeling, Rumination.

Eng_

11 study engagement items: Enjoy, WearingDown, Satisfied, DifficultReconcile, Interesting, Exhausted, OnlyNecessary, Energy, Identification, Expectations, ConsiderQuitting.

Source

Neubauer, A. B., & Schmiedek, F. (2024). Approaching academic adjustment on multiple time scales. Zeitschrift fuer Erziehungswissenschaft, 27(1), 147–168. doi:10.1007/s11618-023-01182-8

Data: https://osf.io/bhq3p | Codebook: https://osf.io/csfwg | Code: https://osf.io/84kdr/files | License: CC-BY 4.0

Examples

survey_snake(student_survey, facet = TRUE, tick_shape = "bar",
             sort_by = "mean", facet_ncol = 2L)

Survey Sequence Plot

Description

Each survey item is a 100\ Color segments represent response levels; percentages are shown inside segments when wide enough. Arcs blend adjacent end-colors.

Usage

survey_sequence(
  counts,
  labels = NULL,
  levels = NULL,
  band_height = 28,
  band_gap = 14,
  plot_width = 500,
  colors = NULL,
  show_percent = TRUE,
  min_segment = 34,
  arc_style = c("gradient", "neutral"),
  arc_opacity = 0.5,
  sort_by = c("none", "mean", "net"),
  shadow = TRUE,
  show_legend = TRUE,
  label_color = "#333333",
  label_size = 0.85,
  label_align = "left",
  reverse_rtl = FALSE,
  start_from = c("left", "right"),
  flow = c("snake", "natural"),
  title = NULL,
  margin = c(top = 30, right = 10, bottom = 55, left = 100),
  background = "white"
)

Arguments

counts

Numeric matrix of response counts (rows=items, cols=levels).

labels

Character vector of item labels.

levels

Character vector of level labels.

band_height

Numeric (default 28).

band_gap

Numeric (default 14).

plot_width

Numeric (default 500).

colors

Character vector of segment colors. Default: diverging palette.

show_percent

Logical. Show percentages inside segments (default TRUE).

min_segment

Numeric. Hide label if segment narrower than this (default 34).

arc_style

Character: "gradient" or "neutral" (default "gradient").

arc_opacity

Numeric 0-1 (default 0.5).

sort_by

Character: "none", "mean", "net" (default "none").

shadow

Logical (default TRUE).

show_legend

Logical (default TRUE).

label_color

Character (default "#333333").

label_size

Numeric (default 0.85).

label_align

Character. Label alignment: "left" (default), "right", or "direction" (follows band reading direction).

reverse_rtl

Logical. Reverse segment order on right-to-left bands so the visual reading direction mirrors the data order (default FALSE).

start_from

Character: "left" (default) or "right". Which side the first band starts from.

flow

Character, "snake" (default) or "natural". "snake" uses alternating boustrophedon direction; "natural" reads all bands in the same direction.

title

Optional title.

margin

Named numeric vector.

background

Background color.

Value

Invisible snake_layout object.

Examples

counts <- matrix(c(
  110, 210, 79, 84, 42,
  126, 205, 68, 100, 26,
  184, 226, 47, 58, 10,
  200, 205, 52, 47, 21,
  205, 210, 42, 53, 15,
  197, 214, 53, 47, 14,
  194, 242, 47, 31, 11
), nrow = 7, byrow = TRUE)
labels <- c("LOC1", "LOC2", "LOC3", "CCA1", "LOC5", "LOC5", "LOC4")
labels <- paste0(labels, " (n=525)")
levs <- as.character(1:5)
survey_sequence(counts, labels, levs)


Survey Snake Plot

Description

Each survey item is a horizontal band in a serpentine layout. The band body is shaded by item mean (warm = low, cool = high). Individual responses are shown as colored tick marks. Inter-item correlations appear at U-turns.

Usage

survey_snake(
  counts,
  labels = NULL,
  levels = NULL,
  var = NULL,
  day = NULL,
  timestamp = NULL,
  level_labels = NULL,
  band_height = 28,
  band_gap = 18,
  plot_width = 500,
  tick_shape = c("line", "dot", "bar"),
  bar_reverse = FALSE,
  tick_opacity = 0.75,
  level_gap = 15,
  color_mode = c("level", "individual"),
  colors = NULL,
  shade_band = TRUE,
  show_mean = TRUE,
  show_median = FALSE,
  show_correlation = TRUE,
  jitter_range = 0.22,
  sort_by = c("none", "mean", "net"),
  shadow = TRUE,
  label_color = "#333333",
  label_size = 0.85,
  label_align = "left",
  show_legend = TRUE,
  legend_text_size = 0.65,
  arc_color = "#2c3e6b",
  arc_opacity = 0.8,
  arc_fill = c("none", "correlation", "mean_prev", "blend"),
  band_palette = NULL,
  start_from = c("left", "right"),
  flow = c("snake", "natural"),
  facet = FALSE,
  facet_ncol = 2L,
  title = NULL,
  margin = c(top = 30, right = 10, bottom = 55, left = 100),
  background = "white",
  seed = 42L
)

Arguments

counts

Input in one of four formats:

Raw responses (data.frame) — each column is a survey item, each row is a respondent. Responses are auto-tabulated into counts. labels and levels are inferred from column names and unique values. Simplest usage: survey_snake(survey_df).

Counts matrix — rows = items, columns = response levels.

Counts data.frame — coerced to matrix.

ESM / longitudinal data.frame — when var and timestamp are provided, data is automatically pivoted by day. Each band becomes one day. Ticks are positioned by time-of-day.

labels

Character vector of item labels (length = nrow(counts)).

levels

Character vector of level labels (length = ncol(counts)).

var

Character, column name of the response variable for ESM mode. When provided with day, data is auto-pivoted by period.

day

Character, column name for the day/period grouping variable (e.g. "day"). Each unique value becomes one band.

timestamp

Character, column name of a POSIXct timestamp for ESM mode. When provided alongside var and day, ticks are positioned by time-of-day within each band.

level_labels

Optional named character vector mapping raw level values to display labels (e.g. c("1"="Str. Disagree", "5"="Str. Agree")). Applied to legend and any level-based text. If unnamed and same length as levels, used positionally.

band_height

Numeric (default 28).

band_gap

Numeric (default 18).

plot_width

Numeric (default 500).

tick_shape

Character: "line" (default), "dot", or "bar" (stacked proportional bars with percentage labels).

bar_reverse

Logical. When TRUE and tick_shape = "bar", draw segments from the highest level (left) to the lowest (right). Default FALSE.

tick_opacity

Numeric 0-1 (default 0.55).

level_gap

Numeric. Gap between response-level zones in plot units (default 15). Set to 0 for no separation.

color_mode

Character, "level" (color by response level) or "individual" (unique hue per respondent). Default "level".

colors

Character vector of colors for response levels. Default uses a diverging palette.

shade_band

Logical. Shade band body by item mean (default TRUE).

show_mean

Logical. Diamond marker at mean (default TRUE).

show_median

Logical. Vertical line at median (default FALSE).

show_correlation

Logical. Show Pearson r at U-turns (default TRUE).

jitter_range

Numeric. Vertical jitter fraction (default 0.22).

sort_by

Character: "none", "mean", or "net" (default "none").

shadow

Logical (default TRUE).

label_color

Character (default "#333333").

label_size

Numeric (default 0.85).

label_align

Character. Label alignment: "left" (default), "right", or "direction" (follows band reading direction).

show_legend

Logical (default TRUE).

legend_text_size

Numeric, legend text size (default 0.65).

arc_color

Character (default "#2c3e6b").

arc_opacity

Numeric (default 0.80).

arc_fill

Character controlling arc fill style:

"none"

(default) Two-tone split: upper half colored by the upper band's mean shade, lower half by the lower band's mean shade.

"correlation"

Brown/blue tint by correlation sign, opacity scaled by |r|. The original behavior.

"mean_prev"

Solid fill using the upper (preceding) band's mean shade.

"blend"

Solid fill: 50/50 RGB average of adjacent band shades.

band_palette

Character vector of 2+ anchor colors for the band shading gradient. Low item means map to the first color, high means to the last. Default NULL uses the built-in brown-to-slate ramp. For darker plots try c("#1a1228", "#1a2a42").

start_from

Character: "left" (default) or "right". Which side the first band starts from.

flow

Character, "snake" (default) or "natural". "snake" uses alternating boustrophedon direction; "natural" reads all bands in the same direction.

facet

Logical or named list. When TRUE, columns are auto-grouped by their name prefix (e.g. LOC1-LOC5 → "LOC") and each group is drawn as a facet panel. A named list of column-name vectors gives explicit grouping. Default FALSE.

facet_ncol

Integer, number of columns in the facet grid (default 2).

title

Optional plot title.

margin

Named numeric vector.

background

Background color.

seed

Integer for reproducible jitter (default 42).

Value

Invisible snake_layout object (or list of layouts when faceted).

Examples

counts <- matrix(c(
  110, 210, 79, 84, 42,
  126, 205, 68, 100, 26,
  184, 226, 47, 58, 10,
  205, 210, 42, 53, 15,
  197, 214, 53, 47, 14
), nrow = 5, byrow = TRUE)
labels <- paste0("LOC", 1:5, " (n=525)")
levs <- as.character(1:5)
survey_snake(counts, labels, levs)


Timeline Snake Plot

Description

Displays a career or life-event timeline as a serpentine sequence of colored phases. Each block represents one month, colored by the current state/role. State names are overlaid inside runs of consecutive blocks, and transition dates are shown at juncture points where the state changes.

Usage

timeline_snake(
  sequence,
  states = NULL,
  colors = NULL,
  rows = NULL,
  band_height = 28,
  band_gap = 30,
  plot_width = 500,
  margin = c(top = 35, right = 10, bottom = 65, left = 20),
  orientation = "horizontal",
  start_from = "left",
  flow = c("natural", "snake"),
  show_labels = FALSE,
  show_legend = TRUE,
  show_numbers = FALSE,
  show_state = TRUE,
  state_size = 1,
  show_ticks = FALSE,
  tick_labels = NULL,
  transition_labels = NULL,
  transition_pos = NULL,
  tick_color = "#444444",
  tick_length = 6,
  tick_size = 0.8,
  border_color = NA,
  block_labels = NULL,
  band_labels = NULL,
  title = NULL,
  background = "white",
  shadow = TRUE,
  text_size = 0.5,
  legend_text_size = 1.2
)

Arguments

sequence

Either a character/factor vector of states (one per time unit), or a data.frame with 3 columns: state/role, start date ("YYYY-MM" or Date), end date. When a data.frame is given, the function auto-generates monthly blocks, transition labels, and band labels.

states

Character vector of unique states in desired order. If NULL, derived from unique(sequence).

colors

Named character vector of colors keyed by state, or an unnamed vector recycled to match states. If NULL, a built-in qualitative palette is used.

rows

Integer, number of serpentine rows. If NULL, auto-calculated targeting approximately 10 blocks per band.

band_height

Numeric, height of each band (default 28).

band_gap

Numeric, gap between bands (default 18).

plot_width

Numeric, width of each band (default 500).

margin

Named numeric vector with top, right, bottom, left margins (default c(top = 35, right = 10, bottom = 65, left = 20)).

orientation

Character, "horizontal" (default) or "vertical".

start_from

Character, "left" (default) or "right".

flow

Character, "natural" (default) or "snake". "natural" reads all bands left-to-right; "snake" uses alternating boustrophedon direction.

show_labels

Logical, show position range labels (default FALSE).

show_legend

Logical, draw color legend (default TRUE).

show_numbers

Logical, print small position numbers inside blocks (default FALSE).

show_state

Logical, show state names inside blocks (default TRUE).

state_size

Numeric, state label size (default 1).

show_ticks

Logical, draw ruler-style tick marks at block boundaries outside the bands (default FALSE).

tick_labels

Character vector of labels for evenly spaced ruler marks within each band (e.g., month.abb for monthly ticks). Implies show_ticks = TRUE.

transition_labels

Character vector of date labels for state transition points (e.g., c("Oct 2017", "Apr 2019")). One label per transition (length = number of state changes).

transition_pos

Numeric vector of fractional block positions for transition labels (e.g., c(6.5, 24.3)). When provided, labels are placed at exact interpolated positions along the serpentine path rather than at state-change boundaries.

tick_color

Color for tick marks (default "#333333").

tick_length

Numeric, length of tick marks in pixels (default 5).

tick_size

Numeric, text size for band and transition labels (default 0.8).

border_color

Color for thin borders between blocks, or NA for no borders (default NA).

block_labels

Optional character vector of labels to display inside each block (same length as sequence). Overrides show_numbers.

band_labels

Character vector of labels to display centered below each band (e.g., year labels). Length must equal rows.

title

Optional character string for plot title.

background

Background color (default "white").

shadow

Logical, draw drop shadows (default TRUE).

text_size

Numeric, text size multiplier for block labels (default 0.5).

legend_text_size

Numeric, legend text size (default 1.2).

Value

Invisible NULL. Called for its side effect of producing a plot.

Examples

# Data.frame input (easiest)
career <- data.frame(
  role  = c("Junior", "Senior", "Lead"),
  start = c("2018-01", "2020-06", "2023-01"),
  end   = c("2020-05", "2022-12", "2024-12")
)
timeline_snake(career, title = "Career Timeline")