I'm trying to build a donut plot in my R Shiny app that labels the number and percentage that corresponds with the portion of the plot. However, when I use geom_label(), it does two undesirable things.
The result looks like this:
I'm flexible with where the labels go as long as its logical, but in an ideal world, the end result would look something like this (note: this is a sample plot, not using the exact data in the code below):
And, of course, that "a" from the label would also be removed.
Reproducible example:
library(shiny)
library(dplyr)
library(ggplot2)
library(Cairo)
options(shiny.usecairo=T) #used to get the plot to look crisp in Shiny
my_colors <- c("#00A3AD", "#FF8200", "#753BBD", "#6CC24A")
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
),
mainPanel(
fluidRow(
plotOutput("count_by_person")
))
))
server <- function(input, output) {
output$count_by_person <- renderPlot({
data <- tibble(name = c("Justin", "Corey", "Sibley", "Kate"),
n = c(10, 30, 59, 1),
prop = c(10, 30, 59, 1))
ggplot(data, aes(x = 2, y = prop, fill = name)) +
geom_bar(stat = "identity", color = "white") +
coord_polar(theta = "y", start = 0)+
geom_label(aes(label = paste0(n, "\n", prop, "%"))) +
scale_fill_manual(values = my_colors) +
theme_void() +
xlim(.5, 2.5)
})
}
shinyApp(ui, server)
Edit with geom_label_repel()
As suggested below, I tried running this same code with geom_label_repel()
from the ggrepel
package instead of geom_label()
. Though it gets the line, it doesn't change the fact that the labels are in the wrong place.
library(shiny)
library(dplyr)
library(ggplot2)
library(Cairo)
library(ggrepel)
options(shiny.usecairo=T) #used to get the plot to look crisp in Shiny
my_colors <- c("#00A3AD", "#FF8200", "#753BBD", "#6CC24A")
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
),
mainPanel(
fluidRow(
plotOutput("count_by_person")
))
))
server <- function(input, output) {
output$count_by_person <- renderPlot({
data <- tibble(name = c("Justin", "Corey", "Sibley", "Kate"),
n = c(10, 30, 59, 1),
prop = c(10, 30, 59, 1)) %>%
dplyr::arrange(prop)
ggplot(data, aes(x = 2, y = prop, fill = name)) +
geom_bar(stat = "identity", color = "white") +
coord_polar(theta = "y", start = 0)+
geom_label_repel(aes(label = paste0(n, "\n", prop, "%")), force_pull = 100, nudge_x = 1) +
scale_fill_manual(values = my_colors) +
theme_void() +
xlim(.5, 2.5)
})
}
shinyApp(ui, server)
Picture of what it looks like with geom_label_repel()
As is explained in the very nice answer by Andrey Kolyadin I linked in the comments, you need to precompute the cumulative position of the text:
library(ggrepel)
data %>%
arrange(desc(name)) %>%
mutate(text_y = cumsum(prop)-prop/2) %>%
ggplot(aes(x = 2, y = prop, fill = name)) +
geom_bar(stat = "identity", color = "white") +
coord_polar(theta = "y", start = 0)+
geom_label_repel(aes(y = text_y, label = paste0(n, "\n", prop, "%")), force_pull = 100, nudge_x = 1) +
scale_fill_manual(values = my_colors) +
theme_void() +
xlim(.5, 2.5)