I created a pie chart like so:
library(dplyr)
library(ggplot2)
#Data
data <- data.frame(my_val = c(10, 12, 4),
my_var = c("A1B", "H2C3+", "LO4"),
stringsAsFactors = F)
#Create variable
data <- data %>%
mutate(per=my_val/sum(my_val)) %>%
arrange(desc(my_var))
data$label <- scales::percent(data$per)
#Plot
ggplot(data=data)+
geom_bar(aes(x="", y=per, fill=my_var), stat="identity", width = 1)+
coord_polar("y", start=0)+
theme_void()+
geom_text(aes(x=1, y = cumsum(per) - per/2, label=label))
I would like to add the legend as a subscript like so:
my_lab <- c(expression(H['2'*'C'*phantom("+")]),
expression(A['1']*B),
expression(LO['4']))
How can I add it in my pie chart code above?
Put my_lab above (before) your plot. Index it for your labels.
my_lab <- c(expression(H['2'*'C'*phantom("+")]),
expression(A['1']*B),
expression(LO['4']))
ggplot(data=data) +
geom_bar(aes(x="", y=per, fill=my_var),
stat="identity", width = 1) +
coord_polar("y", start=0) +
theme_void() +
geom_text(aes(x=1, y = cumsum(per) - per/2,
label=label)) +
scale_fill_discrete(name="Variables",
labels=c(my_lab[1],
my_lab[2],
my_lab[3]))
Making use of a named vector you could do:
Note: For a nice (left) alignment of the legend labels I made use of guide_legend(label.hjust = 0).
library(ggplot2)
ggplot(data=data)+
geom_bar(aes(x="", y=per, fill=my_var), stat="identity", width = 1)+
coord_polar("y", start=0)+
theme_void()+
geom_text(aes(x=1, y = cumsum(per) - per/2, label=label)) +
scale_fill_discrete(labels = c(`H2C3+` = expression(H['2'*'C'*phantom("+")]),
A1B = expression(A['1']*B),
LO4 = expression(LO['4']))) +
guides(fill = guide_legend(label.hjust = 0))
Related
I have a pie chart below, and I would like to create the wheel much more readable. many thanks in advance.
library(ggplot2)
library(dplyr)
# Create Data
data <- data.frame(
group=c("IMAGINE HERE I HAVE A LONG SURVEY QUESTIONS",
"AND THE TEXT IS IN DIFFERENT LENGTH",
"WANNA PLOT THESE IN ORDER",
"WITH 45 DEGREE ANGLE",
"PIE CAN BE PROPORTIONAL WITH THE TEXT LENGTH" ),
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=1, color="white") +
coord_polar("y", start=0) +
theme_void() +
theme(legend.position="none") +
geom_text(aes(y = ypos, label = group), color = "white", size=6) +
scale_fill_brewer(palette="Set1")
You have a better chance of fitting in the labels if you wrap them using str_wrap and curve them using geomtextpath:
# Compute the position of labels
data <- data %>%
arrange(desc(group)) %>%
mutate(prop = value / sum(data$value) *100) %>%
mutate(ypos = cumsum(prop)- 0.5*prop,
group = stringr::str_wrap(group, 20))
library(geomtextpath)
# Basic piechart
ggplot(data, aes(x=1, y=prop, fill=group)) +
geom_bar(stat="identity", width=1, color="white") +
coord_polar("y", start=0) +
theme_void() +
theme(legend.position="none") +
geom_textpath(aes(x = 1.3, y = ypos, label = group,
vjust = group), color = "black", size = 6,
angle = 90) +
scale_fill_brewer(palette="Set1") +
scale_x_continuous(limits = c(0.5, 2)) +
scale_vjust_manual(values = c(2, 1.8, 2.2, 2, 4))
Maybe to wrap the group text and have it plotted in many lines of text is a way to solve the problem.
First strwrap breaks each value in group, then paste inserts newline characters at the break points.
And the graphics device dimensions are made larger, though it doesn't show with reprex.
suppressPackageStartupMessages({
library(ggplot2)
library(dplyr)
})
# Create Data
data <- data.frame(
group=c("IMAGINE HERE I HAVE A LONG SURVEY QUESTIONS",
"AND THE TEXT IS IN DIFFERENT LENGTH",
"WANNA PLOT THESE IN ORDER",
"WITH 45 DEGREE ANGLE",
"PIE CAN BE PROPORTIONAL WITH THE TEXT LENGTH" ),
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 )
data$group2 <- sapply(data$group, \(x) {
s <- strwrap(x, width = 15)
paste(s, collapse = "\n")
})
old_par <- par()[c("fin", "mar")]
par(fin = old_par$fin + 5, mar = rep(0, 4))
# Basic piechart
ggplot(data, aes(x="", y=prop, fill=group)) +
geom_bar(stat="identity", width=1, color="white") +
coord_polar("y", start=0) +
theme_void() +
theme(legend.position="none") +
geom_text(aes(y = ypos, label = group2), color = "white", size=3) +
scale_fill_brewer(palette="Set1")
par(old_par)
Created on 2022-05-29 by the reprex package (v2.0.1)
It is not the best option, but you could use geom_label_repel from ggrepel like this:
library(ggplot2)
library(dplyr)
library(ggrepel)
data <- data %>%
arrange(desc(group)) %>%
mutate(prop = value / sum(data$value) *100) %>%
mutate(ypos = cumsum(prop)- 0.5*prop )
ggplot(data, aes(x="", y=prop, fill=group)) +
geom_bar(stat="identity", width=1, color="white") +
coord_polar("y", start=0) +
theme_void() +
theme(legend.position="none") +
geom_label_repel(data = data,
aes(y = ypos, label = group),
size = 4.5, nudge_x = 3, show.legend = FALSE) +
scale_fill_brewer(palette="Set1")
Output:
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)
I am trying to create a pie chart with ggplot. I want to show how many hours I use for diffrent tasks at work everyday.
# Libraries
library(ggplot2)
library(tidyverse) # function "%>%"
# 1. Read data (semicolon separated)
res = read.csv2(text = "Activity;No_of_Hours
Work;3
Lunch;1
Meetings;2
Talking;1")
# 2. Print table
df <- as.data.frame(res)
df
# 3. Plot Pie chart
res %>% ggplot(aes(x="", # we leave x blank with ""
y= Activity,
fill=No_of_Hours)) +
geom_bar(stat="identity") +
coord_polar("y", start=0) +
theme_classic()
You can calculate the y position of labels with coord_polar and plot them with geom_text
df <- df %>%
arrange(desc(Activity)) %>%
mutate(prop = No_of_Hours / sum(df$No_of_Hours) *100) %>%
mutate(ypos = cumsum(prop)- 0.5*prop )
# 3. Plot Pie chart
ggplot(df, aes(x="", y=prop, fill=Activity)) +
geom_bar(stat="identity", width=1, color="white") +
coord_polar("y", start=0) +
theme_void() +
geom_text(aes(y = ypos, label = No_of_Hours), color = "white", size=6)
which give you:
Or more similar to your example (but IMHO less informative):
ggplot(df, aes(x="", y=prop, fill=No_of_Hours)) +
geom_bar(stat="identity", width=1, color="white") +
coord_polar("y", start=0) +
theme_void() +
geom_text(aes(y = ypos, label =Activity ), color = "white", size=6)
which give you:
I have a bar plot that has 12 x values. Using this code I get the plot I want except for the x-axis labels.
p <- ggplot(data=df.mean, aes(x=stock_name, y=invest_amnt, fill=trend_id)) +
geom_bar(stat="identity", position=position_dodge()) +
geom_errorbar(aes(ymin=invest_amnt-ic, ymax=invest_amnt+ic), width=.2,
position=position_dodge(.9))
p + scale_fill_brewer(palette="Paired") + theme_minimal() +
theme(text = element_text(size=12, hjust = 0.5, family="Times")) +
theme_stata() + scale_color_stata()
Instead of displaying all 12 values on the x-axis I want to determine the labels by myself and only display 4.
I adjusted the code like this
p <- ggplot(data=df.mean, aes(x=stock_name, y=invest_amnt, fill=trend_id)) +
geom_bar(stat="identity", position=position_dodge()) +
geom_errorbar(aes(ymin=invest_amnt-ic, ymax=invest_amnt+ic), width=.2,
position=position_dodge(.9)) +
scale_x_discrete( labels=c("UP\nDOWN", "DOWN\nUP", "STRAIGHT\nGAIN", "STRAIGHT\nLOSS")) +
scale_fill_discrete(name = "Trend", labels = c("negative", "flat", "positive"))
p + scale_fill_brewer(palette="Paired") + theme_minimal() +
theme(text = element_text(size=12, hjust = 0.5, family="Times")) +
theme_stata() + scale_color_stata()
Unfortunately, I get my 4 labels but also 8 NAs. I would like my 4 labels to be evenly spread on my x-axis. Since my labels are factors I do not know how to apply break here.
I've generated some sample data...hope I've understood the situation correctly.
This seems to work, i.e. inserts breaks at the specified locations on a barplot, using the specified labels.
library(tidyverse)
df <- tribble(~x, ~y,
'cat',10,
'dog', 20,
'rabbit', 30,
'fox', 30)
df <- df %>%
mutate(x = factor(x))
df %>% ggplot(aes(x,y))+
geom_bar(stat = 'identity') +
scale_x_discrete(breaks = c('cat','fox'), labels = c('pig', 'hen'))
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()