ggplot2 pie chart bad position of labels - r

Sample data
data <- data.frame(Country = c("Mexico","USA","Canada","Chile"), Per = c(15.5,75.3,5.2,4.0))
I tried set position of labels.
ggplot(data =data) +
geom_bar(aes(x = "", y = Per, fill = Country), stat = "identity", width = 1) +
coord_polar("y", start = 0) +
theme_void()+
geom_text(aes(x = 1.2, y = cumsum(Per), label = Per))
But pie chart actually look like:

You have to sort the data before calculating the cumulative sum. Then, you can optimize label position, e.g. by subtracting half of Per:
library(tidyverse)
data %>%
arrange(-Per) %>%
mutate(Per_cumsum=cumsum(Per)) %>%
ggplot(aes(x=1, y=Per, fill=Country)) +
geom_col() +
geom_text(aes(x=1,y = Per_cumsum-Per/2, label=Per)) +
coord_polar("y", start=0) +
theme_void()
PS: geom_col uses stat_identity by default: it leaves the data as is.
Or simply use position_stack
data %>%
ggplot(aes(x=1, y=Per, fill=Country)) +
geom_col() +
geom_text(aes(label = Per), position = position_stack(vjust = 0.5))+
coord_polar(theta = "y") +
theme_void()
From the help:
# To place text in the middle of each bar in a stacked barplot, you
# need to set the vjust parameter of position_stack()

Related

fancy pie chart in R using ggplot2

I have a pie chart below, and I would like to leave extra white space between each pie and paste the value of each letter in each pie (A=25). how to get around this? many thanks in advance.
library(ggplot2)
library(dplyr)
# Create Data
data <- data.frame(
group=LETTERS[1:5],
value=c(13,7,9,21,2)
)
# Compute the position of labels
data <- data %>%
arrange(desc(group)) %>%
mutate(prop = value / sum(data$value) *100) %>%
mutate(ypos = cumsum(prop)- 0.5*prop )
# Basic piechart
ggplot(data, aes(x="", y=prop, fill=group)) +
geom_bar(stat="identity", width=10, color="white") +
coord_polar("y", start=0) +
theme_void() +
theme(legend.position="none") +
geom_text(aes(y = ypos, label = round(prop,2) ), color = "white", size=4) +
scale_fill_brewer(palette="Set1")
You could do:
ggplot(data, aes(x="", y=prop, fill=group)) +
geom_bar(stat="identity", width=10, size = 3, color = "white") +
coord_polar("y", start=0) +
theme_void() +
theme(legend.position="none") +
geom_text(aes(y = ypos, label = paste(group, round(prop,2), sep = "\n")),
color = "white", size=4, nudge_x = 3) +
scale_fill_brewer(palette="Set1")
Perhaps 3D pie chart in base R can work with explode argument set to true, e.g.
pie3D(num_data, labels = num_data, explode = 0.25)

How can I add a a nested y-axis title in my graph?

I created a ggplot graph using ggsegment for certain subcategories and their cost.
df <- data.frame(category = c("A","A","A","A","A","A","B","B","B","B","B","B","B"),
subcat = c("S1","S2","S3","S4","S5","S6","S7","S8","S9","S10","S11","S12","S13"),
value = c(100,200,300,400,500,600,700,800,900,1000,1100,1200,1300))
df2 <- df %>%
arrange(desc(value)) %>%
mutate(subcat=factor(subcat, levels = subcat)) %>%
ggplot(aes(x=subcat, y=value)) +
geom_segment(aes(xend=subcat, yend=0)) +
geom_point(size=4, color="steelblue") +
geom_text(data=df, aes(x=subcat, y=value, label = dollar(value, accuracy = 1)), position = position_nudge(x = -0.3), hjust = "inward") +
theme_classic() +
coord_flip() +
scale_y_continuous(labels = scales::dollar_format()) +
ylab("Cost Value") +
xlab("subcategory")
df2
This code results in a graph that is shown below:
My main issue is I want the category variable on the left of the subcategory variables. It should look like this:
How do I add the category variables in the y-axis, such that it looks nested?
As mentioned in my comment and adapting this post by #AllanCameron to your case one option to achieve your desired result would be the "facet trick", which uses faceting to get the nesting and some styling to remove the facet look:
Facet by category and free the scales and the space so that the distance between categories is the same.
Remove the spacing between panels and place the strip text outside of the axis text.
Additionally, set the expansion of the discrete x scale to .5 to ensure that the distance between categories is the same at the facet boundaries as inside the facets.
library(dplyr)
library(ggplot2)
library(scales)
df1 <- df %>%
arrange(desc(value)) %>%
mutate(subcat=factor(subcat, levels = subcat))
ggplot(df1, aes(x=subcat, y=value)) +
geom_segment(aes(xend=subcat, yend=0)) +
geom_point(size=4, color="steelblue") +
geom_text(data=df, aes(x=subcat, y=value, label = dollar(value, accuracy = 1)), position = position_nudge(x = -0.3), hjust = "inward") +
theme_classic() +
coord_flip() +
scale_y_continuous(labels = scales::dollar_format()) +
scale_x_discrete(expand = c(0, .5)) +
facet_grid(category~., scales = "free_y", switch = "y", space = "free_y") +
ylab("Cost Value") +
xlab("subcategory") +
theme(panel.spacing.y = unit(0, "pt"), strip.placement = "outside")

How to show value label in stacked and grouped bar chart using ggplot

My question is about how to show data (or value) labels in a stacked and grouped bar chart using ggplot. The chart is in the form of what has been resolved here stacked bars within grouped bar chart .
The code for producing the chart can be found in the first answer of the question in the above link. An example data set is also given in the question in the link. To show the value labels, I tried to extend that code with
+ geom_text(aes(label=value), position=position_dodge(width=0.9), vjust=-0.25)
but this does not work for me. I greatly appreciate any help on this.
You need to move data and aesthetics from geom_bar() up to ggplot() so that geom_text() can use it.
ggplot(data=test, aes(y = value, x = cat, fill = cond)) +
geom_bar(stat = "identity", position = "stack") +
theme_bw() +
facet_grid( ~ year) +
geom_text(aes(label = value), position = "stack")
Then you can play around with labels, e.g. omitting the zeros:
ggplot(data=test, aes(y = value, x = cat, fill = cond)) +
geom_bar(stat = "identity", position = "stack") +
theme_bw() +
facet_grid( ~ year) +
geom_text(aes(label = ifelse(value != 0, value, "")), position = "stack")
... and adjusting the position by vjust:
ggplot(data=test, aes(y = value, x = cat, fill = cond)) +
geom_bar(stat = "identity", position = "stack") +
theme_bw() +
facet_grid( ~ year) +
geom_text(aes(label = ifelse(value != 0, value, "")), position = "stack", vjust = -0.3)
Try this. Probably the trick is to use position_stack in geom_text.
library(tidyverse)
test <- expand.grid('cat' = LETTERS[1:5], 'cond'= c(F,T), 'year' = 2001:2005)
test$value <- floor((rnorm(nrow(test)))*100)
test$value[test$value < 0] <- 0
ggplot(test, aes(y = value, x = cat, fill = cond)) +
geom_bar(stat="identity", position='stack') +
geom_text(aes(label = ifelse(value > 0, value, "")), position = position_stack(), vjust=-0.25) +
theme_bw() +
facet_grid( ~ year)
Created on 2020-06-05 by the reprex package (v0.3.0)

Plotting multiple Pie Charts with label in one plot

I came across this question the other day and tried to re-create it for myself. ggplot, facet, piechart: placing text in the middle of pie chart slices
. My data is in a very similar format, but sadly the accepted answer did not help, hence why I am re posting.
I essentially want to create the accepted answer but with my own data, yet the issue I run into is that coord_polar does not support free scale. Using the first answer:
I tried it using the second version of the answer, with the ddplyr version, but I also do not get my desired output. Using the second answer:
Clearly none of these has the desired effect. I would prefer to create one as with size pie charts, but only showed four as an example, follows: .
This I did in excel, but with one legend, and no background grid.
Code
title<-c(1,1,2,2,3,3,4,4,5,5,6,6)
type<-c('A','B','A','B','A','B','A','B','A','B','A','B')
value<-c(0.25,0.75,0.3,0.7,0.4,0.6,0.5,0.5,0.1,0.9,0.15,0.85)
piec<-data.frame(title,type,value)
library(tidyverse)
p1<-ggplot(data = piec, aes(x = "", y = value, fill = type)) +
geom_bar(stat = "identity") +
geom_text(aes(label = value), position = position_stack(vjust = 0.5)) +
coord_polar(theta = "y")
#facet_grid(title ~ ., scales = "free")
p1
piec <- piec %>% group_by(title) %>% mutate(pos=cumsum(value)-0.5*value)
p2<-ggplot(data = piec) +
geom_bar(aes(x = "", y = value, fill = type), stat = "identity") +
geom_text(aes(x = "", y = pos, label = value)) +
coord_polar(theta = "y")
#facet_grid(Channel ~ ., scales = "free")
p2
You don't have to supply different y values for geom_text and geom_bar (use y = value for both of them). Next you have to specify position in geom_text. Finally, remove scales from facets.
library(ggplot2)
title<-c(1,1,2,2,3,3,4,4,5,5,6,6)
type<-c('A','B','A','B','A','B','A','B','A','B','A','B')
value<-c(0.25,0.75,0.3,0.7,0.4,0.6,0.5,0.5,0.1,0.9,0.15,0.85)
piec<-data.frame(title,type,value)
ggplot(piec, aes("", value, fill = type)) +
geom_bar(stat = "identity", color = "white", size = 1) +
geom_text(aes(label = paste0(value * 100, "%")),
position = position_stack(vjust = 0.5),
color = "white", size = 3) +
coord_polar(theta = "y") +
facet_wrap(~ title, ncol = 3) +
scale_fill_manual(values = c("#0048cc", "#cc8400")) +
theme_void()

Annotation above bars:

dodged bar plot in ggplot again has me stumped. I asked about annotating text above bars on here a few weeks back (LINK) and got a terrific response to use + stat_bin(geom="text", aes(label=..count.., vjust=-1)). I figured since I already have the counts I'll just supply them with out the .. before and after and I told stat_bin that the position was dodge. It lines them up over the center of the group and adjusts up and down. Probably something minor. Please help me to get the text over the bars.
mtcars2 <- data.frame(type=factor(mtcars$cyl),
group=factor(mtcars$gear))
library(plyr); library(ggplot)
dat <- rbind(ddply(mtcars2,.(type,group), summarise,
count = length(group)),c(8,4,NA))
p2 <- ggplot(dat,aes(x = type,y = count,fill = group)) +
geom_bar(colour = "black",position = "dodge",stat = "identity") +
stat_bin(geom="text", aes(position='dodge', label=count, vjust=-.6))
I was having trouble getting the position dodges to line up, so I ended up creating a position_dodge object (is that the right terminology?), saving it to a variable, and then using that as the position for both geoms. Somewhat infuriatingly, they still seem to be a little off centre.
dodgewidth <- position_dodge(width=0.9)
ggplot(dat,aes(x = type,y = count, fill = group)) +
geom_bar(colour = "black", position = dodgewidth ,stat = "identity") +
stat_bin(geom="text", position= dodgewidth, aes(x=type, label=count), vjust=-1)
Updated geom_bar() needs stat = "identity"
I think this does what you want as well.
mtcars2 <- data.frame(type = factor(mtcars$cyl), group = factor(mtcars$gear))
library(plyr); library(ggplot2)
dat <- rbind(ddply(mtcars2, .(type, group), summarise, count = length(group)), c(8, 4, NA))
p2 <- ggplot(dat, aes(x = type,y = count,fill = group)) +
geom_bar(stat = "identity", colour = "black",position = "dodge", width = 0.8) +
ylim(0, 14) +
geom_text(aes(label = count, x = type, y = count), position = position_dodge(width = 0.8), vjust = -0.6)
p2

Resources