upsetly

Interactive UpSet plots built on plotly: explore intersections among multiple sets with rich tooltips, and copy complete intersection details (Intersection, Size, Members, …) with one click in Quarto, R Markdown, and Shiny documents.

upsetly follows the classic UpSet layout of Lex et al. (2014) — set-size bars, intersection-size bars, and a membership dot matrix — and adds JavaScript hooks so that all tooltip text can be synced into a separate text box for copy‑and‑paste.


Installation

Install the released version from CRAN:

install.packages("upsetly")

Or the development version from GitHub:

# install.packages("remotes")
# remotes::install_github("Rbunensi/upsetly")
install.packages("upsetly", repos = c('https://rbunensi.r-universe.dev', 'https://cloud.r-project.org'))

Then load:

library(upsetly)

Basic idea

Given a data frame with:

upsetly() will:

  1. Compute all non-empty intersections across the set columns.
  2. Keep only intersections with size at least min_intersection_size.
  3. Optionally keep only the largest max_n_intersections intersections.
  4. Draw:
    • Left bar chart: size of each set.
    • Top bar chart: size of each intersection.
    • Bottom dot matrix: which sets are present in each intersection.
  5. Build rich tooltip text for each intersection, including:
    • Intersection name (e.g. A_vs_B & B_vs_C)
    • Intersection size
    • Members (element IDs), wrapped onto multiple lines.

In HTML output, you can also display the full tooltip text in a separate box which supports copy‑and‑paste.


Quick example

library(upsetly)

set.seed(1)
df <- data.frame(
  gene = paste0("g", 1:100),
  A = rbinom(100, 1, 0.3),
  B = rbinom(100, 1, 0.4),
  C = rbinom(100, 1, 0.2),
  stringsAsFactors = FALSE
)

p <- upsetly(
  x = df,
  set_cols = c("A", "B", "C"),
  id_col = "gene",
  max_n_intersections = 50,
  members_per_line = 10
)

p  # interactive plotly widget

This works in a regular RStudio viewer (or browser) as an interactive UpSet plot.


Using in Quarto / R Markdown with a copyable text box

To make the tooltip text (Intersection, Size, Members, etc.) easy to copy, you can add a small HTML element with id members_box and let upsetly() sync to it.

Example Quarto document

---
title: "upsetly demo"
format: html
---

```{r}
library(upsetly)
```
```{r}
set.seed(1)
df <- data.frame(
  gene = paste0("g", 1:100),
  A = rbinom(100, 1, 0.3),
  B = rbinom(100, 1, 0.4),
  C = rbinom(100, 1, 0.2),
  stringsAsFactors = FALSE
)

upsetly(
  x = df,
  set_cols = c("A", "B", "C"),
  id_col = "gene",
  max_n_intersections = 50,
  box_id = "members_box",
  members_per_line = 10
)
```
```{=html}
<pre id="members_box" style="
  border: 1px solid #ccc;
  padding: 8px;
  min-height: 120px;
  white-space: pre-wrap;
  font-family: monospace;
"></pre>
```

Interaction behavior

In the rendered HTML:

The content of members_box is pure text, so you can select and copy it easily.


Key arguments

upsetly(
  x,
  set_cols = NULL,
  id_col = NULL,
  min_intersection_size = 1,
  max_n_intersections = NULL,
  point_size = 8,
  bar_color_sets = "black",
  bar_color_inters = "black",
  active_color = "black",
  inactive_color = "lightgray",
  line_color = "black",
  title = "UpSet (plotly)",
  height = 500,
  width = NULL,
  members_per_line = 20,
  box_id = NULL
)

Citation

If you use upsetly in your research, please cite it as:

Anbunensi (2026). upsetly: Interactive UpSet Plots Using 'plotly'. R package version 0.1.1. https://CRAN.R-project.org/package=upsetly


License

MIT © 2026 Anbunensi