| Title: | Spiral Visualisation for Time Series |
| Version: | 0.1.1 |
| Description: | Provides a grammar of graphics geometry for visualising time series using spiral layouts, with each year represented as a separate ring. |
| License: | GPL (≥ 3) |
| Encoding: | UTF-8 |
| Depends: | R (≥ 4.1.0) |
| RoxygenNote: | 7.3.3 |
| URL: | https://github.com/thiyangt/tsspiral, https://thiyangt.github.io/tsspiral/ |
| BugReports: | https://github.com/thiyangt/tsspiral/issues |
| Imports: | ggplot2, dplyr, tibble, lubridate, purrr, tidyr, rlang |
| Suggests: | testthat (≥ 3.0.0), tsibble |
| Config/testthat/edition: | 3 |
| NeedsCompilation: | no |
| Packaged: | 2026-10-05 13:18:14 UTC; DELL |
| Author: | Thiyanga S. Talagala
|
| Maintainer: | Thiyanga S. Talagala <ttalagala@sjp.ac.lk> |
| Repository: | CRAN |
| Date/Publication: | 2026-10-15 17:20:02 UTC |
Spiral Time-Series Geometry
Description
Internal ggproto geometry used by geom_tsspiral().
Usage
GeomTSSpiral
Format
An object of class GeomTSSpiral (inherits from Geom, ggproto, gg) of length 5.
Spiral Time-Series Bar Geometry
Description
Internal ggproto geometry used by geom_tsspiralbar().
Usage
GeomTSSpiralBar
Format
An object of class GeomTSSpiralBar (inherits from Geom, ggproto, gg) of length 5.
Spiral Missingness Geometry
Description
Internal ggproto geometry used by geom_tsspiralmiss().
Usage
GeomTSSpiralMiss
Format
An object of class GeomTSSpiralMiss (inherits from Geom, ggproto, gg) of length 5.
Statistical Transformation for Spiral Time Series
Description
Statistical Transformation for Spiral Time Series
Usage
StatTSSpiral
Format
An object of class StatTSSpiral (inherits from Stat, ggproto, gg) of length 3.
Statistical Transformation for Spiral Bars
Description
Statistical Transformation for Spiral Bars
Usage
StatTSSpiralBar
Format
An object of class StatTSSpiralBar (inherits from Stat, ggproto, gg) of length 3.
Statistical Transformation for Spiral Missingness
Description
Internal statistical transformation used by
geom_tsspiralmiss().
Usage
StatTSSpiralMiss
Format
An object of class StatTSSpiralMiss (inherits from Stat, ggproto, gg) of length 3.
Calendar of Hourly Polar Bar Charts
Description
Creates a monthly calendar visualization in which each calendar day contains a 24-hour polar bar chart. Each bar represents one hour of the day, with the angular position corresponding to the hour and the bar length and colour representing the observed value.
Usage
calendar_hourly_polar(
data,
datetime,
value,
month = NULL,
radius = 0.35,
bar_width = 0.85,
cell_width = 1,
cell_height = 1
)
Arguments
data |
A data frame containing the hourly observations. |
datetime |
A date-time column containing the observation times. |
value |
A numeric column containing the values to be visualized. |
month |
A date or character value specifying the month to plot.
For example, |
radius |
Numeric. Maximum radius of the hourly bars within each
calendar cell. Defaults to |
bar_width |
Numeric between 0 and 1. Controls the angular width
of each hourly bar relative to the 24-hour sector. Defaults to
|
cell_width |
Numeric. Width of each calendar cell. Defaults to
|
cell_height |
Numeric. Height of each calendar cell. Defaults to
|
Details
Missing hourly observations are retained in the calendar but are not drawn as bars. The calendar is arranged from Monday to Sunday, with each day positioned according to its calendar date.
Each day is represented by a separate polar bar chart containing up to 24 bars. Hour 0 starts at the top of the circle and the hours proceed clockwise through hour 23.
The bar length is scaled according to the range of the observed values in the selected month, while colour represents the original value. Missing hourly observations are left blank.
The function is useful for examining intraday patterns while retaining the context of the calendar. For example, daily temperature, air quality, electricity demand, traffic, or other regularly recorded hourly measurements can be displayed.
Value
A ggplot object containing a calendar of hourly polar bar charts.
Examples
set.seed(123)
hourly_data <- tibble::tibble(
datetime = seq(
from = as.POSIXct("2026-01-01 00:00"),
to = as.POSIXct("2026-01-31 23:00"),
by = "hour"
)
) |>
dplyr::mutate(
hour = lubridate::hour(datetime),
day = lubridate::day(datetime),
temperature =
25 +
4 * sin(2 * pi * hour / 24) +
0.05 * day +
stats::rnorm(length(datetime), 0, 0.8)
)
calendar_hourly_polar(
hourly_data,
datetime,
temperature,
month = "2026-01-01"
)
Detect Time-Series Frequency
Description
Internal function used to detect the approximate frequency of the supplied time series.
Usage
detect_tsspiral_frequency(x)
Arguments
x |
Date vector. |
Value
A character string describing the frequency.
Expand Time Series to Daily Resolution
Description
Internal function that converts weekly, monthly, quarterly, and annual observations into daily observations.
Usage
expand_tsspiral_daily(data, frequency)
Arguments
data |
Data frame containing |
frequency |
Detected frequency. |
Value
A data frame with daily observations.
Spiral Time-Series Geometry
Description
Create a spiral time-series plot using a fixed 365-day calendar.
Usage
geom_tsspiral(
mapping = NULL,
data = NULL,
stat = StatTSSpiral,
position = "identity",
na.rm = FALSE,
ring_spacing = 1,
...
)
Arguments
mapping |
Set of aesthetic mappings created by
|
data |
A data frame, tibble, or tsibble containing the time-series data. |
stat |
Statistical transformation used by the layer.
Defaults to |
position |
Position adjustment. Defaults to |
na.rm |
Logical. Should missing values be removed silently? |
ring_spacing |
Numeric value controlling the distance between yearly rings. |
... |
Other arguments passed to |
Details
geom_tsspiral() displays each year of a time series as a radial
ring. The angular position represents the day of the year. The
spiral always contains 365 angular divisions.
The spiral starts at 12 o'clock on January 1 and proceeds clockwise through the year.
The input frequency is detected automatically. Daily observations are used directly. Weekly, monthly, quarterly, and annual observations are expanded to daily observations before plotting.
Calendar labels are displayed only around the outermost ring:
daily data: month names,
monthly data: month names,
quarterly data: quarter names,
weekly data: week numbers,
annual data: month names.
The spiral uses a fixed 365-day calendar. January 1 starts at 12 o'clock and the calendar proceeds clockwise.
For day d, the angular position is
\theta_d =
\frac{\pi}{2}
-
\frac{2\pi(d-1)}{365}.
Consequently, January 1 is positioned at 12 o'clock and later days move clockwise around the spiral.
Leap years do not create a 366th angular division. February 29 is mapped to the February 28 position and the days after February 29 are shifted by one day.
Monthly, quarterly, weekly, and annual observations are expanded to their corresponding daily intervals. Consequently, a monthly observation fills the complete angular region corresponding to that month rather than appearing as a thin radial slice.
Value
A ggplot2 layer.
Examples
library(ggplot2)
#' # daily data
dat <- data.frame(
date = seq.Date(
as.Date("2020-01-01"),
as.Date("2023-12-31"),
by = "day"
)
)
dat$value <- sin(
2 * pi * as.numeric(format(dat$date, "%j")) / 365
) + rnorm(nrow(dat), sd = 0.2)
ggplot(
dat,
aes(
x = date,
y = value,
fill = value
)
) +
geom_tsspiral(ring_spacing = 2) +
theme_void()
Spiral Time-Series Bar Geometry
Description
Create a spiral bar plot for time-series data.
Usage
geom_tsspiralbar(
mapping = NULL,
data = NULL,
stat = StatTSSpiralBar,
position = "identity",
na.rm = FALSE,
ring_spacing = 1,
...
)
Arguments
mapping |
Set of aesthetic mappings created by
|
data |
A data frame, tibble, or tsibble. |
stat |
Statistical transformation used by the layer. |
position |
Position adjustment. |
na.rm |
Logical. Should missing values be removed silently? |
ring_spacing |
Numeric value controlling the distance between yearly rings. |
... |
Other arguments passed to |
Details
Each year is represented by a radial ring. The angular position represents time within the year, while the radial height of each bar represents the magnitude of the time-series value.
January 1 starts at 12 o'clock and the spiral proceeds clockwise.
Value
A ggplot2 layer.
Examples
library(ggplot2)
set.seed(123)
dat <- data.frame(
date = seq.Date(
as.Date("2021-01-01"),
as.Date("2023-12-31"),
by = "day"
),
value = rnorm(1095)
)
ggplot(
dat,
aes(
x = date,
y = value,
fill = value
)
) +
geom_tsspiralbar(
ring_spacing = 2
) +
scale_fill_viridis_c() +
theme_void()
Spiral Missingness Geometry
Description
Create a spiral plot showing missing observations in a time series.
Usage
geom_tsspiralmiss(
mapping = NULL,
data = NULL,
stat = StatTSSpiralMiss,
position = "identity",
na.rm = FALSE,
ring_spacing = 1,
observed_colour = "grey85",
missing_colour = "black",
...
)
Arguments
mapping |
Set of aesthetic mappings created by
|
data |
A data frame, tibble, or tsibble containing the time-series data. |
stat |
Statistical transformation used by the layer.
Defaults to |
position |
Position adjustment. Defaults to |
na.rm |
Logical. Should missing values be removed silently? |
ring_spacing |
Numeric value controlling the distance between yearly rings. |
observed_colour |
Colour used for observed periods. |
missing_colour |
Colour used for missing periods. |
... |
Other arguments passed to |
Details
geom_tsspiralmiss() displays each year of a time series as a
radial ring using a fixed 365-day calendar. Observed periods are
shown in one colour and missing periods are shown in another.
The spiral starts at 12 o'clock on January 1 and proceeds clockwise through the year.
The input frequency is detected automatically. Daily observations are used directly. Weekly, monthly, quarterly, and annual observations are expanded to daily observations before plotting.
The geometry is designed specifically for exploring the temporal structure of missing observations.
January 1 is positioned at 12 o'clock and time proceeds clockwise. Each year is represented by one radial ring, with 365 fixed angular divisions.
A period is classified as observed when a corresponding observation is present in the input data. Periods without an observation are classified as missing.
Leap years do not create a 366th angular division. February 29 is mapped to the February 28 position and dates after February 29 are shifted by one day.
Value
A ggplot2 layer.
Examples
library(ggplot2)
set.seed(123)
df <- data.frame(
date = seq.Date(
as.Date("2020-01-01"),
as.Date("2023-12-31"),
by = "day"
)
)
df$date[1:10] <- NA
ggplot(
df,
aes(x = date)
) +
geom_tsspiralmiss(
ring_spacing = 2
) +
theme_void()
Aligned Temporal Hierarchical Spiral Plot
Description
Visualise a time series at multiple temporal resolutions using concentric rings with a common temporal coordinate system.
Usage
temporal_hierarchical(
data,
date,
value,
fun = mean,
ring_width = 1,
ring_gap = 0.05,
na.value = "grey90",
daily = TRUE,
weekly = TRUE,
monthly = TRUE,
quarterly = TRUE,
yearly = TRUE,
direction = 1,
start_angle = -pi/2
)
Arguments
data |
A data frame containing a date variable and a numeric variable. |
date |
Unquoted name of the date column. |
value |
Unquoted name of the numeric variable to visualise. |
fun |
Aggregation function used for weekly, monthly,
quarterly, and yearly aggregation. Defaults to |
ring_width |
Width of each ring. Defaults to |
ring_gap |
Gap between rings. Defaults to |
na.value |
Colour used for missing values. Defaults to |
daily |
Logical; draw the daily ring. Defaults to |
weekly |
Logical; draw the weekly ring. Defaults to |
monthly |
Logical; draw the monthly ring. Defaults to |
quarterly |
Logical; draw the quarterly ring. Defaults to |
yearly |
Logical; draw the yearly ring. Defaults to |
direction |
Direction of the temporal axis. |
start_angle |
Starting angle in radians. Defaults to
|
Details
The outer ring represents daily observations, followed inward by weekly, monthly, quarterly, and yearly observations. Temporal boundaries are aligned across all rings.
All temporal levels use a common angular coordinate based on the complete date range. Consequently, observations at different temporal resolutions are spatially aligned.
For example, the monthly January ring occupies the same angular region as the corresponding daily observations, weeks, quarter, and year.
The outer-to-inner hierarchy is:
Daily
Weekly
Monthly
Quarterly
Yearly
Value
A ggplot2 object.
Examples
set.seed(123)
dat <- data.frame(
date = seq.Date(
from = as.Date("2020-01-01"),
to = as.Date("2023-12-31"),
by = "day"
)
)
dat$value <- 20 +
5 * sin(
2 * pi * lubridate::yday(dat$date) / 365.25
) +
rnorm(nrow(dat), 0, 1)
temporal_hierarchical(
data = dat,
date = date,
value = value
)
Generate Spiral Calendar Labels
Description
Internal function generating labels for the outer cycle.
Usage
tsspiral_calendar_labels(frequency)
Arguments
frequency |
Detected time-series frequency. |
Value
Data frame containing label positions and labels.
Convert Date to Fixed 365-Day Calendar
Description
Internal function that maps dates onto a fixed 365-day calendar.
Usage
tsspiral_day(x)
Arguments
x |
Date vector. |
Value
Integer vector from 1 to 365.