2014-10-15 1 views
8

Из фрейма данных я хочу построить круговую диаграмму для пяти категорий с их процентами в виде меток на одном и том же графике в порядке от наивысшего до самого низкого, идущего по часовой стрелке.R: Круговая диаграмма с процентом в виде меток с использованием ggplot2

Мой код:

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 

Я использую

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

поместить метку в соответствующей части и

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

для этикеток, который составляет проценты.

я получаю следующий результат:

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

ответ

9

Я сохранившийся большую часть вашего кода. Я нашел это довольно легко отлаживать, оставив coord_polar ... легче видеть, что происходит как гистограмма.

Главное было переупорядочить коэффициент от наивысшего до самого низкого, чтобы правильно установить порядок построения графика, а затем просто сыграть с позициями ярлыков, чтобы получить их право. Я также упрощен код для меток (вам не нужно as.character или rep и paste0 ярлык для 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 

Расчет at является нахождение центров клиньев. (Это легче думать о них как центры баров в столбчатой ​​сюжета, просто запустить выше участок без coord_polar линии, чтобы видеть.) Расчет at можно разбить следующим образом:

table(data) это число строк в каждой группе, а sort(table(data)) помещает их в том порядке, в котором они будут отображаться. Принимая cumsum(), это дает нам края каждого стержня, когда они сложены друг на друга, а умножение на 0,5 дает нам половину высоты каждого бара в стеке (или половину ширины клиньев пирога).

as.numeric() просто гарантирует, что у нас есть числовой вектор, а не объект класса table.

Вычитание полуширины из кумулятивных высот дает центрам каждый стержень при складывании. Но ggplot будет складывать бары с самым большим на дне, тогда как все наши sort() ing ставят самые маленькие, поэтому нам нужно сделать nrow - все, потому что то, что мы на самом деле вычисляем, это позиции ярлыков относительно top на панели , а не снизу. (И, с исходными дезагрегированными данными, - это общее количество строк, следовательно, общая высота бара.)

+0

большое спасибо !! Я сошел с ума, чтобы сделать это. Я ноб с библиотекой ggplot2. – pescobar

+0

@Gregor не могли бы вы объяснить, что делает ваш код при расчете 'at'? Большое спасибо. –

+1

@info_seekeR добавил несколько абзацев внизу, посмотрим, поможет ли это. – Gregor

9

Предисловие: Я не делал круговые диаграммы по своей собственной воле.

Вот модификация функции ggpie, которая включает в себя проценты:

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) 
} 

Пример:

# 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) 

Так же, как типичный 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

Это отличное кодирование. У меня проблемы со всеми решениями, где моя диаграмма кажется построенной против часовой стрелки, но мои метки по часовой стрелке? Спасибо – atclaus

+0

Я попытался изменить направление полярности с 'direction = -1', но, похоже, перевернул оба процента и направление, поэтому я получаю ту же проблему. – atclaus

+2

Решил @Reno. Я изменил следующую строку: 'label_pos = sum (perc) - cumsum (perc) + perc/2' – atclaus

0

Он работал на всех включенных функций сильно вдохновлен от 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) 
} ; 

Пример:

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

Output

Смежные вопросы