0

I have this sample density curve data (found here):

library(tidyverse)
z <- rnorm(1000, mean = 0, sd = 1)
dens <- density(z)
data <- tibble(x = dens$x, y = dens$y) %>% 
  mutate(variable = case_when(
    (x >= -2 & x <= 0) ~ "On",
    (x >= 0.2 & x <= 1) ~ "Off",
    TRUE ~ NA_character_))

I plot this curve with ggplot2, along with highlighted regions using geom_area, along with some text created using geom_text outside the plot boundaries, requiring me to turn off clipping in coord_cartesian:

ggplot(data, aes(x, y)) + geom_line() +
  geom_area(data = filter(data, variable == 'On'), fill = 'grey') + 
  geom_area(data = filter(data, variable == 'Off'), fill = 'light blue') +
  geom_text(aes(x = 7, y = 0.15, label = "test")) +
  theme(plot.margin = unit(c(1,7,1,1), "lines")) +
  coord_cartesian(xlim = c(-5, 5),
                  # ylim = c(0.1, 0.2),
                  clip = "off")

enter image description here

What I would like to do now, is to zoom into y-axis between 0.1 and 0.2. I know that if I use the limits argument in scale_y_continuous, then this can sometimes remove data which is constraining the view, so I use the ylim argument inside coord_cartesian set as c(0.1, 0.2).

However, this causes the density area and curve to overlap the plot boundaries (as I've turned off clipping).

enter image description here

What I could do now, is to turn on clipping in coord_cartesian, however this would now remove the geom_text outside the plot boundaries which I need. Is there any way to reconcile my issue?

enter image description here

Nautica
  • 2,004
  • 1
  • 12
  • 35

1 Answers1

1

This is a good use case to use the oob argument of the position scales in a non-standard way. The scales package has several out-of-bounds function that can serve you here, notably oob_squish(), which sets out-of-bounds to nearest limits, or oob_keep(), which keeps out-of-bounds data, similar to setting coordinate limits.

library(tidyverse)
#> Warning: package 'ggplot2' was built under R version 4.0.2
z <- rnorm(1000, mean = 0, sd = 1)
dens <- density(z)
data <- tibble(x = dens$x, y = dens$y) %>% 
  mutate(variable = case_when(
    (x >= -2 & x <= 0) ~ "On",
    (x >= 0.2 & x <= 1) ~ "Off",
    TRUE ~ NA_character_))

ggplot(data, aes(x, y)) + geom_line() +
  geom_area(data = filter(data, variable == 'On'), fill = 'grey') + 
  geom_area(data = filter(data, variable == 'Off'), fill = 'light blue') +
  geom_text(aes(x = 7, y = 0.15, label = "test")) +
  theme(plot.margin = unit(c(1,7,1,1), "lines")) +
  scale_y_continuous(limits = c(0.1, 0.2),
                     expand = c(0, 0),
                     oob = scales::oob_squish) +
  scale_x_continuous(limits = c(-5, 5), 
                     oob = scales::oob_keep) +
  coord_cartesian(clip = "off")

Created on 2020-12-25 by the reprex package (v0.3.0)

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • Thanks. Any way to remove the constrained horizontal lines at the y axis limits? – Nautica Dec 25 '20 at 18:40
  • This is a good approach, but it seems that it relies on one using the limit argument within the `scale_y_continuous` and `scale_x_continuous` functions. In my case, I cannot do this, because doing so will modify the underlying data by causing certain observations to be omitted; I can only use `coord_cartesian` limits. As a result, using the `oob` argument in scale_y_continuous doesn't accomplish the goal. How would I work around this? – econometrica_33 Apr 22 '22 at 16:31