How to add gaps using geom_tile in R? - r

I plot a heatmap using geom_tile (ggplot2):
library("reshape2")
library("ggplot2")
x <- matrix(1:12, nrow=3)
rownames(x) <- LETTERS[1:3]
colnames(x) <- letters[1:4]
x_melted <- melt(x)
x_melted$group1 <- rep(c("T1","T2"), each=6)
ggplot(x_melted, aes(x = Var1, y = Var2)) + geom_tile(aes(fill = value))
But I need add a gap according to group1 in x_melted so that a gap was produced between the first two rows and the last two rows. How could this be added?

One way would be to use facets -
x_melted$group1 = factor(x_melted$group1, levels = c("T2", "T1"))
ggplot(x_melted, aes(x = Var1, y = Var2)) +
geom_tile(aes(fill = value)) +
facet_grid(group1 ~ ., scales = "free_y")

Related

How to combine legends from different ggplot after extracting via get_legend

(EDIT: Removed original code and added reproducible example.)
I have two ggplot2 geom_tile plots.
Both have a legend.
The first one has one gradient scale.
The second one has two gradient scales.
Now I extract the legends from both plots via cowplot::get_legend(). The aim is to merge them to one legend and add it to the right of the composed final plot.
Then I try to combine them via: cowplot::plot_grid(legend1, legend2, ncol = 1, align = "v").
The problem is, that there is a large (EDIT: actually scaling) space between legend1 and legend2 (see figure below). I tried to remove margins of the legends via theme() when generating the initial geom_tile ggplots, but was not successful.
This there a way to completely "unwrap" the extracted legends and then stack them vertically afterwards into one ggplot figure?
Minimal example to showcase my problem:
m <- matrix(round(rnorm(200), 2), 10, 10)
colnames(m) <- paste("Col", 1:10)
rownames(m) <- paste("Row", 1:10)
df <- melt(m)
colnames(df) <- c("x", "y", "value")
df2 <- df
colnames(df2) <- c("x", "y", "value2")
library(ggnewscale)
ggplot1 <- ggplot(df, aes(x = x, y = y, fill = value)) +
geom_tile()
legend1 <- cowplot::get_legend(ggplot1)
ggplot2 <- ggplot() +
geom_tile(data = df2, aes(x = x, y = y, fill = value2)) +
ggnewscale::new_scale_fill() +
geom_tile(data = df, aes(x = x, y = y, fill = value))
legend2 <- cowplot::get_legend(ggplot2)
library(cowplot)
cowplot::plot_grid(legend1, legend2, ncol = 1, align = "v")
And here the result. The gap between the first scale and the second is too large -- what I learned just now, it that this large gap is being scaled according to the total size. So it seems to not be fixed:
When it comes to arranging plots it's always worthwhile to consider patchwork as an option. In your case you could use guides="collect" to arrange the legends without the need of extracting them first. However, at least for your example data one minor hack is necessary to show all legends, i.e. we have to add a space to the name of one of the value legends to prevent that they get merged.
library(ggplot2)
library(ggnewscale)
p1 <- ggplot(df, aes(x = x, y = y, fill = value)) +
geom_tile()
p2 <- ggplot() +
geom_tile(data = df2, aes(x = x, y = y, fill = value2)) +
ggnewscale::new_scale_fill() +
geom_tile(data = df, aes(x = x, y = y, fill = value)) +
scale_fill_continuous(name = "value ")
library(patchwork)
p1 / p2 + plot_layout(ncol = 1, guides = "collect")
DATA
set.seed(123)
m <- matrix(round(rnorm(100), 2), 10, 10)
colnames(m) <- paste("Col", 1:10)
rownames(m) <- paste("Row", 1:10)
df <- reshape2::melt(m)
colnames(df) <- c("x", "y", "value")
df2 <- df
colnames(df2) <- c("x", "y", "value2")

How to fill a tile plot when it is facetted and with the y axis free? (ggplot2)

The following data frame is represented in a tile plot. Group B data has a different scale and therefore the Y-axis must be free. The plot is separated by facets according to the group. However, the group B tile plot appears as thin bands rather than looking like the group A plot. How can I make it so that, despite the Y-axis being free, the plot of group B fills all the white space as in group A?
library(ggplot2)
X <- 1:3
Y1 <- 1:3
Y2 <- seq(10, 30, 10)
Y <- c(rep(Y1,3), rep(Y2,3))
Grid <- 1:3
Group <- c("A", "B")
DF <- expand.grid(Grid = Grid,
X = X,
Group = Group)
DF$Y <- Y
DF$Grid <- NULL
DF$Z <- 1:18
ggplot(data = DF,
aes(x = X,
y = Y,
fill = Z)) +
geom_tile() +
facet_wrap(~ Group,
scales = "free_y")
One option to achieve your desired result would be to convert Y to a factor:
library(ggplot2)
ggplot(data = DF,
aes(x = X,
y = factor(Y),
fill = Z)) +
geom_tile() +
facet_wrap(~ Group,
scales = "free_y")
library(tidyverse)
DF %>%
complete(X = 1:3,Y = 1:30,Group = c("A","B"),fill = list(Z = NA_real_)) %>%
filter(!(Group == "A" & is.na(Z))) %>%
ggplot(aes(x = X,
y = Y,
fill = Z)) +
geom_tile(col = "white") +
facet_wrap(~ Group,
scales = "free_y")

R ggplot2: draw segment between points

How can I use geom_segment to draw lines on plot, after the data have been melted with reshape2?
# Tiny dataset
facet_group <- c("facet1", "facet1", "facet2", "facet2")
time_group <- c("before", "after", "before", "after")
variable1 <- c(1,5,4,7)
variable2 <- c(2,4,5,8)
variable3 <- c(4,5,6,7)
data <- data.frame(facet_group, time_group, variable1, variable2, variable3)
# Melt data
library(reshape2)
data_melt <- melt(data, id.vars = c("facet_group", "time_group"))
Plot the data:
# Plot 1
library(ggplot2)
ggplot(data_melt, aes(x=variable, y=value, group = time_group)) +
geom_point(aes(color = time_group))
Add faceting:
# Plot 2
ggplot(data_melt, aes(x=variable, y=value, group = time_group)) +
geom_point(aes(color = time_group)) +
facet_grid(facet_group ~ .)
I want to draw a segments from the "before" point to the "after" point for each variable. (see mock up image). How can I do this? I tried some things with geom_segment but I kept having errors. Will casting the data into a new data frame help?? Thanks!
data_cast <- dcast(data_melt, variable + facet_group ~ time_group)
Final "ideal" plot:
You were definitely on the right track with the casted data. Give this a shot:
ggplot(data_melt, aes(x=variable, y=value)) +
geom_point(aes(color = time_group)) +
facet_grid(facet_group ~ .) +
geom_segment(data = data_cast, aes(x = variable, xend = variable,
y = before, yend = after),
arrow = arrow(),
colour = "#FF3EFF",
size = 1.25)

Grouped bins with multiple y axis

I have a data frame with five columns and five rows. the data frame looks like this:
df <- data.frame(
day=c("m","t","w","t","f"),
V1=c(5,10,20,15,20),
V2=c(0.1,0.2,0.6,0.5,0.8),
V3=c(120,100,110,120,100),
V4=c(1,10,6,8,8)
)
I want to do some plots so I used the ggplot and in particular the geom_bar:
ggplot(df, aes(x = day, y = V1, group = 1)) + ylim(0,20)+ geom_bar(stat = "identity")
ggplot(df, aes(x = day, y = V2, group = 1)) + ylim(0,1)+ geom_bar(stat = "identity")
ggplot(df, aes(x = day, y = V3, group = 1)) + ylim(50,200)+ geom_bar(stat = "identity")
ggplot(df, aes(x = day, y = V4, group = 1)) + ylim(0,15)+ geom_bar(stat = "identity")
My question is, How can I do a grouped ggplot with geom_bar with multiple y axis? I want at the x axis the day and for each day I want to plot four bins V1,V2,V3,V4 but with different range and color. Is that possible?
EDIT
I want the y axis to look like this:
require(reshape)
data.m <- melt(df, id.vars='day')
ggplot(data.m, aes(day, value)) +
geom_bar(aes(fill = variable), position = "dodge", stat="identity") +
facet_grid(variable ~ .)
You can also change the y-axis limits if you like (here's an example).
Alternately you may have meant grouped like this:
require(reshape)
data.m <- melt(df, id.vars='day')
ggplot(data.m, aes(day, value)) +
geom_bar(aes(fill = variable), position = "dodge", stat="identity")
For the latter examples if you want 2 Y axes then you just create the plot twice (once with a left y axis and once with a right y axis) then use this function:
double_axis_graph <- function(graf1,graf2){
graf1 <- graf1
graf2 <- graf2
gtable1 <- ggplot_gtable(ggplot_build(graf1))
gtable2 <- ggplot_gtable(ggplot_build(graf2))
par <- c(subset(gtable1[['layout']], name=='panel', select=t:r))
graf <- gtable_add_grob(gtable1, gtable2[['grobs']][[which(gtable2[['layout']][['name']]=='panel')]],
par['t'],par['l'],par['b'],par['r'])
ia <- which(gtable2[['layout']][['name']]=='axis-l')
ga <- gtable2[['grobs']][[ia]]
ax <- ga[['children']][[2]]
ax[['widths']] <- rev(ax[['widths']])
ax[['grobs']] <- rev(ax[['grobs']])
ax[['grobs']][[1]][['x']] <- ax[['grobs']][[1]][['x']] - unit(1,'npc') + unit(0.15,'cm')
graf <- gtable_add_cols(graf, gtable2[['widths']][gtable2[['layout']][ia, ][['l']]], length(graf[['widths']])-1)
graf <- gtable_add_grob(graf, ax, par['t'], length(graf[['widths']])-1, par['b'])
return(graf)
}
I believe there's also a package or convenience function that does the same thing.
First I reshaped as described in the documentation in the link below the question.
In general ggplot does not support multiple y-axis. I think it is a philosophical thing. But maybe faceting will work for you.
df <- read.table(text = "day V1 V2 V3 V4
m 5 0.1 120 1
t 10 0.2 100 10
w 2 0.6 110 6
t 15 0.5 120 8
f 20 0.8 100 8", header = TRUE)
library(reshape2)
df <- melt(df, id.vars = 'day')
ggplot(df, aes(x = variable, y = value, fill = variable)) + geom_bar(stat = "identity") + facet_grid(.~day)
If I understand correctly you want to include facets in your plot. You have to use reshape2 to get the data in the right format. Here's an example with your data:
df <- data.frame(
day=c("m","t","w","t","f"),
V1=c(5,10,20,15,20),
V2=c(0.1,0.2,0.6,0.5,0.8),
V3=c(120,100,110,120,100),
V4=c(1,10,6,8,8)
)
library(reshape2)
df <- melt(df, "day")
Then plot with and include facet_grid argument:
ggplot(df, aes(x=day, y=value)) + geom_bar(stat="identity", aes(fill=variable)) +
facet_grid(variable ~ .)

How to plot a list of vectors with different lengths?

I have a list with 9 different vectors inside. And I want plot them (dot-line) in one figure with different colors by their names. How to do that in R language?
Using a made up example:
# example data:
dat <- list(a=1:5,b=2:7,c=3:10)
# get plotting:
plot(unlist(dat),type="n",xlim=c(1,max(sapply(dat,length))))
mapply(lines,dat,col=seq_along(dat),lty=2)
legend("topleft",names(dat),lty=2,col=seq_along(dat))
No question would be complete without a ggplot answer.
dat <- list(a=1:5,b=2:7,c=3:10)
dat <- lapply(dat, function(x) cbind(x = seq_along(x), y = x))
list.names <- names(dat)
lns <- sapply(dat, nrow)
dat <- as.data.frame(do.call("rbind", dat))
dat$group <- rep(list.names, lns)
library(ggplot2)
ggplot(dat, aes(x = x, y = y, colour = group)) +
theme_bw() +
geom_line(linetype = "dotted")
To plot each line in a separate plot, use
ggplot(dat, aes(x = x, y = y, colour = group)) +
theme_bw() +
geom_line(linetype = "dotted") +
facet_wrap(~ group)

Resources