Compared to ggplot2, ggvis has a much richer data hierarchy. In ggplot2, you could define a data set and aesthetic mappings in the base plot, and override them in each layer, but since layers could not contain other layers, there were only ever two levels in the tree. ggvis is more flexible because ggvis nodes (the equivalent of ggplot2 layers) can contain child nodes. This makes it possible to have whatever level of hierarchy that is best suited to your plot.

This is also related to a confusion in ggplot2 where geom often were actually aliases for a geom + combination. For example:

In ggvis, there is a clear demarkation between marks (pure drawing) and layers (transformation + drawing). The low-level functions for drawing a mark start with emit_, and then the type of mark. For example:

ggplot2 needed special geoms like geom_smooth because the data hierarchy was not deep enough, and there was no standard way for a stat to take the output of another stat as it’s input, and no way for a stat to feed data to multiple layers without either creating a custom geom or duplicating the stat multiple times.

Data pipeline

A ggvis specification creates a data pipeline that flows from the starting node to all of the leaves (marks).

Combining props

In ggplot2, layers had an inherit.aes property which control whether or not a layer would inherit properties from the parent dataset - this is particularly useful when writing functions that add annotation to arbitrary plots - you don’t want other properties that the user set interfering with your layer. In ggvis, that’s now a property of props(): props(inherit = FALSE).

To see how ggvis combines properties, you can use the merge_props function:

merge_props <- ggvis:::merge_props
merge_props(props(x = ~x), props(y = ~y))
#> * x.update: <variable> x (property: x, scale: x, event: update)
#> * y.update: <variable> y (property: y, scale: y, event: update)
merge_props(props(x = ~a), props(x = ~b))
#> * x.update: <variable> b (property: x, scale: x, event: update)
merge_props(props(x = ~a, y = ~a), props(x = ~b, inherit = FALSE))
#> * x.update: <variable> b (property: x, scale: x, event: update)
#> inherit: FALSE

There is currently no way to remove a prop inherited from the parent. See https://github.com/rstudio/ggvis/issues/37 for progress.

Case studies

Minard’s march

ggplot(Minard.cities, aes(x = long, y = lat)) +
  geom_path(
    aes(size = survivors, colour = direction, group = group),
    data = Minard.troops
  ) +
  geom_point() +
  geom_text(aes(label = city), hjust=0, vjust=1, size=4)

In ggvis, we can make it a little more clear that we have one marked based on survivors dataset and two marks based on the cities dataset.

ggvis(data = NULL, x = ~long, y = ~lat) %>%
  layer_points(size = ~survivors, stroke = ~direction, data = Minard.troops) %>%
  layer_text(text := ~city, dx := 5, dy := -5, data = Minard.cities)