0

I have a pie chart below, and I would like to create the wheel much more readable. many thanks in advance.

   library(ggplot2)
library(dplyr)

# Create Data
data <- data.frame(
  group=c("IMAGINE HERE I HAVE A LONG SURVEY QUESTIONS", 
          "AND THE TEXT IS IN DIFFERENT LENGTH", 
          "WANNA PLOT THESE IN ORDER", 
          "WITH 45 DEGREE ANGLE", 
          "PIE CAN BE PROPORTIONAL WITH THE TEXT LENGTH" ),
  value=c(13,7,9,21,2)
)

# Compute the position of labels
data <- data %>% 
  arrange(desc(group)) %>%
  mutate(prop = value / sum(data$value) *100) %>%
  mutate(ypos = cumsum(prop)- 0.5*prop )

# Basic piechart
ggplot(data, aes(x="", y=prop, fill=group)) +
  geom_bar(stat="identity", width=1, color="white") +
  coord_polar("y", start=0) +
  theme_void() + 
  theme(legend.position="none") +
  
  geom_text(aes(y = ypos, label = group), color = "white", size=6) +
  scale_fill_brewer(palette="Set1")
Seyma Kalay
  • 2,037
  • 10
  • 22
  • 1
    You could maybe try using `ggrepel` like advised in [this](https://stackoverflow.com/questions/42654132/r-pie-chart-labels-overlap-ggplot2)? Personally I would use a bar chart, because [pie charts are terrible](https://towardsdatascience.com/pie-charts-considered-harmful-36268a4e42e6). – Andrea M May 29 '22 at 12:22

3 Answers3

4

You have a better chance of fitting in the labels if you wrap them using str_wrap and curve them using geomtextpath:

# Compute the position of labels
data <- data %>% 
  arrange(desc(group)) %>%
  mutate(prop = value / sum(data$value) *100) %>%
  mutate(ypos = cumsum(prop)- 0.5*prop,
         group = stringr::str_wrap(group, 20))

library(geomtextpath)

# Basic piechart
ggplot(data, aes(x=1, y=prop, fill=group)) +
  geom_bar(stat="identity", width=1, color="white") +
  coord_polar("y", start=0) +
  theme_void() + 
  theme(legend.position="none") +
  geom_textpath(aes(x = 1.3, y = ypos, label = group,
                    vjust = group), color = "black", size = 6, 
                angle = 90) +
  scale_fill_brewer(palette="Set1") +
  scale_x_continuous(limits = c(0.5, 2)) +
  scale_vjust_manual(values = c(2, 1.8, 2.2, 2, 4))

enter image description here

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87
3

Maybe to wrap the group text and have it plotted in many lines of text is a way to solve the problem.
First strwrap breaks each value in group, then paste inserts newline characters at the break points.

And the graphics device dimensions are made larger, though it doesn't show with reprex.

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

# Create Data
data <- data.frame(
  group=c("IMAGINE HERE I HAVE A LONG SURVEY QUESTIONS", 
          "AND THE TEXT IS IN DIFFERENT LENGTH", 
          "WANNA PLOT THESE IN ORDER", 
          "WITH 45 DEGREE ANGLE", 
          "PIE CAN BE PROPORTIONAL WITH THE TEXT LENGTH" ),
  value=c(13,7,9,21,2)
)

# Compute the position of labels
data <- data %>% 
  arrange(desc(group)) %>%
  mutate(prop = value / sum(data$value) *100) %>%
  mutate(ypos = cumsum(prop) - 0.5*prop )

data$group2 <- sapply(data$group, \(x) {
  s <- strwrap(x, width = 15)
  paste(s, collapse = "\n")
})

old_par <- par()[c("fin", "mar")]
par(fin = old_par$fin + 5, mar = rep(0, 4))

# Basic piechart
ggplot(data, aes(x="", y=prop, fill=group)) +
  geom_bar(stat="identity", width=1, color="white") +
  coord_polar("y", start=0) +
  theme_void() + 
  theme(legend.position="none") +
  geom_text(aes(y = ypos, label = group2), color = "white", size=3) +
  scale_fill_brewer(palette="Set1")

par(old_par)

Created on 2022-05-29 by the reprex package (v2.0.1)

Rui Barradas
  • 70,273
  • 8
  • 34
  • 66
1

It is not the best option, but you could use geom_label_repel from ggrepel like this:

library(ggplot2)
library(dplyr)
library(ggrepel)

data <- data %>% 
  arrange(desc(group)) %>%
  mutate(prop = value / sum(data$value) *100) %>%
  mutate(ypos = cumsum(prop)- 0.5*prop )

ggplot(data, aes(x="", y=prop, fill=group)) +
  geom_bar(stat="identity", width=1, color="white") +
  coord_polar("y", start=0) +
  theme_void() + 
  theme(legend.position="none") +
  geom_label_repel(data = data,
                   aes(y = ypos, label = group),
                   size = 4.5, nudge_x = 3, show.legend = FALSE) +
  scale_fill_brewer(palette="Set1")

Output:

enter image description here

Quinten
  • 35,235
  • 5
  • 20
  • 53
  • Thank you. But i want to fit the text eith 45 degree angle. And the width of the pie should be based on the text. If the text is so long the width of the pie should be bigger. – Seyma Kalay May 29 '22 at 13:18