BIN
BIN

Reputation: 781

Change label of yaxis face in plot with ggplot package R

This is my dataset and the code to generate the plot.

library(reshape)
library(ggplot2)
set.seed(357)
myLetters <- function(length.out) {
a <- rep(letters, length.out = length.out)
grp <- cumsum(a == "a")
vapply(seq_along(a), 
     function(x) paste(rep(a[x], grp[x]), collapse = ""),
     character(1L))
}
name <- myLetters(90)
x <- data.frame(name = name, before = runif(90,min=-1, max=1),after =    runif(90,min=-0.2, max=0.2))
x <- x[order(x$before),]
xnew <- melt(x, id="name")
adata <- subset(xnew,xnew$variable=="after")
adata$name1 <- rep(1:90)
bdata <- subset(xnew,xnew$variable=="before")
bdata$name1 <- rep(1:90)
d <- rbind(bdata,adata)
d$name1 <- factor(d$name1,levels =c(1:90),labels = bdata$name)
colorname <- c("dark blue","dark red")
plot <- ggplot(data=d,aes(x=value,y=name1,group=variable,color=variable))+
    scale_fill_manual(values=colorname) +  
    scale_colour_manual(values=colorname) +  # I ADDED THIS LINE
    geom_point(size=1)+
    geom_path(aes(linetype = variable),size=0.3)+
    scale_linetype_manual(values=c("dashed", "solid"))+
    geom_vline(xintercept = c(-0.5,0,0.5),color="purple",size=0.5)+
   theme(panel.border = element_rect(colour = "black", fill=NA, size=0.5)
   )

plot

The y-axis tick mark labels are too close to each other because there are 90 labels. Is there a way to position the y-axis tick mark labels so that the first label is positioned as default, the second label is refleced in the y-axis, and so on for all 90 labels? Maybe it will help to make the plot easier to read.

enter image description here

Upvotes: 2

Views: 551

Answers (1)

Sandy Muspratt
Sandy Muspratt

Reputation: 32874

I don't think there is any way to do this using regular ggplot2 commands. But it is possible to edit the plot using grid editing functions. Two possibilities: the first staggers the y axis labels as shown here; the second, as you suggest, is to reflect every second label (and tick mark) in the y axis. I leave it to you to decide if either is any more readable than the original.

## Your data and code to generate the unedited plot

library(reshape)
library(ggplot2)
library(grid)
set.seed(357)
myLetters <- function(length.out) {
a <- rep(letters, length.out = length.out)
grp <- cumsum(a == "a")
vapply(seq_along(a), 
     function(x) paste(rep(a[x], grp[x]), collapse = ""),
     character(1L))
}
name <- myLetters(90)
x <- data.frame(name = name, before = runif(90,min=-1, max=1),after =    runif(90,min=-0.2, max=0.2))
x <- x[order(x$before),]
xnew <- melt(x, id="name")
adata <- subset(xnew,xnew$variable=="after")
adata$name1 <- rep(1:90)
bdata <- subset(xnew,xnew$variable=="before")
bdata$name1 <- rep(1:90)
d <- rbind(bdata,adata)
d$name1 <- factor(d$name1,levels =c(1:90),labels = bdata$name)
colorname <- c("dark blue","dark red")
plot <- ggplot(data=d,aes(x=value,y=name1,group=variable,color=variable))+
    scale_fill_manual(values=colorname) +  
    scale_colour_manual(values=colorname) +  # I ADDED THIS LINE
    geom_point(size=1)+
    geom_path(aes(linetype = variable),size=0.3)+
    scale_linetype_manual(values=c("dashed", "solid"))+
    geom_vline(xintercept = c(-0.5,0,0.5),color="purple",size=0.5)+
   theme(panel.border = element_rect(colour = "black", fill=NA, size=0.5)
   ) + theme_bw()

plot

First possibility

# Get the ggplot grob
g = ggplotGrob(plot)

# Make the relevant column a little wider
g$widths[3] = unit(1.5, "cm")

# Get a hierarchical list of component grobs
grid.ls(grid.force(g)) 

Look through the list to find the section referring to the left axis. The relevant bit is:

axis-l.6-3-6-3   
  axis.line.y..zeroGrob.1864   
  axis   
    axis.1-1-1-1   
      GRID.text.1861   
    axis.1-2-1-2

You will need to set up path (see gPath in the editGrob() function below) from 'axis-l', through 'axis', through 'axis', through to 'GRID.text'. The x coordinate for the labels is currently 1npc. All I do here is move every second label to 0npc.

# The edit 
g = editGrob(grid.force(g), 
      gPath("axis-l", "axis", "axis", "GRID.text"), 
      x = unit(c(1, 0), "npc"), 
      grep = TRUE)

# Draw the plot
grid.newpage()
grid.draw(g)

enter image description here

Second possibility - Requires a bit more work

# Get the ggplot grob
g = ggplotGrob(plot)

# Get a hierarchical list of component grobs.
# Need a path to the labels as before,
# and a path to the tick marks.
grid.ls(grid.force(g))

# Get info about the plot: tick mark length, right margin of the tick mark labels, and
# number of labels 
 plot_theme <- function(p) {
   plyr::defaults(p$theme, theme_get())
 }

tickMarkLength <- plot_theme(plot)$axis.ticks.length 
textRightMargin <- plot_theme(plot)$strip.text.y$margin[2]
numberOfLabels <-  length(unique(ggplot_build(plot)$data[[1]]$y))

## The edits:
# Edit the x positions of every second label
g = editGrob(grid.force(g), 
      gPath("axis-l", "axis", "axis", "GRID.text"), 
      x = unit.c(unit(1, "npc"), unit(1, "npc") + 2*tickMarkLength + textRightMargin - unit(1, "pt")),
      hjust = c(1, 0), 
      grep = TRUE)

# Edit the x coordinates of the tick marks
# Need to check for even or odd number of labels
xcoord = rep(unit.c(unit(1, "npc") - tickMarkLength, unit(1, "npc"),
              unit(1, "npc") + tickMarkLength, unit(1, "npc")), numberOfLabels/2)
if((numberOfLabels %% 2) == 0)   {
      xcoord = xcoord
   } else {
      xcoord = unit.c(xcoord, unit.c(unit(1, "npc") - tickMarkLength, unit(1, "npc")))
   }
g = editGrob(grid.force(g), 
      gPath("axis-l", "axis", "axis.1-2"), 
      x = xcoord, 
      grep = TRUE)


# Draw the plot
grid.newpage()
grid.draw(g)

enter image description here

Upvotes: 4

Related Questions