Home > Software design >  Get varrying x ticks per plot column with grid.arrange or face_grid
Get varrying x ticks per plot column with grid.arrange or face_grid

Time:03-09

I have this sample data.

structure(list(type = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 6L, 6L, 6L, 6L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 
5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L), .Label = c("1", "2", "3", 
"4", "5", "6"), class = "factor"), category = c("fact", "fact", 
"fact", "fact", "fact", "fact", "fake", "fake", "fake", "fake", 
"fake", "fake", "fact", "fact", "fact", "fact", "fact", "fact", 
"fake", "fake", "fake", "fake", "fake", "fake", "fact", "fact", 
"fake", "fake", "fact", "fact", "fact", "fact", "fact", "fact", 
"fake", "fake", "fake", "fake", "fake", "fake", "fact", "fact", 
"fact", "fact", "fact", "fact", "fake", "fake", "fake", "fake", 
"fake", "fake", "fact", "fact", "fact", "fact", "fact", "fact", 
"fake", "fake", "fake", "fake", "fake", "fake"), group = c("TG1", 
"TG1", "TG2", "TG2", "TG3", "TG3", "TG1", "TG1", "TG2", "TG2", 
"TG3", "TG3", "TG1", "TG1", "TG2", "TG2", "TG3", "TG3", "TG1", 
"TG1", "TG2", "TG2", "TG3", "TG3", "TG2", "TG2", "TG2", "TG2", 
"TG1", "TG1", "TG2", "TG2", "TG3", "TG3", "TG1", "TG1", "TG2", 
"TG2", "TG3", "TG3", "TG1", "TG1", "TG2", "TG2", "TG3", "TG3", 
"TG1", "TG1", "TG2", "TG2", "TG3", "TG3", "TG1", "TG1", "TG2", 
"TG2", "TG3", "TG3", "TG1", "TG1", "TG2", "TG2", "TG3", "TG3"
), cred = c("dislikes", "likes", "dislikes", "likes", "dislikes", 
"likes", "dislikes", "likes", "dislikes", "likes", "dislikes", 
"likes", "dislikes", "likes", "dislikes", "likes", "dislikes", 
"likes", "dislikes", "likes", "dislikes", "likes", "dislikes", 
"likes", "dislikes", "likes", "dislikes", "likes", "dislikes", 
"likes", "dislikes", "likes", "dislikes", "likes", "dislikes", 
"likes", "dislikes", "likes", "dislikes", "likes", "dislikes", 
"likes", "dislikes", "likes", "dislikes", "likes", "dislikes", 
"likes", "dislikes", "likes", "dislikes", "likes", "dislikes", 
"likes", "dislikes", "likes", "dislikes", "likes", "dislikes", 
"likes", "dislikes", "likes", "dislikes", "likes"), sum_possible = c(1256L, 
1256L, 1236L, 1236L, 1238L, 1238L, 4396L, 4396L, 4326L, 4326L, 
4333L, 4333L, 9420L, 9420L, 9270L, 9270L, 9285L, 9285L, 6908L, 
6908L, 6798L, 6798L, 6809L, 6809L, 0L, 0L, 1236L, 1236L, 2512L, 
2512L, 2472L, 2472L, 2476L, 2476L, 1884L, 1884L, 1854L, 1854L, 
1857L, 1857L, 11304L, 11304L, 11124L, 11124L, 11142L, 11142L, 
9420L, 9420L, 9270L, 9270L, 9285L, 9285L, 2512L, 2512L, 2472L, 
2472L, 2476L, 2476L, 1884L, 1884L, 1854L, 1854L, 1857L, 1857L
), rate = c(0.02, 0.02, 0.02, 0.03, 0.05, 0.02, 0.05, 0.01, 0.05, 
0.01, 0.08, 0, 0.08, 0.17, 0.07, 0.16, 0.08, 0.18, 0.14, 0.1, 
0.11, 0.09, 0.18, 0.09, NaN, NaN, 0.08, 0.13, 0.05, 0.17, 0.04, 
0.15, 0.05, 0.18, 0.26, 0.14, 0.22, 0.13, 0.36, 0.12, 0.02, 0.13, 
0.02, 0.15, 0.03, 0.21, 0.11, 0.05, 0.13, 0.05, 0.19, 0.07, 0, 
0.02, 0, 0.03, 0, 0.06, 0, 0, 0, 0, 0, 0), sum_clicks = c(27, 
30, 19, 34, 57, 29, 221, 39, 196, 26, 331, 15, 718, 1591, 607, 
1491, 710, 1694, 983, 696, 736, 578, 1196, 630, 0, 0, 103, 155, 
126, 416, 91, 381, 129, 437, 495, 266, 414, 235, 671, 223, 235, 
1515, 201, 1634, 379, 2373, 1083, 450, 1241, 418, 1740, 649, 
3, 61, 1, 62, 10, 158, 2, 1, 2, 0, 5, 3)), row.names = c(NA, 
-64L), class = c("tbl_df", "tbl", "data.frame"))

and want to draw one plot for each category and group.

One could do this using facet_wrap:

library(ggplot2)
library(gridExtra)
library(gtable)
library(grid)

ggplot(sample, aes(x = type, y = rate, fill = cred)) 
  geom_col() 
  labs(y = "Rate")  
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        axis.title.x = element_blank(),
        legend.title = element_blank()) 
  facet_grid(rows = vars(category), cols = vars(group), 
             switch = 'y') 
  scale_fill_discrete(labels = c("Dislikes", "Likes")) 
  ylim(0, 0.5)

which gives:

enter image description here

However, only TG2 has the variable level "6" in the type variable. This is why I don't want the "6" to show in facet column 1 and 3 on the x Axis.

I have learned that if axis are varrying I might not want to use facet_grid And went on to build each plot separately and use grid.arrange

p1 <- ggplot(sample %>% filter(category == "fact", group == "TG1"), aes(x = type, y = rate, fill = cred)) 
  geom_col() 
  labs(y = "Rate")  
  theme(axis.title = element_blank(),
        legend.title = element_blank(),
        #axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank()
  ) 
  facet_grid(rows = vars(category), cols = vars(group),
             switch = 'y') 
  scale_fill_discrete(labels = c("Dislikes", "Likes")) 
  ylim(0, 0.5)

p2 <- ggplot(sample %>% filter(category == "fact", group == "TG2"), aes(x = type, y = rate, fill = cred)) 
  geom_col(show.legend = FALSE) 
  labs(y = "Rate")  
  theme(axis.title = element_blank(),
        legend.title = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank()
  ) 
  facet_grid(rows = vars(category), cols = vars(group),
             switch = 'y') 
  scale_fill_discrete(labels = c("Dislikes", "Likes")) 
  ylim(0, 0.5)

p3 <- ggplot(sample %>% filter(category == "fact", group == "TG3"), aes(x = type, y = rate, fill = cred)) 
  geom_col(show.legend = FALSE) 
  labs(y = "Rate")  
  theme(axis.title = element_blank(),
        legend.title = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank()
  ) 
  facet_grid(rows = vars(category), cols = vars(group),
             switch = 'y') 
  scale_fill_discrete(labels = c("Dislikes", "Likes")) 
  ylim(0, 0.5)


p4 <- ggplot(sample %>% filter(category == "fake", group == "TG1"), aes(x = type, y = rate, fill = cred)) 
  geom_col(show.legend = FALSE) 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        axis.title = element_blank(),
        strip.text.x = element_blank()) 
  facet_grid(rows = vars(category), cols = vars(group),
             switch = 'y') 
  scale_fill_discrete(labels = c("Dislikes", "Likes")) 
  ylim(0, 0.5)

p5 <- ggplot(sample %>% filter(category == "fake", group == "TG2"), aes(x = type, y = rate, fill = cred)) 
  geom_col(show.legend = FALSE) 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        axis.title = element_blank(),
        strip.text.x = element_blank()) 
  facet_grid(rows = vars(category), cols = vars(group),
             switch = 'y') 
  scale_fill_discrete(labels = c("Dislikes", "Likes")) 
  ylim(0, 0.5)

p6 <- ggplot(sample %>% filter(category == "fake", group == "TG3"), aes(x = type, y = rate, fill = cred)) 
  geom_col(show.legend = FALSE) 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        axis.title = element_blank(),
        strip.text.x = element_blank()) 
  facet_grid(rows = vars(category), cols = vars(group),
             switch = 'y') 
  scale_fill_discrete(labels = c("Dislikes", "Likes")) 
  ylim(0, 0.5)

legend = gtable_filter(ggplotGrob(p1), "guide-box")
grid.arrange(arrangeGrob(p1  theme(legend.position="none"),
                         p2,
                         p3,
                         p4,
                         p5,
                         p6,
                         nrow = 2,
                         left = textGrob("Click Rate", rot = 90, vjust = 1)
),
legend,
widths=unit.c(unit(1, "npc") - legend$width, legend$width),
nrow = 1)

This gives me:

enter image description here

Here I do only have type "6" for the the TG2. Though, in my real example the axis.text are actually full words which will crop the bottom row of graphs, which makes them appear with a much different scaling than the top row.

I have further tried to extract the axis.text and add it in an additional row below.

axis.ticks = gtable_filter(ggplotGrob(p4), "axis-b-1")
axis.ticks_tg2 = gtable_filter(ggplotGrob(p5), "axis-b-1")

grid.arrange(arrangeGrob(p1  theme(legend.position="none"),
                         p2,
                         p3,
                         p4  theme(axis.text.x = element_blank()),
                         p5  theme(axis.text.x = element_blank()),
                         p6  theme(axis.text.x = element_blank()),
                         nrow = 2,
                         left = textGrob("Rate", rot = 90, vjust = 1)
),
legend,
widths=unit.c(unit(1, "npc") - legend$width, legend$width),
arrangeGrob(axis.ticks,axis.ticks_tg2,axis.ticks, nrow = 1),
nrow = 2)

However, this doen't match my coordinate systems very well.

enter image description here

Do you have any Idea how I can get my prefered solution:

x axis text ONLY at the bottom of the grid as in facet_grid, but with different number of x axis ticks as in grid.arrange for each column?

very greatful for your help!

CodePudding user response:

Instead of grid.arrange one option would be to free the x scale using facet_grid(...scales = "free_x"):

library(ggplot2)

ggplot(sample, aes(x = type, y = rate, fill = cred)) 
  geom_col() 
  labs(y = "Rate")  
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        axis.title.x = element_blank(),
        legend.title = element_blank()) 
  facet_grid(rows = vars(category), cols = vars(group), 
             switch = 'y', scales = "free_x") 
  scale_fill_discrete(labels = c("Dislikes", "Likes")) 
  ylim(0, 0.5)
#> Warning: Removed 2 rows containing missing values (position_stack).

  • Related