I am working on a donut chart using ggplot2, but I need the center of the plot to contain text.
Here's sample data (found from this site: https://www.datanovia.com/en/blog/how-to-create-a-pie-chart-in-r-using-ggplot2/):
library(dplyr)
count.data <- data.frame(
class = c("1st", "2nd", "3rd", "Crew"),
n = c(325, 285, 706, 885),
prop = c(14.8, 12.9, 32.1, 40.2)
)
count.data <- count.data %>%
arrange(desc(class)) %>%
mutate(lab.ypos = cumsum(prop) - 0.5*prop)
count.data
I then modified their code to get this donut chart:
library(ggplot2)
library(dplyr)
mycols <- c("#0073C2FF", "#EFC000FF", "#868686FF", "#CD534CFF")
ggplot(count.data, aes(x = 2, y = prop, fill = class)) +
geom_bar(stat = "identity", color = "white") +
coord_polar(theta = "y", start = 0)+
geom_text(aes(y = lab.ypos, label = paste0("n = ", n, ", \n", prop, "%")), color = "white")+
scale_fill_manual(values = mycols) +
theme_void() +
xlim(.5, 2.5)
The plot looks like this:
It is exactly what I want except I need the center of the donut to have the proportion from a variable. In this case, I want the center to say 40.2% (the prop of crew, in this example).
How do I do this?
Edit
Used annotate as suggested by #aosmith and made it a direct call to crew.
like this?
ggplot(count.data, aes(x = 2, y = prop, fill = class)) +
geom_bar(stat = "identity", color = "white") +
coord_polar(theta = "y", start = 0)+
geom_text(aes(y = lab.ypos, label = paste0("n = ", n, ", \n", prop, "%")), color = "white")+
scale_fill_manual(values = mycols) +
theme_void() +
xlim(.5, 2.5) +
annotate(geom = 'text', x = 0.5, y = 0, label = paste0(count.data$prop[count.data$class == 'Crew'], "%"))
Related
I've been trying for a while now and also doing a lot of research, but I just can't get it to add a simple legend for my two lines.
I have two lines in my chart and I just want to add a legend for the two lines.
scale_color_manual did not work. I suspect it is because I am using scale_y_break. In other plots (without scale_y_break) scale_color_manual works without problems.
Here is my code:
day <- c(1:5)
altimeter <- c(8.291, 8.872, 7.212, 8.1, 5.92)
slope_kilometers <- c(30.23, 34.8, 29.34, 32.98, 21.23)
df2 <- data.frame(day, altimeter, slope_kilometers)
library(ggbreak)
altimeter_color <- "steelblue"
slope_kilometers_color <- "darkred"
ggplot(df2, aes(x = day)) +
#Altimeter data
geom_line(aes(y = altimeter),
linetype = 2,
linewidth = 1,
color = altimeter_color) +
geom_point(y = altimeter, size = 3, color = altimeter_color) +
#Slope kilometers data
geom_line(aes(y = slope_kilometers),
linetype = 2,
linewidth = 1,
color = slope_kilometers_color) +
geom_point(y = slope_kilometers, size = 3, color = slope_kilometers_color) +
#Y-Axis
scale_y_break( c(9, 20), scales = 1.5) +
#Label
labs(x = "Tage",
y = "[km]") +
#Legend
scale_color_manual(values = c(altimeter_color, slope_kilometers_color)) +
#Title
ggtitle("Höhenmeter und Pistenkilometer meines 5-tägigen Skiurlaubs")
I tried different versions of scale_color_manual, labs, aes(fill="")
Update: I tweaked the former plot (removed):
One way to achieve what you want is:
First bring data in long format then put color inside aesthetics:
Rule of thumb: What is in aesthetics will have a legend:
library(tidyverse)
library(ggbreak)
df2 %>%
pivot_longer(-day) %>%
ggplot(aes(x = day)) +
#Altimeter data
geom_line(data = . %>% filter(name == "altimeter"), aes(y = altimeter, color = name),
linetype = 2, linewidth = 1 ) +
geom_point(data = . %>% filter(name == "altimeter"), aes(y = altimeter, color = name), size = 3) +
#Slope kilometers data
geom_line(data = . %>% filter(name == "slope_kilometers"), aes(y = slope_kilometers, color = name),
linetype = 2, linewidth = 1) +
geom_point(data = . %>% filter(name == "slope_kilometers"), aes(y = slope_kilometers, color = name), size = 3) +
#Y-Axis
scale_y_break( c(9, 20), scales = 1.5) +
#Label
labs(x = "Tage", y = "[km]", color = "") +
#Legend
scale_color_manual(values = c(altimeter_color, slope_kilometers_color)) +
#Title
ggtitle("Höhenmeter und Pistenkilometer meines 5-tägigen Skiurlaubs") +
theme(legend.position = "bottom")
Let say I have below bar chart
require(ggplot2)
require(dplyr)
df <- data.frame (Origin = c("Canada", "Canada","USA","USA"),
Year = c("2021", "2022","2021","2022"),
Sales = c(103, 192, 144, 210),
diff = c(89, " ",66," "),
perdiff = c(86.4, " ",45.83," "))
df <- df %>% mutate(label= ifelse(diff!=" ",paste0(diff,", ",perdiff,'%'),NA))
ggplot(df, aes(fill=Year, y=Origin, x=Sales)) +
geom_bar(position="dodge", stat="identity")+
geom_text(aes(label=label, x=200), fontface='bold') +
scale_x_continuous(breaks=seq(0,200,25))+
theme()
While this is fine, I want to add coloured underline under the figures (e.g. 89, 86.4%) which are displayed at the right side of each bar. I should also be able to control the width of such an underline.
Is there any way to achieve this programmatically?
Any pointer will be really helpful
Not sure what you mean by "control the width of such an underline". But one option to add colored underlines to your labels would to add your colored underlines a second geom_text where I use plotmath's underline and phantom to just add the underlines.
library(ggplot2)
library(dplyr)
df <- df %>%
mutate(label = ifelse(diff != " ", paste0(diff, ", ", perdiff, "%"), NA)) %>%
mutate(label1 = ifelse(diff != " ", paste0("underline(bold(phantom(\"", diff, ", ", perdiff, "%", "\")))"), NA))
ggplot(df, aes(fill = Year, y = Origin, x = Sales)) +
geom_bar(position = "dodge", stat = "identity") +
geom_text(aes(label = label, x = 200), fontface = "bold") +
geom_text(aes(label = label1, x = 200), color = "red", parse = TRUE) +
scale_x_continuous(breaks = seq(0, 200, 25))
#> Warning: Removed 2 rows containing missing values (geom_text).
#> Removed 2 rows containing missing values (geom_text).
EDIT To add some padding between the label and the line you could increase the vjust in the second geom_text, e.g.:
ggplot(df, aes(fill = Year, y = Origin, x = Sales)) +
geom_bar(position = "dodge", stat = "identity") +
geom_text(aes(label = label, x = 200), fontface = "bold") +
geom_text(aes(label = label1, x = 200), color = "red", parse = TRUE, vjust = 1) +
scale_x_continuous(breaks = seq(0, 200, 25))
I have this code:
as_tibble(earlyCiliated[[]]) %>%
ggplot(aes(x="", y=Phase, fill=Phase)) + geom_col() +
coord_polar("y", start=0) +
geom_text(aes(label = paste0(Phase, "%")))
and my output looks like this:
What am I doing wrong that's causing the labels to all be on top of each other?
I can't completely recreate your plot because I do not have your data. That being said, you can try this:
install.packages("ggrepel")
library(ggrepel)
as_tibble(earlyCiliated[[]]) %>%
ggplot(aes(x="", y=Phase, fill=Phase)) + geom_col() +
coord_polar("y", start=0) +
geom_label_repel(data = earlyCiliated[[]],
aes(y = Phase, label = paste0(Phase, "%")),
size = 4.5, nudge_x = 1, show.legend = FALSE)
This is what it will look like (using other data because none was provided)
library(ggplot2)
library(ggrepel)
library(tidyverse)
df <- data.frame(value = c(15, 25, 32, 28),
group = paste0("G", 1:4))
# Get the positions
df2 <- df %>%
mutate(csum = rev(cumsum(rev(value))),
pos = value/2 + lead(csum, 1),
pos = if_else(is.na(pos), value/2, pos))
ggplot(df, aes(x = "" , y = value, fill = fct_inorder(group))) +
geom_col(width = 1, color = 1) +
coord_polar(theta = "y") +
scale_fill_brewer(palette = "Pastel1") +
geom_label_repel(data = df2,
aes(y = pos, label = paste0(value, "%")),
size = 4.5, nudge_x = 1, show.legend = FALSE) +
guides(fill = guide_legend(title = "Group")) +
theme_void()
For the data frame below, how can I display labels outside the circle with arrows pointing at them?
asd <- data.frame(a=c("fs","dfg","gf"), b=c(3,5,6))
ggplot(asd, aes(x="", y= b, fill = factor(a))) +
geom_bar(stat = "identity", width =1) +
coord_polar(theta = "y") + theme_void() +
geom_text(aes(label=paste(a, sep = " ", b, "%"), x= 1.3, angle = 0))
Try with this:
library(ggplot2)
library(dplyr)
asd <- data.frame(a = c("fs","dfg","gf"),
b = c(3,10,5)) # changed to show that order doesnt matter
asd %>%
mutate(prop = b/sum(b)) %>%
arrange(desc(a)) %>%
mutate(lab.ypos = cumsum(prop) - 0.5*prop) %>%
ggplot(aes(x = "", y = prop, fill = a)) +
geom_bar(width = 1, stat = "identity", color = "white") +
coord_polar("y", start = 0, clip = "off")+
geom_segment(aes(x = 1, y = lab.ypos, xend = 2, yend = lab.ypos, colour = a),
size = 1) +
geom_label(aes(y = lab.ypos, label = paste(a, scales::percent(prop))),
x = 2,
size = 5,
color = "white") +
theme_void() +
theme(legend.position = "none")
For the record: don't use pie chart.
There is a reason why doing a pie chart is complicated: you are not supposed to use them.
Bar charts are always better.
df.test <- data.frame(val=c(0.55,0.42,-0.05),name=letters[1:3],
desc='This is the description of values'
p <- ggplot(df.test, aes(name, val, label = desc)) +
geom_bar(stat = "identity", col = 'black', fill = 'lightgreen') +
labs(title = "Test", x = " ", y = "value", fill = "") +
theme_bw() +
guides(fill = FALSE)
p + geom_text(angle = 90, size = 8, hjust = 1.25, position = position_dodge(width = 0.9))
This generates the following plot:
I want to align the text and force the it to start at the beginning of each chart, so that all of them can be visible (it is ok if it falls outside the small chart). How can I achieve this?
Is this what you're looking for?
p <- ggplot(df.test,aes(name,val,label=desc))+
geom_bar(stat="identity",col='black',fill='lightgreen')+
labs(title = "Test", x = " ", y = "value",fill = "")+
theme_bw()+
guides(fill=FALSE)
p+geom_text(angle=90,size=8,hjust=0,aes(x=name,y=rep(0,nrow(df.test)),label=desc),inherit.aes=F)