Overview
The sugarglider
package extends the capabilities of
ggplot2 by introducing functions specifically designed for visualizing
seasonal patterns in spatio-temporal data. It includes
geom_glyph_ribbon()
and geom_glyph_segment()
,
which represent measurements recorded over time at specific locations
through the use of glyph maps. These functions enable clear depictions
of seasonal trends by leveraging the combination of x_major and
y_major coordinates.
The structure of glyph maps in sugarglider
consists of
four main layers: the base map, glyph boxes, reference lines, and ribbon
or segment glyphs. Additionally, users can create a legend, adding an
extra layer to the glyph maps. Apart from the base map, sugarglider
offers functionalities to generate all the elements of a comprehensive
glyph map, as illustrated in the figure below.
Each layer can be plotted independently, and the package supports the creation of glyph plots using either ribbon or segment geometries. The core functionality includes:
geom_glyph_ribbon()
: Displays an interval on the y-axis for each x_minor value, with the bounds defined by ymin_minor and ymax_minor. This function draws ribbon geometry usinggeom_ribbon()
fromggplot2
to draw ribbon geometry, resulting in ribbon glyphs. Each glyph is plotted by combining x_major and y_major coordinates. This functionality is handy for visualizing ranges or uncertainties in the data.geom_glyph_segment()
: Connects y_minor to yend_minor with a straight line usinggeom_segment()
fromggplot2
, resulting in segment glyphs. Each glyph is plotted by combining x_major and y_major coordinates.
vic_temp <- aus_temp |>
filter(id %in% c("ASN00026021", "ASN00085291", "ASN00084143"))
# Define a color palette
color_palette <- c("deepskyblue4", "coral3")
p1 <- vic_temp |>
ggplot(aes(x_major = long,
y_major = lat,
x_minor = month,
ymin_minor = tmin,
ymax_minor = tmax)) +
geom_sf(data = abs_ste |> filter(NAME == "Victoria"),
fill = "antiquewhite", color = "white", inherit.aes = FALSE) +
# Customize the size of each glyph box using the width and height parameters.
add_glyph_boxes(color = color_palette[1]) +
add_ref_lines(color = color_palette[1]) +
geom_glyph_ribbon(color = color_palette[1], fill = color_palette[1]) +
# Theme and aesthetic
theme_glyph() +
labs(title = "geom_glyph_ribbon()") +
theme(plot.title = element_text(hjust = 0.5),
title = element_text(color = color_palette[1],
family = "mono"))
p2 <- vic_temp |>
ggplot(aes(x_major = long,
y_major = lat,
x_minor = month,
y_minor = tmin,
yend_minor = tmax)) +
geom_sf(data = abs_ste |> filter(NAME == "Victoria"),
fill = "antiquewhite", color = "white", inherit.aes = FALSE) +
# Customize the size of each glyph box using the width and height parameters.
add_glyph_boxes(color = color_palette[2]) +
add_ref_lines(color = color_palette[2]) +
geom_glyph_segment(color = color_palette[2]) +
# Theme and aesthetic
theme_glyph() +
labs(title = "geom_glyph_segment()") +
theme(plot.title = element_text(hjust = 0.5),
title = element_text(color = color_palette[2]))
grid.arrange(p1, p2, ncol = 2)
In addition to these two functions, sugarglider
offers
several other features that enhance the aesthetic and interpretability
of glyph maps. The add_ref_box()
function introduces
reference boxes that visually frame individual glyphs, helping to define
boundaries and distinguish glyphs from each other. The
add_ref_line()
function draws a horizontal midpoint for
each glyph, facilitating comparisons across data points. The
add_glyph_legend()
function allows users to display an
enlarged version of a randomly chosen glyph in the bottom-left corner of
the panel, enabling users to visualize the data range. Lastly, the
theme_glyph()
function provides a customized theme for
glyph maps, built on top of theme_map()
from
ggthemes
. It adjusts the plot’s appearance, including the
legend position, text styles, and background settings, to create a
clean, visually consistent layout for glyph maps.
Aesthetics
The functions in sugarglider
expect spatial coordinates
as the major axis and temporal data, along with some measurements, as
minor axes. For minor axes, sugarglider
adopts the same
aesthetics as ggplot2::geom_ribbon()
and
ggplot2::geom_segment()
, but appends _minor
to
each aesthetic name for use in geom_glyph_ribbon()
and
geom_glyph_segment()
. To incorporate a variable into the
glyph plot, it needs to be explicitly defined as an aesthetic.
To produce glyph-maps, the following aesthetics are required:
Aesthetics | Description |
---|---|
x_major ,y_major
|
Spatial coordinates that define the position of glyphs. |
x_minor |
Represents temporal data associated with each glyph. |
ymin_minor , ymax_minor
|
Used by geom_glyph_ribbon() to establish the lower and
upper bounds of the ribbon geometry within each glyph. |
y_minor , yend_minor
|
Used by geom_glyph_segment() to set the start and end
points of the segment geometry within each glyph. |
The functions add_ref_box()
,
add_ref_line()
, and add_geom_legend()
are
compatible with either ymin_minor, ymax_minor, or
y_minor, yend_minor. Additionally, sugarglider
introduces several customizable options to further tailor the visual
aspects:
Option | Default | Description |
---|---|---|
colour |
"black" |
Sets the color for line segments and borders. |
linewidth |
0.5 |
Specifies the width of the line for borders. |
linetype |
1 |
Defines the style of the line for borders. |
fill |
"black" |
Determines the color of the interior area of the geometries. |
alpha |
0.8 |
Controls the transparency level of the glyphs. |
Options
Options within the sugarglider
package allow you to
tailor the behavior of your visualizations to meet the specific needs of
your analysis. The global_rescale argument provides control
over whether rescaling should occur globally across all data points or
be handled individually for each glyph.
sugarglider
also offers a variety of customizable
features to enhance the flexibility and precision of visualizations. For
example, it facilitates the scaling of minor values within the glyph
along the x and y axes. Users can specify their rescale function by
replacing “identity” with a custom function in x_scale
and y_scale. Suppose a user wishes to modify the rescaling
function on only one axis. In that case, they can replace the value of
the corresponding parameter with their chosen function and retain
“identity” for the other. In this package, “identity” rescales the minor
axes to an interval of [-1,1]. The impact of rescaling on glyphs and its
implications for visual interpretation will be thoroughly discussed in
the upcoming section.
Additionally, the width and height of the glyphs are adjustable,
allowing users to modify the appearance of each glyph to match the
dimensions and scaling of the data being visualized. These customization
options ensure that sugarglider
can adapt to a broad range
of data types and requirements, making it a versatile tool for seasonal
spatiotemporal data visualization.
Option | Default | Description |
---|---|---|
x_scale |
"identity" |
This function scales each set of minor values within a grid cell along the x-dimension. |
y_scale |
"identity" |
This function scales each set of minor values within a grid cell along the y-dimension. |
width |
default |
The width of each glyph. The default is set to the
smallest distance between two consecutive coordinates, converted from
meters to degrees of latitude using the Haversine method. |
height |
default |
The height of each glyph. The default is calculated
using the ratio (1:1.618) relative to the width , to
maintain a consistent aspect ratio. |
global_rescale |
TRUE |
Determines whether rescaling is applied globally across all glyphs or individually for each glyph. |
Interactivity
Interactive graphics are particularly useful when working with
spatio-temporal data as they allow users to explore the data from
multiple perspectives. The cubble
package, exemplifies this
by creating linked interactive plots using
crosswalk::bscols()
. In this vignette, we will demonstrate
how to create interactive glyph maps using Leaflet.
Create glyph maps with leaflet
The dataset used in this example, train
, provides a
comprehensive monthly summary of daily patronage at each train station
in Victoria for the fiscal year 2023-2024. To create interactive glyph
maps with Leaflet, we first need to save each glyph as images and then
add these to the Leaflet basemap as icons. The process begins by
creating a list of all unique train stations that service both metro and
vline. We then iterate over each station and generate ribbon glyphs
using geom_glyph_ribbon()
, add_glyph_boxes()
and add_ref_lines()
. Each glyph is saved in PNG format, and
the file paths for all the images are stored in an object for the next
step.
# Generate a list of unique train stations
df_station <- train$station_name |> unique()
# Generate PNG of all the ribbon glyph
purrr::map(1:length(df_station), function(i) {
dt <- train |> filter(station_name == df_station[i])
p <- dt |>
ggplot(aes(x_major = long, y_major = lat,
x_minor = hour, ymin_minor = min_weekday,
ymax_minor = max_weekday)) +
add_glyph_boxes(color = "#FFAD60",
fill = "#FFEEAD", alpha = 0.5,
linewidth = 1, width = 3, height =2) +
add_ref_lines(color = "#FFAD60", alpha = 1,
linewidth = 1, width = 3, height =2) +
geom_glyph_ribbon(color = "#A66E38", fill = "#A66E38",
width = 3, height =2) +
theme_void()
file_path <- paste0("figures/glyph_", df_station[i], ".png")
ggsave(file_path, plot = p, width = 3, height = 2, units = "in", dpi = 300,
bg = "transparent")
return(file_path)
}) -> train_png
To create the base map for Leaflet, we use the leaflet()
function and addProviderTiles()
with CartoDB.Positron as
the provider to achieve a light, grey map aesthetic. Additionally, a
scale bar is added at the bottom left corner for reference.
# Create a leaflet map
leaflet_map <- leaflet() |>
addProviderTiles("CartoDB.Positron") |>
addScaleBar(position = "bottomleft")
Next, we iterate through all the images and convert them into icons
using the makeIcon()
function. Users can control the
dimensions of each icon by modifying the iconWidth
and
iconHeight
arguments. The final step is to add each icon to
the Leaflet map using addMarkers()
. Within the options
argument of addMarkers
, users can fine-tune each glyph’s
display properties, such as the opacity level. The label
argument allows users to specify the information they wish to display
with the hover-over effect, which in this example is set to display the
station ID.
# Loop through the PNG files and add them to the map
for (i in seq_along(train_png)) {
icon <- makeIcon(iconUrl = train_png[i], iconWidth = 100, iconHeight = 60)
dt <- train |> filter(station_name == df_station[i])
leaflet_map <- leaflet_map |>
addMarkers(lng = dt$long[1], lat = dt$lat[1], icon = icon,
label = dt$station_name, options = markerOptions(opacity = 0.1))
}
leaflet_map
Create interative glyph maps with ggiraph
User can generate interactive glyphs with
ggiraph::girafe
using sugarglider. To illustrate, we will
use the aus_temp
dataset in this example. First, users need
to specify tooltips, which are the details displayed when hovering over
the glyphs. In this example, the tooltips consist of station id, month,
minimum and maximum temperature across all month.
vic_nsw <- aus_temp |>
filter(id %in% c("ASN00026021", "ASN00085291", "ASN00084143",
"ASN00055325", "ASN00049000"))
# Specify tooltip for ggiraph
vic_nsw <- vic_nsw |>
mutate(tooltip = paste("Station ID: ", id,
"\nmonth: ", month,
"\nmin-temp: ", round(tmin,2),
"\nmax-temp: ", round(tmax,2)))
Tooltips needs to be provided in the asethetic to in the
tooltip
argument. User can then plot their desired glyph
map and save it as a ggplot object. This ggplot object is then converted
into girafe object using the girafe()
function.
temp <- vic_nsw |>
ggplot(aes(x_major = long, y_major = lat,
x_minor = month, y_minor = tmin,
yend_minor = tmax,
tooltip = tooltip)) +
geom_sf(data = abs_ste |> filter(NAME %in% c("New South Wales", "Victoria")),
color = "white",
fill = "antiquewhite", inherit.aes = FALSE) +
add_glyph_boxes(color = "#CD5C08") +
add_ref_lines(color = "#CD5C08") +
geom_glyph_segment(color = "#CD5C08") +
coord_sf(xlim = c(140,153)) +
theme_glyph()
# Interactive plot using ggiraph
girafe(ggobj = temp)