| Title: | Sigmoid-Curved Ribbons for Rank Comparison Charts |
|---|---|
| Description: | Provides 'ggplot2' geoms and stats for creating bump charts with sigmoid-curved filled ribbons and lines. Supports rank comparison visualizations where smooth S-shaped curves connect categorical positions across an ordered axis. Offers two interpolation methods (logistic sigmoid and cubic Hermite) with C1-continuous segment joins. Includes custom scales and themes optimized for bump chart readability. |
| Authors: | Sondre Skarsten [aut, cre, cph] |
| Maintainer: | Sondre Skarsten <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.2.0 |
| Built: | 2026-05-19 05:47:56 UTC |
| Source: | https://github.com/sondreskarsten/ggbumpribbon |
geom_bump_line() renders smooth curves connecting discrete
rank positions across time periods. It is the line counterpart to
geom_bump_ribbon(), producing stroked paths instead of filled areas.
geom_bump_line( mapping = NULL, data = NULL, position = "identity", ..., smooth = 8, n = 100, method = "sigmoid", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE )geom_bump_line( mapping = NULL, data = NULL, position = "identity", ..., smooth = 8, n = 100, method = "sigmoid", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE )
mapping |
Set of aesthetic mappings created by |
data |
The data to be displayed in this layer. There are three options: If A A |
position |
A position adjustment to use on the data for this layer. This
can be used in various ways, including to prevent overplotting and
improving the display. The
|
... |
Other arguments passed on to
|
smooth |
Steepness of the sigmoid curve. Higher values produce
sharper S-shaped transitions. Only used when |
n |
Number of interpolation points per segment. Default is |
method |
Interpolation method. |
na.rm |
If |
show.legend |
logical. Should this layer be included in the legends?
|
inherit.aes |
If |
A ggplot2 layer that can be added to a plot.
geom_bump_line() understands the following aesthetics
(required aesthetics are in bold):
x
y
alpha
colour
group
linetype
linewidth
avg_yMean of y values in the group, inverse-transformed to
original data space. Works correctly with scale_y_reverse().
Map to colour via after_stat(avg_y).
The number of bends is controlled by the data, not by parameters. Two x-values produce one sigmoid. Four x-values (with the two middle points holding the start/end y positions) produce three sigmoids that mimic the "exit–channel–enter" pattern common in infographics:
df <- data.frame( x = rep(c(1, 1.4, 1.6, 2), each = 5), y = c(from, from, to, to), group = rep(groups, 4) )
geom_bump_ribbon(), ggplot2::geom_path()
Other bump geoms:
geom_bump_ribbon()
library(ggplot2) # basic 2-point line bump df <- data.frame( x = rep(1:2, each = 5), y = c(1, 2, 3, 4, 5, 3, 1, 5, 2, 4), group = rep(LETTERS[1:5], 2) ) ggplot(df, aes(x, y, group = group, colour = after_stat(avg_y))) + geom_bump_line(linewidth = 1) + scale_colour_viridis_c() + scale_y_reverse() # 3-bend pattern (exit-channel-enter) df3 <- data.frame( x = rep(c(1, 1.4, 1.6, 2), each = 5), y = c(1,2,3,4,5, 1,2,3,4,5, 3,1,5,2,4, 3,1,5,2,4), group = rep(LETTERS[1:5], 4) ) ggplot(df3, aes(x, y, group = group, colour = after_stat(avg_y))) + geom_bump_line(linewidth = 1.2) + scale_colour_viridis_c() + scale_y_reverse()library(ggplot2) # basic 2-point line bump df <- data.frame( x = rep(1:2, each = 5), y = c(1, 2, 3, 4, 5, 3, 1, 5, 2, 4), group = rep(LETTERS[1:5], 2) ) ggplot(df, aes(x, y, group = group, colour = after_stat(avg_y))) + geom_bump_line(linewidth = 1) + scale_colour_viridis_c() + scale_y_reverse() # 3-bend pattern (exit-channel-enter) df3 <- data.frame( x = rep(c(1, 1.4, 1.6, 2), each = 5), y = c(1,2,3,4,5, 1,2,3,4,5, 3,1,5,2,4, 3,1,5,2,4), group = rep(LETTERS[1:5], 4) ) ggplot(df3, aes(x, y, group = group, colour = after_stat(avg_y))) + geom_bump_line(linewidth = 1.2) + scale_colour_viridis_c() + scale_y_reverse()
geom_bump_ribbon() renders filled ribbons that follow smooth curves
between discrete rank positions. It is the filled-area counterpart to
ggbump's geom_bump() (https://github.com/davidsjoberg/ggbump).
geom_bump_ribbon( mapping = NULL, data = NULL, position = "identity", ..., smooth = 8, n = 100, width = 0.8, method = "sigmoid", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE )geom_bump_ribbon( mapping = NULL, data = NULL, position = "identity", ..., smooth = 8, n = 100, width = 0.8, method = "sigmoid", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE )
mapping |
Set of aesthetic mappings created by |
data |
The data to be displayed in this layer. There are three options: If A A |
position |
A position adjustment to use on the data for this layer. This
can be used in various ways, including to prevent overplotting and
improving the display. The
|
... |
Other arguments passed on to
|
smooth |
Steepness of the sigmoid curve. Higher values produce
sharper S-shaped transitions. Only used when |
n |
Number of interpolation points per segment. Default is |
width |
Ribbon full width in data units. Default is |
method |
Interpolation method. |
na.rm |
If |
show.legend |
logical. Should this layer be included in the legends?
|
inherit.aes |
If |
A ggplot2 layer that can be added to a plot.
geom_bump_ribbon() understands the following aesthetics
(required aesthetics are in bold):
x
y
alpha
colour
fill
group
linetype
linewidth
yminLower ribbon boundary.
ymaxUpper ribbon boundary.
avg_yMean of y values in the group, inverse-transformed to
original data space. Works correctly with scale_y_reverse() and
other scale transforms. Map to fill via after_stat(avg_y).
When a group has 3 or more time points, adjacent segments must be joined.
"sigmoid" (default)Each segment follows a logistic sigmoid
on where
is the smooth parameter. Endpoints are clamped to
exact knot values by rescaling to ,
and a Hermite-basis derivative correction drives the slope to
zero at every interior knot, guaranteeing C1 (first-derivative)
continuity across segments. The smooth parameter controls
steepness: lower values (e.g. 2–3) give gentle S-curves, higher
values (e.g. 12–15) give near-step-function transitions.
"hermite"Uses stats::splinefunH() with zero slopes at
all knots (the cubic Hermite "smoothstep"). This is
mathematically simpler: a single spline is evaluated across all
knots, with C1 continuity guaranteed by construction. The
smooth parameter is ignored. The visual shape is similar to
"sigmoid" but not identical — the cubic polynomial
has slightly different curvature distribution
than the logistic function.
Both methods produce identical results for 2-point groups (a single segment has no join to worry about).
geom_bump_line(), ggplot2::geom_ribbon()
Other bump geoms:
geom_bump_line()
library(ggplot2) # basic: 5 items, 2 time points df <- data.frame( x = rep(1:2, each = 5), y = c(1, 2, 3, 4, 5, 3, 1, 5, 2, 4), group = rep(LETTERS[1:5], 2) ) ggplot(df, aes(x, y, group = group, fill = after_stat(avg_y))) + geom_bump_ribbon() + scale_fill_viridis_c() + scale_y_reverse() # multi-period: 3 time points df3 <- data.frame( x = rep(1:3, each = 4), y = c(1,2,3,4, 3,1,4,2, 2,4,1,3), group = rep(LETTERS[1:4], 3) ) ggplot(df3, aes(x, y, group = group, fill = after_stat(avg_y))) + geom_bump_ribbon(alpha = 0.7) + scale_fill_viridis_c() + scale_y_reverse() # Hermite method ggplot(df3, aes(x, y, group = group, fill = after_stat(avg_y))) + geom_bump_ribbon(method = "hermite", alpha = 0.7) + scale_fill_viridis_c() + scale_y_reverse() # mtcars: MPG rank vs HP rank mt <- mtcars[1:10, ] mt$car <- rownames(mt) mt_long <- data.frame( x = rep(1:2, each = 10), y = c(rank(-mt$mpg), rank(-mt$hp)), group = rep(mt$car, 2) ) ggplot(mt_long, aes(x, y, group = group, fill = after_stat(avg_y))) + geom_bump_ribbon() + scale_fill_gradientn(colours = c("#2ecc71", "#f7dc6f", "#eb4d4b"), guide = "none") + scale_y_reverse() + theme_void()library(ggplot2) # basic: 5 items, 2 time points df <- data.frame( x = rep(1:2, each = 5), y = c(1, 2, 3, 4, 5, 3, 1, 5, 2, 4), group = rep(LETTERS[1:5], 2) ) ggplot(df, aes(x, y, group = group, fill = after_stat(avg_y))) + geom_bump_ribbon() + scale_fill_viridis_c() + scale_y_reverse() # multi-period: 3 time points df3 <- data.frame( x = rep(1:3, each = 4), y = c(1,2,3,4, 3,1,4,2, 2,4,1,3), group = rep(LETTERS[1:4], 3) ) ggplot(df3, aes(x, y, group = group, fill = after_stat(avg_y))) + geom_bump_ribbon(alpha = 0.7) + scale_fill_viridis_c() + scale_y_reverse() # Hermite method ggplot(df3, aes(x, y, group = group, fill = after_stat(avg_y))) + geom_bump_ribbon(method = "hermite", alpha = 0.7) + scale_fill_viridis_c() + scale_y_reverse() # mtcars: MPG rank vs HP rank mt <- mtcars[1:10, ] mt$car <- rownames(mt) mt_long <- data.frame( x = rep(1:2, each = 10), y = c(rank(-mt$mpg), rank(-mt$hp)), group = rep(mt$car, 2) ) ggplot(mt_long, aes(x, y, group = group, fill = after_stat(avg_y))) + geom_bump_ribbon() + scale_fill_gradientn(colours = c("#2ecc71", "#f7dc6f", "#eb4d4b"), guide = "none") + scale_y_reverse() + theme_void()
A convenience wrapper around ggplot2::scale_fill_gradientn() with
defaults suited to rank comparison charts (green = best, red = worst).
scale_fill_rank( colors = c("#2ecc71", "#a8e063", "#f7dc6f", "#f0932b", "#eb4d4b", "#c0392b"), limits = NULL, ... )scale_fill_rank( colors = c("#2ecc71", "#a8e063", "#f7dc6f", "#f0932b", "#eb4d4b", "#c0392b"), limits = NULL, ... )
colors |
Character vector of gradient colours. Default is a six-colour green-yellow-red ramp. |
limits |
Numeric vector of length 2 giving the scale limits, or
|
... |
Passed to |
A ggplot2 scale object.
ggplot2::scale_fill_gradientn(), geom_bump_ribbon()
Other bump scales:
theme_bump()
library(ggplot2) df <- data.frame( x = rep(1:2, each = 5), y = c(1,2,3,4,5, 3,1,5,2,4), group = rep(LETTERS[1:5], 2) ) ggplot(df, aes(x, y, group = group, fill = after_stat(avg_y))) + geom_bump_ribbon() + scale_fill_rank() + scale_y_reverse()library(ggplot2) df <- data.frame( x = rep(1:2, each = 5), y = c(1,2,3,4,5, 3,1,5,2,4), group = rep(LETTERS[1:5], 2) ) ggplot(df, aes(x, y, group = group, fill = after_stat(avg_y))) + geom_bump_ribbon() + scale_fill_rank() + scale_y_reverse()
These ggproto objects implement the statistical transformations for
bump ribbon and line charts. They are exported for extensibility but
should typically be used through geom_bump_ribbon() and
geom_bump_line().
ggproto objects that should not be called directly.
ggplot2::Stat, ggplot2::ggproto()
A minimal dark theme based on ggplot2::theme_void() with a dark
background and light text, suited to rank comparison infographics.
theme_bump(bg = "#1a1a2e", title_color = "#e74c3c", base_size = 10)theme_bump(bg = "#1a1a2e", title_color = "#e74c3c", base_size = 10)
bg |
Background fill colour. Default |
title_color |
Title text colour. Default |
base_size |
Base font size. Default |
A ggplot2 theme object.
ggplot2::theme_void(), geom_bump_ribbon()
Other bump scales:
scale_fill_rank()
library(ggplot2) ggplot(mtcars, aes(wt, mpg)) + geom_point(colour = "white") + labs(title = "Motor Trend Cars") + theme_bump()library(ggplot2) ggplot(mtcars, aes(wt, mpg)) + geom_point(colour = "white") + labs(title = "Motor Trend Cars") + theme_bump()