Overlaying Two Graphs Using Ggplot2 in R

Overlaying two plots using ggplot2 in R

If you redefine data, that will change where that geom layer is sourcing from. ggplot will always look to the initializing call for the aesthetic mappings and try to inherit from there, so you don't need to redfine aes() unless you want to change/add a mapping.

Also no need to use the df[,2] syntax, ggplot is already looking inside df1 as soon as you set data = df1.

df1 <- data.frame(x = seq(2, 8, by = 2),
y = seq(30, 15, by = -5))
df2 <- data.frame(x = seq(2, 8, by = 2),
y = seq(12, 24, by = 4))

ggplot(df1, aes(x, log(y))) +
geom_line() +
geom_line(data = df2, color = "red") # re-define data and overwrite top layer inheritance

Sample Image

Overlaying two graphs using ggplot2 in R

One way is to add the geom_line command for the second plot to the first plot. You need to tell ggplot that this geom is based on a different data set:

ggplot(avg, aes(x=Gene, y=mean)) + 
geom_point() +
geom_line() +
geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd), width=.1) +
geom_line(data = ge, aes(x=Gene, y=Exp, group=Sample, colour="#000099"),
show_guide = FALSE)

The last geom_line command is for creating the lines based on the raw data.
Sample Image

Overlaying two plots with different dimensions using ggplot in R

You need to have the same time labels for each of the datasets and then they can be plotted together using geom_line.

library(scales)
library(tidyverse)
library(ggplot2)

Canada <- c(383.927, 387.088, 390.648, 393.926, 395.947, 393.98, 388.772,
392.391, 391.804, 389.321, 390.583, 390.062, 390.596, 392.19,
392.267, 397.572, 397.807, 394.64, 391.737, 392.659, 392.483,
392.012, 391.842, 394.06, 391.661, 390.621, 392.533, 396.218,
401.802, 397.298, 392.468, 392.056, 394.752, 392.947, 392.606,
391.839, 392.169, 393.29, 399.993, 396.114, 403.1, 398.263, 395.066,
397.16, 399.562, 396.865, 392.898, 396.89, 398.529, 402.269,
-9.999e+09, 398.294, 401.033, 399.328, -9.999e+09, 400.062, 395.829,
397.754, 395.306, 394.87, 398.469, 399.91, 405.053, 404.678,
402.185, 396.605, -9.999e+09, 402.252, 405.295, 401.08, 400.527,
398.38, 400.152, 396.42, 402.497, 406.855, 403.56, -9.999e+09,
-9.999e+09, 405.773, 402.306, 403.146, 403.079, 400.712)

time <- c("Jan. 2010","","","","","July 2010","","","","","",
"Dec. 2010","","","","","","July 2011","","","","","",
"Dec. 2011","","","","","","July 2012","","","","","",
"Dec. 2012","","","","","","July 2013","","","","","",
"Dec. 2013","","","","","","July 2014","","","","","",
"Dec. 2014","","","","","","July 2015","","","","","",
"Dec. 2015","","","","","","July 2016","","","","","",
"Dec. 2016")

Canada1 <- c(390.704083333333, 393.322083333333, 393.900083333333, 396.780833333333,
398.3274, 401.312181818182, 402.45) # The second set of data

Here all of the months are listed out and a dataframe storing all the months, CO2 values and the labels that you want are kept.

## Set the date range and select by month
d1 <- as.Date(paste0("201001","01"), "%Y%m%d")
d2 <- as.Date(paste0("201612","01"), "%Y%m%d")

date1 <- format(seq(d1,d2,by="month"), "%Y%m%d")
dat <- data.frame(co2 = Canada, labels = as.character(time), date = date1, group = 1)

## Set the date range and select by year
d1 <- as.Date(paste0("201006","01"), "%Y%m%d")
d2 <- as.Date(paste0("201606","01"), "%Y%m%d")
date2 <- format(seq(d1,d2,by="year"), "%Y%m%d")

dat2 <- data.frame(co2 = Canada1, date = date2, group = 2)

The 2 datasets are plotted and the x labels are set to dat$labels

Canplot <- ggplot() + 
geom_line(data = dat, aes(x = date, y = co2, group = group)) +
geom_line(data = dat2, aes(x = date, y = co2, group = group), color = "Red") +
ylim(380,410) +
scale_x_discrete(labels = data$labels)+
theme_classic(base_size=12) + ylab("CO2 (ppm)") + xlab("Time") +
theme(axis.text.x = element_text(angle = 45, hjust=1))

Canplot

Overlay two ggplots with different x and y axes scales

Since they don't have matching scales ggplot won't allow us to plot them one on top of the other. (ggplot doesn't even really allow for two y-scales) To get around that, we'll have to treat them as images rather than plots.

To make the to images as similar to each other as possible, we need to strip everything except for the lines. Having axes, labels, titles, etc would 'misalign' the "plots".

library(ggplot2)
library(magick)
#> Linking to ImageMagick 6.9.7.4
#> Enabled features: fontconfig, freetype, fftw, lcms, pango, x11
#> Disabled features: cairo, ghostscript, rsvg, webp

df_1 <- data.frame(x=c(1:200), y=rnorm(200))

df_2 <- rpois(100000, 1)
df_2 <- data.frame(table(df_2))
df_2$df_2 <- as.numeric(levels(df_2$df_2))[df_2$df_2]

p1 <- ggplot() +
geom_line(data=df_1, aes(x=x,y=y)) +
theme_void() +
theme(
panel.background = element_rect(fill = "transparent"), # bg of the panel
plot.background = element_rect(fill = "transparent", color = NA), # bg of the plot
panel.grid.major = element_blank(), # get rid of major grid
panel.grid.minor = element_blank(), # get rid of minor grid
legend.background = element_rect(fill = "transparent"), # get rid of legend bg
legend.box.background = element_rect(fill = "transparent") # get rid of legend panel bg
)
ggsave(filename = 'plot1.png', device = 'png', bg = 'transparent')
#> Saving 7 x 5 in image

p2 <- ggplot() +
geom_line(data=df_2, aes(x=df_2,y=Freq)) +
theme_void() +
theme(
panel.background = element_rect(fill = "transparent"), # bg of the panel
plot.background = element_rect(fill = "transparent", color = NA), # bg of the plot
panel.grid.major = element_blank(), # get rid of major grid
panel.grid.minor = element_blank(), # get rid of minor grid
legend.background = element_rect(fill = "transparent"), # get rid of legend bg
legend.box.background = element_rect(fill = "transparent") # get rid of legend panel bg
)
ggsave(filename = 'plot2.png', device = 'png', bg = 'transparent')
#> Saving 7 x 5 in image

cowplot::plot_grid(p1, p2, nrow = 1)

The two plots:

Sample Image


plot1 <- image_read('plot1.png')
plot2 <- image_read('plot2.png')

img <- c(plot1, plot2)

image_mosaic(img)

Created on 2020-01-10 by the reprex package (v0.3.0)

Both "plots" combined:

Sample Image

Plot two graphs in same plot in R

lines() or points() will add to the existing graph, but will not create a new window. So you'd need to do

plot(x,y1,type="l",col="red")
lines(x,y2,col="green")

Overlay two plots on top of each other

Unfortunately, the stem function doesn't return anything, which makes life difficult. Plus, the code is written in C, which is available here. I've tried to replicate the stem function using simple R functions and this certainly doesn't match the C code, but it works for this sample dataset. I certainly haven't incorporated any of stem's arguments (scale, width, atom).

data(mtcars)

x <- mtcars$wt
stem(x) # you can see the result from the question.

mu = mean(x)
sdev <- sd(x)

y <- (1/(sdev * sqrt(2*pi))) * exp(-((x-mu)^2)/(2*sdev^2))

This is your density plot:

par(mar=c(2,1,1,1))
plot(x, y, pch = 8, xaxt="n", yaxt="n", ylab="", col="grey)

Now we need to reinvent the stem function from scratch. I first use the hist function to define to "best" breakpoints, which I'm guessing is similar to what stem does.

h <- hist(round(x,1), right=FALSE, plot=F)
bin <- h$breaks; bin
#[1] 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5

Then I use cut to assign the x values into the correct bins.

xgr <- sort(cut(round(x,1), breaks = bin, right=FALSE, labels = FALSE, include = TRUE))

Then I use the rowid function from data.table to define the y-axis values, dividing by its length to get the densities so that the two plots are using the same y-axis system.

library(data.table)
y <- rowid(xgr)/length(xgr); y

The actual characters to plot (pch) come from the first digit after the decimal place.

pch <- as.character(round(10*(round(sort(x),1) %% 1))); pch
# [1] "5" "6" "8" "9" "1" "2" "3" "5" "6" "8" "8" "9" "1" "2" "2" "2"
#[17] "4" "4" "4" "4" "5" "5" "6" "6" "7" "8" "8" "8" "1" "2" "3" "4"

And finally the "at" for the x-axis.

at <- seq(min(x), max(x), length.out=length(bin)-1)
x <- rep(at, h$counts)

points(x, y, pch = pch, col="red")
axis(side=1, at=at, labels=trunc(bin[-length(bin)]), tck=-0.02, mgp=c(1,0.3,0), col="red", col.axis="red")

Sample Image

A notable difference is that stem doesn't use round as I've done here. It appears to use floor(x+0.5) at lines 96 and 103, which explains the slight differences. Another problem is that it will need tweaking to be more robust.

For example, replacing x with mtcars$drat would need changing the scale argument to 0.5.

x <- mtcars$drat
stem(x, scale=0.5)

The decimal point is at the |

2 | 889
3 | 0111112222
3 | 567778999999
4 | 111224
4 | 9

Sample Image

overlaying two plots, one with flipped coordinates, ggplot

You can use geom_path instead of geom_line for the flipped line, after sorting your dataset's rows in the desired order. From ?geom_path:

geom_path() connects the observations in the order in which they
appear in the data. geom_line() connects them in order of the
variable on the x axis.

library(dplyr)

df1 %>%
arrange(x, y) %>%
ggplot()+
geom_line(aes(x, y), color = "black")+
geom_path(aes(y, x), color = "red")

plot

Overlapping two graphs with different y-axis in ggplot

I also summarised the dataframe to improve the interpretation of the week 5 spike and plotted separate layers

x1 <- structure(list(Views = c(1749, 241, 309, 326, 237, 276, 2281, 
1573, 10790, 1089, 1732, 3263, 2601, 2638, 2929, 3767, 2947,
65, 161), Week = c(1, 2, 2, 2, 3, 3, 4, 5, 5, 5, 6, 8, 8, 8,
8, 9, 10, 10, 10)), row.names = c(NA, -19L), class = c("tbl_df",
"tbl", "data.frame"))

x2 <- x1 %>%
group_by(Week) %>%
summarise(Views = sum(Views))
library(ggplot2)

ggplot() +
geom_line(data = x2, mapping = aes(x = Week, y = Views/15000 * 20))+
geom_bar(data = x1, mapping = aes(x = Week), stat = 'count')+
scale_x_continuous(breaks = seq(from = 0, to = 21, by = 1))+
scale_y_continuous( name = expression("Count"),
ylim.prim <- c(0, 20),
ylim.sec <- c(0, 15000),
sec.axis = sec_axis(~ . * 15000 / 20, name = "Views"))

Sample Image



Related Topics



Leave a reply



Submit