Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ggplot pie chart labeling

I am struggling with getting the pie chart labels correct. Looked around and thought that I could easily implement what mathematicalCoffee did. So far I have this code:

ltr = LETTERS[seq( from = 1, to = 26)]

wght = runif(length(ltr))
wght = wght/sum(wght)
wght = round(wght, digits = 2)

alloc = as.data.frame(cbind(ltr, wght))
alloc$wght = as.numeric(as.character(alloc$wght))

ggpie <- function (dat, by, totals) {
  ggplot(dat, aes_string(x=factor(1), y=totals, fill=by)) +
    geom_bar(stat='identity', color='black') +
    guides(fill=guide_legend(override.aes=list(colour=NA))) +
    coord_polar(theta='y') +
    theme(axis.ticks=element_blank(),
          axis.text.y=element_blank(),
          axis.text.x=element_text(colour='black'),
          axis.title=element_blank()) +
    ## scale_fill_brewer(palette = "GnBu") +
    scale_y_continuous(breaks=cumsum(dat[[totals]]) - dat[[totals]] / 2, labels=paste(dat[[by]], ":", dat[[totals]]))    
}

AA = ggpie(alloc, by = "ltr", totals = "wght") +
  ggtitle("Letter weights")

AA

The resulting pie chart:Pie

Is there any way to generate something like this, for example:

CoolPie

Update for suggested dup - I think that thread is more about alternatives to pie charts and why pie charts are bad. I would like to stick to pie charts and want to find a solution to handling labels correctly/user-friendly.

like image 604
AK88 Avatar asked Jun 08 '17 12:06

AK88


2 Answers

For pie charts plotly works a lot easier than ggplot. Perhaps something like this:

library(plotly)

p <- plot_ly(alloc, labels = ~ltr, values = ~wght, type = 'pie',textposition = 'outside',textinfo = 'label+percent') %>%
  layout(title = 'Letters',
         xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
         yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))

enter image description here

like image 105
timfaber Avatar answered Oct 20 '22 17:10

timfaber


We can make it work with ggplot2 and the ggrepel package.

Unfortunately geom_text_repel() does not support a position = argument, so we have to calculate the starting position of the line by hand.

With your data.frame:

alloc$pos = (cumsum(c(0, alloc$wght)) + c(alloc$wght / 2, .01))[1:nrow(alloc)]

This calculates the mean point for each group (or obs, or whtvr you want to call it).

Plugging it in in the geom_text_repel's y aes gives a nice result:

library(ggplot2)
library(ggrepel)
ggplot(alloc, aes(1, wght, fill = ltr)) +
    geom_col(color = 'black', 
             position = position_stack(reverse = TRUE), 
             show.legend = FALSE) +
    geom_text_repel(aes(x = 1.4, y = pos, label = ltr), 
                    nudge_x = .3, 
                    segment.size = .7, 
                    show.legend = FALSE) +
    coord_polar('y') +
    theme_void()

I made some choices, as the use of text instead of label, the removal of the legend and the axes. Feel free to change them

like image 20
GGamba Avatar answered Oct 20 '22 17:10

GGamba