Adjust widths of multiple plots made by lapply, arrangeGrob - r

I have code to make plots following:
My question is how to adjust the widths of 1st plot and last plot in the figure made?
dat=data.frame(x=rep(c("M","D"),each=60),y=rep(rep(c(4,6,8,10,12),each=12),2),z=runif(120,0,100),s=rep(c(1:4),each=3,len=120))
gp=lapply(split(dat,dat$y),function(dfr){
g=ggplot(data = dfr, aes(s,z)) +
geom_point(aes(shape=x,colour=x),size=4)+
ylim(0,100)+
xlab("Int segs")+
ggtitle(paste(dfr[1,2],"hours"))
return(g)})
tiff(file="Pas.tiff",width=60, height = 22,units="cm",res=300)
require(gridExtra)
rg=arrangeGrob(grobs=list(gp$`4` + theme(legend.position="none"),
gp$`6` + theme(legend.position="none",
axis.title.y = element_blank(),
axis.text.y = element_blank()),
gp$`8` + theme(legend.position="none",
axis.title.y = element_blank(),
axis.text.y = element_blank()),
gp$`10` + theme(legend.position="none",
axis.title.y = element_blank(),
axis.text.y = element_blank()),
gp$`12` + theme(axis.title.y = element_blank(),
axis.text.y = element_blank())),ncol=5,
top=textGrob("Pas rate",
gp=gpar(fontsize=20,fontface="bold"),
y = unit(.4, "cm")),
theme(margin(t=70,r=0.2,b=0.5,l=0.3,unit="mm")))
grid.newpage()
#grid.draw(cbind(lg, rg, size = "last"))
grid.draw(rg)
dev.off()

i'd use cbind() here (if facetting isn't an option)
gp[[1]] <- gp[[1]] + theme(legend.position="none")
gp[[5]] <- gp[[5]] + theme(axis.title.y = element_blank(),
axis.text.y = element_blank())
gp[c("6", "8", "10")] <- lapply(gp[c("6", "8", "10")], "+", e2 = theme(legend.position="none",
axis.title.y = element_blank(),
axis.text.y = element_blank()))
grid.newpage()
grid.draw(do.call(gridExtra::cbind.gtable, lapply(gp, ggplotGrob)))

I suggest you use gtable: you can extract legend and y.label from a first "dummy" plot, then plot each graph within a cell and with the same dimensions (having removed both legend and y.label from all of them, including 1st and last) to then add y.label and legend into separate cells.
require(ggplot2)
require(gtable)
require(grid)
library(dplyr)
library(scales)
dat <- data.frame(x=rep(c("M","D"),each=60),
y=rep(rep(c(4,6,8,10,12),each=12),2),
z=runif(120,0,100),
s=rep(c(1:4),each=3,len=120))
gp <- lapply(split(dat,dat$y),function(dfr){
g=ggplot(data = dfr, aes(s,z)) +
geom_point(aes(shape=x,colour=x),size=4)+
ylim(0,100)+
xlab("Int segs")+
ggtitle(paste(dfr[1,2],"hours"))
return(g)
})
tiff(file="Pas.tiff",width=60, height = 22,units="cm",res=300)
## Step 1:
## "dummy" plot, just to take y axis title/text and legend
dummy <- ggplotGrob(gp[[1]] + theme(panel.background = element_blank()))$grobs
legend <- dummy[[which(sapply(dummy, function(x) x$name) == "guide-box")]]
ytitle <- dummy[[grep("axis.title.y",sapply(dummy, function(x) x$name))]]
yticks <- dummy[[2]]
## Step 2:
## actual plots, all of them without y axis title/text and legend
pp <- 1
tab <- ggplotGrob(gp[[pp]] + theme(legend.position="none",
axis.title.y = element_blank(),
axis.text.y = element_blank()))
for(pp in 2:length(gp)){
tab <- gtable_add_cols(tab, unit(1,"null"))
tab <- gtable_add_grob(tab, ggplotGrob(gp[[pp]] + theme(legend.position="none",
axis.title.y = element_blank(),
axis.text.y = element_blank())),
t = 1, l = ncol(tab), b=nrow(tab), r=ncol(tab))
}
## Step 2:
## adding back ytitle, yticks and legend
## add narrow column to the left and put yticks labels withint
tab <- gtable_add_cols(tab, unit(1,"cm"), pos=0)
tab <- gtable_add_grob(tab, yticks,
t = 3, l = 2, b=nrow(tab)-3, r=1)
## add narrow column to the left and put y.axis label withint
ab <- gtable_add_cols(tab, unit(1,"cm"), pos=0)
tab <- gtable_add_grob(tab, ytitle,
t = 1, l = 1, b=nrow(tab), r=1)
## add narrow column to the right and put legend within
tab <- gtable_add_cols(tab, unit(1.5,"cm"))
tab <- gtable_add_grob(tab, legend,
t = 1, l = ncol(tab), b=nrow(tab), r=ncol(tab))
grid.newpage()
grid.draw(tab)
dev.off()

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.

Align a piechart in plot area

I'm generating a pie chart that I would like to incorporate into a Shiny page. The plot area (i.e.: the white space surrounding the plot) will be fluid. I'd like the plot itself (the grey area and the pie chart) to align to the left-hand side of the plot area, instead of appearing centered. Any ideas?
ggplot(treeData, aes(x = "", fill = ClassName)) +
ggtitle("Species distribution") +
geom_bar(width = 1) +
coord_polar("y", start=0) +
xlab("") + ylab("") +
theme(
axis.text.x=element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
panel.grid = element_blank(),
plot.margin=unit(c(25,0,0,0), "pt")) +
scale_fill_manual(values= c("#ffff00", "#008080", "#00ff00"))
The more detailed explanation for why this answer works is provided here. In brief, you need to place the plot into a grid that can expand as you resize the enclosing image.
library(ggplot2)
library(grid)
library(gtable)
# some test data
animals <- as.data.frame(
table(Species =
c(rep("Moose", sample(1:100, 1)),
rep("Frog", sample(1:100, 1)),
rep("Dragonfly", sample(1:100, 1))
)))
# make the pie chart
g <- ggplot(animals, aes(x = "", y = Freq, fill = Species)) +
geom_bar(width = 1, stat = "identity") +
coord_polar("y", start=0) +
theme(
axis.text.x=element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
panel.grid = element_blank(),
plot.margin=unit(c(25,0,0,0), "pt"))
# set the desired width and height of the
# pie chart (need to play around to find
# numbers that work
plotwidth = unit(6.1, "inch")
plotheight = unit(5, "inch")
# place into matrix that can expand
grob <- ggplotGrob(g)
mat <- matrix(list(grob, nullGrob(), nullGrob(), nullGrob()), nrow = 2)
widths <- unit(c(1, 1), "null")
widths[1] <- plotwidth
heights <- unit(c(1, 1), "null")
heights[1] <- plotheight
gm <- gtable_matrix(NULL, mat, widths, heights)
grid.newpage()
grid.draw(gm)
You can try to change the margins by adding
theme(plot.margin = unit(c(5.5, 100, 5.5, -100), "points"))
or use the cowplot function
cowplot::plot_grid(your_plot, NULL, ncol=2, rel_widths = c(2,1))

How to set legend height to be the same as the height of the plot area?

I have arranged two plots: a line chart on top and a heatmap below.
I want the heatmap legend to have the same height as the plot area of the heatmap, i.e. the same length as the y-axis. I know that I can change the height and size of the legend using theme(legend.key.height = unit(...)), but this would take many trial and errors before I find an adequate setting.
Is there a way to specify the height of the legend so that it is exactly the same height of the plot area of the heatmap and would retain that ratio when plotting to a pdf?
A reproducible example with code I have tried:
#Create some test data
pp <- function (n, r = 4) {
x <- seq(1:100)
df <- expand.grid(x = x, y = 1:10)
df$z <- df$x*df$y
df
}
testD <- pp(20)
#Define groups
colbreaks <- seq(min(testD[ , 3]), max(testD[ , 3] + 1), length = 5)
library(Hmisc)
testD$group <- cut2(testD[ , 3], cuts = c(colbreaks))
detach(package:Hmisc, unload = TRUE)
#Create data for the top plot
testD_agg <- aggregate(.~ x, data=testD[ , c(1, 3)], FUN = sum)
#Bottom plot (heatmap)
library(ggplot2)
library(gtable)
p <- ggplot(testD, aes(x = x, y = y)) +
geom_tile(aes(fill = group)) +
scale_fill_manual(values = c("red", "orange", "yellow", "lightgreen")) +
coord_cartesian(xlim = c(0, 100), ylim = c(0.5, 10.5)) +
theme_bw() +
theme(legend.position = "right",
legend.key = element_blank(),
legend.text = element_text(colour = "black", size = 12),
legend.title = element_blank(),
axis.text.x = element_text(size = 12, angle = 45, vjust = +0.5),
axis.text.y = element_text(size = 12),
axis.title = element_text(size = 14),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
plot.margin = unit(c(0, 0, 0, 0), "line"))
#Top plot (line)
p2 <- ggplot(testD_agg, aes(x = x, y = z)) +
geom_line() +
xlab(NULL) +
coord_cartesian(xlim = c(0, 100), ylim = c(0, max(testD_agg$z))) +
theme_bw() +
theme(legend.position = "none",
legend.key = element_blank(),
legend.text = element_text(colour = "black", size = 12),
legend.title = element_text(size = 12, face = "plain"),
axis.text.x = element_blank(),
axis.text.y = element_text(size = 12),
axis.title = element_text(size = 14),
axis.ticks.x = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
plot.margin = unit(c(0.5, 0.5, 0, 0), "line"))
#Create gtables
gp <- ggplotGrob(p)
gp2 <- ggplotGrob(p2)
#Add space to the right of the top plot with width equal to the legend of the bottomplot
legend.width <- gp$widths[7:8] #obtain the width of the legend in pff2
gp2 <- gtable_add_cols(gp2, legend.width, 4) #add a colum to pff with with legend.with
#combine the plots
cg <- rbind(gp2, gp, size = "last")
#set the ratio of the plots
panels <- cg$layout$t[grep("panel", cg$layout$name)]
cg$heights[panels] <- unit(c(2,3), "null")
#remove white spacing between plots
cg <- gtable_add_rows(cg, unit(0, "npc"), pos = nrow(gp))
pdf("test.pdf", width = 8, height = 7)
print(grid.draw(cg))
dev.off()
#The following did not help solve my problem but I think I got close
old.height <- cg$grobs[[16]]$heights[2]
#It seems the height of the legend is given in "mm", change to "npc"?
gp$grobs[[8]]$grobs[[1]]$heights <- c(rep(unit(0, "npc"), 3), rep(unit(1/4, "npc"), 4), rep(unit(0, "mm"),1))
#this does allow for adjustment of the heights but not the exact control I need.
My actual data has some more categories, but the gist is the same.
Here is an image produced with the code above and annotated with what I would like to do.
Thanks in advance!
Maarten
It seems there are two sets of heights that need adjustment: the heights of the legend keys, and the overall height of the legend. Picking up from your cg grob, I extract the legend, make the adjustments to the heights, then insert the legend grob back into the layout.
leg = gtable_filter(cg, "guide-box")
library(grid)
# Legend keys
leg[[1]][[1]][[1]][[1]]$heights = unit.c(rep(unit(0, "mm"), 3),
rep(unit(1/4, "npc"), 4),
unit(0, "mm"))
# Legend
leg[[1]][[1]]$heights[[3]] = sum(rep(unit(0, "mm"), 3),
rep(unit(1/4, "npc"), 4),
unit(0, "mm"))
# grid.draw(leg) # Check that heights are correct
cg.new = gtable_add_grob(cg, leg, t = 17, l = 8)
grid.newpage()
grid.draw(cg.new)

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