ggplot pie chart choose axes ticks - r

I would like to know if it's possible to modify the ticks of x axis with a ggplot pie chart.
Here what I can do :
# Some colors
couleurs <- data.frame(
id=seq(1,17,1),
mix=c(c(rep(1,6),rep(2,7),rep(3,4))),
html=c("#A00020","#109618","#388EE4","#C484D1","#FFAA33","#CCCDD0","#004AC5","#F80094","#CB5023","#638995","#33CFCF","#95DC4E","#F7D633","#5C403C","#F72020","#00D96C","#FDE4C5")
)
couleurs$html <- factor(couleurs$html, levels = couleurs$html[order(couleurs$id, decreasing = FALSE)])
# Data
activite <- data.frame(label=c("B to B","B to C","B to B / B to C", "B to B"), cible=c(rep("Externe",3), "Interne"), nb=c(12,9,3,12))
activite$label <- factor(activite$label, levels = activite$label[order(activite$nb[activite$cible=="Externe"], decreasing = TRUE)])
library(plyr)
activite<-ddply(activite,.(cible),transform,pc=(nb/sum(nb))*100)
activite
# Pie chart
library(ggplot2)
ggplot(data = activite, aes(x = "", y = nb, fill = label )) +
geom_bar(stat = "identity", position = position_fill(), width = 1) +
coord_polar(theta= "y", start = 0, direction = -1) +
labs(fill="") +
scale_fill_manual(values=as.character(couleurs$html[1:nrow(activite)]), labels=paste(activite$label,"\t\t\t",sep="")) +
geom_text(aes(label = paste(pc,"%", sep=" ")), size=4, colour = "white", fontface = "bold", position = position_fill(vjust = 0.5)) +
theme(strip.text = element_text(size=20, face = "bold", ), strip.background = element_rect(fill="grey75")) +
theme(panel.background = element_rect(fill = "white")) +
theme(plot.background = element_rect(fill = "grey92")) +
theme(legend.position="bottom", legend.background = element_rect(fill="grey92")) +
theme(legend.key = element_blank()) +
theme(panel.grid.minor = element_blank(), panel.grid.major = element_line(colour = "grey75")) +
theme(axis.text.y = element_blank()) +
theme(axis.ticks.length = unit(0, "mm")) +
theme(axis.title.x = element_blank(),axis.title.y = element_blank()) +
theme(legend.box.spacing = unit(1, "mm")) +
facet_wrap(~ cible)
Here my result:
After several hours of serach, I didn't find a solution to create what I want. The exact same pie chart but with personalised ticks like that :
With these particular conditions :
- do not change the direction of the data in the pie chart, I want it like exactly this
- if possible (but if not possible, it's okay), I would like the ticks' labels not superposed with the axis.
If someone can help me, I would really appreciate.

Here's one solution:
ggplot(data = activite %>%
group_by(cible) %>%
arrange(desc(nb)) %>%
mutate(axis.label = cumsum(nb),
axis.position = cumsum(pc)/100) %>%
mutate(axis.label = ifelse(pc == min(pc),
paste(axis.label, "0", sep = "-"),
axis.label)),
aes(x = 1, y = nb, fill = label )) +
geom_segment(aes(x = 1, xend = 1.6, y = axis.position, yend = axis.position),
colour = "grey75") +
geom_vline(xintercept = 1.6, colour = "grey75") +
geom_bar(stat = "identity", position = position_fill(reverse = T), width = 1) +
coord_polar(theta= "y", start = 0, direction = 1) +
labs(fill="") +
scale_fill_manual(values=as.character(couleurs$html[1:nrow(activite)]), labels=paste(activite$label,"\t\t\t",sep="")) +
geom_text(aes(label = paste(pc,"%", sep=" ")), size=4, colour = "white",
fontface = "bold", position = position_fill(vjust = 0.5, reverse = T)) +
geom_text(aes(x = 1.7, label = axis.label), size = 3,
position = position_fill(reverse = T)) +
theme(strip.text = element_text(size=20, face = "bold", ), strip.background = element_rect(fill="grey75")) +
theme(panel.background = element_rect(fill = "white")) +
theme(plot.background = element_rect(fill = "grey92")) +
theme(legend.position="bottom", legend.background = element_rect(fill="grey92")) +
theme(legend.key = element_blank()) +
theme(panel.grid = element_blank()) +
theme(axis.text = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(axis.title = element_blank()) +
theme(legend.box.spacing = unit(1, "mm")) +
facet_wrap(~ cible)
Explanation:
The sequence in your labels went clockwise, while the direction of the polar coordinates went counter-clockwise. That makes labelling rather troublesome. I switched the direction for polar coordinates, & added reverse = T inside the position adjustment calls for the geoms.
It's hard to assign different axis breaks to different facets of the same plot, so I didn't. Instead, I modified the data to include calculated axis labels / margin positions, added margins via geom_segment / geom_vline, & hid the axis text / ticks in theme().

Related

How to set a conditional size scale based on name in ggplot?

Below is a simple bubble plot for three character traits (Lg_chr, Mid_chr, and Sm_chr) across three locations.
All good, except that because the range of Lg_chr is several orders of magnitude larger than the ranges for the other two traits, it swamps out the area differences between the smaller states, making the differences very difficult to see - for example, the area of the points for for Location_3's Mid_chr (70) and Sm_chr (5), look almost the same.
Is there a way to set a conditional size scale based on name in ggplot2 without having to facit wrap them? Maybe a conditional statement for scale_size_continuous(range = c(<>, <>)) separately for Lg_chr, Mid_chr, and Sm_chr?
test_df = data.frame(lg_chr = c(100000, 150000, 190000),
mid_chr = c(50, 90, 70),
sm_chr = c(15, 10, 5),
names = c("location_1", "location_2", "location_3"))
#reformat for graphing
test_df_long<- test_df %>% pivot_longer(!names,
names_to = c("category"),
values_to = "value")
#plot
ggplot(test_df_long,
aes(x = str_to_title(category),
y = str_to_title(names),
colour = str_to_title(names),
size = value)) +
geom_point() +
geom_text(aes(label = value),
colour = "white",
size = 3) +
scale_x_discrete(position = "top") +
scale_size_continuous(range = c(10, 50)) +
scale_color_manual(values = c("blue", "red",
"orange")) +
labs(x = NULL, y = NULL) +
theme(legend.position = "none",
panel.background = element_blank(),
panel.grid = element_blank(),
axis.ticks = element_blank()) ```
Edit:
You could use ggplot_build to manually modify the point layer [[1]] to specify the sizes of your points like this:
#plot
p <- ggplot(test_df_long,
aes(x = str_to_title(category),
y = str_to_title(names),
colour = str_to_title(names),
size = value)) +
geom_point() +
geom_text(aes(label = value),
colour = "white",
size = 3) +
scale_x_discrete(position = "top") +
scale_color_manual(values = c("blue", "red",
"orange")) +
labs(x = NULL, y = NULL) +
theme(legend.position = "none",
panel.background = element_blank(),
panel.grid = element_blank(),
axis.ticks = element_blank())
q <- ggplot_build(p)
q$data[[1]]$size <- c(7,4,1,8,5,2,9,6,3)*5
q <- ggplot_gtable(q)
plot(q)
Output:
You could use scale_size with a log10 scale to make the difference more visuable like this:
#plot
ggplot(test_df_long,
aes(x = str_to_title(category),
y = str_to_title(names),
colour = str_to_title(names),
size = value)) +
geom_point() +
geom_text(aes(label = value),
colour = "white",
size = 3) +
scale_size(trans="log10", range = c(10, 50)) +
scale_x_discrete(position = "top") +
scale_color_manual(values = c("blue", "red",
"orange")) +
labs(x = NULL, y = NULL) +
theme(legend.position = "none",
panel.background = element_blank(),
panel.grid = element_blank(),
axis.ticks = element_blank())
Output:

Increase Vertical Spacing between Legend Key in ggplot2

How can I increase vertical spacing between legend keys:
p1 <- ggplot(data = HSS, mapping = aes(x = EVENT, y = HSS, fill = TIME)) +
geom_bar(stat = "identity",width=0.7, colour = "black", position = position_dodge(0.7)) +
scale_fill_manual("HSS", values = c("deepskyblue3", "indianred2"),
labels = c("1200 UTC (0.049)", "0000 UTC (0.031)")) + theme_bw()
p1 <- p1 + scale_y_continuous(expand = expansion(mult = c(0.0085, -0.085)),
limits = c(-0.03,0.5), breaks = c(-0.03,-0.01, 0.01, 0.03, 0.05, 0.07,0.09,0.11,0.13,0.15,0.17,
0.19, 0.21,0.23,0.25,0.27,0.29,0.31,0.33,0.45),
labels = c("-0.03","-0.01","0.01","0.03","0.05","0.07","0.09","0.11","0.13","0.15","0.17",
"0.19","0.21","0.23","0.25","0.27","0.29","0.31","0.33","0.45")) +
theme(axis.text.x=element_text(color = "black", size=12, face = "bold", angle=90, vjust=.5,
hjust=0.8)) +
theme(axis.text.y = element_text(color = "black", size=12, face = "bold"))
p1 <- p1 + theme( axis.line = element_line(colour = "black", size = 0.5, linetype = "solid")) +
labs( y = "HSS")
p1 <- p1 + theme(axis.title=element_text(colour = "blue2" ,size=14,face="bold", vjust = 0.1))
p1 <- p1 + theme(legend.position=c(0.98,0.98)) + theme(legend.title=element_blank(),
legend.text = element_text(face = "bold", size = "12"),
legend.box.background = element_rect(size=0.7, linetype="solid"),
legend.justification = c("right", "top"),
legend.box.margin = margin(1, 1, 1, 1)
)
p1
I tried using legend.key.height legend.spacing.y guide but it only stretched legend keys without adding space between them. Also how can I remove alternate lables (encircled) of Y-axis keeping tickmark with plot.
After browsing ggplot2's source code for a bit, I come to the conclusion that the legend.spacing.y is only applied when the byrow = TRUE as argument to the legend.
Simplied example below.
library(ggplot2)
ggplot(iris, aes(Sepal.Width)) +
geom_density(aes(fill = Species)) +
guides(fill = guide_legend(byrow = TRUE)) +
theme(legend.spacing.y = unit(1, "cm"))
With regards to the labels, just remove the values from the breaks argument in scale_y_continuous() that you don't want to show, you're already specifying them manually.

Overlapping text on top of geom_bar in ggplot2

I have made a barplot similar to the one below using ggplot2.
I cannot get the percentages on top of the bars to be centered and not overlapping of other bars and numbers. Sample code is below.
library(tidyverse)
cat1=c("cat1","cat1","cat1","cat1","cat1","cat1","cat1","cat1","cat1","cat1","cat1","cat1",
"cat2","cat2","cat2","cat2","cat2","cat2","cat2","cat2","cat2","cat2","cat2","cat2",
"cat3","cat3","cat3","cat3","cat3","cat3","cat3","cat3","cat3","cat3","cat3","cat3",
"cat4","cat4","cat4","cat4","cat4","cat4","cat4","cat4","cat4","cat4","cat4","cat4")
cat2=c("c1","c2","c3","c4","c5","c6","c7","c8","c9","c10","c11","c12",
"c1","c2","c3","c4","c5","c6","c7","c8","c9","c10","c11","c12",
"c1","c2","c3","c4","c5","c6","c7","c8","c9","c10","c11","c12",
"c1","c2","c3","c4","c5","c6","c7","c8","c9","c10","c11","c12")
count1=round(rnorm(48,10))
fakeperc=rnorm(48,9)
df1=cbind(count1,fakeperc)
df2=cbind(cat1,cat2)
finaldf=as.data.frame(cbind(df1,df2))
finaldf$cat1=as.factor(finaldf$cat1)
finaldf$fakeperc=as.numeric(finaldf$fakeperc)
#finaldf$cat1=factor(finaldf$cat1,levels = c("cat1","cat2","cat3","cat4"))
finaldf$cat2 = factor(finaldf$cat2,
levels = c("c1","c2","c3","c4","c5","c6","c7","c8","c9","c10","c11","c12"))
a=ggplot(data=finaldf,aes(x=cat1, y=count1,
fill=cat2,group=cat2)) +
geom_bar(stat='identity',color='black',width=.65,position=position_dodge(width=.9))+
scale_y_discrete(limits=0:50,breaks=c(0,10,20,30,40,50))+
scale_fill_brewer(palette="Set3") +
theme_classic() +
geom_text(data = finaldf,
aes(x=cat1,y=count1,group=cat2,
label=format(paste(round(fakeperc),"%",sep = ""))),inherit.aes = F,
color='black',position=position_dodge(.9),vjust=-.5,size=3)
a
When trying to add either nudge_y or nudge_x to the geom_text call, nothing happens. I suspect this is because there is already a position_dodge call. I am open any and all solutions to make these percentages non-overlapping and legible.
What do you think of this?
# I think you meant count1 to be numeric
finaldf$count1 <- as.numeric(finaldf$count1)
ggplot(data = finaldf,
aes(x = cat1,
y = count1,
fill = cat2,
group = cat2)) +
geom_col(color = 'black',
width = 0.65,
position = position_dodge(width = 0.9)) +
geom_text(data = finaldf,
aes(x = cat1,
y = count1,
group = cat2,
label = scales::percent(fakeperc/100, accuracy = 0.01)),
inherit.aes = FALSE,
color = 'black',
position = position_dodge(0.9),
hjust = -0.1,
size = 3) +
scale_y_continuous(limits = c(0,50), breaks = c(0,10,20,30,40,50)) +
scale_fill_brewer(palette = "Set3") +
theme_classic() +
coord_flip()
I cleaned up a bit the code (according to my taste)
I changed scale_y_numeric to scale_y_continuous (since count1 should be numeric)
I used coord_flip() to make it more readable
I used scales::percent to write percentage numbers
(don't know why you set up limits from 0 to 50 but I left them as I suppposed they were intended)
If you don't want to use coor_flip:
finaldf$count1 <- as.numeric(finaldf$count1)
ggplot(data = finaldf,
aes(x = cat1,
y = count1,
fill = cat2,
group = cat2)) +
geom_col(color = 'black',
width = 0.65,
position = position_dodge(width = 0.9)) +
geom_text(data = finaldf,
aes(x = cat1,
y = count1,
group = cat2,
label = scales::percent(fakeperc/100, accuracy = 0.01)),
inherit.aes = FALSE,
color = 'black',
position = position_dodge(0.9),
hjust = -0.1,
angle = 90,
size = 3) +
scale_y_continuous(limits = c(0,50), breaks = c(0,10,20,30,40,50)) +
scale_fill_brewer(palette = "Set3") +
theme_classic()
Is this what you are looking for:
library(ggplot2)
#Code
ggplot(data=finaldf,aes(x=cat2, y=count1,
fill=cat2,group=cat2)) +
geom_bar(stat='identity',color='black',
position=position_dodge(width=1))+
scale_fill_brewer(palette="Set3") +
theme_bw() +
geom_text(aes(x=cat2,y=count1,group=cat2,
label=format(paste(round(fakeperc),"%",sep = ""))),inherit.aes = F,
color='black',position=position_dodge(1),
size=3,vjust=-0.5)+
facet_wrap(.~cat1,scales = 'free_x',nrow = 1,strip.position = 'bottom')+
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
legend.position = 'top',
strip.background = element_blank(),
panel.spacing = unit(2, "lines"),
panel.grid = element_blank())+
guides(fill = guide_legend(nrow = 1))
Output:

Trouble with overlapping labels (geom_text)

Trouble with overlapping geom_text labels on pie chart
library(scales)
blank_theme <- theme_minimal()+
theme(
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.border = element_blank(),
panel.grid=element_blank(),
axis.ticks = element_blank(),
plot.title=element_text(size=14, face="bold")
)
df6 <- data.frame(group = c("Seedling","Ground", "Fern", "Moss"),value = c(2.125,80.125, 11.376,6.375))
# Create a basic bar
pie6 = ggplot(df6, aes(x="", y=value, fill=group)) + geom_bar(stat="identity", width=1) + blank_theme + theme(axis.text.x=element_blank())
# Convert to pie (polar coordinates) and add labels
pie6 = pie6 + coord_polar("y", start=0) + geom_text(aes( label = paste0((value), "%")),position = position_stack(vjust = 0.5))
# Remove labels and add title
pie6 = pie6 + labs(x = NULL, y = NULL, fill = NULL, title = "Understory Composition, Site 2")
# Tidy up the theme
pie6 = pie6 + theme_classic() + theme(axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
plot.title = element_text(hjust = 0.5, color = "black"))
pie6
This is my current output. How can i change the labels such that they do not overlap? i have tried various hjust and vjust, positions and position_stack but to no avail
Any help appreciated. thank you.
A manual approach to this problem could be to manipulate the orientation of the text by setting the angle parameter in the geom_text function. This allows you to set the orientation of all text fragments at once by assigning a singel value to angle. You may also set the angle for the individual text items as illustrated below.
ggplot(df6, aes(x = "", y = value, fill = group)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
blank_theme +
theme(axis.text.x = element_blank()) +
geom_text(aes(label = paste0((value), "%")),
position = position_stack(vjust = 0.5),
angle = c(-90, -90, 0, -90)) ####### here
The code below adjust the angle depending on the pie it describes.
ggplot(df6, aes(x = "", y = value, fill = group)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
blank_theme +
theme(axis.text.x = element_blank()) +
geom_text(aes(label = paste0((value), "%")),
position = position_stack(vjust = 0.5),
angle = c(-97, -110, 0, -70)) ####### here
Another way to work around the problem you state, is to play with the start parameter of the coord_polar function:
ggplot(df6, aes(x = "", y = value, fill = group)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 180) + ####### here
blank_theme +
theme(axis.text.x = element_blank()) +
geom_text(aes(label = paste0((value), "%")) ,
position = position_stack(vjust = 0.5))
Have you tried using the package ggrepel? If so I recommend. It automatically stops labels overlapping and finds a fit for each other them.
#Install ggrepel package
install.packages("ggrepel", dependencies=TRUE)
df6 <- data.frame(group = c("Seedling","Ground", "Fern", "Moss"),value = c(2.125,80.125, 11.376,6.375))
# Create a basic bar
pie6 = ggplot(df6, aes(x="", y=value, fill=group)) + geom_bar(stat="identity",
width=1) + blank_theme + theme(axis.text.x=element_blank())
# Convert to pie (polar coordinates) and add labels using ggrepel
pie6 = pie6 + coord_polar("y", start=0) + ggrepel::geom_text_repel(aes( label =
paste0((value), "%")),position = position_stack(vjust = 0.5))
# Remove labels and add title
pie6 = pie6 + labs(x = NULL, y = NULL, fill = NULL, title = "Understory Composition, Site 2")
# Tidy up the theme
pie6 = pie6 + theme_classic() + theme(axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
plot.title = element_text(hjust = 0.5, color = "black"))
pie6

ggplot2: How to move x-axis up, so it can be under arbitrarily picked bar on horizontal barplot?

I made horizontal barplot. I need to move x-axis up, so it is placed not under the last bar, but under some bar, picked based on other criterion.
I've tried some things, like gtable, but with no success. I would appreciate any help.
This is a picture that illustrats what I want to achieve:
Here is the code to produce sample horizontal barplot:
library("ggplot2")
library("RColorBrewer")
colours <- brewer.pal(11, "RdYlGn")[3:9]
no.names <- 4
name.percentage <- data.frame(name = paste0(LETTERS[1:no.names], letters[1:no.names], sample(LETTERS[1:no.names], size = no.names, replace = TRUE )), percentage = 0.85 + runif(no.names, 0, 0.15))
name.percentage <- rbind(
transform(name.percentage, type = 1, fill = cut(percentage, breaks = c(-Inf,(1:6 * 3 + 81)/100, Inf), right = T, labels = colours)),
transform(name.percentage, percentage = 1 - percentage, type = 2, fill = "#EEEEEE")
)
plot <- ggplot(data = name.percentage,
aes( x = name, y = percentage, fill = fill)) +
geom_bar(stat = "identity", position = "stack", width = 0.75) +
scale_fill_identity(guide = "none") +
labs(x = NULL, y = NULL) +
scale_y_continuous(expand = c(0,0)) +
scale_x_discrete(expand = c(0,0)) +
coord_flip() +
theme_classic() +
theme(axis.ticks.y = element_blank(),
axis.text.y = element_text(size = 11, colour = "black" ),
axis.text.x = element_text(size = 11, colour = "black" ),
axis.line = element_blank(),
plot.margin = grid::unit(c(5,5,5,5),"mm"),
aspect.ratio = ((no.names %% 30) / 30 ) * 1.70)
print(plot)
You could create two separate plots first, removing the axis ticks and labels in one of them entirely:
plot1 <- ggplot(data = subset(name.percentage, name=="AaC" | name=="BbA"),
aes( x = name, y = percentage, fill = fill)) +
geom_bar(stat = "identity", position = "stack", width = 0.75) +
scale_fill_identity(guide = "none") +
labs(x = NULL, y = NULL) +
scale_y_continuous(expand = c(0,0)) +
scale_x_discrete(expand = c(0,0)) +
coord_flip() +
theme_classic() +
theme(axis.ticks.y = element_blank(),
axis.text.y = element_text(size = 11, colour = "black" ),
axis.text.x = element_blank(),
axis.line=element_blank(),
axis.ticks=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
aspect.ratio = ((no.names %% 30) / 30 ) * 1.70)
plot2 <- ggplot(data = subset(name.percentage, name=="CcA" | name=="DdD"),
aes( x = name, y = percentage, fill = fill)) +
geom_bar(stat = "identity", position = "stack", width = 0.75) +
scale_fill_identity(guide = "none") +
labs(x = NULL, y = NULL) +
scale_y_continuous(expand = c(0,0)) +
scale_x_discrete(expand = c(0,0)) +
coord_flip() +
theme_classic() +
theme(axis.ticks.y = element_blank(),
axis.text.y = element_text(size = 11, colour = "black" ),
axis.text.x = element_text(size = 11, colour = "black" ),
axis.line = element_blank(),
aspect.ratio = ((no.names %% 30) / 30 ) * 1.70)
Then you can use plot_grid from package cowplot to arrange the two plots, with align="h" aligning both plots horizontally:
library(cowplot)
plot_grid(plot2, plot1, align="h", ncol=1)

Resources