Serpentine Plots for Long Timeline, Sequential and Survey Data

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.


snakeplot

License: MIT R-CMD-check Codecov Version Dependencies

Serpentine (snake) plots for survey responses, experience sampling (EMA/ESM) data, and activity timelines using base R graphics. Zero external dependencies.

Installation

# From GitHub.
devtools::install_github("mohsaqr/snakeplot")

# Once on CRAN
install.packages("snakeplot")

Overview

Snake plots arrange data as horizontal bands in a serpentine layout — each row reverses direction and connects to the next through a U-turn arc. The package provides six plotting functions and 10 built-in color palettes:

Function Purpose
survey_snake() Survey/EMA responses with ticks, bars, correlations, faceting
activity_snake() Daily activity timelines with event blocks or rug ticks
sequence_snake() State sequence as colored blocks flowing through serpentine layout
timeline_snake() Career/life-event timeline from a 3-column data.frame (role, start, end)
survey_sequence() Stacked 100% horizontal bars in serpentine layout
sequential_dist() Sequential (monochrome) variant of survey_sequence()
line_snake() Continuous intensity line plot (experimental)
facet_snake() Generic multi-panel wrapper for any snake function

Bundled datasets

Three datasets from Neubauer & Schmiedek (2024) are included:

Dataset Rows Description
ema_emotions 280 Person-level means for 10 emotions (1-7 scale)
student_survey 280 34 items across 4 constructs, prefixed for faceting
ema_beeps 11 474 Beep-level timestamps + anger/happiness ratings (14 days)

Examples

library(snakeplot)

labs7 <- c("1" = "Not at all", "2" = "Slightly", "3" = "Somewhat",
           "4" = "Moderate",   "5" = "Quite",    "6" = "Very",
           "7" = "Extremely")

survey_snake() — daily value distribution ticks

survey_snake(ema_beeps, var = "angry", day = "day",
             colors = snake_palettes$ocean, level_labels = labs7,
             title = "Anger — 14 days, value distribution")

survey_snake() — correlation arcs

survey_snake(ema_emotions, tick_shape = "line",
             arc_fill = "correlation", sort_by = "mean",
             colors = snake_palettes$ocean, level_labels = labs7,
             title = "Emotions — correlations at U-turns")

survey_snake() — dot plot with dark bands

survey_snake(ema_emotions, tick_shape = "dot", sort_by = "mean",
             colors = snake_palettes$ocean, level_labels = labs7,
             band_palette = c("#1a1228", "#1a2a42"),
             title = "Emotions — dots on dark bands")

survey_snake() — faceted multi-construct

survey_snake(student_survey, facet = TRUE, facet_ncol = 2L,
             tick_shape = "bar", sort_by = "mean",
             colors = snake_palettes$ocean, level_labels = labs7)

survey_snake() — daily distribution bars

survey_snake(ema_beeps, var = "happy", day = "day",
             tick_shape = "bar", bar_reverse = TRUE,
             colors = snake_palettes$ocean, level_labels = labs7,
             title = "Happiness — 14 days, distribution bars")

activity_snake() — rug ticks

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)

activity_snake() — 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")

sequence_snake() — state sequence

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")

timeline_snake() — career/event timeline

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)")

survey_sequence() — stacked bars

survey_sequence(ema_emotions, colors = snake_palettes$ocean)

line_snake() — continuous intensity

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")

Built-in palettes

10 palettes ship with the package — 5 diverging, 5 sequential:

names(snake_palettes)
#> "classic" "earth" "ocean" "sunset" "berry" "blues" "greens" "grays" "warm" "viridis"

# Use directly
survey_snake(ema_emotions, colors = snake_palettes$earth, tick_shape = "bar")

# Interpolate to any length
snake_palette("sunset", n = 5)

Key parameters for survey_snake()

Parameter Description
tick_shape "line" (default), "dot", or "bar" (stacked proportional)
sort_by "none", "mean", or "net"
arc_fill "none" (two-tone), "correlation", "mean_prev", "blend"
colors Custom color palette or snake_palettes$name
band_palette 2+ anchor colors for band shading (default: brown-to-slate)
bar_reverse TRUE to draw bars from highest level first
level_labels Named vector mapping levels to display labels
facet TRUE (auto-group by prefix) or named list of column groups
var, day, timestamp Auto-pivot EMA data into daily bands
show_mean, show_median Toggle diamond/dashed-line markers

Data source

The bundled datasets are derived from:

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

License

MIT

Reference manual

It appears you don't have a PDF plugin for this browser. You can click here to download the reference manual.

install.packages("snakeplot")

0.3.0 by Mohammed Saqr, 7 months ago


https://github.com/mohsaqr/snakeplot


Report a bug at https://github.com/mohsaqr/snakeplot/issues


Browse source code at https://github.com/cran/snakeplot


Authors: Mohammed Saqr [aut, cre, cph] , Sonsoles Lopez-Pernas [aut]


Documentation:   PDF Manual  


MIT + file LICENSE license


Imports graphics, grDevices, stats

Suggests testthat, knitr, rmarkdown


See at CRAN