Borrowing heavily from @agstudy's proposed solution on the question you linked to, we can create a custom axis function. We do that with
element_grob.element_custom <- function(element, x ,...) {
cat <- list(...)[[1]]
groups <- levels(element$categories)
ll <- split(element$levels, element$categories)
tt <- as.numeric(x)
group.pos <- sapply(groups, function(g) mean(range(tt[ cat %in% ll[[g]] ])))
tg <- textGrob(groups, x=unit(group.pos, 'native'))
gTree(children=gList(tg), cl = "custom_axis")
}
axis.groups = function(levels, categories) {
stopifnot(is.factor(levels) & is.factor(categories))
structure(
list(categories=categories, levels=levels),
class = c("element_custom","element_blank")
)
}
grobHeight.custom_axis <-
heightDetails.custom_axis = function(x, ...)
unit(1, "lines")
These functions collectively define the properties of the custom axis. Then, let's use your sample data
dat1 <- structure(list(GROUP = structure(c(2L, 1L, 1L, 1L, 1L, 1L, 1L,
2L, 1L, 2L), .Label = c("A", "B"), class = "factor"), id = structure(c(17L,
1L, 1L, 4L, 4L, 1L, 7L, 13L, 4L, 15L), .Label = c("G1", "G2",
"G3", "G4", "G5", "G6", "G7", "G8", "G9", "G10", "G11", "G12",
"G13", "G14", "G15", "G16", "G17"), class = "factor"), variable = structure(c(1L,
3L, 2L, 2L, 3L, 4L, 2L, 2L, 4L, 4L), .Label = c("P1", "P2", "P3",
"P4"), class = "factor"), value = c(0.002, 0.002, 0.003, 0.003,
0.003, 0.003, 0.004, 0.004, 0.004, 0.004)), .Names = c("GROUP",
"id", "variable", "value"), row.names = c(NA, -10L), class = "data.frame")
And now, we call the custom function. The function axis.groups
takes two parameters, first, the names for each of the individual bars, then the categories each of those groups belong to.
Now we draw the plot
ggplot(data=dat1, aes(x=id, y=value, fill=variable))+
geom_bar(stat="identity", width=1)+
scale_y_continuous(expand = c(0,0))+
scale_fill_brewer(palette="Set1") +
xlab(" ")+ylab(" ") +
panel +
theme(axis.text.x = axis.groups(un$id, un$GROUP))
and that results in
You will want to make sure that your levels are sorted by "GROUP" than "id" because the label will just go in the center of the bars so you don't want the groups to overlap
If there were always an odd number in each group, then you could also do
gb<-tapply(as.numeric(dat1$id), dat1$GROUP,
function(x) levels(dat1$id[])[floor(median(x))])
ggplot(data=dat1, aes(x=id, y=value, fill=variable))+
geom_bar(stat="identity", width=1)+
scale_y_continuous(expand = c(0,0))+
scale_fill_brewer(palette="Set1") +
panel +
xlab("")+ylab("") +
scale_x_discrete(breaks=gb, labels=names(gb))
which requires far less work. This time the labels doesn't necessarily go in the middle, it goes directly beneath a bar in the middle (or just left of it if there are an even number of bars in a group)