Search code examples
rchartsggvis

r: Create waterfall chart with ggvis instead of ggplot


I created the following waterfall chart with ggplot, based on this nice post http://analyticstraining.com/2015/waterfall-charts-using-ggplot2-in-r/

enter image description here

Now I want to create this chart in ggvis. I understand that there is a waterfall package which creates this kind of plot, but I want it in ggvis. (Here is a link to the package https://www.r-bloggers.com/waterfall-plots-in-r/)

I started several attempts to create to the chart with ggvis, but by now I failed. The best I could do is the following with layer_paths:

enter image description here

I've tried to use layer_bars, which seems not work with negative values. I tried to use layer_rects, like in the ggplot, but I was not able to set the props for ymin and so on.

My knowledge about the inner workings of ggvis and Vega Marks is not very deep, can somebody give me a tip how I can succeed?

Here is the code for the two plots with example data.

library(dplyr)
library(ggplot2)
library(ggvis)
library(lubridate)
library(tidyr)


test_data <- structure(list(id = 1:11,
                            process = c("Inventory", "Add_to_Storage", 
                                       "Remove_from_storage", "Remove_from_storage", "Remove_from_storage", "Remove_from_storage", 
                                       "Remove_from_storage", "Remove_from_storage", "Remove_from_storage", "Remove_from_storage", 
                                       "Remove_from_storage"), 
                            date = structure(c(16161,16161, 16161, 16161, 16161, 16161, 16161, 16161, 16161, 16161,16161), class = "Date"), 
                            timestamp = structure(1:11, .Label = c("00:00:01","10:04:00", "12:23:33", "12:43:23", "13:36:37", "19:08:27", "19:26:56", "19:49:41", "20:01:04", "20:02:27", "20:11:32"), class = "factor"), 
                            inv_yest = c(0,NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
                            inv_added = c(NA, 3, NA, NA, NA, NA, NA, NA, NA, NA, NA), 
                            inv_remove = c(NA, NA, 1, 1, 1, 1, 1, 1, 1, 1, 1), 
                            inv_change = c(0, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1), 
                            inv_end = c(0,3, 2, 1, 0, -1, -2, -3, -4, -5, -6), 
                            inv_start = c(0, 0, 3, 2, 1, 0, -1, -2, -3, -4, -5)
                            ), 
                       .Names = c("id", "process","date", "timestamp", "inv_yest", "inv_added", "inv_remove","inv_change","inv_end", "inv_start"), 
                       row.names = c(NA, -11L), 
                       class = c("tbl_df", "tbl", "data.frame")
                       )

# Waterfall Plot with ggplot
ggplot(test_data,
       aes(x = timestamp,
           fill = process
           )
) +
  geom_rect(aes(x = timestamp,
                xmin = id - 0.45,
                xmax = id + 0.45,
                ymin = inv_end,
                ymax = inv_start
                )
  ) +
  geom_text(
    aes(
      x = timestamp,
      y = inv_end + 2,
      label = inv_change
    ),
    position = position_dodge(width = 1)
  ) +
  theme(axis.text.x=element_text(angle=90),
        axis.title.y=element_blank(),
        plot.title = element_text(
          lineheight=1.0,
          face="bold",
          hjust = 0.5
        ) 
  ) +
  ggtitle(paste0("Inventory development on day ",unique(test_data$date)))  # fügt Titel hinzu

# Add lower boundaries and only positive changes
test_data %>%
  dplyr::mutate(inv_lower = pmin(inv_start,inv_end)) %>%
  dplyr::mutate(inv_upper = ifelse(inv_change < 0,inv_change*(-1),inv_change)) -> test_data


# Test with ggplot geom_step
ggplot() +
  geom_step(data=test_data, mapping=aes(x=timestamp, y=inv_end,group = 1)) +
  geom_step(data=test_data, mapping=aes(x=timestamp, y=inv_end,group = 1), 
            direction="vh", linetype=1) +
  geom_point(data=test_data, mapping=aes(x=timestamp, y=inv_end), color="red") 

# Test with ggvis layer_paths
# geom_step = layer_paths + transform_step # http://ggvis.rstudio.com/layers.html
# http://stackoverflow.com/questions/31395410/plotting-a-step-function-in-ggvis
test_data %>%
  ggvis(x=~timestamp,
        y=~inv_end
        ) %>%
  layer_paths(interpolate:="step-after"
              ) %>%
  layer_paths(interpolate:="step-before"
              ) %>%
  layer_points(fill:="red")

Thank you in advance for your help


Solution

  • In ggvis and layer_rects, the arguments are y and y2 instead of ymin and ymax. I put y2 and fill in the rectangle layer rather than in ggvis.

    The width of the rectangles is set using width instead of manually via your "id" variable.

    Setting the text position to the center takes a bit of work, and uses "xcenter" for "timestamp" and the padding argument in scale_nominal.

    test_data %>%
        ggvis(x = ~timestamp, y = ~inv_end) %>%
        layer_rects(y2 = ~inv_start, width = band(),
                  fill = ~process) %>%
        layer_text(x = prop("x", ~timestamp, scale = "xcenter"),
                 y = ~inv_end + 2,
                 text := ~inv_change) %>%
        scale_nominal("x", name = "xcenter", padding = .9)
    

    enter image description here