Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In ggplot, how to create line visualization with pointy edges (like "toothpicks")?

Tags:

r

ggplot2

I'm looking for a way to create lines with ggplot() that have "pointy" edges, to get an overall look of "toothpicks".

For example, consider the following visualization:

library(tibble)
library(ggplot2)

my_df <-
  tribble(~name, ~value,
        "a", 1,
        "a", 2,
        "b", 1,
        "b", 2)


my_df %>%
  ggplot(aes(x = name, y = value)) +
  geom_line(size = 1.5, lineend = "round") +
  expand_limits(y = c(0.5, 2.5)) +
  theme_bw()

Created on 2021-07-21 by the reprex package (v2.0.0)


Now, let's say I set

y_top    <- 1.75
y_bottom <- 1.25

as the values from which the lines start to get "sharpened".
How can I get something similar to:
thoothpicks

Although it would be ideal to also have the fade-out effect, the "toothpick" look is most important to me. Unfortunately, geom_lines()'s lineend argument doesn't support the "pointiness" I'm looking for.

Any idea how this could be achieved?

Thanks!

like image 806
Emman Avatar asked Dec 23 '22 15:12

Emman


1 Answers

One way is using the ggforce package to access some "tweened" geoms which vary in appearance along their length, like geom_link2. Here, I do some prep work to add observations that are 0.25 in from the extremes for each name, and to assign widths depending on whether we're at an extreme or not.

library(tidyverse); library(ggforce)
my_df %>%
  group_by(name) %>%
  summarize(min_val = min(value), max_val = max(value)) %>%
  mutate(min_taper = min_val + 0.25, max_taper = max_val - 0.25) %>% 
  pivot_longer(-name, names_to = "step") %>%
  mutate(width = if_else(str_detect(step, "val"), 0, 1)) %>%
  arrange(name, value) %>%

#Here's what it looks like at this point:
## A tibble: 8 x 4
#  name  step      value width
#  <chr> <chr>     <dbl> <dbl>
#1 a     min_val    1        0
#2 a     min_taper  1.25     1
#3 a     max_taper  1.75     1
#4 a     max_val    2        0
#5 b     min_val    1        0
#6 b     min_taper  1.25     1
#7 b     max_taper  1.75     1
#8 b     max_val    2        0
  
  # now that it's prepped, it's a short call in ggplot2/ggforce:
  ggplot(aes(name, value, size = width)) +
  ggforce::geom_link2() +
  scale_size_continuous(range = c(0,0.6)) +  # controls width range of lines 
  theme_bw()

enter image description here

like image 122
Jon Spring Avatar answered Feb 23 '23 01:02

Jon Spring