I have multivariate longitudinal samples that I am plotting in a large facet_grid, specifically using facet_grid so that when I don't have a certain time point for a certain sample it still keeps everything in a nicely ordered grid. I am trying to add some sort of indicator to empty facets to show that they don't have data (rather than just having no dots show up), because sometimes the empty facet is a result of not having collected that sample yet. What I have been able to get is a label that shows up in every facet that DOES have data, but I can't seem to figure out how to get a label that shows up in every facet that does NOT have data. It would be even better if I could add a red X through select facets, or some other indication of "No Data Available", rather than a text label, if you have suggestions about that as well.
ggplot(mpg, aes(displ, cty)) + geom_point() +
facet_grid(vars(drv), vars(cyl)) + geom_text(x = 5, y = 20, label = "Blah")
You could add rows for the missing combinations with a full_join
. These new rows will have no data, so nothing will be plotted, but you can add an additional column with the message that geom_text
will use:
library(tidyverse)
theme_set(theme_bw())
mpg %>%
full_join(crossing(drv=unique(mpg$drv), cyl=unique(mpg$cyl))) %>%
mutate(empty=ifelse(is.na(model), "No data available", NA_character_),
x=mean(range(displ, na.rm=TRUE)),
y=mean(range(cty, na.rm=TRUE))) %>%
ggplot(aes(displ, cty)) +
geom_point() +
facet_grid(vars(drv), vars(cyl)) +
geom_text(aes(x, y, label=empty), colour="red", size=3)
For an "X", change the empty
text to "X"
and plot it with a large size. For example:
mpg %>%
full_join(crossing(drv=unique(mpg$drv), cyl=unique(mpg$cyl))) %>%
mutate(empty=ifelse(is.na(model), "X", NA_character_),
x=mean(range(displ, na.rm=TRUE)),
y=mean(range(cty, na.rm=TRUE))) %>%
ggplot(aes(displ, cty)) +
geom_point() +
geom_text(aes(x, y, label=empty), colour="red", size=20) +
facet_grid(vars(drv), vars(cyl))
Or we could use geom_segment
:
mpg %>%
full_join(crossing(drv=unique(mpg$drv), cyl=unique(mpg$cyl))) %>%
ggplot(aes(displ, cty)) +
geom_point() +
geom_segment(data=. %>% filter(is.na(model)),
x=min(mpg$displ), xend=max(mpg$displ),
y=min(mpg$cty), yend=max(mpg$cty),
colour="red") +
geom_segment(data=. %>% filter(is.na(model)),
x=min(mpg$displ), xend=max(mpg$displ),
y=max(mpg$cty), yend=min(mpg$cty),
colour="red") +
facet_grid(vars(drv), vars(cyl))
The above can be done with a single call to geom_segment
, but it requires (AFAICT) a more complex data prep:
mpg %>%
full_join(crossing(drv=unique(mpg$drv), cyl=unique(mpg$cyl))) %>%
ggplot(aes(displ, cty)) +
geom_point() +
geom_segment(data=. %>%
filter(is.na(model)) %>%
select(-displ, -cty) %>%
crossing(
displ=range(mpg$displ),
cty=range(mpg$cty)
),
aes(xend=rev(displ), yend=rev(cty)), colour="red") +
facet_grid(vars(drv), vars(cyl))