user3206440
user3206440

Reputation: 5059

ggplot - plotting bars and lines in the same chart

I need to generate a plot with bar graph for two variables and a line with the third variable.

I can create a column graph for one variable like below

df <- head(mtcars)
df$car <- row.names(df)
ggplot(df) + geom_col(aes(x=car, y=disp))

Ref this answer - I can plot two variables - disp and hp as below

library(tidyr)
df$car = row.names(df)
df_long = gather(df, key = var, value = value, disp, hp)
ggplot(df_long, aes(x = car, y = value, fill = var)) +
  geom_bar(stat = 'identity', position = 'dodge')

I need to have a third variable qsec plotted as a line like as in the below chart - how to go about this ?

enter image description here

Upvotes: 0

Views: 2736

Answers (2)

Roman
Roman

Reputation: 17648

You can try:

library(tidyverse)
# some data
data <- mtcars %>%  
  mutate(car = rownames(mtcars)) %>% 
  slice(1:6) %>% 
  select(car, disp, hp) 

data %>% 
  gather(key, value, -car) %>% 
  group_by(car) %>% 
  mutate(qsec_value = median(value)) %>% 
  mutate(qsec = factor("qsec")) %>% 
  ggplot() +
    geom_col(aes(x=car, y=value, fill = key), position = "dodge") +
    geom_point(aes(x=car, y=qsec_value,color = qsec)) +
    geom_line(aes(x=car, y=qsec_value, color = qsec, group =1)) +
    scale_colour_manual(name= "", values = 1) +
     theme(legend.position = "top", 
           legend.title = element_blank())

enter image description here

Less code, same result:

data %>% 
  pivot_longer(-1) %>% 
  ggplot(aes(x = car)) + 
    geom_col(aes(y=value, fill = name), position = "dodge") + 
    stat_summary(aes(y=value, group=1, color="qseq"), fun = "median", geom = "point")+
    stat_summary(aes(y=value, group=1, color="qseq"), fun = "median", geom = "line")+
    scale_colour_manual(name= "", values = 1) 

Upvotes: 2

Tino
Tino

Reputation: 2101

You need another layer and because geom_line is for continuous data, you need to do as if your x-values are for the line-layer. By doing so, order of data becomes crucial, hence you have also to sort it:

gather(df, key = var, value = value, disp, hp, qsec) %>% 
  arrange(car) %>% 
  {
    print(
      ggplot() +
        geom_bar(stat = 'identity', position = 'dodge', data = filter(., var != "qsec"), mapping = aes(x = car, y = value, fill = var)) +
        geom_line(mapping = aes(x = 1:length(car), y = value), data = filter(., var == "qsec"))
    )
  }

Edit:

btw, you can check the correct order of qsec to the respective x-value by calling plotly::ggplotly(), then you can read the values better and compare them to the df, because they will show up if you point on the element...

Upvotes: 0

Related Questions