2

I am trying to make a plot where the x-axis values are clipped (cut-off beyond the axis limits) but the y-axis values are not.

Questions:

  1. Is this possible using ggplot?
  2. How to code this?

Code:

Z <- data.frame(X = c(1,2,3,4,5,6,7,8), 
                Y = c(0,3,2,5,5.2,2,4,3))

# plotting with not filter (just toggle clip = on/off)
ggplot(Z, aes(x=X, y=Y)) + 
   geom_line() + 
   coord_cartesian(xlim = c(0, 7), 
                   ylim = c(0, 5), 
                   clip = 'off') + 
   theme_bw() +
   scale_y_continuous(expand = c(0,0)) +
   theme(plot.margin = unit(c(0.5, 0.5, 0.5, 0.5), 'cm'))

# plotting filter
ggplot(Z[Z$X < 7, ], aes(x=X, y=Y)) + 
   geom_line() + 
   coord_cartesian(xlim = c(0, 7), ylim = c(0, 5), clip = 'off') + 
   theme_bw() +
   scale_y_continuous(expand = c(0,0)) +
   theme(plot.margin = unit(c(0.5, 0.5, 0.5, 0.5), 'cm'))

Output (clip off/on/filtering the X values):

I want the x-axis to be stopped at x=6, but the y-values to be able to go outside the plots borders.

enter image description here

If I filter, then the x-axis doesn't go far enough, despite higher x-values existing. This is also the reason I have to use coord_cartesian in the first place as scale_x_continuous and xlim both disregard all future x-axis times when plotting, so stop lines earlier than they should, as descrived here

enter image description here

Attempt:

I can sort of get the effect I want by slightly increasing the upper y-axis limit (in this example to 5.2), but then the limit goes beyond what I want and looks odd when I plot this using my actual data.

Output of actual plot of data with the y-limit increased:

When plotting my actual data this extra line above the 100 mark doesn't make sense, because it should never go above 100%, which is why I want to avoid this workaround. (data/plot code not added for that plot for security reasons)

enter image description here

morgan121
  • 2,213
  • 1
  • 15
  • 33

2 Answers2

3

In this case, you can take advantage of the different behaviour of coord_cartesian(xlim = ...) and scale_x_continuous(limits = ...). The coords function will do a soft clipping, i.e. they draw the data and then clip it. The scales function will hard clip it, removing out of bounds values before drawing. You can be a bit more precise on the clipping behaviour of the scales functions, by setting an out-of-bounds (oob) argument to that scale. By default it will censor, i.e. remove data, but you can use the squish() function from the scales function to just have it render the points at the most extreme value.

ggplot(Z, aes(x=X, y=Y)) + 
  geom_line() + 
  coord_cartesian(ylim = c(0, 5), 
                  clip = 'off') + 
  theme_bw() +
  scale_y_continuous(expand = c(0,0)) +
  scale_x_continuous(limits = c(0, 7), expand = c(0,0), oob = scales::squish) +
  theme(plot.margin = unit(c(0.5, 0.5, 0.5, 0.5), 'cm'))

enter image description here

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • this is very close, but if you remove the border you can see a solid vertical line where the values have been switched. Anyway, I made a workaround where I just plot everything and then add a white rectangle on the end of the plot to hide any extra hanging over bits :P – morgan121 Jul 14 '19 at 23:42
  • I can just add a white line on top of that border, so this is actually a great solution – morgan121 Feb 19 '20 at 23:08
  • omg sorry to keep coming back to this, but `oob = scales::censor` does exactly what I want! – morgan121 May 22 '20 at 01:33
0

I might be misunderstanding your question, but can't you just filter your data?

library(tidyverse)

df <- iris # load data

ggplot(filter(df, Sepal.Width <= 4), aes(x = Sepal.Width, y = Sepal.Length)) + # plot data
    geom_point() +
    coord_cartesian(xlim = c(2, 4),    # set the x limits
                    ylim = c(4, 7.5),  # set the y limits
                    clip = 'off') +    # toggle on/off 
    theme_bw()                         # make graph a little nicer 

enter image description here

heds1
  • 3,203
  • 2
  • 17
  • 32
  • Thanks for the replay, but not exactly. That example probably didn't explain my reasoning very well, but if I limit my data the second plot simply wont plot the lines when the survival is at 100%, which would be bad. I need to be able to show the vertical tick marks along the top, even though they are technically above 100%. Make sense? – morgan121 Jul 12 '19 at 06:10
  • And If I filter the x-axis ones, then the lines will not go all the way to the edge (which they should do if there are future data points available, like the black line in plot 2). If I filter only up to time 10, then the black line would stop just before time 6 as there is not more data to plot – morgan121 Jul 12 '19 at 06:12
  • 1
    I see. I think you should try to provide reproducible data in the format that you would like for the desired output (rather that the iris data that seems to be irrelevant in this case), – heds1 Jul 12 '19 at 06:21