16

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.

Jojo
  • 4,951
  • 7
  • 23
  • 27
  • If you use ggplot2, take a look at `facet_wrap`, with `ncol = 1` and `scales = "free_y"`. – Paul Hiemstra Aug 03 '12 at 11:15
  • @PaulHiemstra The problem I face when I ever try to use the ggplot plotting function in ggplot2 is the error: Error: ggplot2 doesn't know how to deal with data of class numeric Which people continually tell me is due to my data not being a data.frame when it is. Do you have any idea what this error is telling me? – Jojo Aug 03 '12 at 11:19
  • just provide a _reproducible_ example and we can see what goes wrong. – Paul Hiemstra Aug 03 '12 at 11:28

5 Answers5

14

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

aaronwolen
  • 3,723
  • 1
  • 20
  • 21
  • 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? – Jojo Aug 03 '12 at 14:36
  • 3
    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. – Ben Bolker Aug 03 '12 at 14:39
  • @BenBolker Thanks this is very helpful. Just one final thing. Is there a way to change the strip labels on the right hand side? – Jojo Aug 03 '12 at 15:03
  • 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"))` – aaronwolen Aug 03 '12 at 15:07
  • You can also use `+ facet_wrap(variable ~ ., ncol = 1)` for a variation on this. See http://docs.ggplot2.org/0.9.3.1/facet_wrap.html. – Matt Jan 27 '16 at 21:22
8

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

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • 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. – Jojo Aug 03 '12 at 14:20
  • 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. – Dirk Eddelbuettel Aug 03 '12 at 14:23
  • 2
    Try [this link from my site](http://dirk.eddelbuettel.com/code/snippets/bollingerBands.R). The code is nine years old though... – Dirk Eddelbuettel Jan 28 '14 at 12:35
6

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

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
  • Good call, that probably makes more sense. – aaronwolen Aug 03 '12 at 13:25
  • @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 Aug 03 '12 at 13:34
  • I would also like to invert the yaxis for DEPTH if possible? – Jojo Aug 03 '12 at 13:38
  • (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. – Ben Bolker Aug 03 '12 at 13:50
  • @aaronwolen any suggestions as to how I might handle each plot individually in terms of formatting colour/yaxis labelling etc? – Jojo Aug 03 '12 at 14:14
  • 2
    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. – aaronwolen Aug 03 '12 at 15:03
5

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.

Jojo
  • 4,951
  • 7
  • 23
  • 27
  • 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! – Jojo Aug 04 '12 at 10:49
  • 1
    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? – Ben Bolker Aug 04 '12 at 17:30
0

Please read this example:

Generate example data:

dt = read_table("Time        A       B       C       D
10:12:54    2376.2  1.462   3.462   48
10:12:55    2410    1.462   3.462   48
10:12:56    2400    1.462   3.462   48
10:12:57    2409    1.462   3.462   48.6
10:12:58    2400    1.462   3.462   48.6
10:12:59    2385.1  1.462   3.462   46.6
10:13:00    2400    1.462   3.462   46.6
10:13:01    2410    1.462   3.462   46.6
10:13:02    2400    1.462   3.462   46.6
10:13:03    2106    1.463   3.463   46.6
10:13:04    2406    1.463   3.463   44.8
10:13:05    2376.2  1.463   3.463   44.8
10:13:06    2406    1.463   3.463   44.8
10:13:07    2400    1.463   3.463   44.8")
dt$Time=as.POSIXct(dt$Time)

If you want to plot it quickly, try this:

library(foqat)
geom_ts_batch(dt, panelgap=4)

enter image description here

If you want to plot it with more degree of freedom, try this:

library(foqat)
library(patchwork)
blankx=theme(axis.title.x=element_blank(),axis.text.x=element_blank(),axis.ticks.x=element_blank())
p2=geom_ts(dt, yl=2, llist=2, lcc="blue", yllab="A")+blankx
p3=geom_ts(dt, yl=3, llist=3, lcc="red", yllab="B")+blankx
p4=geom_ts(dt, yl=4, llist=4, lcc="green", yllab="C")+blankx
p5=geom_ts(dt, yl=5, llist=5, lcc="grey", yllab="D", xlab="Time")
p2/p3/p4/p5

enter image description here

TichPi
  • 146
  • 5