3

With the code

library(ggplot2)
library(dplyr)

mydata = tribble(
  ~x, ~y, ~data, ~more,
  0, 50, 'iris', 'this', 
  10, 100, 'iris', 'this',
  0, 50, 'iris', 'that', 
  10, 100, 'iris', 'that',
  0, 0, 'wine', 'this', 
  10, 10, 'wine', 'this',
  0, 0, 'wine', 'that', 
  10, 10, 'wine', 'that',
)

ggplot(mydata, aes(x,y)) + facet_grid(data~more, scale='free') + theme_gray() + geom_point()

ggplot(mydata, aes(x,y)) + facet_grid(more~data, scale='free') + theme_gray() + geom_point()

I am getting the graphics:

enter image description here

enter image description here

Please note, how much better the first graph fills out the space in the panels. Because of the color coding my real plot, I do not need to show "this" and "that", so I would like to get rid of it in the first plot. But then the data labels are weird to the side. I would prefer if they were like this:

enter image description here

This is similar to ggplot2: Using gtable to move strip labels to top of panel for facet_grid, but that other link did not work for me and the situation is a little different, I think.

How can I do this?

Make42
  • 12,236
  • 24
  • 79
  • 155

2 Answers2

2

To get the strips to span the columns, you will probably need to use gtable functions (and a couple of grid functions).

In the solution, rows are added to the chart's gtable, then the strips are added to the new rows. The strips could be constructed from scratch, but it's probably easier to draw a second chart with the strip oriented horizontally, then extract the strips.

(Note: This could easily break with the next ggplot version.)

library(ggplot2)
library(dplyr)


mydata = tribble(
  ~x, ~y, ~data, ~more,
  0, 50, 'iris', 'this', 
  10, 100, 'iris', 'this',
  0, 50, 'iris', 'that', 
  10, 100, 'iris', 'that',
  0, 0, 'wine', 'this', 
  10, 10, 'wine', 'this',
  0, 0, 'wine', 'that', 
  10, 10, 'wine', 'that',
)

### Construct two charts:
# 1. ToKeep - the data~more chart, but without the strip labels. 
# The strips across the tops of the two rows of panels will be added later.

(ToKeep <- ggplot(mydata, aes(x,y)) + 
           facet_grid(data ~ more, scale ='free') + 
           geom_point() +
           theme(strip.text.y = element_blank(),
                 strip.text.x= element_blank()) )

# 2. ToGetStrip - Get the strips from the more~data chart
ToGetStrip <- ggplot(mydata, aes(x,y)) + 
              facet_grid(more ~ data, scale = 'free') +
              geom_point()

# Get the ggplot grob
gt = ggplotGrob(ToGetStrip)

# Get the strips
library(gtable)
library(grid)
strip = gtable_filter(grid.force(gt), "strip-t")


# Make sure
grid.newpage()
grid.draw(strip$grobs[[1]])

grid.newpage()
grid.draw(strip$grobs[[2]])


## Add the strips to the ToKeep chart.

# Get ggplot grob
gt = ggplotGrob(ToKeep)

# Check heights and widths
gt$heights
gt$widths

# The 1null heights and widths are the panels' heights and widths.
# Add rows to the gtable immediately above the panel rows (that is, after row 9 then row 7).
# The height of the new rows is the height of the strip grobs.

gt <- gtable_add_rows(gt, height = strip$grobs[[1]]$height, pos = 9)
gt <- gtable_add_rows(gt, height = strip$grobs[[1]]$height, pos = 7)

# Add the strips to the new rows (  t = c(8, 11)  )
# and make sure they span the two columns of panels (  l = 5, r = 7   ) 
gt <- gtable_add_grob(gt, list(strip$grobs[[1]], strip$grobs[[2]]), t = c(8, 11), l = 5, r = 7)

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

enter image description here

Following is an attempt to select rows and columns in terms of panel positions. However, it has not been tested beyond your 2 X 2 chart. (This could be a little more resilient to changes to ggplot.)

# Construct the two charts
ToKeep <- ggplot(mydata, aes(x,y)) + 
           facet_grid(data ~ more, scale ='free') + 
           geom_point() +
           theme(strip.text.y = element_blank(),
                 strip.text.x= element_blank())


ToGetStrip <- ggplot(mydata, aes(x,y)) + 
              facet_grid(more ~ data, scale = 'free') +
              geom_point()

# Get the strips from the second chart
gt = ggplotGrob(ToGetStrip)

library(grid)
library(gtable)
strip = gtable_filter(grid.force(gt), "strip-t")


# Add rows to the ToKeep chart, and add the strips to the new rows
gt = ggplotGrob(ToKeep)
PanelPos = subset(gt$layout, grepl("panel", gt$layout$name), select = t:r)

PanelRows = rev(unique(PanelPos$t))
for(i in seq_along(PanelRows)) {
gt <- gtable_add_rows(gt, height = strip$grobs[[1]]$height, pos = PanelRows[i]-1)
}

PanelRows = unique(subset(gt$layout, grepl("panel", gt$layout$name), select = t, drop = TRUE))
gt <- gtable_add_grob(gt, strip$grobs, t = PanelRows - 1, l = min(PanelPos$l), r = max(PanelPos$r))

# Draw it
grid.newpage()
grid.draw(gt)
Sandy Muspratt
  • 31,719
  • 12
  • 116
  • 122
0

I haven't seen a way to get the strip headers to bridge multiple columns like that, but you could achieve something similar by just hiding the x axis strip headers:

ggplot(mydata, aes(x,y)) + 
  geom_point() + 
  facet_grid(data~more, scale='free') + 
  theme_gray() + 
  theme(strip.background.x = element_blank(), 
        strip.text.x = element_blank()
)

enter image description here

Jon Spring
  • 55,165
  • 4
  • 35
  • 53