2

I am trying to recreate a geological cross section similar to the one below, which show various rock parameters (x axis) plotted against depth (y axis)

geological cross section

I can nicely recreate the individual plots in ggplot2 and grid together to create something very similar. To finish off i would really like to join lines between the plots which show regions of similar geology as in the picture.

Below is some code which plots the charts with the horizontal lines, what i would really to do is to join lines ( if possible in R) and if possible align the charts based on the line

library(ggplot2)
library(gridExtra)

df1 = data.frame(replicate(2,sample(0:200,100,rep=TRUE)))
df1$depth = seq.int(nrow(df1))

df2 = data.frame(replicate(2,sample(0:200,100,rep=TRUE)))
df2$depth = seq.int(nrow(df1))


top1 = 32
top2 = 50

plot1 = ggplot(df1, aes(y = depth, x = X1))+
  scale_y_continuous(trans = "reverse")+
  geom_path()+
  geom_hline(yintercept=top1, colour = "red")+
  annotate(geom="text", x=25, y=top1, label=top1, color="red")+
  theme_bw()+
  theme(panel.grid.major = element_line(colour = "grey"), panel.background = element_rect(colour = "black", size=0.5))+
  ylab("Depth ft")+
  ggtitle("plot1")


plot2 = ggplot(df2, aes(y = depth, x = X1))+
  scale_y_continuous(trans = "reverse")+
  geom_path()+
  geom_hline(yintercept=top2, colour = "red")+
  annotate(geom="text", x=25, y=top2, label=top2, color="red")+
  theme_bw()+
  theme(panel.grid.major = element_line(colour = "grey"), panel.background = element_rect(colour = "black", size=0.5))+
  ylab("Depth ft")+
  ggtitle("plot2")

grid.arrange (plot1, plot2, ncol=2)

This would be the desired result i would be looking for with the lines joined and if possible aligned.

enter image description here

Thanks for any help or advice given

Cheers

berwyn72
  • 45
  • 6
  • Similar to this? https://stackoverflow.com/q/52864447/5325862 – camille Jul 19 '19 at 12:39
  • Hi Camille,thanks for that, my problem with adding in a blank plot between the plots was that the Y axis from the various plots i have can vary a lot i.e one maybe from 0 to 3000, and another maybe from 4000-7000 and i don't think ggplot can handle separate Y axis scales if it could (which would be good) this approach would work nicely. I will have to find a way to rescale the y axis for the plot between the two somehow and adapt the Y coords of the hlines cheers – berwyn72 Jul 19 '19 at 13:29
  • If you don't have to reproduce this thousand times, I would consider doing this outside of `R` (Inkscape for example) and call it a day – Tung Jul 19 '19 at 14:24

1 Answers1

1

I can't help with the line-joining part, but the idea of the shifted scales sounded pretty interesting. This solution takes an arbitrary number of dataframes and an accompanying list of isolines, then shifts the y-scale so that each isoline is at 0.

Each dataframe is then plotted and the y-axes are renumbered appropriately.

library(purrr)
library(dplyr)
library(ggplot2)

# library(cowplot)
#   I never load `cowplot` because it changes some settings onload.
#   I just call the namespace with `cowplot::plot_grid(...)`
#   You will need it installed though.

depth_plots <- function(..., isolines) {
  dats <- list(...)
  stopifnot(length(dats) == length(isolines))

  scaled_dats <- map2(dats, isolines, ~.x %>% mutate(sc_depth = depth - .y))

  new_range <- 
    map(scaled_dats, ~range(.x$sc_depth)) %>% 
    unlist() %>% 
    range() %>% 
    scales::expand_range(mul = 0.05)

  plots <- map2(
    scaled_dats, isolines,
    ~ggplot(.x, aes(y = sc_depth, x = X1)) +
      scale_y_continuous(
        trans = "reverse", 
        breaks = scales::extended_breaks()(.x$depth) - .y,
        labels = scales::extended_breaks()(.x$depth)
        ) +
      geom_path() +
      geom_hline(yintercept=0, colour = "red") +
      annotate(geom="text", x=25, y=0, label=.y, color="red") +
      coord_cartesian(
        ylim = new_range
      ) +
      theme_bw()
  ) 

  cowplot::plot_grid(plotlist = plots, nrow = 1)
}

To test out the varying depth structures, I changed your sample data a bit:

df1 = data.frame(replicate(2,sample(0:200,100,rep=TRUE)))
df1$depth = seq.int(nrow(df1))

df2 = data.frame(replicate(2,sample(0:200,100,rep=TRUE)))
df2$depth = seq.int(nrow(df1))*0.75

df3 = data.frame(replicate(2,sample(0:200,100,rep=TRUE)))
df3$depth = seq.int(nrow(df1))*2

depth_plots(df1, df2, df3, isolines = c(32,50, 4))

enter image description here

Hope that gets you started!

Brian
  • 7,900
  • 1
  • 27
  • 41
  • cool thanks a lot Brain got this to work well and using Camille's join idea's i can get exactly what i need, its a bit hacky overall but if anyone wants the complete code drop me a message – berwyn72 Jul 23 '19 at 09:48