Reputation: 781
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.
Upvotes: 2
Views: 551
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)
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)
Upvotes: 4