2

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()?

eipi10
  • 91,525
  • 24
  • 209
  • 285
Share
  • 395
  • 7
  • 19
  • Looks from [the documentation](https://rdrr.io/cran/plotrix/man/twoord.plot.html) that this function does not use facets. – neilfws Sep 05 '17 at 03:33
  • I know. But I was wondering if there was any "trick" that I could employ to get around this? – Share Sep 05 '17 at 03:34
  • There is no "trick". You'd have to subset the data, generate separate plots and combine them using _e.g._ `par(mfrow = ...)` or perhaps [panes](https://rdrr.io/cran/plotrix/man/panes.html). But I wonder why you would not simply use `ggplot2`. – neilfws Sep 05 '17 at 03:42
  • Because ggplot2 is giving me a lot of trouble. I tried using sec_axis(), but no one seems to know the correct solution for it. See here: https://stackoverflow.com/questions/46045258/how-to-use-sec-axis-for-discrete-data-in-ggplot2-r – Share Sep 05 '17 at 03:44

2 Answers2

2

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

eipi10
  • 91,525
  • 24
  • 209
  • 285
  • I think this is a great demonstration of precisely why independent variables on secondary axes are discouraged :) – neilfws Sep 05 '17 at 04:26
  • Yes, I very much agree! – eipi10 Sep 05 '17 at 04:26
  • This really helps. To your first code, if you just add `facet_wrap(~set)` it does the trick and divides it into blocks. – Share Sep 05 '17 at 04:37
  • I agree that independent variables should not be encouraged. In my real data, I'm looking at different positions of objects on the x-axis. This is a quick and dirty way of looking at relationships without doing a bunch of circular stats. – Share Sep 05 '17 at 04:39
0

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

neilfws
  • 32,751
  • 5
  • 50
  • 63