ggplot, facet, piechart: colocando o texto no meio das fatias do gráfico de pizza

Eu estou tentando produzir um gráfico de pizza facetada com ggplot e enfrentando problemas com a colocação de texto no meio de cada fatia:

dat = read.table(text = "Channel Volume Cnt AGENT high 8344 AGENT medium 5448 AGENT low 23823 KIOSK high 19275 KIOSK medium 13554 KIOSK low 38293", header=TRUE) vis = ggplot(data=dat, aes(x=factor(1), y=Cnt, fill=Volume)) + geom_bar(stat="identity", position="fill") + coord_polar(theta="y") + facet_grid(Channel~.) + geom_text(aes(x=factor(1), y=Cnt, label=Cnt, ymax=Cnt), position=position_fill(width=1)) 

A saída: insira a descrição da imagem aqui

Que parâmetros de geom_text devem ser ajustados para colocar labels numéricos no meio de fatias de charts?

A questão relacionada é o gráfico de pizza ficando o texto um em cima do outro, mas ele não manipula o caso com a faceta.

ATUALIZAÇÃO: seguindo o conselho e abordagem de Paul Hiemstra na pergunta acima, alterei o código da seguinte forma:

 ---> pie_text = dat$Cnt/2 + c(0,cumsum(dat$Cnt)[-length(dat$Cnt)]) vis = ggplot(data=dat, aes(x=factor(1), y=Cnt, fill=Volume)) + geom_bar(stat="identity", position="fill") + coord_polar(theta="y") + facet_grid(Channel~.) + geom_text(aes(x=factor(1), ---> y=pie_text, label=Cnt, ymax=Cnt), position=position_fill(width=1)) 

Como eu esperava tweaking texto coordiantes é absoluta, mas precisa estar dentro de dados faceta: insira a descrição da imagem aqui

NOVA RESPOSTA: Com a introdução do ggplot2 v2.2.0 , position_stack() pode ser usado para posicionar as etiquetas sem a necessidade de calcular uma variável de posição primeiro. O código a seguir fornecerá o mesmo resultado da resposta antiga:

 ggplot(data = dat, aes(x = "", y = Cnt, fill = Volume)) + geom_bar(stat = "identity") + geom_text(aes(label = Cnt), position = position_stack(vjust = 0.5)) + coord_polar(theta = "y") + facet_grid(Channel ~ ., scales = "free") 

Para remover o centro “oco”, adapte o código para:

 ggplot(data = dat, aes(x = 0, y = Cnt, fill = Volume)) + geom_bar(stat = "identity") + geom_text(aes(label = Cnt), position = position_stack(vjust = 0.5)) + scale_x_continuous(expand = c(0,0)) + coord_polar(theta = "y") + facet_grid(Channel ~ ., scales = "free") 

RESPOSTA ANTIGA: A solução para este problema é criar uma variável de posição, que pode ser feita facilmente com base em R ou com os pacotes data.table , plyr ou dplyr :

Etapa 1: criando a variável de posição para cada canal

 # with base R dat$pos <- with(dat, ave(Cnt, Channel, FUN = function(x) cumsum(x) - 0.5*x)) # with the data.table package library(data.table) setDT(dat) dat <- dat[, pos:=cumsum(Cnt)-0.5*Cnt, by="Channel"] # with the plyr package library(plyr) dat <- ddply(dat, .(Channel), transform, pos=cumsum(Cnt)-0.5*Cnt) # with the dplyr package library(dplyr) dat <- dat %>% group_by(Channel) %>% mutate(pos=cumsum(Cnt)-0.5*Cnt) 

Passo 2: Criando o gráfico facetado

 library(ggplot2) ggplot(data = dat) + geom_bar(aes(x = "", y = Cnt, fill = Volume), stat = "identity") + geom_text(aes(x = "", y = pos, label = Cnt)) + coord_polar(theta = "y") + facet_grid(Channel ~ ., scales = "free") 

O resultado:

insira a descrição da imagem aqui

Eu gostaria de falar contra o modo convencional de fazer tortas em ggplot2, que é desenhar um gráfico de barras empilhadas em coordenadas polares. Embora eu aprecie a elegância matemática dessa abordagem, ela causa todos os tipos de dores de cabeça quando o enredo não parece exatamente como deveria. Em particular, ajustar com precisão o tamanho da pizza pode ser difícil. (Se você não sabe o que quero dizer, tente criar um gráfico de pizza que se estenda até a borda do painel de plotagem.)

Eu prefiro desenhar tortas em um sistema de coordenadas cartesiano normal, usando geom_arc_bar() de ggforce. Isso requer um pouco de trabalho extra no front end, porque temos que calcular os ângulos, mas isso é fácil e o nível de controle que obtemos como resultado é mais do que valido a pena. Eu usei essa abordagem em respostas anteriores aqui e aqui.

Os dados (da pergunta):

 dat = read.table(text = "Channel Volume Cnt AGENT high 8344 AGENT medium 5448 AGENT low 23823 KIOSK high 19275 KIOSK medium 13554 KIOSK low 38293", header=TRUE) 

O código de desenho de pizza:

 library(ggplot2) library(ggforce) library(dplyr) # calculate the start and end angles for each pie dat_pies <- left_join(dat, dat %>% group_by(Channel) %>% summarize(Cnt_total = sum(Cnt))) %>% group_by(Channel) %>% mutate(end_angle = 2*pi*cumsum(Cnt)/Cnt_total, # ending angle for each pie slice start_angle = lag(end_angle, default = 0), # starting angle for each pie slice mid_angle = 0.5*(start_angle + end_angle)) # middle of each pie slice, for the text label rpie = 1 # pie radius rlabel = 0.6 * rpie # radius of the labels; a number slightly larger than 0.5 seems to work better, # but 0.5 would place it exactly in the middle as the question asks for. # draw the pies ggplot(dat_pies) + geom_arc_bar(aes(x0 = 0, y0 = 0, r0 = 0, r = rpie, start = start_angle, end = end_angle, fill = Volume)) + geom_text(aes(x = rlabel*sin(mid_angle), y = rlabel*cos(mid_angle), label = Cnt), hjust = 0.5, vjust = 0.5) + coord_fixed() + scale_x_continuous(limits = c(-1, 1), name = "", breaks = NULL, labels = NULL) + scale_y_continuous(limits = c(-1, 1), name = "", breaks = NULL, labels = NULL) + facet_grid(Channel~.) 

insira a descrição da imagem aqui

Para mostrar por que eu acho que essa abordagem é muito mais poderosa do que a abordagem convencional ( coord_polar() ), digamos que queremos os labels do lado de fora do bolo, e não do lado de dentro. Isso cria um par de problemas, como teremos que ajustar o hjust e o vjust dependendo do lado da torta que um label cai, e também teremos que fazer o painel de plotagem mais largo do que alto para dar espaço para os labels no lado sem gerar espaço excessivo acima e abaixo. Resolver esses problemas na abordagem de coordenadas polares não é divertido, mas é trivial nas coordenadas cartesianas:

 # generate hjust and vjust settings depending on the quadrant into which each # label falls dat_pies <- mutate(dat_pies, hjust = ifelse(mid_angle>pi, 1, 0), vjust = ifelse(mid_angle3*pi/2, 0, 1)) rlabel = 1.05 * rpie # now we place labels outside of the pies ggplot(dat_pies) + geom_arc_bar(aes(x0 = 0, y0 = 0, r0 = 0, r = rpie, start = start_angle, end = end_angle, fill = Volume)) + geom_text(aes(x = rlabel*sin(mid_angle), y = rlabel*cos(mid_angle), label = Cnt, hjust = hjust, vjust = vjust)) + coord_fixed() + scale_x_continuous(limits = c(-1.5, 1.4), name = "", breaks = NULL, labels = NULL) + scale_y_continuous(limits = c(-1, 1), name = "", breaks = NULL, labels = NULL) + facet_grid(Channel~.) 

insira a descrição da imagem aqui

Para ajustar a posição do texto da etiqueta em relação à coordenada, você pode usar os argumentos vjust e hjust de geom_text . Isso determinará a posição de todos os labels simultaneamente, portanto, isso pode não ser o que você precisa.

Como alternativa, você pode ajustar a coordenada do label. Defina um novo data.frame qual você calcula a média da coordenada Cnt ( label_x[i] = Cnt[i+1] + Cnt[i] ) para posicionar o label no centro da pizza em questão. Basta passar este novo data.frame para o geom_text em substituição ao data.frame original.

Além disso, os piecharts possuem algumas falhas de interpretação visual. Em geral eu não os usaria, especialmente onde existem boas alternativas, por exemplo, um dotplot:

 ggplot(dat, aes(x = Cnt, y = Volume)) + geom_point() + facet_wrap(~ Channel, ncol = 1) 

Por exemplo, a partir desta plotagem, é óbvio que o Cnt é mais alto para o Kiosk do que para o Agent, essa informação é perdida no gráfico de setores.

insira a descrição da imagem aqui

A resposta a seguir é parcial, desajeitada e não aceitarei. A esperança é que ele solicite uma solução melhor.

 text_KIOSK = dat$Cnt text_AGENT = dat$Cnt text_KIOSK[dat$Channel=='AGENT'] = 0 text_AGENT[dat$Channel=='KIOSK'] = 0 text_KIOSK = text_KIOSK/1.7 + c(0,cumsum(text_KIOSK)[-length(dat$Cnt)]) text_AGENT = text_AGENT/1.7 + c(0,cumsum(text_AGENT)[-length(dat$Cnt)]) text_KIOSK[dat$Channel=='AGENT'] = 0 text_AGENT[dat$Channel=='KIOSK'] = 0 pie_text = text_KIOSK + text_AGENT vis = ggplot(data=dat, aes(x=factor(1), y=Cnt, fill=Volume)) + geom_bar(stat="identity", position=position_fill(width=1)) + coord_polar(theta="y") + facet_grid(Channel~.) + geom_text(aes(y=pie_text, label=format(Cnt,format="d",big.mark=','), ymax=Inf), position=position_fill(width=1)) 

Ela produz o seguinte gráfico: insira a descrição da imagem aqui

Como você percebeu, não consigo mover as etiquetas para verde (baixo).

    Intereting Posts