I am trying to create a barplot with two x-axis (grouped x-axis):
# read data
tmp <- read.table(text = "label CNV_x CNV_Type
17p -1 Loss
9p -1 Loss
16q 1 Gain
10p 1 Gain
8q 1 Gain
13q 1 Gain", header = T)
tmp$CNV_Type <- relevel(tmp$CNV_Type, ref = 'Loss')
# plot
ggplot(tmp, aes(x = label, y = CNV_x)) +
geom_bar(stat = 'identity') +
theme_bw() +
geom_hline(yintercept = 0) +
coord_flip() +
facet_wrap(~CNV_Type, strip.position = "bottom", scales = "free_x") +
theme(panel.spacing = unit(0, "lines"),
strip.background = element_blank(),
strip.placement = "outside",
panel.border = element_rect(colour = NA))
This creates a plot like this:
This plot shows 0.00 twice on x-axis and I can't figure out a way to remove the spacing between the two vertical lines separating the strips (one is Gain and other is Loss).
Any help would be much appreciated. Thanks!
UPDATE: I added scale_y_continuous(expand = c(0, 0)) as suggested below:
ggplot(tmp, aes(x = label, y = CNV_x)) +
geom_bar(stat = 'identity') +
theme_bw() +
geom_hline(yintercept = 0) +
scale_y_continuous(expand = c(0, 0)) +
coord_flip() +
facet_wrap(~CNV_Type, strip.position = "bottom", scales = "free_x") +
theme(panel.spacing = unit(0, "lines"),
strip.background = element_blank(),
strip.placement = "outside",
panel.border = element_rect(colour = NA))
This creates a plot like this:
The only issue now is there is no spacing between the bars and the left and right margins of the plot - not sure why that happened.
I would not use facets here. A couple of options. You could indicate the type by colour:
tmp %>%
ggplot(aes(label, CNV_x)) +
geom_col(aes(fill = CNV_Type)) +
geom_hline(yintercept = 0) +
coord_flip() +
scale_fill_manual(values = c("darkorange", "skyblue3"))
And/or add the labels for type to the plot using annotate. That requires some manual fiddling with x, y and expand to get it right:
tmp %>%
ggplot(aes(label, CNV_x)) +
geom_col() +
geom_hline(yintercept = 0) +
coord_flip() +
annotate("text",
label = c("Loss", "Gain"),
x = c(7, 7),
y = c(-0.5, 0.5)) +
scale_x_discrete(expand = c(0.1, 0.1))
Related
I'm trying to recreate a bar graph found on page 4 of the following report:
The figure has three bars with the first two stacked and the third dodged next to it. I've seen iterations of this question but none that recreate the figure in this exact way.
Here is the data:
a <- rep(c('RHB', 'FERS', 'CSRS'), 3)
b <- c(rep('Assets', 3), rep('Amount Past Due', 3),
rep('Actuarial Liability', 3))
c <- c(45.0, 122.5, 152.3, 47.2, 3.4, 4.8, 114.4, 143.4, 181.3)
df <- data.frame(a,b,c)
names(df) <- c('Fund', 'Condition', 'Value')
And what I've managed so far:
p <- ggplot(subset_data, aes(fill=Condition, y=Value, x=Fund)) +
geom_bar(position="stack", stat="identity") +
coord_flip()
I'm not partial to ggplot so if there's another tool that works better I'm ok using another package.
Taking some ideas from the link #aosmith posted.
You can call geom_bar twice, once with Assets and Amounts Past Due stacked, and again with just Actuarial Liability.
You can use width to make the bars thinner, then nudge one set of bars so the two geom_bar calls are not overlapping. I chose to make the width 0.3 and nudge by 0.3 so the edges just line up. If you nudge by more you will see a gap between the two bars.
Edit: add some more formatting and numeric labels
library(tidyverse)
library(scales)
df_al <- filter(df, Condition == 'Actuarial Liability')
df_xal <- filter(df, Condition != 'Actuarial Liability')
bar_width <- 0.3
hjust_lab <- 1.1
hjust_lab_small <- -0.2 # hjust for labels on small bars
ggplot() +
theme_classic() +
geom_bar(data = df_al,
aes(fill=Condition, y=Value, x=Fund),
position = position_nudge(x = -bar_width),
width = bar_width,
stat="identity") +
geom_bar(data = df_xal,
aes(fill=Condition, y=Value, x=Fund),
position="stack",
stat="identity",
width = bar_width) +
geom_text(data = df_al,
aes(label= dollar(Value, drop0trailing = TRUE), y=Value, x=Fund),
position = position_nudge(x = -bar_width),
hjust = hjust_lab) +
geom_text(data = df_xal,
aes(label= dollar(Value, drop0trailing = TRUE), y=Value, x=Fund),
position="stack",
hjust = ifelse(df_xal$Value < 5, hjust_lab_small, hjust_lab)) +
scale_fill_manual(values = c('firebrick3', 'lightsalmon', 'dodgerblue')) +
scale_y_continuous(breaks = seq(0,180, by = 20), labels = dollar) +
coord_flip() +
labs(x = NULL, y = NULL, fill = NULL) +
theme(legend.position = "bottom")
I think I would use the "sneaky facet" method, after adding a dummy variable to dodge the columns and making Fund a factor with the correct order:
df$not_liability <-df$Condition != "Actuarial Liability"
df$Fund <- factor(df$Fund, levels = c('RHB', 'FERS', 'CSRS'))
Most of the plotting code is then an attempt to copy the look of the supplied plot:
ggplot(df, aes(fill=Condition, y=Value, x=not_liability)) +
geom_bar(position = "stack", stat = "identity") +
scale_x_discrete(expand = c(0.5, 0.5)) +
scale_y_continuous(breaks = 0:10 * 20, labels = scales::dollar) +
coord_flip() +
facet_grid(Fund~., switch = "y") +
scale_fill_manual(values = c("#c00000", "#f7c290", "#0071bf"), name = "") +
theme_classic() +
theme(panel.spacing = unit(0, "points"),
strip.background = element_blank(),
axis.text.y = element_blank(),
axis.ticks.length.y = unit(0, "points"),
axis.title = element_blank(),
strip.placement = "outside",
strip.text = element_text(),
legend.position = "bottom",
panel.grid.major.x = element_line())
I have created a R visualisation in Power BI and looking at having only 1 grid line where the horizontal axis value crosses the axis value at 1.
I am not good with words and not sure if I have explained it well in words. Please see the screenshots below to get a better understanding of what I want to achieve.
Any help is greatly appreciated.
First screenshot is from Excel where I was able to do it and I want to replicate the same in the R chart (second screenshot)
library(ggplot2)
ggplot(unique(dataset), aes(x = reorder(Condition, Rate), y = Rate)) +
labs(x = "Condition")+
geom_point(size = 5, stroke = 0, shape = 18, colour="brown") +
geom_point() + geom_line() +
geom_errorbar(aes(ymin = LL, ymax = UL), width=.2, position=position_dodge(.9), colour="brown", alpha=0.6, size=.7) +
theme_bw()+
theme(panel.grid.major = element_blank()) +
theme(axis.text.x = element_text(angle=90, hjust = 1))+
theme(axis.text.x = element_text(size = 10))
Let p is your original ggplot object
step 1: remove the original x axis
p + theme(axis.line.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.x = element_blank()) +
labs(x = '') -> p1
step 2: add a line at 1
p1 + geom_hline(yintercept = 1, color = "black")
As you have not provided any data, so I am using iris dataset. You can use the following code
library(ggplot2)
ggplot(unique(iris), aes(x = Species, y = Petal.Width)) +
labs(x = "Condition")+
geom_point(size = 5, stroke = 0, shape = 18, colour="brown") +
geom_point() + geom_line() +
theme_bw()+
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank()) +
theme(axis.text.x = element_text(angle=90, hjust = 1))+
theme(axis.text.x = element_text(size = 10)) +
geom_abline(slope=0, intercept=1, col = "darkblue",lty=1,size = 0.5)
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
I have this plot, but i want to change around the order of the X axis labels.
It should start with the site number (eg. X27a, X28a, W15c, W17c) Then the group (eg. A, B, C, D) and then the last one.
So basically i want the very bottom row of labels at the top.
How do i reorder it?
Code
ggplot(data = inf, aes(x = COMPARTMENT, y = MI, fill = SPECIES)) +
geom_bar(stat = "identity") +
scale_y_continuous(expand = c(0, 0), limits = c(-0.1, 12.5), breaks = 2*c(0:6)) +
theme_bw() +
facet_grid(~COMP.COMP*REGION, switch = "x", scales = "free_x", space = "free_x") +
theme(strip.text.x = element_text(size = 10)) +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5, size = 10)) +
theme(panel.spacing = unit(0, "lines"),
strip.background = element_blank()) +
scale_fill_manual(name = "SPECIES",
values=c("#999999", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2")) +
ylab("Average infestation rate (%)") +
xlab("Compartment by Comparable Groups by Region") +
theme(panel.grid.major.y = element_line("lightgray"),
panel.grid.major.x = element_blank()) +
theme(axis.line = element_line(color = "black"),
legend.position = "right",
legend.title=element_text())
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().