ggplot2 and gridExtra: reduce spacing among plots that have facet strips removed - r

I wish to plot a number of tightly spaced graphs as illustrated by the following toy example:
library(ggplot2)
library(gridExtra)
set.seed(314159)
n <- 100
data <- data.frame(x = rnorm(n), y = rnorm(n), z = rep("dummy var", n))
p00 <- ggplot(data, aes(x)) + stat_density() + theme(plot.margin = unit(c(0,0,0,0), units = "lines" ), axis.text = element_blank(), axis.title = element_blank(), axis.ticks = element_blank()) + labs(x = NULL, y = NULL)
p01 <- ggplot(data, aes(x, y)) + geom_point() + theme(plot.margin = unit(c(0,0,0,0), units = "lines" ), axis.text = element_blank(), axis.title = element_blank(), axis.ticks = element_blank()) + labs(x = NULL, y = NULL)
p10 <- ggplot(data, aes(y, x)) + geom_point() + theme(plot.margin = unit(c(0,0,0,0), units = "lines" ), axis.text = element_blank(), axis.title = element_blank(), axis.ticks = element_blank()) + labs(x = NULL, y = NULL)
p11 <- ggplot(data, aes(y)) + stat_density() + theme(plot.margin = unit(c(0,0,0,0), units = "lines" ), axis.text = element_blank(), axis.title = element_blank(), axis.ticks = element_blank()) + labs(x = NULL, y = NULL)
grid.arrange(p00, p01, p10, p11, ncol = 2)
In spite of my best efforts, I have been unable to overcome a complication that arises when I attempt to do so after having removed the facet strips from my graphs. In the following example, I have added horizontal and vertical strips to each graph by faceting on a dummy variable:
p00 <- p00 + facet_grid(z ~ z)
p01 <- p01 + facet_grid(z ~ z)
p10 <- p10 + facet_grid(z ~ z)
p11 <- p11 + facet_grid(z ~ z)
grid.arrange(p00, p01, p10, p11, ncol = 2)
Next I remove the strips according to the procedure outlined in this post. However, the resulting graphs are rather widely spaced by comparison:
p00 <- p00 + theme(plot.margin = unit(c(0,0.5,0.5,0), units = "lines" ), strip.background = element_blank(), strip.text = element_blank())
p01 <- p01 + theme(plot.margin = unit(c(0,0.5,0.5,0), units = "lines" ), strip.background = element_blank(), strip.text = element_blank())
p10 <- p10 + theme(plot.margin = unit(c(0,0.5,0.5,0), units = "lines" ), strip.background = element_blank(), strip.text = element_blank())
p11 <- p11 + theme(plot.margin = unit(c(0,0.5,0.5,0), units = "lines" ), strip.background = element_blank(), strip.text = element_blank())
grid.arrange(p00, p01, p10, p11, ncol = 2)
Any suggestions on how to reduce the spacing between graphs would be much appreciated.

To remove all elements associated with the axes, in addition to the elements you have set to element_blank, the tick margins and tick lengths need to be set to zero. But space will remain for the facet strips. Setting the background and text to element_blank does not affect the height and width of the strips. To remove the strips, I use functions that manipulate the gtable layout. However, I think it is better to leave some white space between the plots. I have set a small plot margin to 0.2 lines.
library(ggplot2)
library(gridExtra)
set.seed(314159)
n <- 100
data <- data.frame(x = rnorm(n), y = rnorm(n), z1 = rep("dummy var", n), z2 = rep("dummy var", n))
theme = theme(plot.margin = unit(c(.2,.2,.2,.2), units = "lines"),
axis.text = element_blank(),
axis.title = element_blank(),
axis.ticks = element_blank(),
axis.ticks.length = unit(0, "lines"))
labs = labs(x = NULL, y = NULL)
p00 <- ggplot(data, aes(x)) + stat_density() + theme + labs + facet_grid(z1 ~ z2)
p01 <- ggplot(data, aes(x, y)) + geom_point() + theme + labs + facet_grid(z1 ~ z2)
p10 <- ggplot(data, aes(y, x)) + geom_point() + theme + labs + facet_grid(z1 ~ z2)
p11 <- ggplot(data, aes(y)) + stat_density() + theme + labs + facet_grid(z1 ~ z2)
This is where the gtable layout is manipulated.
# Get the four gtables (and the four plots) into a list
pList = list(p00, p01, p10, p11)
gList = lapply(pList, ggplotGrob)
# Remove the top strip from each plot
stripT <- subset(gList[[1]]$layout, grepl("strip-t", gList[[1]]$layout$name))
gList = lapply(gList, function(x) x[-stripT$t, ])
# Remove the right strip from each plot
stripR <- subset(gList[[1]]$layout, grepl("strip-r", gList[[1]]$layout$name))
gList = lapply(gList, function(x) x[, -stripR$r])
# Draw the revised plots
nCol <- floor(sqrt(length(pList)))
do.call(grid.arrange, c(gList, ncol = nCol))
Edit: Using revised data and plot.
library(grid)
data <- data.frame(x = rnorm(n), y = rnorm(n), z = rep("dummy var", n), u = seq(1, n) %% 2)
p01 <- ggplot(data, aes(x, y)) + geom_point() + theme + labs + facet_grid(z ~ u)
g = ggplotGrob(p01)
stripT = subset(g$layout, grepl("strip-t", g$layout$name))
g = g[-stripT$t, ]
stripR = subset(g$layout, grepl("strip-r", g$layout$name))
g = g[, -stripR$r]
grid.draw(g) # Still got the space between the facets
g$widths # where is the space? it's the 5.55 pt width
g$widths[[5]] = unit(0, "lines") # remove it completely
g$width
grid.draw(g)

Related

Equalise panel height in mutliplot figure using ggplot2 and grid.arrange

How can I equalise the height of the grey panel and at the same time align all panels (even the flipped and reversed)? The problem is that due to the fact that the top plot does have no axis labels etc, the panel height is slightly larger.
library(ggplot2)
library(gridExtra)
library(grid)
# Plot 1
df1 <- data.frame(n = 1:10, y = rnorm(10, 5))
plot1 <- ggplot(df1, aes(x = n, y = y)) +
geom_bar(stat = "identity") +
labs(y = 'AU', x = NULL) +
theme(axis.title.x = element_blank(),
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
plot.margin = unit(c(0.1, 0.1, 0.1, 0), "cm"))
# Plot 2
df2 <- data.frame(x = rnorm(100), y = rnorm(100))
plot2 <- ggplot(df2, aes(x = x, y = y)) +
geom_point() +
labs(y = 'AU', x = NULL) +
theme(axis.title.x = element_blank(),
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
plot.margin = unit(c(0.1, 0.1, 0.1, 0), "cm"))
# Plot 3
df3 <- data.frame(x = rnorm(100))
plot3 <- ggplot(df3, aes(x = x)) +
coord_flip() +
geom_histogram() +
theme(axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.x = element_blank(),
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
plot.margin = unit(c(0.1, 0.1, 0.1, 0), "cm"))
# Plot 4
df4 <- data.frame(n = 1:10, y = rnorm(10, 4))
plot4 <- ggplot(df4, aes(x = n, y = y)) +
scale_y_reverse() +
geom_bar(stat = "identity") +
labs(y = 'AU', x = 'N') +
theme(plot.margin = unit(c(0.1, 0.1, 0.1, 0), "cm"))
# Get blank plot
blank <- grid.rect(gp=gpar(col="white"))
# Combine everything into one plot
## Get Grobs
gplot1 <- ggplotGrob(plot1)
gplot2 <- ggplotGrob(plot2)
gplot3 <- ggplotGrob(plot3)
gplot4 <- ggplotGrob(plot4)
# Align widths
maxWidth = grid::unit.pmax(gplot1$widths, gplot2$widths, gplot4$widths)
gplot1$widths <- as.list(maxWidth)
gplot2$widths <- as.list(maxWidth)
gplot4$widths <- as.list(maxWidth)
# Grid arrange
grid.arrange(grobs = list(gplot1, blank, gplot2, gplot3, gplot4, blank),
newpage = FALSE,
ncol = 2,
widths = c(12, 3))
Since I want the middle scatter plot's y-axis to be aligned to the flipped x-axis of the righthand side plot, I can't see how I can use rbind() as suggested here would work for here.
Also, setting the grob heights manually, e.g.
gplot4$heights<- gplot1$heights
just cuts of the labels. While, the reverse order (gplot1$heights<- gplot4$heights) introduces a big gap between the top and the middle plot.

Multiple fill legends for each variable in heat map

I have an input file file1.txt:
V1 V2 Score
rs4939134 SIFT 1
rs4939134 Polyphen2 0
rs4939134 MutationAssessor -1.75
rs151252290 SIFT 0.101
rs151252290 Polyphen2 0.128
rs151252290 MutationAssessor 1.735
rs12364724 SIFT 0
rs12364724 Polyphen2 0.926
rs12364724 MutationAssessor 1.75
rs34448143 SIFT 0.005
rs34448143 Polyphen2 0.194
rs34448143 MutationAssessor 0.205
rs115694714 SIFT 0.007
rs115694714 Polyphen2 1
rs115694714 MutationAssessor 0.895
And this is my R code to plot this table as a heatmap:
library(ggplot2)
mydata <- read.table("file7.txt", header = FALSE, sep = "\t")
names(mydata) <- c("V1", "V2", "Score")
ggplot(data = mydata, aes(x = V1, y = V2, fill = Score)) +
geom_tile() +
geom_text(aes(V1, V2, label = Score), color = "black", size = 3) +
scale_fill_continuous(type = "viridis", limits = c(-5.76, 5.37)) +
labs(x = "pic1", y = "") +
theme_bw()
theme(panel.border = element_rect(colour = "black"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.line = element_line(colour = "black"),
axis.text = element_text(size = 4))
And this the plot I got:
what I need is for each row (each type in V2) I need to put a legend that represented, so at the end there will be 3 legends, each represent (one for SIFT, second for Polyphen and the third for MutationAssessor) with different range that I can specify.
for example: SIFT from (0,1)
and Polyphen from (0,1)
and MutationAssessor from (-6,6)
I tried different thing of previous asked questions but nothing work with me.
I appreciate any help.
You can loop over three given variables and plot different plots for each of them. In the end you have to combine them.
Create dataset with wanted limits:
myLimits <- list(
list("SIFT", 0, 1),
list("Polyphen2", 0, 1),
list("MutationAssessor", -6, 6)
)
Function to plot heatmap only for one variable at a time:
plotHeat <- function(type, MIN, MAX) {
library(ggplot2)
p <- ggplot(subset(mydata, V2 == type),
aes(V1, V2, fill = Score, label = Score)) +
geom_tile() +
geom_text(color = "black", size = 3) +
scale_fill_continuous(type = "viridis", limits = c(MIN, MAX)) +
labs(x = "SNP",
y = NULL,
fill = type) +
theme_bw()
# Output x-axis only for the last plot
if (type != myLimits[[length(myLimits)]][[1]]) {
p <- p + theme(axis.text.x = element_blank(),
axis.title.x = element_blank(),
axis.line.x = element_blank(),
axis.ticks.x = element_blank())
}
return(p)
}
Plot and combine plots using egg package:
res <- lapply(myLimits, function(x) {plotHeat(x[[1]], x[[2]], x[[3]])})
egg::ggarrange(plots = res)
This is maybe related to this.
xs <- split(mydata, f = mydata$V2)
p1 <- ggplot(data = xs$MutationAssessor, aes(x = V1, y = 0, fill = Score)) +
geom_tile() +
geom_text(aes(label = Score), color = "black", size = 3) +
scale_fill_continuous(type = "viridis", limits = c(-5.76, 5.37)) +
labs(x = "pic1", y = "") +
facet_grid(V2 ~ .) +
theme_bw() +
theme(panel.border = element_rect(colour = "black"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.line = element_line(colour = "black"),
axis.text = element_text(size = 4))
p2 <- p1 %+% xs$Polyphen2
p3 <- p1 %+% xs$SIFT
library(gridExtra)
grid.arrange(p1, p2, p3)
And the result is:
EDIT:
In case you want different range for facets but you want values to be comparable (e.g. value around 5 should be yellow in all plots), there is a possible solution
First discretize your fill variable
mydata$colour <- cut(mydata$Score,
quantile(mydata$Score, c(0, 0.25, 0.5, 0.75, 1)),
include.lowest = T)
Then create plots:
xs <- split(mydata, f = mydata$V2)
p1 <- ggplot(data = xs$MutationAssessor, aes(x = V1, y = 0, fill = colour)) +
geom_tile() +
geom_text(aes(label = Score), color = "black", size = 3) +
labs(x = "pic1", y = "") +
facet_grid(V2 ~ .) +
theme_bw() +
theme(panel.border = element_rect(colour = "black"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.line = element_line(colour = "black"),
axis.text = element_text(size = 4))
p2 <- p1 %+% xs$Polyphen2
p3 <- p1 %+% xs$SIFT
And finally change palette:
mypalette <- c("#FFFFCC", "#A1DAB4", "#41B6C4", "#2C7FB8", "#253494")
names(mypalette) <- levels(mydata$colour)
p1 <- p1 + scale_fill_manual(values = mypalette[levels(xs$MutationAssessor$colour)])
p2 <- p2 + scale_fill_manual(values = mypalette[levels(xs$Polyphen2$colour)])
p3 <- p3 + scale_fill_manual(values = mypalette[levels(xs$SIFT$colour)])
And the result is:
grid.arrange(p1, p2, p3)

ggplot2: Make the filled area of the spatial plot flush with facet strip [duplicate]

I am creating some maps and want to remove all margins between the plot region and panel border.
This is the minimal example to reproduce my question
library(ggplot2)
library(grid)
df <- expand.grid(list(x = seq(1, 10), y = seq(1, 10), z = seq(1, 2)))
p <- ggplot(df) + geom_tile(aes(x, y)) + facet_wrap(~z)
p <- p + theme_minimal() + xlab('') + ylab('')
p <- p + theme(axis.text = element_blank(),
panel.grid = element_blank(),
axis.ticks = element_blank(),
panel.border = element_rect(colour = 'black', fill = 'transparent'),
panel.margin = unit(0, 'mm'))
p + ylim(2, 6) + xlim(2, 6)
This is the result of my codes.
How could I remove all white areas in the figure above? Thanks for any suggestions.
(Alright, here's my comment as an answer..)
Just add the following to the plot:
+ scale_y_continuous(expand = c(0,0)) + scale_x_continuous(expand = c(0,0))

How to make a complex heatmap using ggplot2?

I tried to plot a complex heatmap using ggplot2 with the cancer somatic mutation.
The data is here, and here is the code:
library(reshape2)
library(ggplot2)
library(scales)
library(gridExtra)
library(ggdendro)
library(zoo)
library(plyr)
#data process
mm8<-read.csv("mm8.csv",header=TRUE)
rownames(mm8)<-mm8$X
mm8<-mm8[,-2]
mm8[1:4,2:5]
#cluster from http://stackoverflow.com/questions/21474388/colorize-clusters-in-dendogram-with-ggplot2
df<-t(mm8)
df<-df[-1,]
cut <- 4 # Number of clusters
hc <- hclust(dist(df), "ave") # heirarchal clustering
dendr <- dendro_data(hc, type = "rectangle")
clust <- cutree(hc, k = cut) # find 'cut' clusters
clust.df <- data.frame(label = names(clust), cluster = clust)
# Split dendrogram into upper grey section and lower coloured section
height <- unique(dendr$segments$y)[order(unique(dendr$segments$y), decreasing = TRUE)]
cut.height <- mean(c(height[cut], height[cut-1]))
dendr$segments$line <- ifelse(dendr$segments$y == dendr$segments$yend &
dendr$segments$y > cut.height, 1, 2)
dendr$segments$line <- ifelse(dendr$segments$yend > cut.height, 1, dendr$segments$line)
# Number the clusters
dendr$segments$cluster <- c(-1, diff(dendr$segments$line))
change <- which(dendr$segments$cluster == 1)
for (i in 1:cut) dendr$segments$cluster[change[i]] = i + 1
dendr$segments$cluster <- ifelse(dendr$segments$line == 1, 1,
ifelse(dendr$segments$cluster == 0, NA, dendr$segments$cluster))
dendr$segments$cluster <- na.locf(dendr$segments$cluster)
# Consistent numbering between segment$cluster and label$cluster
clust.df$label <- factor(clust.df$label, levels = levels(dendr$labels$label))
clust.df <- arrange(clust.df, label)
clust.df$cluster <- factor((clust.df$cluster), levels = unique(clust.df$cluster), labels = (1:cut) + 1)
dendr[["labels"]] <- merge(dendr[["labels"]], clust.df, by = "label")
# Positions for cluster labels
n.rle <- rle(dendr$segments$cluster)
N <- cumsum(n.rle$lengths)
N <- N[seq(1, length(N), 2)] + 1
N.df <- dendr$segments[N, ]
N.df$cluster <- N.df$cluster - 1
# Plot the dendrogram
# Plot the dendrogram
p3<-ggplot() +
geom_segment(data = segment(dendr),
aes(x=x, y=y, xend=xend, yend=yend, size=factor(line), colour=factor(cluster)),
lineend = "square", show_guide = FALSE) +
scale_colour_manual(values = c("grey60", rainbow(cut))) +
scale_size_manual(values = c(.1, 1)) +
labs(x = NULL, y = NULL) +
theme(axis.line.y = element_blank(),
axis.ticks.y = element_blank(),
axis.text.y = element_blank(),
axis.title.y = element_blank(),
panel.background = element_blank(),
panel.grid = element_blank()) +
guides(fill = FALSE)+
theme(axis.ticks.x = element_blank(),
axis.text.x = element_blank(),
axis.title.x = element_blank(),
plot.background = element_blank())
#priparing a bar???
p4<-ggplot(clust.df,aes(x=label,y=1,fill=cluster))+geom_raster()+
theme(axis.line.y = element_blank(),
axis.ticks.y = element_blank(),
axis.text.y = element_blank(),
axis.title.y = element_blank(),
panel.background = element_blank(),
panel.grid = element_blank()) +
guides(fill = FALSE)+
theme(axis.ticks.x = element_blank(),
axis.text.x = element_blank(),
axis.title.x = element_blank(),
plot.background = element_blank())
#data for ggplot2 geom_raster
data.m = melt(mm8)
colnames(data.m)<-c("Var1", "Var2", "value")
head(data.m)
#plotting
p1 <- ggplot(data.m, aes(Var2, Var1)) + geom_raster(aes(fill = value),colour ="white")
p1<-p1 + theme(axis.ticks = element_blank(), axis.text = element_blank(),axis.title=element_blank(),plot.background = element_blank())
p2<-ggplot(data.m,aes(Var1,value*(-1)))+geom_bar(data.m, aes(fill=Var2),position="stack",stat="identity")+coord_flip()
p2<-ggplot(data.m,aes(Var1,value*(-1)))+geom_bar(data.m, aes(fill=Var2),position="stack",stat="identity")+coord_flip()+guides(fill = FALSE)+theme(axis.ticks.x = element_blank(), axis.text.x = element_blank(),axis.title.x = element_blank(),plot.background = element_blank())
#plotting 4 panels on a page
vplayout <- function(x, y) viewport(layout.pos.row = x, layout.pos.col = y)
#open graphic device
win.graph(width=860/72, height=450/72,pointsize = 12)
#plotting
grid.newpage()
pushViewport(viewport(layout = grid.layout(24, 50))) # 1 rows, 8 columns
#plotting
print(p2, vp = vplayout(5:24, 1:10))
print(p1, vp = vplayout(5:24, 10:50),newpage=FALSE)
print(p3, vp = vplayout(1:3, 9:47),newpage=FALSE)
print(p4, vp = vplayout(3:5, 10:46),newpage=FALSE)
#save
savePlot(filename="complex", type="emf")
dev.off()
And I got the picture like this:
1) How to automatically align P1,p3 and P4? For a sample on X, its features on p1, p3 and p4 are align automatically ?
2) Any good ideas to control the space between pancels? for example, reducing the space between p1 and p2, or p1 and p4.
3) How to reorder the samples on X-axis according to the cluster results? And how to control the order on X-axis for p1,p3,and p4 simultaneously?

How to show all the labels in X-axis 45 degree in R 2x2 bar plot

With the following data:
Method Metric E0 E1 E2 E4
Method-XXX Precision 0.9661017 0.9622642 1 0.9655172
Method-YYY Precision 0.533 0.535 0.378 0.214
Method-ZZZ Precision 0.595 0.843 0.77 0.689
Method-XZZZ Precision 0.573 0.698 0.53 0.708
Method-XZZZY Precision 0.008 0.011 0.004 0.002
Method-XXX Recall 0.9736842 0.9736842 0.9473684 0.9473684
Method-YYY Recall 1 1 1 0.667
Method-ZZZ Recall 0.833 1 1 1
Method-XZZZ Recall 1 1 1 1
Method-XZZZY Recall 0.167 0.75 1 1
I can create this plot:
However as you can see, the x-axis are not all assigned with labels.
How can I achieve that?
It's also ok if we rotate the x-axis 45 degree. But then I'm not sure how to do that:
This is my code (Courtesy of thelatemail):
dat <- read.table("http://dpaste.com/1563769/plain/",header=TRUE)
layout(matrix(c(1,2,5,3,4,5),nrow=2,byrow = TRUE))
barcols <- c("red","blue")
sapply(3:6,
function(x) {
bp <- barplot(matrix(dat[,x],nrow=2,byrow=TRUE),beside=TRUE,col=barcols)
title(main=names(dat[x]))
axis(1,at=colMeans(bp),c("Method-XXX","Method-YYY"," Method-ZZZ","Method-XZZZ"," Method-XZZZY"),lwd=0,lwd.tick=1)
abline(h=0)
}
)
plot(NA,xlim=c(0,1),ylim=c(0,1),ann=FALSE,axes=FALSE)
legend(0,0.6,c("Precision","Recall"),fill=barcols,cex=1.5)
Update
I tried the following to generate the 45 degree. But didn't work either:
sapply(3:6,
function(x) {
bp <- barplot(matrix(dat[,x],nrow=2,byrow=TRUE),xaxt="n",beside=TRUE,col=barcols)
title(main=names(dat[x]))
xaxislab <- c("Method-XXX","Method-YYY"," Method-ZZZ","Method-XZZZ"," Method-XZZZY")
text(cex=1, x=colMeans(bp)-.25, y=-1.25, xaxislab, xpd=TRUE, srt=45)
#axis(1,at=colMeans(bp),xaxislab,lwd=0,lwd.tick=1)
#abline(h=0)
}
)
plot(NA,xlim=c(0,1),ylim=c(0,1),ann=FALSE,axes=FALSE)
legend(0,0.1,c("Precision","Recall"),fill=barcols,cex=1.5)
Following basically the same strategy used in this answer (and demo'd in the first example in the gridBase vignette (pdf)) you could use grid.text() to annotate the base graphics output.
library(gridBase)
## Function that plots barplots with x-axes annotated with slanted
ff <- function(x) {
barcols <- c("red","blue")
## Plot, suppressing the labels
bp <- barplot(matrix(dat[,x], nrow = 2, byrow = TRUE), xaxt = "n",
beside = TRUE, col = barcols)
title(main=names(dat[x]))
xaxislab <- c("Method-XXX", "Method-YYY", " Method-ZZZ",
"Method-XZZZ", " Method-XZZZY")
## Compute x-axis coordinate at center of each group
bp <- colMeans(bp)
## Use gridBase to compute viewport coordinates and
## grid to push/pop viewports and add the labels
vps <- baseViewports()
pushViewport(vps$inner, vps$figure, vps$plot)
grid.text(xaxislab,
x = unit(bp, "native"), y = unit(-0.5, "lines"),
just = "right", rot = 45, gp=gpar(cex=0.7))
popViewport(3)
}
## Apply it to your data
dat <- read.table("http://dpaste.com/1563769/plain/",header=TRUE)
layout(matrix(c(1,2,5,3,4,5),nrow=2,byrow = TRUE))
sapply(3:6, ff)
With the reshape2 (for reshaping your data into long format) and ggplot2 (for plotting) packages, it will be quite a lot easier to make such a plot.
The code:
dat <- read.table("http://dpaste.com/1563769/plain/",header=TRUE)
library(reshape2)
library(ggplot2)
# reshape your data into long format
long <- melt(dat, id=c("Method","Metric"),
measure=c("E0","E1","E2","E4"),
variable = "E.nr")
# make the plot
ggplot(long) +
geom_bar(aes(x = Method, y = value, fill = Metric),
stat="identity", position = "dodge", width = 0.7) +
facet_wrap(~E.nr) +
scale_fill_manual("Metric\n", values = c("red","blue"),
labels = c(" Precision", " Recall")) +
labs(x="",y="") +
theme_bw() +
theme(
panel.grid.major.y = element_line(colour = "black", linetype = 3, size = .5),
panel.background = element_blank(),
axis.title.x = element_text(size=16),
axis.text.x = element_text(size=14, angle=45, hjust=1, vjust=1),
axis.title.y = element_text(size=16, angle = 90),
axis.text.y = element_text(size=14),
strip.background = element_rect(color="white", fill="white"),
strip.text = element_text(size=16)
)
The result:
When you want to keep axis-labels on each seperate plot, you'll need the ggplot2 and gridExtra packages.
The code:
dat <- read.table("http://dpaste.com/1563769/plain/",header=TRUE)
library(ggplot2)
library(gridExtra)
# making the seperate plots
pE0 <- ggplot(dat) +
geom_bar(aes(x = Method, y = E0, fill = Metric),
stat="identity", position = "dodge", width = 0.7) +
scale_fill_manual("Metric\n", values = c("red","blue"),
labels = c(" Precision", " Recall")) +
labs(title="E0\n",x="",y="") +
theme_bw() +
theme(
panel.grid.major.y = element_line(colour = "black", linetype = 3, size = .5),
panel.background = element_blank(),
axis.title.x = element_text(size=16),
axis.text.x = element_text(size=14, angle=30, hjust=1, vjust=1),
axis.title.y = element_text(size=16, angle = 90),
axis.text.y = element_text(size=14)
)
pE1 <- ggplot(dat) +
geom_bar(aes(x = Method, y = E1, fill = Metric),
stat="identity", position = "dodge", width = 0.7) +
scale_fill_manual("Metric\n", values = c("red","blue"),
labels = c(" Precision", " Recall")) +
labs(title="E1\n",x="",y="") +
theme_bw() +
theme(
panel.grid.major.y = element_line(colour = "black", linetype = 3, size = .5),
panel.background = element_blank(),
axis.title.x = element_text(size=16),
axis.text.x = element_text(size=14, angle=30, hjust=1, vjust=1),
axis.title.y = element_text(size=16, angle = 90),
axis.text.y = element_text(size=14)
)
pE2 <- ggplot(dat) +
geom_bar(aes(x = Method, y = E2, fill = Metric),
stat="identity", position = "dodge", width = 0.7) +
scale_fill_manual("Metric\n", values = c("red","blue"),
labels = c(" Precision", " Recall")) +
labs(title="E2\n",x="",y="") +
theme_bw() +
theme(
panel.grid.major.y = element_line(colour = "black", linetype = 3, size = .5),
panel.background = element_blank(),
axis.title.x = element_text(size=16),
axis.text.x = element_text(size=14, angle=30, hjust=1, vjust=1),
axis.title.y = element_text(size=16, angle = 90),
axis.text.y = element_text(size=14)
)
pE4 <- ggplot(dat) +
geom_bar(aes(x = Method, y = E4, fill = Metric),
stat="identity", position = "dodge", width = 0.7) +
scale_fill_manual("Metric\n", values = c("red","blue"),
labels = c(" Precision", " Recall")) +
labs(title="E4\n",x="",y="") +
theme_bw() +
theme(
panel.grid.major.y = element_line(colour = "black", linetype = 3, size = .5),
panel.background = element_blank(),
axis.title.x = element_text(size=16),
axis.text.x = element_text(size=14, angle=30, hjust=1, vjust=1),
axis.title.y = element_text(size=16, angle = 90),
axis.text.y = element_text(size=14)
)
# function to extract the legend (borrowed from: https://github.com/hadley/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs )
g_legend<-function(a.gplot){
tmp <- ggplot_gtable(ggplot_build(a.gplot))
leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
legend <- tmp$grobs[[leg]]
return(legend)}
legend <- g_legend(pE1)
lwidth <- sum(legend$width)
# combining the plots with gridExtra
grid.arrange(arrangeGrob(pE0 + theme(legend.position="none"),
pE1 + theme(legend.position="none"),
pE2 + theme(legend.position="none"),
pE4 + theme(legend.position="none")
),
legend, widths=unit.c(unit(1, "npc") - lwidth, lwidth), nrow=1)
The result:
Here's a way to get all the labels without rotating. You plot the axis labels on two lines instead of one to avoid overlap. I've done it with a single graph to demonstrate the method.
dat <- read.table("http://dpaste.com/1563769/plain/",header=TRUE)
# Create barplot
barplot(height=dat$E0, beside=TRUE, col=c("red","blue"))
# Get x-coordinates of bars
x.coords = barplot(height=dat$E0, beside=TRUE, plot=FALSE)
# Create new coordinates between each pair of bars
new.x.coords = seq(sum(x.coords)[1:2]/2, sum(x.coords)[9:10]/2, x.coords[2]-x.coords[1])
# Plot axis labels, but not axis or tickmarks
axis(side=1, at=new.x.coords[c(1,3,5)], labels=dat$Method[c(1,3,5)], line=0, tick=FALSE)
axis(side=1, at=new.x.coords[c(2,4)], labels=dat$Method[c(2,4)], line=1, tick=FALSE)
# Plot just axis and tickmarks, but not labels
axis(side=1, at=new.x.coords, labels=NA)
add to rotate 45 degrees
dat <- read.table("http://dpaste.com/1563769/plain/",header=TRUE)
layout(matrix(c(1,2,5,3,4,5),nrow=2,byrow = TRUE))
barcols <- c("red","blue")
sapply(3:6,
function(x) {
#par(las = 2)
bp <- barplot(matrix(dat[,x],nrow=2,byrow=TRUE),beside=TRUE,col=barcols)
title(main=names(dat[x]))
#axis(1,at=colMeans(bp),lwd=0,lwd.tick=1,srt=45)
text(colMeans(bp), par("usr")[3] , labels = c("Method-XXX","Method-YYY"," Method-ZZZ","Method-XZZZ"," Method-XZZZY"), srt = 45, pos = 1, xpd = TRUE)
abline(h=0)
}
)
plot(NA,xlim=c(0,1),ylim=c(0,1),ann=FALSE,axes=FALSE)
legend(0,0.6,c("Precision","Recall"),fill=barcols,cex=1.5)
add this to rotate 180 degrees the labels par(las = 2)
dat <- read.table("http://dpaste.com/1563769/plain/",header=TRUE)
layout(matrix(c(1,2,5,3,4,5),nrow=2,byrow = TRUE))
barcols <- c("red","blue")
sapply(3:6,
function(x) {
#add this to rotate the labels
par(las = 2)
bp <- barplot(matrix(dat[,x],nrow=2,byrow=TRUE),beside=TRUE,col=barcols)
title(main=names(dat[x]))
axis(1,at=colMeans(bp),c("Method-XXX","Method-YYY"," Method-ZZZ","Method-XZZZ"," Method-XZZZY"),lwd=0,lwd.tick=1)
abline(h=0)
}
)
plot(NA,xlim=c(0,1),ylim=c(0,1),ann=FALSE,axes=FALSE)
legend(0,0.6,c("Precision","Recall"),fill=barcols,cex=1.5)

Resources