1

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:

enter image description here

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)
Community
  • 1
  • 1
neversaint
  • 60,904
  • 137
  • 310
  • 477

4 Answers4

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)

enter image description here

Community
  • 1
  • 1
Josh O'Brien
  • 159,210
  • 26
  • 366
  • 455
3

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: enter image description here

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: enter image description here

Jaap
  • 81,064
  • 34
  • 182
  • 193
1

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)
eipi10
  • 91,525
  • 24
  • 209
  • 285
0

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)
Keniajin
  • 1,649
  • 2
  • 20
  • 43