Stacking multiple plots, vertically with the same x axis but different Y axes in R

33,070

Solution 1

If you want to be old-fashioned you can use lattice. Unlike @aaronwolen I assumed there was a missing time variable in the data set, so I made one up:

dt$time <- seq(nrow(dt))
library(reshape2)
mm <- melt(subset(dt,select=c(time,DEPTH,X,Y,Z)),id.var="time")
library(lattice)
xyplot(value~time|variable,data=mm,type="l",
       scales=list(y=list(relation="free")),
       layout=c(1,4))

enter image description here

Solution 2

I agree with @PaulHiemstra, ggplot2 is the way to go.

Assuming Smooth.Vert.Speed is the common x-axis variable against which you want to plot DEPTH, X, Y and Z...

library(ggplot2)
library(reshape2)

# Add time variable as per @BenBolker's suggestion
dt$time <- seq(nrow(dt))

# Use melt to reshape data so values and variables are in separate columns
dt.df <- melt(dt, measure.vars = c("DEPTH", "X", "Y", "Z"))

ggplot(dt.df, aes(x = time, y = value)) +
  geom_line(aes(color = variable)) +
  facet_grid(variable ~ ., scales = "free_y") +
  # Suppress the legend since color isn't actually providing any information
  opts(legend.position = "none")

Plotting multiple y-variables against a common x-variable

Solution 3

Just to be different, let me mention a solution involving neither lattice nor ggplot2 -- I posted this to Romain's R Graph Gallery a few years back as entry 65 with the code here. It just stacks the graphs up, using par() settings to keep them stacked.

Note that the vertical sizes are different by choice, they could easily be of the same height as well.

enter image description here

Solution 4

I've actually figured out another interesting way of doing this with the zoo library:

library(zoo)
z <- with(dt, zoo(cbind(DEPTH, X, Y, Z),as.POSIXct(time))) 
plot.zoo(z,  ylab=c("Depth (m)", "Pitch Angle (degrees)", "Swaying Acceleration (m/s^2)", "Heaving Acceleration (m/s^2)"), col=c("black", "blue", "darkred", "darkgreen"), 
     xlab = c("Time"), lwd=2, ylim=list((rev(range(dt$DEPTH))), c(-90,90), c(-10,10), c(-10,10)))

So within a zoo plot you can create new axis labels as a list form and all plots can have different colours.

Share:
33,070
Jojo
Author by

Jojo

Updated on February 03, 2022

Comments

  • Jojo
    Jojo over 2 years

    I have a data.frame with multiple time series vectors against a date:time vector. I would like to plot all of the relevant vectors, vertically stacked on separate graphs with the same X axis but unique Y axes. A graph similar to this one: enter image description here

    my data looks like this:

     dt <- structure(list(DEPTH = c(156, 156.5, 157.4, 158.15, 158.8, 159.2, 
    159.75, 160.35, 160.85, 161.1, 161.6, 162.05, 162.5, 162.65, 
    163.15, 163.45, 163.55, 163.8, 163.65, 163.75, 163.8, 163.8, 
    163.75, 164.45, 164.8, 165.35, 165.65, 165.75, 166.1, 166.75, 
    167, 167.2, 167.65, 168, 168.8, 169.3, 169.7, 170.2, 170.65, 
    170.9, 171.45, 171.65, 172, 172.1, 172.25, 173, 173.4, 173.9, 
    174.2, 174.6, 175, 175.25, 175.45, 175.9, 176.25, 176.7, 177, 
    177.15, 177.5, 178, 178.5, 179.05, 179.2, 180.7, 181.05, 181.25, 
    181.5, 181.7, 182.1, 182.3, 182.35, 182.75, 183.1, 183.65, 184.3, 
    184.6, 185.1, 185.15, 185.3, 185.15, 185.25, 185.3, 185.15), 
        Smooth.Vert.Speed = c(-0.550000000000011, -0.5, -0.900000000000006, 
        -0.75, -0.650000000000006, -0.399999999999977, -0.550000000000011, 
        -0.599999999999994, -0.5, -0.25, -0.5, -0.450000000000017, 
        -0.449999999999989, -0.150000000000006, -0.5, -0.299999999999983, 
        -0.100000000000023, -0.25, 0.150000000000006, -0.0999999999999943, 
        -0.0500000000000114, 0, 0.0500000000000114, -0.699999999999989, 
        -0.350000000000023, -0.549999999999983, -0.300000000000011, 
        -0.0999999999999943, -0.349999999999994, -0.650000000000006, 
        -0.25, -0.199999999999989, -0.450000000000017, -0.349999999999994, 
        -0.800000000000011, -0.5, -0.399999999999977, -0.5, -0.450000000000017, 
        -0.25, -0.549999999999983, -0.200000000000017, -0.349999999999994, 
        -0.0999999999999943, -0.150000000000006, -0.75, -0.400000000000006, 
        -0.5, -0.299999999999983, -0.400000000000006, -0.400000000000006, 
        -0.25, -0.199999999999989, -0.450000000000017, -0.349999999999994, 
        -0.449999999999989, -0.300000000000011, -0.150000000000006, 
        -0.349999999999994, -0.5, -0.5, -0.550000000000011, -0.149999999999977, 
        -1.5, -0.350000000000023, -0.199999999999989, -0.25, -0.199999999999989, 
        -0.400000000000006, -0.200000000000017, -0.049999999999983, 
        -0.400000000000006, -0.349999999999994, -0.550000000000011, 
        -0.650000000000006, -0.299999999999983, -0.5, -0.0500000000000114, 
        -0.150000000000006, 0.150000000000006, -0.0999999999999943, 
        -0.0500000000000114, 0.150000000000006), DIVE_SURF = c("dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21", "dive21", "dive21", 
        "dive21", "dive21", "dive21", "dive21"), X = c(2050L, 2062L, 
        2026L, 2078L, 2058L, 2076L, 2050L, 2068L, 2060L, 2078L, 2058L, 
        2088L, 2080L, 2065L, 2088L, 2076L, 2084L, 2105L, 2084L, 2102L, 
        2123L, 2096L, 2074L, 2054L, 2090L, 2089L, 2080L, 2078L, 2068L, 
        2092L, 2084L, 2082L, 2094L, 2056L, 2062L, 2067L, 2082L, 2084L, 
        2091L, 2058L, 2076L, 2098L, 2104L, 2090L, 2058L, 2050L, 2080L, 
        2074L, 2074L, 2082L, 2070L, 2088L, 2062L, 2062L, 2082L, 2086L, 
        2070L, 2081L, 2092L, 2058L, 2060L, 2076L, 2094L, 2083L, 2072L, 
        2107L, 2104L, 2066L, 2110L, 2104L, 2072L, 2076L, 2065L, 2042L, 
        2066L, 2093L, 2080L, 2083L, 2108L, 2107L, 2086L, 2096L, 2126L
        ), Y = c(2036L, 2000L, 2049L, 1966L, 2042L, 2078L, 2072L, 
        2055L, 2036L, 2128L, 2044L, 2112L, 2066L, 2051L, 2102L, 2060L, 
        2054L, 2043L, 2034L, 2086L, 1980L, 2076L, 2003L, 2033L, 2107L, 
        1992L, 2028L, 2027L, 2024L, 2005L, 2050L, 2010L, 1944L, 2010L, 
        2046L, 2020L, 2088L, 2086L, 2034L, 2066L, 2060L, 2152L, 2044L, 
        2078L, 2040L, 2067L, 2080L, 2072L, 2073L, 2028L, 2066L, 2082L, 
        2030L, 2042L, 1990L, 2076L, 2054L, 2064L, 2016L, 2048L, 2029L, 
        2008L, 2090L, 2038L, 2026L, 2096L, 2002L, 2025L, 2001L, 2098L, 
        2061L, 2022L, 2054L, 2064L, 2043L, 2090L, 2042L, 2086L, 2073L, 
        2066L, 2040L, 2081L, 2087L), Z = c(2488L, 2484L, 2490L, 2486L, 
        2488L, 2492L, 2498L, 2490L, 2492L, 2484L, 2491L, 2494L, 2497L, 
        2493L, 2488L, 2493L, 2494L, 2484L, 2486L, 2487L, 2478L, 2490L, 
        2478L, 2493L, 2490L, 2486L, 2488L, 2486L, 2488L, 2482L, 2488L, 
        2480L, 2480L, 2488L, 2490L, 2490L, 2490L, 2489L, 2492L, 2490L, 
        2486L, 2480L, 2488L, 2491L, 2486L, 2488L, 2488L, 2494L, 2490L, 
        2488L, 2492L, 2498L, 2484L, 2491L, 2480L, 2491L, 2497L, 2487L, 
        2482L, 2490L, 2490L, 2478L, 2488L, 2492L, 2492L, 2482L, 2484L, 
        2489L, 2482L, 2484L, 2485L, 2492L, 2488L, 2493L, 2487L, 2490L, 
        2492L, 2488L, 2490L, 2487L, 2484L, 2486L, 2478L)), .Names = c("DEPTH", 
    "Smooth.Vert.Speed", "DIVE_SURF", "X", "Y", "Z"), row.names = 7222:7304, class = "data.frame")
    

    and I am looking to plot DEPTH, X, Y and Z on separate graphs with a common X axis.

  • aaronwolen
    aaronwolen almost 12 years
    Good call, that probably makes more sense.
  • Jojo
    Jojo almost 12 years
    @BenBolker Ah this is perfect thankyou. Is there a way with this plot to have every variable a different colour and to name each y-axis differently? You are right, I left out the time variable as its a date-time variable and I havn't figured out how to plot it properly yet using the POSIXct function.
  • Jojo
    Jojo almost 12 years
    I would also like to invert the yaxis for DEPTH if possible?
  • Ben Bolker
    Ben Bolker almost 12 years
    (1) your best bet for assigning colours and naming the axes is as in @aaronwolen's answer. (2) I think both lattice and ggplot2 should handle POSIXct axes OK. (3) inverting depth could be tricky: @DirkEddelbuettel's answer will allow you the greatest flexibility.
  • Jojo
    Jojo almost 12 years
    @aaronwolen any suggestions as to how I might handle each plot individually in terms of formatting colour/yaxis labelling etc?
  • Jojo
    Jojo almost 12 years
    This is excellent however a little complicated for my purposes and am finding it a little difficult to tease apart what would be appropriate for me to use with my example. Which part of the code is specific to "connecting" the plots together vertically and creating a common x-axis? +1 for this brilliant example of data visualisation.
  • Dirk Eddelbuettel
    Dirk Eddelbuettel almost 12 years
    Yes, the code does too much for your purposes as I have all the computing (and data gathering) to do. Look into the final function which uses the excellent layout() function, and the calls the individual plots. I have another (simpler) example at home where I set up a regular grid in a similar way and the plot multiple functions; hopefully I'll remember to add this at some point.
  • Jojo
    Jojo almost 12 years
    This code works very nicely aswell. Is there any way to change the colours for each plot and get individual y axis labels for this one?
  • Ben Bolker
    Ben Bolker almost 12 years
    changing colours is very easy (add colour=variable as an argument to the aes() function; see ?scale_colour_manual if you want to assign the colours manually rather than automatically). Individual y-axis labels will be harder, but the strip labels on the right hand side might be an acceptable substitute. I like theme_update(theme_bw()) and importing library(grid) and adding +opts(panel.margin=unit(0,"lines")) to the ggplot call, for aesthetic reasons. As I said above, @DirkEddelbuettel's approach will be most customizable.
  • aaronwolen
    aaronwolen almost 12 years
    I updated the code so each variable would be colored differently. I don't know of a way to add individual labels for each y-axis or invert the y-axis for DEPTH only. The intent of ggplot2's faceting functions are to place subsets of your data in separate panels while still plotting them against the same x & y variables. Hence only one label per axis. Given what you want to do, perhaps it would be best just to generate 4 separate plots stacked on top of each another and only label the bottom plot's x-axis.
  • Jojo
    Jojo almost 12 years
    @BenBolker Thanks this is very helpful. Just one final thing. Is there a way to change the strip labels on the right hand side?
  • aaronwolen
    aaronwolen almost 12 years
    The strip labels come from your data.frame, so renaming there will change the labels in the plot: dt.df$variable <- factor(dt.df$variable, levels = c("DEPTH", "X", "Y", "Z"), labels = c("depth-var", "x-var", "y-var", "z-var"))
  • Jojo
    Jojo almost 12 years
    You can input a list of sequential ylim values within the plot function that are applied to each individual plot in order. Ive updated the code in the answer. Thanks for all the Help @BenBolker!
  • Ben Bolker
    Ben Bolker almost 12 years
    it would be OK with me if you accepted your own answer rather than mine, since you've come closer to fully answering your question. Perhaps you could edit your answer to show a picture of the result?
  • Dirk Eddelbuettel
    Dirk Eddelbuettel over 10 years
    Try this link from my site. The code is nine years old though...
  • Matt
    Matt over 8 years
    You can also use + facet_wrap(variable ~ ., ncol = 1) for a variation on this. See docs.ggplot2.org/0.9.3.1/facet_wrap.html.