dumbbell R Package

knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7,
  fig.height = 4,
  message = FALSE,
  warning = FALSE
)

Overview

The dumbbell package creates dumbbell plots in ggplot2. A dumbbell plot compares two numeric values for the same item and connects them with a line segment. This is useful when you want to show before/after values, treatment/control values, male/female values, or any paired comparison.

The main function is dumbbell(). It expects a data frame with at least four columns:

  1. an ID column for the y-axis labels,
  2. a grouping or facet key,
  3. the first numeric value,
  4. the second numeric value.

The function returns a ggplot object, so you can add standard ggplot2 layers such as facet_wrap(), labs(), theme(), or coord_cartesian().

Installation

Install the package from CRAN with:

install.packages("dumbbell")

Or install a development version from a local source directory:

devtools::install("path/to/dumbbell")

Load packages

suppressPackageStartupMessages({
  library(dumbbell)
  library(dplyr)
  library(ggplot2)
})

Example data

The example below creates paired measurements for two groups. Each subject has a value for group A and group B. The data are then reshaped into the format expected by dumbbell().

set.seed(123)

raw_data <- data.frame(
  Group = rep(c("A", "B"), each = 10),
  Subject = rep(paste0("sub_", 1:10), times = 2),
  result = sample(1:100000, 20, replace = TRUE),
  analysis = rep(rep(c("a", "b"), each = 5), times = 2)
)

group_a <- raw_data %>% filter(Group == "A")
group_b <- raw_data %>% filter(Group == "B")

plot_data <- merge(
  group_a,
  group_b,
  by = c("Subject", "analysis")
)

plot_data <- plot_data %>%
  mutate(diff = result.x - result.y) %>%
  arrange(diff)

plot_data$Subject <- factor(plot_data$Subject, levels = plot_data$Subject)

head(plot_data)

Basic dumbbell plot

Use id for the labels on the y-axis, key for the grouping variable, and column1/column2 for the paired numeric values.

dumbbell(
  xdf = plot_data,
  id = "Subject",
  key = "analysis",
  column1 = "result.x",
  column2 = "result.y",
  lab1 = "Group A",
  lab2 = "Group B"
)

Add a delta column

Set delt = 1 to add the difference between the two values at the right side of the plot.

dumbbell(
  xdf = plot_data,
  id = "Subject",
  key = "analysis",
  column1 = "result.x",
  column2 = "result.y",
  lab1 = "Group A",
  lab2 = "Group B",
  delt = 1,
  expandx = 0.1
)

Add value labels

Set pt_val = 1 to print the numeric values next to the points. Use col_lab1 and col_lab2 to control the label colors.

dumbbell(
  xdf = plot_data,
  id = "Subject",
  key = "analysis",
  column1 = "result.x",
  column2 = "result.y",
  lab1 = "Group A",
  lab2 = "Group B",
  pt_val = 1,
  expandx = 0.05,
  col_lab1 = "blue",
  col_lab2 = "red"
)

Add arrows

Set arrow = 1 to draw arrows along the connecting segments. Use arrow_size, segsize, pointsize, pt_alpha, col_seg1, and col_seg2 to customize the display.

dumbbell(
  xdf = plot_data,
  id = "Subject",
  key = "analysis",
  column1 = "result.x",
  column2 = "result.y",
  lab1 = "Group A",
  lab2 = "Group B",
  arrow = 1,
  arrow_size = 0.2,
  segsize = 0.7,
  pointsize = 1.5,
  pt_alpha = 0.6,
  col_seg1 = "#A9A9A9",
  col_seg2 = "#A9A9A9"
)

Facet by group

Because dumbbell() returns a ggplot object, you can add facet_wrap() directly.

dumbbell(
  xdf = plot_data,
  id = "Subject",
  key = "analysis",
  column1 = "result.x",
  column2 = "result.y",
  lab1 = "Group A",
  lab2 = "Group B"
) +
  facet_wrap(~ analysis, ncol = 1, scales = "free_y")

Add paired p-values

The pval argument adds a paired test result to the facet label:

The current implementation uses base R functions from the stats package, so the package does not need to depend on rstatix for these tests.

dumbbell(
  xdf = plot_data,
  id = "Subject",
  key = "analysis",
  column1 = "result.x",
  column2 = "result.y",
  lab1 = "Group A",
  lab2 = "Group B",
  pval = 1
) +
  facet_wrap(~ analysis, ncol = 1, scales = "free_y")

Complete customized example

This example combines facets, arrows, highlighted segment colors, point transparency, and delta labels.

dumbbell(
  xdf = plot_data,
  id = "Subject",
  key = "analysis",
  column1 = "result.x",
  column2 = "result.y",
  lab1 = "Group A",
  lab2 = "Group B",
  delt = 1,
  col_seg2 = "red",
  col_seg1 = "blue",
  arrow = 1,
  pt_alpha = 0.6,
  pointsize = 2,
  expandx = 0.2,
  segsize = 0.5,
  textsize = 2,
  pval = 1
) +
  facet_wrap(~ analysis, ncol = 1, scales = "free_y")

Working with axis limits

Because dumbbell() already adds an x-axis scale, xlim() will replace that scale and may remove data outside the requested range. To zoom without dropping observations, use coord_cartesian():

dumbbell(
  xdf = plot_data,
  id = "Subject",
  key = "analysis",
  column1 = "result.x",
  column2 = "result.y",
  lab1 = "Group A",
  lab2 = "Group B"
) +
  coord_cartesian(xlim = c(0, 100000))

Main arguments

| Argument | Description | |---|---| | xdf | Input data frame. | | id | Column used for the y-axis labels. | | key | Grouping variable, commonly used with facet_wrap(). | | column1, column2 | Paired numeric columns to compare. | | lab1, lab2 | Labels for the two compared values. | | delt | Set to 1 to display the difference between the two values. | | pt_val | Set to 1 to display point value labels. | | pval | Set to 1 for paired Wilcoxon test or 2 for paired t-test. | | arrow | Set to 1 to add arrows to the connecting segments. | | pointsize, textsize, segsize | Control point, label, and segment sizes. | | p_col1, p_col2 | Colors for the two point groups. | | col_seg1, col_seg2 | Segment colors by direction. | | expandx, expandy | Expansion around the x- and y-axes. |

Notes for package maintainers



Try the dumbbell package in your browser

Any scripts or data that you put into this service are public.

dumbbell documentation built on July 7, 2026, 1:06 a.m.