Facet_grid a layered ggplot?

Hello Everyone,

I have a question that seems simple to achieve but I'm not sure how to do it. I'm plotting a data frame and I'm layering different variables on to one plot, but I was wondering if there was a way to facet my plot. I want the top 2 trend lines on one plot and to have the bar graph underneath. Usually you can do this with facet_grid or facet_wrap but I'm not sure how to since they all belong in the same group.

sample_df <- data.frame(x = c(1,2,3,4,5,6,7,8), y = c(rnorm(8, mean = 200, sd = 28)), y1 = c(rnorm(8, mean = 240, sd = 57)),y2 = c(rnorm(8, mean = 0, sd = 27))) 
sample_df$group <- "rand_nums"
sample_df$type <- ifelse(sample_df$y2 < 0, "neg", "pos")

sample_df %>% ggplot()+
  geom_line(aes(x = x, y = y, group = group), color = "forestgreen", size = 2)+
  geom_line(aes(x = x, y = y1, group = group),color = "violet",size = 2)+
  geom_bar(stat = "identity", aes(x = x, y = y2, group = group, fill = type))+
  scale_fill_manual(name = "Pos or Neg",
                    values = c("pos" = "yellow", "neg" = "red"))

If you need further explanation don't hesitate to ask,

Thanks in advance!

Hey @marbpma,

You did not notice, but in the process of copying and pasting your code, you added some stuff that you don't want in there (probably the script to upload your picture). I am referring to the first line of ggplot().

This looks like a great use case for the patchwork package. Unfortunately, it's not yet on CRAN, but you can download it from Github in the following way:

# Install the remotes package if you haven't done so yet
install.packages("remotes")
install_github("thomasp85/patchwork")

# Code for creating the sample_df dataset
# ...
#....

p <- ggplot(data = sample_df)

p1 <- p +
  geom_line(aes(x = x, y = y, group = group), color = "forestgreen", size = 2)+
  geom_line(aes(x = x, y = y1, group = group),color = "violet",size = 2)

p2 <- p + 
  geom_bar(stat = "identity", aes(x = x, y = y2, group = group, fill = type))+
  scale_fill_manual(name = "Pos or Neg",
                    values = c("pos" = "yellow", "neg" = "red"))

p1 + p2 + plot_layout(ncol = 1)

Rplot

I highly encourage you to take a look at the short tutorial here: https://github.com/thomasp85/patchwork

Hope this helps.

3 Likes

Is patchwork package strictly available for the newest version of ggplot2?

I am not sure, but it's always a good idea to update your packages whenever you think about it. If you use RStudio, there is a very convenient way to do it by clicking on the "Packages" tab (usually on the bottom-right corner of the layout) and then click on "Update". RStudio will automatically let you know the packages which need updates. Click on "Select All" and finally on "Install Updates". Be aware that it COULD take a bit of time.

1 Like

patchwork depens on ggplot2 (>= 3.0.0) and the latest CRAN version of ggplot2 is 3.1.0

2 Likes

I would use cowplot:



# New: 
library(cowplot)
theme_set(theme_gray())
# Make the 2 plots: 
plot_line  = sample_df %>% ggplot()+
  geom_line(aes(x = x, y = y, group = group), color = "forestgreen", size = 2)+
  geom_line(aes(x = x, y = y1, group = group),color = "violet",size = 2)
plot_bar = sample_df %>% ggplot() + 
  geom_bar(stat = "identity", aes(x = x, y = y2, group = group, fill = type))+
  scale_fill_manual(name = "Pos or Neg",
                    values = c("pos" = "yellow", "neg" = "red"))
# default: 
plot_grid(plot_line, plot_bar)
# vertical instead: 
plot_grid(plot_line, plot_bar, nrow = 2)

# align them by extracting the legend, and deleting from plot_bar: 
legend = get_legend(plot_bar)
plot_bar = plot_bar + theme(legend.position = 'none')

plots = plot_grid(plot_line, plot_bar, nrow = 2, align = 'v')
# first put the 2 graphs together, then center the legend to their right like this: 
plots_2 = plot_grid(plots, legend, rel_widths = c(1,0.3))
plots_2

The main writeup for this package is here!

3 Likes

With some data reshaping, you can actually create a single facetted plot, as shown in the code below, although you may ultimately decide that you need the greater flexibility that comes with generating separate plots.

# Setup
library(tidyverse)

# Sample data
set.seed(2)
sample_df <- data.frame(x = 1:8,
                        y = rnorm(8, mean = 200, sd = 28), 
                        y1 = rnorm(8, mean = 240, sd = 57),
                        y2 = rnorm(8, mean = 0, sd = 27))
sample_df$group <- "rand_nums"
sample_df$type <- ifelse(sample_df$y2 < 0, "neg", "pos")
# Reshape and plot

# Reshape data to long format and add grouping column to mark the
#  facet each data series belongs to
sample_df_long = sample_df %>% 
  gather(key, value, y, y1, y2) %>% 
  mutate(facet.group = case_when(key %in% c("y", "y1") ~ "line",
                                 TRUE ~ "bar") %>% fct_rev())
  
ggplot(data=sample_df_long, aes(x, value)) +
  geom_line(data=. %>% filter(facet.group=="line"), aes(colour=key), 
            size=2) +
  geom_col(data=. %>% filter(facet.group=="bar"), aes(fill=type)) +
  facet_grid(facet.group ~ ., scales="free_y") +
  theme_bw() +
  theme(strip.text=element_blank()) +
  guides(color = guide_legend(order = 1),
         fill = guide_legend(order = 2, reverse=TRUE)) +
  scale_fill_manual(values=c("red","blue")) +
  scale_colour_manual(values=c("violet", "forestgreen")) +
  labs(x="", y="", colour="Line Title", fill="Pos or Neg") +
  expand_limits(y=0)

Rplot01

3 Likes

I think these are all great solutions to my problem. Unfortunately I cannot update my packages frequently due to IT security, so I do not have ggplot2 (>= 3.00) yet.

If that is the case, then the solution provided by @joels and @limacina should work for you since they do not rely on newer version of ggplot2.

1 Like

If you have issues with using these packages, and in general have issues with IT and package updates, you can fairly easily do this in base R as well?

sample_df  = sample_df %>%
  mutate(bar_color = ifelse(y2>0, 'yellow', 'red'))

par(mfrow = c(2,1))
plot(y~x, data = sample_df, col = 'forestgreen', type = 'l', ylim = range(c(sample_df$y, sample_df$y1)))
lines(y1~x, data = sample_df, col = 'violet', type = 'l')

barplot(height = sample_df$y2, data = sample_df, col = sample_df$bar_color)

Rplot02

That being said I really like @joels solution of making a dummy column to facet over. That may be the only ggplot solution here that doesn't have additional dependencies.

... and then of course there's always photoshop/illustrator/powerpoint. This is of course not the optimal way to do this, but if you are having issues with IT and need graphs for your research then we'll lower our pitchforks and look the other way :slight_smile:

1 Like

Yay @joels and @limacina solutions worked for me!! Thank you all!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.