How to plot multiple graphs (faceting) using twoord.plot () in R?

1.3k views Asked by At

I have data that looks like this:

height <- c(1,2,3,4,2,4,6,8)
weight <- c(12,13,14,15,22,23,24,25)
person <- c("Jack","Jim","Jill","Tess","Jack","Jim","Jill","Tess")
set <- c(1,1,1,1,2,2,2,2)
dat <- data.frame(set,person,height,weight)

I'm trying to plot a graph with same x-axis(person), and 2 different y-axis (weight and height) using the twoord.plot function from the plotrix package. However, I do not know how to facet the plots like in ggplot2.

For example, if my plots could overlay in ggplot2, my code would look something like this:

ggplot(data = dat, aes(x = person, y = weight)) + 
  geom_point(color = "red") + facet_wrap(~set, scales="free") 
#And similarly have the height on the other axis.

Any idea on how to achieve this in twoord.plot()?

2

There are 2 answers

4
eipi10 On BEST ANSWER

I find this plot really confusing, but this seems to be more or less what plotrix::twoord.plot does, so let me know if this is what you had in mind.

In ggplot2, a second axis has to be based on a transformation of the first axis. So, we first transform the plotted height values to put them within the same range as the weight values (so they'll appear within the y-range of a graph based on weight). Then we do the inverse transformation to the scale of the second y-axis (so that the y-axis scale will correspond to the actual height values in the data).

ggplot(dat, aes(person)) + 
  geom_point(aes(y=weight), colour="blue") + 
  geom_point(aes(y=height/mean(height/weight)), colour="red", shape=17) +
  scale_y_continuous(sec.axis=sec_axis(~ . * mean(dat$height/dat$weight), 
                                       breaks=seq(0,max(dat$height),1),
                                       name="height")) +
  theme_classic() +
  theme(axis.text.y.right=element_text(colour="red"),
        axis.text.y=element_text(colour="blue"),
        axis.title.y.right=element_text(colour="red"),
        axis.title.y=element_text(colour="blue"))

enter image description here

This seems more intuitive to me, especially if the measurements of each person are (implicitly) ordered in time:

ggplot(dat, aes(weight, height, label=person, group=person)) +
  geom_line(colour="grey70") +
  geom_text()

enter image description here

0
neilfws On

Based on the comments, it seems like the real question is how to achieve an appropriate plot using ggplot2, rather than how to force plotrix to do something it cannot do.

Secondary axes are discouraged in ggplot2, because they are misleading. The eye is tempted to compare values that are not comparable, especially where lines cross. For this reason, sec_axis is restricted to cases where one variable is a direct transformation of the other.

I think it would be better to use height and weight for the facets, and color by set. This would clearly show the changes in each variable, for each person, in each of the sets (which I assume to be something like time points). The key thing is to think about which aspects of the dataset you are trying to highlight and create the chart accordingly.

A couple of examples. First, facet by height/weight, color by set:

library(tidyr)
library(ggplot2)
dat %>% 
  gather(var, value, -(1:2)) %>% 
  ggplot(aes(person, value)) + 
    geom_point(aes(color = factor(set))) + 
    facet_wrap(~var, scales = "free_y")

enter image description here

Or color by person, plot set versus each variable. I'd be tempted to use lines in this case:

dat %>% 
  gather(var, value, -(1:2)) %>% 
  ggplot(aes(factor(set), value)) + 
    geom_line(aes(color = person, group = person)) + 
    facet_wrap(~var, scales = "free_y")

enter image description here