Trollbrot
Trollbrot

Reputation: 1351

Drawing elements (arrows & circle) in ggplot (R) to show the difference between two bars

I am trying to create a plot in R using ggplot that shows the difference between my two bars in a nice way.

I found an example that did part of what I wanted, but I have two major problems:

  1. It is based on comparing groups of bars, but I only have two, so I added one group with both of them.
  2. I would like to draw the arrow in nicer shape. I attached an image.

Code:

transactions <- c(5000000, 1000000)
time <- c("Q1","Q2")
group <- c("A", "A")

data <- data.frame(transactions, time, group)

library(ggplot2)

fun.data <- function(x){
  print(x)
  return(data.frame(y = max(x) + 1,
                    label = paste0(round(diff(x), 2), "cm")))
}

ylab <- c(2.5, 5.0, 7.5, 10)

gg <- ggplot(data, aes(x = time, y = transactions, fill = colors_hc[1], label = round(transactions, 0))) +
  geom_bar(stat = "identity", show.legend = FALSE) +
  geom_text(position = position_dodge(width = 0.9),
            vjust = 1.1) +
  geom_line(aes(group = group), position = position_nudge(0.1),
            arrow = arrow()) +
  stat_summary(aes(x = group, y = transactions),
               geom = "label",
               fun.data = fun.data,
               fontface = "bold", fill = "lightgrey",
               inherit.aes = FALSE) +
  expand_limits(x = c(0, NA), y = c(0, NA)) +
  scale_y_continuous(labels = paste0(ylab, "M"),
                     breaks = 10 ^ 6 * ylab) 

gg

The arrows I am aiming for:

enter image description here

Where I am (ignore the ugliness, didn't style it yet): enter image description here

Upvotes: 1

Views: 1153

Answers (1)

DS_UNI
DS_UNI

Reputation: 2650

This works, but you still need to play around a bit with the axes (or rather beautify them)

library(dplyr)
library(ggplot2)    
transactions <- c(5000000, 1000000)
time <- c("Q1","Q2")
group <- c("A", "A")

my_data <- data.frame(transactions, time, group)

fun.data <- function(x){
  return(data.frame(y = max(x) + 1,
                    label = as.integer(diff(x))))
}

my_data %>% 
ggplot(aes(x = group, y = transactions, fill = time)) + 
  geom_bar(stat = 'identity', position = 'dodge') +
  geom_text(aes(label = as.integer(transactions)), 
            position = position_dodge(width = 0.9),
            vjust = 1.5) +
  geom_line(aes(group = group), position = position_nudge(0.1),
            arrow = arrow()) +
  stat_summary(aes(x = group, y = transactions), 
               geom = "label",
               size = 5,
               position = position_nudge(0.05),
               fun.data = fun.data,
               fontface = "bold", fill = "lightgrey",
               inherit.aes = FALSE)

enter image description here

Edit2:

y_limit <- 6000000
my_data %>% 
  ggplot(aes(x = time, y = transactions)) + 
  geom_bar(stat = 'identity',
           fill = 'steelblue') +
  geom_text(aes(label = as.integer(transactions)),
            vjust = 2) +
  coord_cartesian(ylim = c(0, y_limit)) + 
  geom_segment(aes(x = 'Q1', y = max(my_data$transactions), 
                   xend = 'Q1', yend = y_limit)) + 
  geom_segment(aes(x = 'Q2', y = y_limit, 
                   xend = 'Q2', yend = min(my_data$transactions)), 
               arrow = arrow()) + 
  geom_segment(aes(x = 'Q1', y = y_limit, 
                   xend = 'Q2', yend = y_limit)) +
  geom_label(aes(x = 'Q2', 
                 y = y_limit, 
                 label = as.integer(min(my_data$transactions)- max(my_data$transactions))),
             size = 10,
             position = position_nudge(-0.5),
             fontface = "bold", fill = "lightgrey")

enter image description here

Upvotes: 3

Related Questions