Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add lines connecting segments to values outside a donut chart

Adding lines to the donut chart in ggplot2

I've been trying to create a chart that displays values outside its perimeter for a long time. I would like to connect these values to the corresponding segments on the chart using dashed lines that should start at the centers of the segments. my plot I was able to create a chart that met the requirements except for the (seemingly) trivial lines using this code:

library(ggplot2)
library(dplyr)

COUNTRY <- c("Sweden", "France", "USA", "Britain", "Argentina", "Brazil")
Revenue <- c(190, 146, 131, 129, 121, 937)
Percent <- c(0.11487304, 0.08827086, 0.07920193, 0.07799274, 0.07315599, 0.56650544)
color <- c('A', 'B', 'C', 'D', 'E', 'F')

TOP_5 <- data.frame(COUNTRY, Revenue, Percent, color)

colors <- c('A'='#D9553B', 'B'='#E17A65', 'C'='#EBA799', 'D'='#F2C8C0', 'E'='#F9E3DF', 'F'='#A7A8A9')

PLOT <- ggplot(data = TOP_5, aes(x = 2, y = Percent, fill = color)) +
  geom_col(color = "white") +
  coord_polar("y", start = 1) +
  geom_text(aes(x = 3, label = paste0(" ", round(Percent * 100), "%")), 
            position = position_stack(vjust = 0.5), 
            hjust = 0,
            angle = 0,
            color = "black") +
  geom_text(aes(x = 3, label = COUNTRY), 
            position = position_stack(vjust = 0.5), 
            hjust = 1, 
            angle = 0,
            color = "#B43C23") +
  geom_point(position = position_stack(vjust = 0.5), 
             color = "#B43C23", 
             size = 3) +
  theme(panel.background = element_blank(),
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank(),
        axis.title = element_blank(),
        plot.title = element_text(hjust = 0.5, size = 18)) +
  scale_fill_manual(values = colors) +
  theme(legend.position = "none") +
  xlim(0.5, 3.2)  

The expected result would be something like this: desired plot I tried to achieve this using geom_segment but without success. I would appreciate your help in convicting a possible solution. Ideally, I would like to limit myself to just these two libraries, but of course I am open to additional solutions

like image 697
Matt0 Avatar asked Sep 05 '25 03:09

Matt0


1 Answers

One option to achieve your desired result would be to use a geom_segment to connect the labels and the points. To this end I computed the y positions manually. Additionally I switched to geom_label as it allows for "background" box around the labels:

library(ggplot2)
library(dplyr)

TOP_5 <- TOP_5 %>%
  arrange(desc(color)) %>%
  mutate(
    Percent_cum = cumsum(Percent),
    y = .5 * (Percent_cum + lag(Percent_cum, default = 0))
  )

ggplot(data = TOP_5, aes(x = 2, y = Percent, fill = color)) +
  geom_col(color = "white") +
  coord_polar("y", start = 1, clip = "off") +
  geom_segment(aes(x = 2.1, xend = 3, y = y, yend = y, group = color)) +
  geom_label(aes(x = 3, label = paste0(" ", round(Percent * 100), "%")),
    position = position_stack(vjust = 0.5),
    fill = "white",
    label.size = 0,
    hjust = 0,
    angle = 0,
    color = "black"
  ) +
  geom_label(aes(x = 3, label = COUNTRY),
    position = position_stack(vjust = 0.5),
    fill = "white",
    label.size = 0,
    hjust = 1,
    angle = 0,
    color = "#B43C23"
  ) +
  geom_point(
    position = position_stack(vjust = 0.5),
    color = "#B43C23",
    size = 3
  ) +
  theme(
    panel.background = element_blank(),
    axis.line = element_blank(),
    axis.text = element_blank(),
    axis.ticks = element_blank(),
    axis.title = element_blank(),
    plot.title = element_text(hjust = 0.5, size = 18)
  ) +
  scale_fill_manual(values = colors) +
  theme(legend.position = "none") +
  xlim(0.5, 3.2)

enter image description here

like image 138
stefan Avatar answered Sep 07 '25 21:09

stefan