2014-10-15 25 views
8

Da un frame di dati, desidero stampare un grafico a torta per cinque categorie con le relative percentuali come etichette nello stesso grafico in ordine dal più alto al più basso, in senso orario.R: Grafico a torta con percentuale come etichette utilizzando ggplot2

mio codice è:

League<-c("A","B","A","C","D","E","A","E","D","A","D") 
data<-data.frame(League) # I have more variables 

p<-ggplot(data,aes(x="",fill=League)) 
p<-p+geom_bar(width=1) 
p<-p+coord_polar(theta="y") 
p<-p+geom_text(data,aes(y=cumsum(sort(table(data)))-0.5*sort(table(data)),label=paste(as.character(round(sort(table(data))/sum(table(data)),2)),rep("%",5),sep=""))) 
p 

Io uso

cumsum(sort(table(data)))-0.5*sort(table(data)) 

di posizionare l'etichetta nella porzione corrispondente e

label=paste(as.character(round(sort(table(data))/sum(table(data)),2)),rep("%",5),sep="") 

per le etichette che è le percentuali.

ottengo il seguente output:

Error: ggplot2 doesn't know how to deal with data of class uneval 

risposta

9

ho conservai la maggior parte del codice. Ho trovato abbastanza facile eseguire il debug lasciando fuori coord_polar ... più facile vedere cosa sta succedendo sotto forma di grafico a barre.

L'elemento principale era quello di riordinare il fattore dal più alto al più basso per ottenere l'ordine di tracciamento corretto, quindi solo giocando con le posizioni dell'etichetta per farli correttamente. Ho anche semplificato il codice per le etichette (non è necessario il as.character o rep, e paste0 è una scorciatoia per sep = "".)

League<-c("A","B","A","C","D","E","A","E","D","A","D") 
data<-data.frame(League) # I have more variables 

data$League <- reorder(data$League, X = data$League, FUN = function(x) -length(x)) 

at <- nrow(data) - as.numeric(cumsum(sort(table(data)))-0.5*sort(table(data))) 

label=paste0(round(sort(table(data))/sum(table(data)),2) * 100,"%") 

p <- ggplot(data,aes(x="", fill = League,fill=League)) + 
    geom_bar(width = 1) + 
    coord_polar(theta="y") + 
    annotate(geom = "text", y = at, x = 1, label = label) 
p 

Il calcolo at è trovare i centri dei cunei. (E 'più facile pensare a loro come i centri di barre in un grafico a barre in pila, basta eseguire la trama sopra senza la linea coord_polar per vedere.) Il calcolo at può essere suddiviso come segue:

table(data) è il numero di righe in ciascun gruppo e sort(table(data)) li inserisce nell'ordine in cui verranno tracciati. Prendendo il cumsum() di quello ci dà i bordi di ogni barra quando impilati uno sopra l'altro, e moltiplicando per 0,5 ci dà la metà delle altezze di ogni barra nella pila (o metà delle larghezze dei cunei della torta).

as.numeric() garantisce semplicemente che abbiamo un vettore numerico anziché un oggetto della classe table.

La sottrazione delle mezze larghe dalle altezze cumulative conferisce ai centri ogni barra una volta impilati. Ma ggplot impilerà le barre con il più grande in basso, mentre tutto il nostro sort() ing mette il più piccolo per primo, quindi dobbiamo fare nrow - tutto perché quello che abbiamo effettivamente calcolare sono le posizioni dell'etichetta rispetto allo superiore della barra , non il fondo. (E, con i dati disaggregati originali, nrow() è il numero totale di righe quindi l'altezza totale della barra.)

+0

grazie mille !! Stavo diventando pazzo a farlo. Sono noob con la libreria ggplot2. – pescobar

+0

@Gregor potresti spiegare cosa sta facendo il tuo codice quando calcoliamo 'at'? Molte grazie. –

+1

@info_seekeR aggiunto alcuni paragrafi in fondo, vedere se questo aiuta. – Gregor

9

Prefazione: Non ho creato grafici a torta di mia spontanea volontà.

Ecco una modifica della funzione ggpie che comprende le percentuali:

library(ggplot2) 
library(dplyr) 

# 
# df$main should contain observations of interest 
# df$condition can optionally be used to facet wrap 
# 
# labels should be a character vector of same length as group_by(df, main) or 
# group_by(df, condition, main) if facet wrapping 
# 

pie_chart <- function(df, main, labels = NULL, condition = NULL) { 

    # convert the data into percentages. group by conditional variable if needed 
    df <- group_by_(df, .dots = c(condition, main)) %>% 
    summarize(counts = n()) %>% 
    mutate(perc = counts/sum(counts)) %>% 
    arrange(desc(perc)) %>% 
    mutate(label_pos = cumsum(perc) - perc/2, 
      perc_text = paste0(round(perc * 100), "%")) 

    # reorder the category factor levels to order the legend 
    df[[main]] <- factor(df[[main]], levels = unique(df[[main]])) 

    # if labels haven't been specified, use what's already there 
    if (is.null(labels)) labels <- as.character(df[[main]]) 

    p <- ggplot(data = df, aes_string(x = factor(1), y = "perc", fill = main)) + 

    # make stacked bar chart with black border 
    geom_bar(stat = "identity", color = "black", width = 1) + 

    # add the percents to the interior of the chart 
    geom_text(aes(x = 1.25, y = label_pos, label = perc_text), size = 4) + 

    # add the category labels to the chart 
    # increase x/play with label strings if labels aren't pretty 
    geom_text(aes(x = 1.82, y = label_pos, label = labels), size = 4) + 

    # convert to polar coordinates 
    coord_polar(theta = "y") + 

    # formatting 
    scale_y_continuous(breaks = NULL) + 
    scale_fill_discrete(name = "", labels = unique(labels)) + 
    theme(text = element_text(size = 22), 
      axis.ticks = element_blank(), 
      axis.text = element_blank(), 
      axis.title = element_blank()) 

    # facet wrap if that's happening 
    if (!is.null(condition)) p <- p + facet_wrap(condition) 

    return(p) 
} 

Esempio:

# sample data 
resps <- c("A", "A", "A", "F", "C", "C", "D", "D", "E") 
cond <- c(rep("cat A", 5), rep("cat B", 4)) 
example <- data.frame(resps, cond) 

Proprio come una tipica chiamata ggplot:

ex_labs <- c("alpha", "charlie", "delta", "echo", "foxtrot") 

pie_chart(example, main = "resps", labels = ex_labs) + 
    labs(title = "unfacetted example") 

Unfacetted pie chart abomination

ex_labs2 <- c("alpha", "charlie", "foxtrot", "delta", "charlie", "echo") 

pie_chart(example, main = "resps", labels = ex_labs2, condition = "cond") + 
    labs(title = "facetted example") 

enter image description here

+0

Questa è una grande codifica. Sto riscontrando problemi con tutte le soluzioni in cui il mio grafico sembra essere costruito in senso antiorario, ma le mie etichette sono in senso orario? Grazie – atclaus

+0

Ho provato a cambiare direzione del polar con 'direction = -1' ma sembra capovolgere sia le percentuali che la direzione in modo da ottenere lo stesso problema – atclaus

+2

Risolto il problema con @Reno. Ho modificato la seguente riga 'label_pos = sum (perc) - cumsum (perc) + perc/2' – atclaus

0

Ha funzionato su tutte le funzioni incluse fortemente ispirato da here

ggpie <- function (data) 
{ 
    # prepare name 
    deparse(substitute(data)) -> name ; 

    # prepare percents for legend 
    table(factor(data)) -> tmp.count1 
    prop.table(tmp.count1) * 100 -> tmp.percent1 ; 
    paste(tmp.percent1, " %", sep = "") -> tmp.percent2 ; 
    as.vector(tmp.count1) -> tmp.count1 ; 

    # find breaks for legend 
    rev(tmp.count1) -> tmp.count2 ; 
    rev(cumsum(tmp.count2) - (tmp.count2/2)) -> tmp.breaks1 ; 

    # prepare data 
    data.frame(vector1 = tmp.count1, names1 = names(tmp.percent1)) -> tmp.df1 ; 


    # plot data 
    tmp.graph1 <- ggplot(tmp.df1, aes(x = 1, y = vector1, fill = names1)) + 
    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(), 
      plot.title = element_text(hjust = 0.5, vjust = 0.5)) + 
    scale_y_continuous(breaks = tmp.breaks1, labels = tmp.percent2) + 
    ggtitle(name) + 
    scale_fill_grey(name = "") ; 

    return(tmp.graph1) 
} ; 

Un esempio:

sample(LETTERS[1:6], 200, replace = TRUE) -> vector1 ; 
ggpie(vector1) 

Output