16

I know the question was asked here: Is there a way to increase the height of the strip.text bar in a facet?

I want to decrease the height of the strip.text bar without changing the text size. In the current case there is always a space left between text and strip bar walls.

Here is what I tried so far,

library(gcookbook) # For the data set
library(ggplot2)

ggplot(cabbage_exp, aes(x=Cultivar, y=Weight)) + geom_bar(stat="identity") +
facet_grid(.~ Date) +
theme(strip.text = element_text(face="bold", size=9,lineheight=5.0),
strip.background = element_rect(fill="lightblue", colour="black",
size=1))

In my case it seems that lineheight does not affect anything even if changed to 5. Why?
How can I make the strip bar size a little smaller but keeping the text size the same?

enter image description here

edit after @Sandy Muspratt answer

we are able to reduce the strip size if there is only one row of facets.

g = ggplotGrob(p)
g$heights[c(3)] = unit(.4, "cm")  # Set the height

grid.newpage()
grid.draw(g)

enter image description here

However, in my real data I have many rows of plot like below and when I changed the elements of g$heights nothing happened!

p = ggplot(cabbage_exp, aes(x=Cultivar, y=Weight)) + geom_bar(stat="identity") +
  facet_wrap(~ Date,ncol = 1) +
  theme(strip.text = element_text(face="bold", size=9),
        strip.background = element_rect(fill="lightblue", colour="black",size=1))

enter image description here

 g = ggplotGrob(p)
g$heights
#    [1] 5.5pt               0cm                 0.66882800608828cm  #1null               0cm                 0.193302891933029cm
#     [7] 0.66882800608828cm  1null               0cm                 #0.193302891933029cm 0.66882800608828cm  1null              
#    [13] 0.456194824961948cm 0cm                 1grobheight         5.5pt

then I attempted to change 1,7 and 11 elements

g$heights[c(3,7,11)] = unit(.4, "cm")  # Set the height

grid.newpage()
grid.draw(g)

enter image description here

No change in the facet label size.

> g$heights
 [1] 5.5pt                                                       1grobheight                                                
 [3] sum(0.2cm, sum(0.15cm, 0.8128cm, 0cm, 0.15cm), 0.2cm)+0.2cm 0.2                                                        
 [5] 1null                                                       0cm                                                        
 [7] 0.193302891933029cm                                         0.2                                                        
 [9] 1null                                                       0cm                                                        
[11] 0.193302891933029cm                                         0.2                                                        
[13] 1null                                                       0cm                                                        
[15] 0.193302891933029cm                                         0.2                                                        
[17] 1null                                                       0.456194824961948cm                                        
[19] 0cm                                                         1grobheight                                                
[21] 5.5pt  
Community
  • 1
  • 1
Alexander
  • 4,527
  • 5
  • 51
  • 98
  • @hrbrmstr because when i have many window for `facet_wrap`, that white space is becoming very important. if I can control its size the area of plot would increase for each window. thats why! – Alexander Apr 22 '16 at 02:18
  • 1
    as suggested in the answer the link to which you posted in your question, it's necessary to modify a little your facetting variable adding `"\n"` at the beginning and end of each string `cabbage_exp$Date <- paste0("\n", cabbage_exp$Date, "\n")` – inscaven Apr 22 '16 at 06:17
  • @inscaven yes I couldn't realized though. thanks! – Alexander Apr 22 '16 at 06:27

1 Answers1

24

Use margins

From about ggplot2 ver 2.1.0: In theme, specify margins in the strip_text element (see here).

library(ggplot2)
library(gcookbook) # For the data set

p = ggplot(cabbage_exp, aes(x=Cultivar, y=Weight)) + geom_bar(stat="identity") +
facet_grid(. ~ Date) +
theme(strip.text = element_text(face="bold", size=9),
strip.background = element_rect(fill="lightblue", colour="black",size=1))

  p +
  theme(strip.text.x = element_text(margin = margin(.1, 0, .1, 0, "cm")))



The original answer updated to ggplot2 v2.2.0

Your facet_grid chart

This will reduce the height of the strip (all the way to zero height if you want). The height needs to be set for one strip and three grobs. This will work with your specific facet_grid example.

library(ggplot2)
library(grid)
library(gtable)
library(gcookbook) # For the data set

p = ggplot(cabbage_exp, aes(x=Cultivar, y=Weight)) + geom_bar(stat="identity") +
facet_grid(. ~ Date) +
theme(strip.text = element_text(face="bold", size=9),
strip.background = element_rect(fill="lightblue", colour="black",size=1))

g = ggplotGrob(p)

g$heights[6] = unit(0.4, "cm")  # Set the height

for(i in 13:15) g$grobs[[i]]$heights = unit(1, "npc") # Set height of grobs

grid.newpage()
grid.draw(g)

Your Facet_wrap chart

There are three strips down the page. Therefore, there are three strip heights to be changed, and the three grob heights to be changed.

The following will work with your specific facet_wrap example.

p = ggplot(cabbage_exp, aes(x=Cultivar, y=Weight)) + geom_bar(stat="identity") +
  facet_wrap(~ Date,ncol = 1) +
  theme(strip.text = element_text(face="bold", size=9),
        strip.background = element_rect(fill="lightblue", colour="black",size=1))

g = ggplotGrob(p)

for(i in c(6,11,16)) g$heights[[i]] = unit(0.4,"cm")   # Three strip heights changed
for(i in c(17,18,19)) g$grobs[[i]]$heights <-  unit(1, "npc")   # The height of three grobs changed

grid.newpage()
grid.draw(g)

How to find the relevant heights and grobs?

g$heights returns a vector of heights. The 1null heights are the plot panels. The strip heights are one before - that is 6, 11, 16.

g$layout returns a data frame with the names of the grobs in the last column. The grobs that need their heights changed are those with names beginning with "strip". They are in rows 17, 18, 19.

To generalise a little

p = ggplot(cabbage_exp, aes(x=Cultivar, y=Weight)) + geom_bar(stat="identity") +
  facet_wrap(~ Date,ncol = 1) +
  theme(strip.text = element_text(face="bold", size=9),
        strip.background = element_rect(fill="lightblue", colour="black",size=1))

g = ggplotGrob(p)

# The heights that need changing are in positions one less than the plot panels
pos =  c(subset(g$layout, grepl("panel", g$layout$name), select = t))
for(i in pos) g$heights[i-1] = unit(0.4,"cm")

# The grobs that need their heights changed:
grobs = which(grepl("strip", g$layout$name))
for(i in grobs) g$grobs[[i]]$heights <-  unit(1, "npc")      
grid.newpage()
grid.draw(g)

Multiple panels per row

Nearly the same code can be used, even with a title and a legend positioned on top. There is a change in the calculation of pos, but even without that change, the code runs.

library(ggplot2)
library(grid)

# Some data
df = data.frame(x= rnorm(100), y = rnorm(100), z = sample(1:12, 100, T), col = sample(c("a","b"), 100, T))

# The plot
p = ggplot(df, aes(x = x, y = y, colour = col)) +
   geom_point() +
   labs(title = "Made-up data") + 
   facet_wrap(~ z, nrow = 4) +
   theme(legend.position = "top")

g = ggplotGrob(p)

# The heights that need changing are in positions one less than the plot panels
pos =  c(unique(subset(g$layout, grepl("panel", g$layout$name), select = t)))
for(i in pos) g$heights[i-1] = unit(0.2, "cm")

# The grobs that need their heights changed:
grobs = which(grepl("strip", g$layout$name))
for(i in grobs) g$grobs[[i]]$heights <-  unit(1, "npc") 

grid.newpage()
grid.draw(g)
Community
  • 1
  • 1
Sandy Muspratt
  • 31,719
  • 12
  • 116
  • 122
  • dear Sandy I appreciate your answer. I checked your solution and it is working only if I have one row of plots. But in the case of 3 row of graph it doesn't work. I tried to change every some parameters but it didn't helped. Maybe I'm missing something please see the modified question. – Alexander May 20 '16 at 05:36
  • 1
    @Alexander, the original solution applies to the `facet_grid` example. `facet-wrap` requires a different approach. See the edit with the facet_wrap heading. – Sandy Muspratt May 20 '16 at 06:20
  • Thanks for your elegant answer. Its fabulous with the reproducible data here. On the other hand when I apply finally `grid.draw(g)` in my real data, I am getting `Error in grid.Call.graphics(L_setviewport, vp, TRUE) : INTEGER() can only be applied to a 'integer', not a 'NULL'` – Alexander May 20 '16 at 08:38
  • Are you getting this error with the example posted here, or with your real data? – Sandy Muspratt May 20 '16 at 08:43
  • with my real data. I can plot my real data without no problem. I added how it is it look like for temporally to the end of question. – Alexander May 20 '16 at 08:46
  • 1
    Okay, it could be that the problem is due multiple panels in a row. The previous example had just one panel per row. I'look into it, but maybe tomorrow. But still, can you post your command. – Sandy Muspratt May 20 '16 at 08:52
  • 2
    I've added some code to the answer. But I can't reproduce your error. First, are you using latest versions for R and ggplot2? Then, begin with the simplest plot. Also, what values do you get for `pos` and `grobs`? Do they agree with what you would get from `g$heights` and `g$layout`? – Sandy Muspratt May 20 '16 at 21:03
  • 1
    worked smoothly. Thank you very much. very much appreciated it. Have a nice weekend. – Alexander May 21 '16 at 05:32
  • today I tried your `Multiple panels per-row` post again. But I got error `Error in grid.Call.graphics(L_setviewport, vp, TRUE) : INTEGER() can only be applied to a 'integer', not a 'NULL'`. I think the error is coming from when the `guides` because when I added this code `guides(col="none")` there is no error. But In real I also need this guides too! How can I solve this? – Alexander May 23 '16 at 01:34
  • 1
    I don't. Regardless of the position of the legend, or whether or not there is a legend, I get the plot. Are you using the code and data frame exactly as given in the answer? Do you get the ggplot? After getting the ggplot grob, can you draw the grow with grid.draw? What do you get fro `pos`? After you apply the first set of changes in height, what do you get for g$heights? what do you get for `grobs`? After you apply the second set of changes, what do you get for g$grobs[[13]]$heights? – Sandy Muspratt May 23 '16 at 03:01
  • Ok. I got for `pos` =`$t [1] 5 9 13 17` for `grobs` `[1] 14 15 16 17 18 19 20 21 22 23 24 25` and `g$grobs[[13]]$heights` giving `NULL` – Alexander May 23 '16 at 03:10
  • Okay, should have been `g$grobs[[14]]$heights`, or 15, or 16, etc in place of 14. Also, what do you get for `g$heights`? – Sandy Muspratt May 23 '16 at 03:27
  • ok I see. You are right. I got for g$grobs[[14]] 1npc. and for g$heighs I put the result at the end of the question. Please find it. – Alexander May 23 '16 at 03:39
  • 1
    You'll notice that heights 4, 8, 12, and 16 are `0.2`. They should be `0.2cm`. This suggests to me that your grid version is out of date. What version of R are you using? If not 3.3.0, then update R which will in turn update grid. – Sandy Muspratt May 23 '16 at 03:50
  • 1
    And indeed, when I use an old version of R (and therefore grid), I get the error. Update and all will be good. – Sandy Muspratt May 23 '16 at 03:57
  • 1
    Yes you were right about the R version. I installed newest R version and the problem was solved. Thanks man! – Alexander May 23 '16 at 04:42
  • Great answer, this also helps `plotly::ggplotly` when wraps ggplot2 with multi-factor `facet_wrap (~a + b)` since strips got flattened in `plotly`. Thank you. – Yang Liu Nov 08 '19 at 12:17