I have the following plot:
score = c(5,4,8,5)
Group = c('A','A','B','B')
Time = c('1','2','1','2')
df = data.frame(score,Group,Time)
df$Group = factor(df$Group)
df$Time = factor(df$Time)
a = ggplot(df, aes(x=Time, y=score, fill=Group)) +
geom_bar(position=position_dodge(), stat="identity", width = 0.8, color = 'black')
How do I reorder the bars such that Group A will be grouped together, followed by Group B, and the x-axis will be labelled as Time 1,2,1,2 for each bar? As shown below:
Having repeated elements on an axis is kinda against the principles of how ggplot2 works. But we can cheat a bit. I would suggest you use #RLave suggestion of using faceting. But if that doesn't suit you, I tried to do without facetting:
df2 <- rbind(df, data.frame(score=NA, Group=c('A'), Time=c('9')))
df2$x <- as.character(interaction(df2$Group, df2$Time))
ggplot(df2, aes(x=x, y=score, fill=Group)) +
geom_col(position='dodge', colour='black') +
scale_x_discrete(labels=c('1','2','','1','2')) +
theme(axis.ticks.x = element_blank(), panel.grid.major.x = element_blank())
As you can see, we have to create a dummy variable for the x-axis, and manually put on the labels.
Now consider a better solution using facet:
ggplot(df, aes(x=Time, y=score, fill=Group)) +
geom_col(width = 1, color = 'black') +
facet_grid(~Group) +
theme(strip.background = element_blank(), strip.text = element_blank(), panel.spacing.x=grid::unit(3, 'pt'))
The distance between the panels is adjusted with the theme argument panel.spacing.x.
Related
I have a sample dataset which I want to plot in ggplot, assigning with scale_fill_manual an individual color for each factor in the variable group. However, the individual assignment does not work properly, as you can see the factors a and b do not get a different color.
Here is my code and the resulting plot.
#data
trt<-c("trt1","trt2","trt3","trt4","trt5","trt6","trt7")
emmean<-c(7.75,7.5,5.75,7,6,8,4)
group<-c("c","c","b","bc","b","c","a")
#specify color vector to get as many colors as group levels
library(RColorBrewer)
color_pallete_function <- colorRampPalette(
colors = brewer.pal(8,"Dark2"),
space = "Lab")
dat<-data.frame(trt,emmean,group)
dat$group<-as.factor(dat$group)
num_colors <- nlevels(dat$group)
diamond_color_colors <- color_pallete_function(num_colors)
#letter display plot
ggplot(data=dat, aes(x=reorder(trt,emmean),y=emmean,fill=group)) +
geom_bar( stat="identity", width=0.8) +
scale_fill_manual(values =diamond_color_colors[dat$group])+
#geom_errorbar(aes(ymin=lower.CL, ymax=upper.CL), width=0.4) +
geom_text(aes(y=8, label=group, angle=90)) +
theme(legend.position = "none",
axis.text.x = element_text(angle = 45,hjust=1)) +
annotate(geom="label", y=1, x=length(rownames(dat))-1, size=3, color="black", fill="white",
label="Means with the same letter are according\n to Tukey test (alpha=5%) not significantly different.")
How can this be solved?
To assign colors to categories in a robust way name your color vector and use this named color vector inside scale_fill_manual. Try this:
library(ggplot2)
library(RColorBrewer)
trt<-c("trt1","trt2","trt3","trt4","trt5","trt6","trt7")
emmean<-c(7.75,7.5,5.75,7,6,8,4)
group<-c("c","c","b","bc","b","c","a")
#specify color vector to get as many colors as group levels
color_pallete_function <- colorRampPalette(
colors = brewer.pal(8,"Dark2"),
space = "Lab")
dat<-data.frame(trt,emmean,group)
dat$group<-as.factor(dat$group)
num_colors <- nlevels(dat$group)
diamond_color_colors <- color_pallete_function(num_colors)
# Name your color vector
diamond_color_colors <-setNames(diamond_color_colors, levels(dat$group))
#letter display plot
ggplot(data=dat, aes(x=reorder(trt,emmean),y=emmean,fill=group)) +
geom_bar( stat="identity", width=0.8) +
scale_fill_manual(values = diamond_color_colors)+
geom_text(aes(y=8, label=group, angle=90)) +
theme(legend.position = "none",
axis.text.x = element_text(angle = 45,hjust=1)) +
annotate(geom="label", y=1, x=length(rownames(dat))-1, size=3, color="black", fill="white",
label="Means with the same letter are according\n to Tukey test (alpha=5%) not significantly different.")
I have a dataset that looks like the following:
df <- data.frame(Name=rep(c('Sarah', 'Casey', 'Mary', 'Tom'), 3),
Scale=rep(c('Scale1', 'Scale2', 'Scale3'), 4),
Score=sample(1:7, 12, replace=T))
I am trying to create a barchat in ggplot2 that currently looks like this:
ggplot(df, aes(x=Name, y=Score, fill=Scale)) + geom_bar(stat='identity', position='dodge') +
coord_flip() +
scale_y_continuous(breaks=seq(0, 7, 1), limits = c(0, 7)) +
scale_x_discrete() +
scale_fill_manual(values=c('#253494', '#2c7fb8', '#000000')) +
theme(panel.background = element_blank(),
legend.position = 'right',
axis.line = element_line(),
axis.title = element_blank(),
axis.text = element_text(size=10))
However, I only want to show one observation (one Name) at a time. Is this possible to do without creating a ton of separate datasets, one for each person? I would like the end result to look like the example below, where I can just iterate through the names to produce a separate plot for each, or some similar process.
# Trying to avoid creating separate datasets, but for the sake of the example:
df2 <- data.frame(Name=rep(c('Sarah'), 3),
Scale=c('Scale1', 'Scale2', 'Scale3'),
Score=sample(1:7, 3, replace=T))
ggplot(df2, aes(x=Name, y=Score, fill=Scale)) + geom_bar(stat='identity', position='dodge') +
coord_flip() +
scale_y_continuous(breaks=seq(0, 7, 1), limits = c(0, 7)) +
scale_x_discrete() +
scale_fill_manual(values=c('#253494', '#2c7fb8', '#000000')) +
theme(panel.background = element_blank(),
legend.position = 'right',
axis.line = element_line(),
axis.title = element_blank(),
axis.text = element_text(size=10))
Since your data is already tidy ie. in long format, you can use facet_wrap as suggested and set the scales as "free" thus creating facets with your different Name groups.
df %>% ggplot(aes(y = Score, x = Name)) +
geom_bar(stat = "identity", aes(colour = Scale, fill = Scale),
position = "dodge") +
coord_flip() +
facet_wrap(~Name, scales = "free")
You can get rid of the facet labels or the axis labels depending which you prefer.
EDIT: in response to comment.
You can use the same data frame to create seperate plots by just piping a filter in at the start, hence,
df %>%
filter(Name == "Sarah") %>%
ggplot(aes(y = Score, x = Name)) +
geom_bar(stat = "identity", aes(colour = Scale, fill = Scale),
position = "dodge") +
coord_flip()
Since you are using Rmarkdown you could throw a for loop around that to plot all the names
for(i in c("Sarah", "Casey", "Mary", "Tom")){
df %>%
filter(Name == i) %>%
ggplot(aes(y = Score, x = Name)) +
geom_bar(stat = "identity", aes(colour = Scale, fill = Scale),
position = "dodge") +
coord_flip()
}
If you want to arrange all these into a group you can use ggpubr::ggarrange to place all the plots into the same object.
facet_grid(.~Name)
Maybe somehow implement this, it'll plot them all, but should do so in individual plots.
I've been stuck on an issue and can't find a solution. I've tried many suggestions on Stack Overflow and elsewhere about manually ordering a stacked bar chart, since that should be a pretty simple fix, but those suggestions don't work with the huge complicated mess of code I plucked from many places. My only issue is y-axis item ordering.
I'm making a series of stacked bar charts, and ggplot2 changes the ordering of the items on the y-axis depending on which dataframe I am trying to plot. I'm trying to make 39 of these plots and want them to all have the same ordering. I think ggplot2 only wants to plot them in ascending order of their numeric mean or something, but I'd like all of the bar charts to first display the group "Bird Advocates" and then "Cat Advocates." (This is also the order they appear in my data frame, but that ordering is lost at the coord_flip() point in plotting.)
I think that taking the data frame through so many changes is why I can't just add something simple at the end or use the reorder() function. Adding things into aes() also doesn't work, since the stacked bar chart I'm creating seems to depend on those items being exactly a certain way.
Here's one of my data frames where ggplot2 is ordering my y-axis items incorrectly, plotting "Cat Advocates" before "Bird Advocates":
Group,Strongly Opposed,Opposed,Slightly Opposed,Neutral,Slightly Support,Support,Strongly Support
Bird Advocates,0.005473026,0.010946052,0.012509773,0.058639562,0.071149335,0.31118061,0.530101642
Cat Advocates,0.04491726,0.07013396,0.03624901,0.23719464,0.09141056,0.23404255,0.28605201
And here's all the code that takes that and turns it into a plot:
library(ggplot2)
library(reshape2)
library(plotly)
#Importing data from a .csv file
data <- read.csv("data.csv", header=TRUE)
data$s.Strongly.Opposed <- 0-data$Strongly.Opposed-data$Opposed-data$Slightly.Opposed-.5*data$Neutral
data$s.Opposed <- 0-data$Opposed-data$Slightly.Opposed-.5*data$Neutral
data$s.Slightly.Opposed <- 0-data$Slightly.Opposed-.5*data$Neutral
data$s.Neutral <- 0-.5*data$Neutral
data$s.Slightly.Support <- 0+.5*data$Neutral
data$s.Support <- 0+data$Slightly.Support+.5*data$Neutral
data$s.Strongly.Support <- 0+data$Support+data$Slightly.Support+.5*data$Neutral
#to percents
data[,2:15]<-data[,2:15]*100
#melting
mdfr <- melt(data, id=c("Group"))
mdfr<-cbind(mdfr[1:14,],mdfr[15:28,3])
colnames(mdfr)<-c("Group","variable","value","start")
#remove dot in level names
mylevels<-c("Strongly Opposed","Opposed","Slightly Opposed","Neutral","Slightly Support","Support","Strongly Support")
mdfr$variable<-droplevels(mdfr$variable)
levels(mdfr$variable)<-mylevels
pal<-c("#bd7523", "#e9aa61", "#f6d1a7", "#999999", "#c8cbc0", "#65806d", "#334e3b")
ggplot(data=mdfr) +
geom_segment(aes(x = Group, y = start, xend = Group, yend = start+value, colour = variable,
text=paste("Group: ",Group,"<br>Percent: ",value,"%")), size = 5) +
geom_hline(yintercept = 0, color =c("#646464")) +
coord_flip() +
theme(legend.position="top") +
theme(legend.key.width=unit(0.5,"cm")) +
guides(col = guide_legend(ncol = 12)) + #has 7 real columns, using to adjust legend position
scale_color_manual("Response", labels = mylevels, values = pal, guide="legend") +
theme(legend.title = element_blank()) +
theme(axis.title.x = element_blank()) +
theme(axis.title.y = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(axis.text.x = element_blank()) +
theme(legend.key = element_rect(fill = "white")) +
scale_y_continuous(breaks=seq(-100,100,100), limits=c(-100,100)) +
theme(panel.background = element_rect(fill = "#ffffff"),
panel.grid.major = element_line(colour = "#CBCBCB"))
The plot:
I think this works, you may need to play around with the axis limits/breaks:
library(dplyr)
mdfr <- mdfr %>%
mutate(group_n = as.integer(case_when(Group == "Bird Advocates" ~ 2,
Group == "Cat Advocates" ~ 1)))
ggplot(data=mdfr) +
geom_segment(aes(x = group_n, y = start, xend = group_n, yend = start + value, colour = variable,
text=paste("Group: ",Group,"<br>Percent: ",value,"%")), size = 5) +
scale_x_continuous(limits = c(0,3), breaks = c(1, 2), labels = c("Cat", "Bird")) +
geom_hline(yintercept = 0, color =c("#646464")) +
theme(legend.position="top") +
theme(legend.key.width=unit(0.5,"cm")) +
coord_flip() +
guides(col = guide_legend(ncol = 12)) + #has 7 real columns, using to adjust legend position
scale_color_manual("Response", labels = mylevels, values = pal, guide="legend") +
theme(legend.title = element_blank()) +
theme(axis.title.x = element_blank()) +
theme(axis.title.y = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(axis.text.x = element_blank()) +
theme(legend.key = element_rect(fill = "white"))+
scale_y_continuous(breaks=seq(-100,100,100), limits=c(-100,100)) +
theme(panel.background = element_rect(fill = "#ffffff"),
panel.grid.major = element_line(colour = "#CBCBCB"))
produces this plot:
You want to factor the 'Group' variable in the order by which you want the bars to appear.
mdfr$Group <- factor(mdfr$Group, levels = c("Bird Advocates", "Cat Advocates")
I am using the following piece of code to create a bar graph:
temp1 <- melt(final,id='Time')
p <- ggplot(temp1, aes(x=Time, y=value, fill=variable)) +
geom_bar(stat="identity", position = "fill") +
scale_y_continuous(labels = percent_format()) +
ggtitle('Cost Structure Breakdown') + theme_bw() + ylab('Percent Spread') +
theme(panel.grid.minor.x = element_blank(),
panel.grid.minor.y = element_blank(),
panel.grid.major.x=element_line(color='grey90',linetype='dashed'),
panel.grid.major.y=element_line(color='grey90',linetype='dashed'),
plot.title=element_text(size=20),
axis.text=element_text(size=15),
legend.text=element_text(size=15),
legend.key=element_blank(),
legend.title=element_blank()) +
scale_color_manual(values=c("#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6"))
p
The presence of scale_color_manual doesn't seem to have any affect on the resulting plot, it stays the same even if I remove scale_color_manual. My dataframe final has 10 variables and I am using melt on Time. Therefore, I have used 9 colors for the plot. The dataset itself can be found here.
Any help on this would be much appreciated.
There is no reproducible data. I, therefore, created a simple data here. I also simplified the code of the OP. What is necessary here is scale_fill_manual.
mydf <- data.frame(time = letters[1:3],
variable = LETTERS[1:3],
value = runif(3, 10, 15),
stringsAsFactors = FALSE)
ggplot(mydf, aes(x=time, y=value, fill=variable)) +
geom_bar(stat="identity") +
scale_fill_manual(values=c("#a6cee3","#1f78b4","#b2df8a"))
I am trying to demonstrate the soil type (soil column) at different depths in the ground using box plots. However, as the sampling interval is not consistent, there are also gaps in between the samples.
My questions are as follows:
Is it possible to put the box plots within the same column? i.e. all box plots in 1 straight column
Is it possible to remove the x-axis labels and ticks when using ggdraw? I tried to remove it when using plot, but appears again when I use ggdraw.
My code looks like this:
SampleID <- c("Rep-1", "Rep-2", "Rep-3", "Rep-4")
From <- c(0,2,4,9)
To <- c(1,4,8,10)
Mid <- (From+To)/2
ImaginaryVal <- c(1,1,1,1)
Soiltype <- c("organic", "silt","clay", "sand")
df <- data.frame(SampleID, From, To, Mid, ImaginaryVal, Soiltype)
plot <- ggplot(df, aes(x=ImaginaryVal, ymin=From, lower=From,fill=Soiltype,
middle=`Mid`, upper=To, ymax=To)) +
geom_boxplot(colour= "black", stat="identity") + scale_y_reverse(breaks = seq(0,10,0.5)) + xlab('Soiltype') + ylab('Depth (m)') + theme(axis.text.x = element_blank(), axis.ticks.x = element_blank())
ggdraw(switch_axis_position(plot + theme_bw(8), axis = 'x'))
In the image I have pointed out what I want, using the red arrows and lines.
You can use position = position_dodge() like so:
plot <- ggplot(df, aes(x=ImaginaryVal, ymin=From, lower=From,fill=Soiltype, middle=Mid, upper=To, ymax=To)) +
geom_boxplot(colour= "black", stat="identity", position = position_dodge(width=0)) +
scale_y_reverse(breaks = seq(0,10,0.5)) +
xlab('Soiltype') +
ylab('Depth (m)') +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank())
edit: I don't think you need cowplot at all, if this is what you want your plot to look like:
ggplot(df, aes(x=ImaginaryVal, ymin=From, lower=From,fill=Soiltype, middle=Mid, upper=To, ymax=To)) +
geom_boxplot(colour= "black", stat="identity", position = position_dodge(width=0)) +
scale_y_reverse(breaks = seq(0,10,0.5)) +
xlab('Soiltype') +
ylab('Depth (m)') +
theme_bw() +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank()) +
xlab("") +
ggtitle("Soiltype")