Принудительно использовать метки оси x на ggplot facet_grid: метки оси x различаются для каждой строки

Я был так счастлив найти большую часть решения моего вопроса в сообщении "Принудительно включить текст по оси X для всех граней графика facet_grid".

Я хотел бы создать график, похожий на график OP Drew Steen, за исключением того, что у меня более двух рядов фасетов, и я хотел бы, чтобы метки осей X были разными для каждого ряда.

Я сделал супер-хакерское решение из потрясающего ответа @baptiste (в основном потому, что я не знаком с пакетом gtable), и я хотел бы знать:

  1. Если есть более элегантное решение, чем беспорядок, который я написал ниже
  2. Как вставить метки для "Премиум" (средний) ряд.

Вот код, который я адаптировал от @Drew Steen и @baptiste,

library(ggplot2)

diamondSub <-subset(diamonds, (cut=="Ideal" | cut=="Premium" | cut == "Very Good") & (color=="E" | color=="I"))

p<- ggplot(diamondSub, aes(x=carat, y=price)) + 
  geom_blank()+ 
  geom_point() +
  scale_x_discrete(breaks=c(1, 2, 3, 4), labels=c("a", "b", "c", "d")) +
  facet_grid(cut~color, scales="free_x")
p

p2<- ggplot(diamondSub, aes(x=carat, y=price)) + 
  geom_blank()+ 
  geom_point() +
  scale_x_discrete(breaks=c(1, 2, 3, 4), labels=c("f", "g", "h", "i")) +
  facet_grid(cut~color, scales="free_x")
p2

library(gtable)

g <- ggplotGrob(p)
g2 <- ggplotGrob(p2)

# locate the panels
panels <- grep("panel", g$layout$name)
panels2 <- grep("panel", g2$layout$name)

top <- unique(g$layout$t[panels])
top2 <- unique(g2$layout$t[panels2])
# intersperse a copy of the bottom axes
all <- gtable:::rbind_gtable(gtable:::rbind_gtable(g[seq.int(min(top)), ], 
                                                   g[max(top)+1,], "first"), 
                             g2[seq(min(top2)+1, nrow(g2)),], "first")
grid.newpage()
grid.draw(all)

см. график


person Nova    schedule 17.11.2014    source источник


Ответы (1)


Альтернативная версия (добавлена ​​24 апреля 2015 г.), демонстрирующая ручное построение элементов и содержащая дополнительные комментарии.

## Alternative version
library(gtable)
library(grid)

# Get the ggplot grobs
g <- ggplotGrob(p)
g2 <- ggplotGrob(p2)

# Show the layout.
# Note the rows and columns
# In this case, the g2 layout is the same as the g layout
gtable_show_layout(g)

# The large panels are the plot panels.
# We will need rows 4, 6 and 8.

# For the top "Very Good" row, we will also need rows 1, 2, and 3.

# The axis is located in row 9

# Therefore rbind the grob in rows 1, 2, 3, and 4, with the grob in row 9.
top.row <- rbind(g[1:4, ], g[9, ], size = "first")

# The second "Premium" row
# We need the panels in row 6 plus the small gap row above,
# and rbind that to the axis
middle.row = rbind(g2[5:6, ], g2[9,], size = "first")

# The bottom "Ideal" row
# We need the panel in row 8 plus the small gap in the row above
# plus the axis in the row below
# plus rows below that (axis label and margin)
bottom.row = g2[7:11, ]


# rbind the three rows 
all <- rbind(rbind(top.row, middle.row, size = "first"), bottom.row, size = "first")

# Draw it
grid.newpage()
grid.draw(all)

# Maybe add a little more space between the rows
gtable_show_layout(all)
all$heights[c(6,9)] = unit(1, "lines")

# Draw it
grid.newpage()
grid.draw(all)

Но даже привязку панели к оси делать не нужно; просто выберите соответствующие строки из макета:

top.row <- g[c(1:4, 9), ]
middle.row = g2[c(5:6, 9), ]
bottom.row = g2[7:11, ]

затем свяжите эти три новых ряда.

Исходная версия

Только в вязке рядов вы ошиблись. Вы привязали ось к верхней строке «Очень хорошо». В нижней строке «Идеал» уже есть ось, поэтому привязка не требуется. Чтобы исправить: среднему ряду «Премиум» нужна ось.

Я построил каждую строку отдельно, привязав ось к верхней и средней строкам, а затем привязав три строки.

Я добавил еще один шаг, чтобы добавить немного больше места между строками.

g <- ggplotGrob(p)
g2 <- ggplotGrob(p2)

# locate the panels
panels <- grep("panel", g$layout$name)
panels2 <- grep("panel", g2$layout$name)

top <- unique(g$layout$t[panels])
top2 <- unique(g2$layout$t[panels2])

# Construct each row separately
top.row <- gtable:::rbind_gtable(g[seq.int(min(top)), ], g[max(top)+1,], "first")
middle.row <- gtable:::rbind_gtable(g2[c(top[2]-1,top[2]), ], g2[max(top)+1,], "first")
bottom.row <- g2[(max(top2)-1):nrow(g2), ]

all <- gtable:::rbind_gtable(gtable:::rbind_gtable(top.row, middle.row, "first"), bottom.row, "first")

# Draw it
grid.newpage()
grid.draw(all)

# Maybe add a little more space between the rows
all$heights[c(6,9)] = unit(1, "lines")

grid.newpage()
grid.draw(all)

введите здесь описание изображения

person Sandy Muspratt    schedule 22.04.2015
comment
Это заставило меня ухмыльнуться — мне все еще нужно было это понять; Я рассчитываю использовать это совсем немного! Это сработало прекрасно для меня. Спасибо. Не могли бы вы немного больше прокомментировать код, чтобы помочь новичку в gtable понять, что происходит на каждом этапе? Например, когда мы создаем панели, я знаю, что мы находим строки, в которых информация о панелях хранится в TableGrob, а затем находим верхние ____ этих панелей, но после этого я теряюсь в синтаксисе построения каждой строки. . Если я когда-нибудь изменю это, это будет очень полезно. Спасибо еще раз! - person Nova; 23.04.2015
comment
@Nova, я добавил альтернативную версию, которая создает компоненты вручную и с дополнительными комментариями. - person Sandy Muspratt; 24.04.2015