teunbrand / ggh4x

ggplot extension: options for tailored facets, multiple colourscales and miscellaneous
https://teunbrand.github.io/ggh4x/
Other
533 stars 32 forks source link

[FR, facet_nested] show nestlines for facets with single child #90

Closed pank closed 12 months ago

pank commented 1 year ago

Hi,

I really like facet_nested with nestlines. But I would like to always use them, also when there's only one level in the inner facet.

E.g. consider the following example:

library(ggh4x)
theme_set(theme(strip.background = element_blank(),
                strip.text = element_text(color = "black"),
                strip.placement = "outside"))

dd <- data.frame(
    outer = c(rep("A", 4), "B", "B"),
    inner = c(rep(c("c", "d"), 2), "", ""), 
    y = paste("x label", 1:6),
    x = abs(rnorm(6)))

ggplot(dd, aes(x, y)) +
    geom_col() +
    facet_nested(outer + inner ~ .,
                 nest_line = element_line(),
                 scales = "free_y",
                 switch = "y") +
    labs(x=NULL, y=NULL)

(sorry upload isn't working for me so I can't upload the graph).

Here, some outer facets have children while others only have the outer facet. But there's still categorical levels on the y-axis. It would be nice if nestlines could always be shown.

Of course, you could try to get it working nestlines by putting the y-labels in the facet and hide the actual y labels and then apply different formatting (not included here), but it becomes a bit messy and doesn't quite work:

ggplot(dd, aes(x, y)) +
    geom_col() +
    facet_nested(outer + inner + y ~ .,
                 nest_line = element_line(),
                 scales = "free_y",
                 switch = "y") +
    theme(strip.placement = "outside",
          axis.text.y = element_blank(),
          strip.text.y.left = element_text(angle = 0)) +
    labs(x=NULL, y=NULL)
pank commented 1 year ago

It seems that it's a question of extending the selection of strips in add_nest_indicator. in particular these:

  h_strip <- layout[layout$l != layout$r,]
# ...
  v_strip <- layout[layout$t != layout$b,]

In particular, If I set v_strip <- layout[1:2,] in the example above I get the desired outcome.

Can one tell which strips are the outer ones from the panels$layout df? This is the layout df:

Browse[2]> layout
    t l  b r z clip      name index
16  2 1  6 1 2   on strip-l-1    16
17 10 1 10 1 2   on strip-l-2    17
18  2 1  2 1 2   on strip-l-3    18
19  6 1  6 1 2   on strip-l-4    19
20 10 1 10 1 2   on strip-l-5    20
teunbrand commented 1 year ago

As a workaround, you can manually set strip backgrounds and set the one for the B-strip to be a partial rectangle. I'd probably make sense to make it an option, but I don't know when I'll have time to get to this.

library(ggh4x)
#> Loading required package: ggplot2

theme_set(theme(strip.background = element_blank(),
                strip.text = element_text(color = "black"),
                strip.placement = "outside"))

dd <- data.frame(
  outer = c(rep("A", 4), "B", "B"),
  inner = c(rep(c("c", "d"), 2), "", ""), 
  y = paste("x label", 1:6),
  x = abs(rnorm(6)))

bg <- list(element_part_rect(side = "r", linewidth = 0.5), element_blank())
bg <- bg[c(2, 1, 2, 2, 2)]

ggplot(dd, aes(x, y)) +
  geom_col() +
  facet_nested(
    outer + inner ~ .,
    nest_line = element_line(),
    scales = "free_y",
    switch = "y",
    strip = strip_nested(background_y = bg)
  ) +
  labs(x=NULL, y=NULL)

Created on 2023-01-31 with reprex v2.0.2

pank commented 1 year ago

Thanks for the workaround! I did not know element_part_rect so I'd never have thought about it.

I know the feeling re lack of time...

teunbrand commented 12 months ago

This is now implemented in the development version as the solo_line argument.

library(ggh4x)
#> Loading required package: ggplot2
theme_set(theme(strip.background = element_blank(),
                strip.text = element_text(color = "black"),
                strip.placement = "outside"))

dd <- data.frame(
  outer = c(rep("A", 4), "B", "B"),
  inner = c(rep(c("c", "d"), 2), "", ""), 
  y = paste("x label", 1:6),
  x = abs(rnorm(6)))

ggplot(dd, aes(x, y)) +
  geom_col() +
  facet_nested(outer + inner ~ .,
               nest_line = element_line(),
               solo_line = TRUE,
               scales = "free_y",
               switch = "y") +
  labs(x=NULL, y=NULL)

Created on 2023-07-15 by the reprex package (v2.0.1)