---
title: "dumbbell R Package"
author: "Foo Cheung"
date: "`r Sys.Date()`"
output:
  html_document:
    toc: true
    toc_depth: 2
    theme: united
    df_print: paged
vignette: >
  %\VignetteIndexEntry{dumbbell}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, echo=FALSE}
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:

```{r install-cran, eval=FALSE}
install.packages("dumbbell")
```

Or install a development version from a local source directory:

```{r install-local, eval=FALSE}
devtools::install("path/to/dumbbell")
```

## Load packages

```{r 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()`.

```{r example-data}
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.

```{r basic-plot}
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.

```{r delta-column}
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.

```{r value-labels}
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.

```{r arrows}
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.

```{r facets}
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:

- `pval = 1` uses a paired Wilcoxon test.
- `pval = 2` uses a paired t-test.

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

```{r pvalues}
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.

```{r complete-example}
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()`:

```{r axis-limits, eval=FALSE}
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

- The p-value functionality should rely on `stats::wilcox.test()` and `stats::t.test()` to avoid an unnecessary dependency on `rstatix`.
- If the roxygen comments are changed, run `devtools::document()` to regenerate `NAMESPACE` and help files.
- If a `docs/` website is used, regenerate it from the source vignette/R Markdown rather than editing generated HTML by hand.
