问题
I want longer tick marks for those with labels in a facet grid. So I worked through this attempt and tried to adapt it to facet gridded plots like so:
Defining breaks and labels, minor and major:
range.f <- range(unique(df1$weeks))
minor.f <- 1 # every 1 week, NOTE: range.f[2] should be divisible by minor.f!
major.f <- 5 # every 5 weeks
breaks.f <- seq(range.f[1], range.f[2], minor.f)
every_nth.lt <- function (x, nth) {x[1:nth != 1] <- ""; x}
# (lite version of https://stackoverflow.com/a/34533473/6574038
# works better for me than `insert_minor()`)
labels.f <- every_nth.lt(sequence(range.f[2]), major.f)
n_minor.f <- major.f / minor.f - 1
Normal plot:
library(ggplot2)
p.f <- ggplot(df1, aes(weeks, births)) +
geom_bar(stat="identity", fill="#F48024") + theme_bw() +
scale_x_continuous(breaks=breaks.f, labels=labels.f) +
coord_cartesian(xlim=range.f) +
facet_wrap(year ~ .) +
theme(panel.grid = element_blank(),
axis.text.x = element_text(margin=margin(t=5, unit="pt")))
Manipulating plot:
g.f <- ggplotGrob(p.f)
xaxis.f <- g.f$grobs[grep("^axis-b", g.f$layout$name)] # get x-axes
ticks.f <- do.call(c, lapply(lapply(xaxis.f, "["),
function(x) x$children[[2]])) # get ticks
marks.f <- ticks.f$grobs[[1]] # get tick marks
# editing y-positions of tick marks
marks.f$y <- unit.c(unit.c(unit(1, "npc") - unit(6, "pt"),
unit(1, "npc"),
rep(unit.c(unit(1, "npc") - unit(3, "pt"),
unit(1, "npc")), n_minor.f)))
# putting tick marks back into plot
ticks.f$grobs[[1]] <- marks.f
for(i in seq_along(xaxis.f)) {
xaxis.f[[i]]$children[[2]]$grob <- ticks.f[[i]]
}
g.f$grobs[grep("^axis-b", g.f$layout$name)] <- xaxis.f
Drawing the plot:
library(grid)
grid.newpage()
grid.draw(g.f)
Yielding:
I followed all the steps of the linked answer, just adapted it to the situation that there are lists in the grob. But, the longer tick marks won't show up.
Does anybody see what I did wrong?
Or, maybe is there another way how to lengthen the axis ticks of those axis ticks which have labels?
Expected Output:
At the end the tick marks of all three plots should look like this:
Data:
tmp <- data.frame(date=as.Date(sample(1:1095, 10000, replace=TRUE),
origin="2014-01-01"),
births=sample(0:10, 10000, replace=TRUE))
tmp$year <- factor(substr(tmp$date, 1, 4))
df1 <- aggregate(births ~ date + year, tmp, sum)
rm(tmp) # remove tmp
df1$weeks <- as.integer(strftime(lubridate::floor_date(as.Date(df1$date,
format="%m/%d/%Y"),
unit="week"), "%W")) + 1
回答1:
I'm sure you could improve upon this. I just worked through it and got things correctly pulled out, and put back in. Mostly by comparing it to a single plot, and then making it loop over a list of grobs.
The range and breaks may need to change, since here they're all the same, but with different x-axes
you could customize the breaks appropriately.
tmp <- data.frame(date=as.Date(sample(1:1095, 10000, replace=TRUE),
origin="2014-01-01"),
births=sample(0:10, 10000, replace=TRUE))
tmp$year <- factor(substr(tmp$date, 1, 4))
df1 <- aggregate(births ~ date + year, tmp, sum)
rm(tmp) # remove tmp
df1$weeks <- as.integer(strftime(lubridate::floor_date(as.Date(df1$date,
format="%m/%d/%Y"),
unit="week"), "%W")) + 1
# breaks and labels, minor and major
range.f <- 1:(max(unique(df1$weeks)))
minor.f <- 1 # every 1 week, NOTE: range.f[2] should be divisible by minor.f!
major.f <- 5 # every 5 weeks
breaks.f <- seq(min(range.f), max(range.f), minor.f)
every_nth.lt <- function (x, nth) {x[1:nth != 1] <- ""; x}
# (lite version of https://stackoverflow.com/a/34533473/6574038)
labels.f <- every_nth.lt(range.f, major.f)
n_minor.f <- major.f / minor.f - 1
# plot
library(ggplot2)
library(grid)
p.f <- ggplot(df1, aes(weeks, births)) +
geom_bar(stat="identity", fill="#F48024") + theme_bw() +
scale_x_continuous(breaks=breaks.f, labels=labels.f) +
coord_cartesian(xlim=range.f) +
facet_wrap(year ~ .) +
theme(panel.grid = element_blank(),
axis.text.x = element_text(margin=margin(t=5, unit="pt")))
# manipulating plot
g.f <- ggplotGrob(p.f)
xaxis.f <- g.f$grobs[grep("^axis-b", g.f$layout$name)] # get x-axes
ticks.f <- c()
for(i in seq_along(xaxis.f)) {
ticks.f[[i]] <- xaxis.f[[i]]$children[[2]]
}
marks.f <- c()
for(i in seq_along(ticks.f)) {
marks.f[[i]] <- ticks.f[[i]][1]$grobs
}
# editing y-positions of tick marks
for(i in seq_along(marks.f)) {
marks.f[[i]][[1]]$y <- unit.c(unit.c(unit(1, "npc") - unit(6, "pt"),
unit(1, "npc"),
rep(unit.c(unit(1, "npc") - unit(3, "pt"),
unit(1, "npc")), n_minor.f)))
}
# putting tick marks back into plot
for(i in seq_along(ticks.f)) {
ticks.f[[i]]$grobs[[1]] <- marks.f[[i]][[1]]
}
for(i in seq_along(xaxis.f)) {
xaxis.f[[i]]$children[[2]] <- ticks.f[[i]]
}
g.f$grobs[grep("^axis-b", g.f$layout$name)] <- xaxis.f
# plot
grid.newpage()
grid.draw(g.f)
回答2:
And here's the revised code of the way I started, with a few less for
loops.
# Defining breaks and labels, minor and major:
range.f <- range(unique(df1$weeks))
minor.f <- 1 # every 1 week, NOTE: range.f[2] should be divisible by minor.f!
major.f <- 5 # every 5 weeks
breaks.f <- seq(range.f[1], range.f[2], minor.f)
every_nth.lt <- function (x, nth) {x[1:nth != 1] <- ""; x}
# (lite version of https://stackoverflow.com/a/34533473/6574038
# works better for me than `insert_minor()`)
labels.f <- every_nth.lt(sequence(range.f[2]), major.f)
n_minor.f <- major.f / minor.f - 1
# Normal plot:
library(ggplot2)
p.f <- ggplot(df1, aes(weeks, births)) +
geom_bar(stat="identity", fill="#F48024") + theme_bw() +
scale_x_continuous(breaks=breaks.f, labels=labels.f) +
coord_cartesian(xlim=range.f) +
facet_wrap(year ~ .) +
theme(panel.grid = element_blank(),
axis.text.x = element_text(margin=margin(t=5, unit="pt")))
# Manipulating plot:
g.f <- ggplotGrob(p.f)
xaxis.f <- g.f$grobs[grep("^axis-b", g.f$layout$name)] # get x-axes
ticks.f <- lapply(lapply(xaxis.f, "["),
function(x) x$children[[2]]) # get ticks
marks.f <- lapply(lapply(ticks.f, "["),
function(x) x[1]$grobs) # get ticks
# editing y-positions of tick marks
library(grid)
marks.f <- lapply(marks.f, function(x) {
x[[1]]$y <- unit.c(unit.c(unit(1, "npc") - unit(6, "pt"),
unit(1, "npc"),
rep(unit.c(unit(1, "npc") - unit(3, "pt"),
unit(1, "npc")), n_minor.f)))
x
})
# putting tick marks back into plot
for(i in seq_along(ticks.f)) {
ticks.f[[i]]$grobs[[1]] <- marks.f[[i]][[1]]
}
for(i in seq_along(xaxis.f)) {
xaxis.f[[i]]$children[[2]] <- ticks.f[[i]]
}
g.f$grobs[grep("^axis-b", g.f$layout$name)] <- xaxis.f
# Drawing the plot:
grid.newpage()
grid.draw(g.f)
data
tmp <- data.frame(date=as.Date(sample(1:1095, 10000, replace=TRUE),
origin="2014-01-01"),
births=sample(0:10, 10000, replace=TRUE))
tmp$year <- factor(substr(tmp$date, 1, 4))
df1 <- aggregate(births ~ date + year, tmp, sum)
rm(tmp) # remove tmp
df1$weeks <- as.integer(strftime(lubridate::floor_date(as.Date(df1$date,
format="%m/%d/%Y"),
unit="week"), "%W")) + 1
来源:https://stackoverflow.com/questions/53660703/how-to-lengthen-specific-tick-marks-in-facet-gridded-ggplot