4

First, well wishes of health and safety. I am presenting a toy data set and problem in regard to plotting multilevel data. I have manipulated my data to solve the age old debate of which gives you a worse stomach ache, candy or hot dogs, but the structure of this code mimics my workflow so far.

#load reproducible data
SEdata <- read.table(sep="\t", text="
  Phase Food    BellyAche   .upper  .lower  NumberEaten
                   One  Hotdog   1.619398    1.791600    1.573005    1
                   One  Hotdog   1.639763    1.873902    1.574589    2
                   One  Hotdog   1.670704    2.017667    1.576659    3
                   One  Hotdog   1.718359    2.257239    1.579538    4
                   One  Hotdog   1.792363    2.613699    1.582602    5
                   Two  Hotdog   2.100298    3.837023    1.612238    6
                   Two  Hotdog   2.361419    4.849432    1.636528    7
                   Two  Hotdog   2.737556    6.210441    1.673419    8
                   Two  Hotdog   3.262118    7.832566    1.727361    9
                   Two  Hotdog   3.963321    9.651391    1.806301   10
                   Two  Hotdog   4.853788   11.417294    1.916514   11
                   Two  Hotdog   5.921110   13.011963    2.063637   12
                   Two  Hotdog   7.124559   14.209065    2.276479   13
                   Two  Hotdog   8.400826   15.080815    2.564494   14
                   Two  Hotdog   9.677213   15.670715    2.943689   15
                   One  Candy    1.607732    1.735073    1.572547    1
                   One  Candy    1.612335    1.750510    1.573150    2
                   One  Candy    1.618680    1.783547    1.573605    3
                   One  Candy    1.627416    1.828664    1.573896    4
                   One  Candy    1.639511    1.896757    1.574104    5
                   Two  Candy    3.308415    7.686174    1.767004    6
                   Two  Candy    4.396891   10.113005    1.942515    7
                   Two  Candy    5.901714   12.291984    2.286095    8
                   Two  Candy    7.757451   14.026539    2.858342    9
                   Two  Candy    9.769149   15.157586    3.845456   10
                   Two  Candy   11.678319   15.817868    5.306654   11
                   Two  Candy   13.275916   16.184320    7.239952   12
                   Two  Candy   14.473242   16.374915    9.497268   13
                   Two  Candy   15.293162   16.472143   11.619491   14
                   Two  Candy   15.817047   16.521788   13.348949   15", header=TRUE, stringsAsFactors=FALSE)
SEdata$Phase <- factor(SEdata$Phase)
SEdata$Food <- factor(SEdata$Food)

My target figure splits between phase 1 and 2 with a facet and plots the two different food types for the number eaten and the relative belly ache one would have from this. In my first example, I plot the data with two facets, but you will find that the plots have identical x axes; however, this leaves a lot of blank space between phase 1 and 2. Remember, the goal is to have the x axis of plot 2 be the next observation following the last plot point in plot 1.

#load required libraries
library(tidyverse)
#Plot one:
SEdata %>%
  group_by(Food) %>%
  ggplot(aes(x = NumberEaten, y = BellyAche, color = Food)) +
  facet_wrap(~ Phase) +
  geom_point() +
  geom_ribbon(aes(ymin=.lower, ymax=.upper), linetype=1, alpha=0.1)
  #scale_fill_brewer()

enter image description here

What I have gleaned is that the recommended way to get rid of this empty space is to change

facet(~phase)

to

facet_wrap(~ Phase, scales = "free_x")

The result does indeed make the x axis continuous, but the incremental scale and removes the unnecessary blank space in the figure.

The figure code and output are as follows:

SEdata %>%
  group_by(Food) %>%
  ggplot(aes(x = NumberEaten, y = BellyAche, color = Food)) +
  facet_wrap(~ Phase, scales = "free_x") +
  geom_point() +
  geom_ribbon(aes(ymin=.lower, ymax=.upper), linetype=1, alpha=0.1)

enter image description here

The problem with the second plot is now that the axis ticks on the x axis are no longer the same.

So that is where I come to you. Can anyone help me identify a way to make the axis of the second faceted plot consistent with the first?

Carl
  • 4,232
  • 2
  • 12
  • 24
Aswiderski
  • 166
  • 9
  • So you want to shrink the left side, or just make the scale go up by the same number of units but have different sizes per unit? – Allan Cameron Jul 22 '20 at 18:51
  • That is an interesting question. My original thought was to just make the scale go up by the same number units. But after your question the answer is probably both. Shrink the left side to accommodate for each facet having the same unit and size per unit. – Aswiderski Jul 22 '20 at 19:05
  • Does this answer your question? [different size facets proportional of x axis on ggplot 2 r](https://stackoverflow.com/questions/10454805/different-size-facets-proportional-of-x-axis-on-ggplot-2-r) – tjebo Jul 22 '20 at 19:36
  • @Tjebo It answers the question to the comment that Allan brought up about augmenting the size of a facet. However, it was not actually my original question. Thanks! – Aswiderski Jul 22 '20 at 20:30

3 Answers3

3

One of the options is to precompute the breaks and use those as x-axis breaks. To adress the different spacings; setting facet_grid(..., space = "free") means that 1 unit on the left axis is also 1 unit on the right axis.

breaks <- scales::extended_breaks(n = 8)(range(SEdata$NumberEaten))

SEdata %>%
  group_by(Food) %>%
  ggplot(aes(x = NumberEaten, y = BellyAche, color = Food)) +
  facet_grid(~ Phase, scales = "free_x", space = "free_x") +
  geom_point() +
  geom_ribbon(aes(ymin=.lower, ymax=.upper), linetype=1, alpha=0.1) +
  scale_x_continuous(breaks = breaks)

enter image description here

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • literally 20 seconds before I posted it :D – tjebo Jul 22 '20 at 19:35
  • but much nicer with the same breaks – tjebo Jul 22 '20 at 19:36
  • 1
    Haha, I had a bit of a streak of this with @Allan Cameron a few weeks ago! Good to see answers converge though :D – teunbrand Jul 22 '20 at 19:38
  • 1
    @teunbrand Thanks for this. I also really appreciate your explanation of precomputing the breaks. As a reward you not only get the accepted answer, but also the remaining hot dogs and candy from the competition! – Aswiderski Jul 22 '20 at 20:43
1

You can use facet_grid with space = "free_x"

The units are evenly spaced, but the breaks are not the same

library(tidyverse)
SEdata %>%
  group_by(Food) %>%
  ggplot(aes(x = NumberEaten, y = BellyAche, color = Food)) +
  facet_grid(~ Phase, space = "free_x", scale = "free_x") +
  geom_point() +
  geom_ribbon(aes(ymin=.lower, ymax=.upper), linetype=1, alpha=0.1)

Created on 2020-07-22 by the reprex package (v0.3.0)

tjebo
  • 21,977
  • 7
  • 58
  • 94
  • This was close; however, it did not address the inconsistent scale as presented in the first figure I provided. In fact, other than the size difference on facet two, the second figure I provided and this are identical. Thank you for your feedback! – Aswiderski Jul 22 '20 at 20:35
1

You could try one of these options:

library(ggplot2)
library(scales)

# A function factory for getting integer x-axis values.
integer_breaks <- function(n = 5, ...) {
  fxn <- function(x) {
    breaks <- floor(pretty(x, n, ...))
    names(breaks) <- attr(breaks, "labels")
    breaks
  }
  return(fxn)
}

SEdata %>%
  group_by(Food) %>%
  ggplot(aes(x = NumberEaten, y = BellyAche, color = Food)) +
  geom_point() +
  geom_ribbon(aes(ymin=.lower, ymax=.upper), linetype=1, alpha=0.1)+
  facet_wrap(~ Phase, scales = "free_x")+
  scale_x_continuous(breaks=integer_breaks(n = 8))

enter image description here

Or this:

SEdata %>%
  group_by(Food) %>%
  ggplot(aes(x = NumberEaten, y = BellyAche, color = Food)) +
  geom_point() +
  geom_ribbon(aes(ymin=.lower, ymax=.upper), linetype=1, alpha=0.1)+
  facet_wrap(~ Phase, scales = "free_x")+
  scale_x_continuous(breaks= pretty_breaks())

enter image description here

Duck
  • 39,058
  • 13
  • 42
  • 84
  • The second figure is ALMOST there. However, the scale changes from the first facet to the second fact of the x axis ticks. However, I really glad you utilized pretty_breaks() because I was trying to use it incorrectly in the facet_wrap command, instead of "free_x" – Aswiderski Jul 22 '20 at 20:33