简体   繁体   中英

Plot multiple time series one below the other using R

I want to achive a plot similar to this one, having each channel of an eeg time series below another while using the plotting space as good as possible since there are 64 channels. Here is the image. column 1, 2 and 4 are interesting for me:

在此输入图像描述

At te moment I am using gg plot and facet wrap which is wasting so much space on labels and axis. A simple plot like the first colum will be enough to compare the different channels with each other.

Here is my current code:

library(ggplot2)
library(reshape2)

X1 <- c(1,2,3,4,5,6,7,8,9,19)
X2 <- c(1,4,2,4,1,4,1,4,1,4)
X3 <- c(1,2,3,4,5,6,7,8,9,10)
X4 <- c(1,2,3,4,5,6,7,8,9,1)
X5 <- c(1,4,2,4,1,4,1,4,1,4)
X6 <- c(1,2,3,4,5,6,7,8,9,10)
X7 <- c(1,2,3,4,5,6,7,8,9,11)
X8 <- c(1,4,2,4,1,4,1,4,1,4)
X9 <- c(1,2,3,4,5,6,7,8,9,10)
X10 <- c(1,2,3,4,5,6,7,8,9,10)

icaFrame <- data.frame(X1, X2, X3, X4, X5, X6, X7, X8, X9, X10)

scale <- rep.int(c(1:10),10)


df_melt = melt(icaFrame[,1:10])
ggplot(df_melt, aes(x = scale, y = value)) + 
  geom_line() + 
  facet_wrap(~ variable, scales = 'free_y', ncol = 1)

So how can I create such a simple plot with each time series plotted below the other using R?

I think I was able to get something close to the first column using facets. To put the names of the facets in the y axis, use strip.position = 'left' in the facet function. This will save a lot of space.

Then, to get aa look closer to first column, you need to play around with the theme() elements.

library(ggplot2)
library(reshape2)

X1 <- c(1,2,3,4,5,6,7,8,9,19)
X2 <- c(1,4,2,4,1,4,1,4,1,4)
X3 <- c(1,2,3,4,5,6,7,8,9,10)
X4 <- c(1,2,3,4,5,6,7,8,9,1)
X5 <- c(1,4,2,4,1,4,1,4,1,4)
X6 <- c(1,2,3,4,5,6,7,8,9,10)
X7 <- c(1,2,3,4,5,6,7,8,9,11)
X8 <- c(1,4,2,4,1,4,1,4,1,4)
X9 <- c(1,2,3,4,5,6,7,8,9,10)
X10 <- c(1,2,3,4,5,6,7,8,9,10)

icaFrame <- data.frame(X1, X2, X3, X4, X5, X6, X7, X8, X9, X10)

scale <- rep.int(c(1:10),10)

df_melt <- melt(icaFrame[,1:10])

ggplot(df_melt, aes(x = scale, y = value)) + 
  geom_line() + 
  # remove extra space in x axis
  scale_x_continuous(expand=c(0,0)) +
  # standard black and white background theme 
  theme_bw() +
  # customized theme elements (you can play around with them to get a better look:
  theme(axis.title = element_blank(),              # remove labels from axis
        panel.spacing = unit(0, units = 'points'), # remove spacing between facet panels
        panel.border = element_blank(),            # remove border in each facet
        panel.grid.major.y=element_blank(),        # remove grid lines from y axis
        panel.grid.minor.y=element_blank(),
        axis.line = element_line(),                # add axis lines to x and y
        axis.text.y=element_blank(),               # remove tick labels from y axis
        axis.ticks.y = element_blank(),            # remove tick lines from y axis
        strip.background = element_blank(),        # remove gray box from facet title
        # change rotation and alignment of text in facet title
        strip.text.y = element_text(angle = 180,   
                                  face = 'bold',
                                  hjust=1,
                                  vjust=0.5),
        # place facet title to the left of y axis
        strip.placement = 'outside'
        ) +
  # call facet_wrap with argument strip.position = 'left'
  facet_wrap(~ variable, scales = 'free_y', ncol = 1, strip.position = 'left')

My resulting plot

EDIT: Added another approach at the bottom for tighter packing if irregular spacing is ok.

Here's another approach to allow you to squeeze in more closely and allow overlaps:

scaling_factor = 2.5  # Adjust this to make more or less room between series

ggplot(df_melt, aes(x = scale, group = variable,
                    y = value + as.numeric(variable) * scaling_factor)) + 
  geom_line() +
  scale_y_continuous(breaks = (as.numeric(df_melt$variable) + 0.5) * scaling_factor,
                     labels = df_melt$variable, minor_breaks = NULL) +
  labs(y="")

在此输入图像描述


Here's another approach, which finds the minimum necessary spacing between each series to avoid any overlaps.

library(dplyr)
min_space = 2
vertical_shift <- df_melt %>%
  # Add scale as a variable for use in next step
  group_by(variable) %>% mutate(scale = row_number()) %>% ungroup() %>%
  # Group by scale and track gap vs. prior variable
  group_by(scale) %>% mutate(gap = value - lag(value, default = 0)) %>% ungroup() %>%
  # Group by variable and find minimum gap
  group_by(variable) %>% 
  summarize(gap_needed_below = 1 - min(gap) + min_space) %>%
  ungroup() %>%
  mutate(cuml_gap = cumsum(gap_needed_below))

df_melt %>%
  group_by(variable) %>% mutate(scale = row_number()) %>% ungroup() %>%
  left_join(vertical_shift) %>%
  mutate(shifted_value = value + cuml_gap) %>%
ggplot(aes(x = scale, group = variable,
           y = shifted_value)) + 
  geom_line() +
  scale_y_continuous(breaks = vertical_shift_headers$cuml_gap + 1,
                     labels = vertical_shift_headers$variable,
                     minor_breaks = NULL) +
  labs(y="")

在此输入图像描述

I think you were pretty close. I'll use data.table just to get a number you need to label the y axis, but you can use any other base or dplyr tool. I'll also use some dummy data that allows us to see better the result (your data crosses the values, unlike the image you pasted).

# load libraries

library(data.table)
library(ggplot2)

# create dummy data

set.seed(1)
dt <- data.table(time = 1:10, 
                 EOG = sample(1:5, 10, TRUE), 
                 Pz = sample(6:10, 10, TRUE), 
                 Cz = sample(15:21, 10, TRUE))

# melt that data

melt_dt <- melt(dt, id.vars = 1)

# find mean values for each variable

crossings <- melt_dt[, mean(value), by = variable]

Now, plot the whole thing:

ggplot(melt_dt, 
       aes(x = time, 
           y = value, 
           group = variable))+
   geom_line()+
   scale_y_continuous(breaks = crossings$V1, 
                      labels = crossings$variable)

Which produces:

情节

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM