Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overlay two ggplots with different x and y axes scales

Let's suppose I have two data.frames as follows:

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]

When I plot them singularly I get:

library(ggplot2)
p1=ggplot() +
  geom_line(data=df_1, aes(x=x,y=y))

print(p1)

enter image description here

p2=ggplot() +
  geom_line(data=df_2, aes(x=df_2,y=Freq))

print(p2)

enter image description here

These two plots have different x and y axes.

How can I overlay the two plots into one?

Thanks

like image 642
aaaaa Avatar asked Nov 17 '25 08:11

aaaaa


2 Answers

Here is another option. We can use the sec.axis argument in the scale_*_continuous() function to map the data on top of each other through transformations.

ggplot() +
  geom_line(data=df_1, aes(x=x,y=y))+
  geom_line(data=df_2, aes(x=df_2*25,y=Freq/9000))+
  scale_x_continuous(sec.axis = sec_axis(trans = ~./25))+
  scale_y_continuous(sec.axis = sec_axis(trans = ~.*9000))

The rescaling is arbitrary, so you can play with it until it looks good to you.

like image 140
AndS. Avatar answered Nov 19 '25 00:11

AndS.


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:


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:

enter image description here

like image 45
mrhellmann Avatar answered Nov 18 '25 23:11

mrhellmann