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')
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.