8

I'm trying to get interactive zooming to work in ggvis, more in particular zooming using a brush. Judging from https://github.com/rstudio/ggvis/issues/143 I thought this should work.

I have the following shiny and ggvis code (is fully reproducible):

## ui.R
library(ggvis)

shinyUI(fluidRow(
  uiOutput('ui_plot1'),
  ggvisOutput("graph_plot1")
))

## server.R
shinyServer(function(input, output, session) {
  domains <- reactiveValues(x = c(NA, NA), y = c(NA, NA))

  zoom_brush = function(items, session, page_loc, plot_loc, ...) {
    domains$x = c(200, 400)
  }

  plot = reactive({
    mtcars %>% 
      ggvis(~disp, ~mpg) %>%
      layer_points() %>%
      scale_numeric('x', domain = domains$x, clamp = TRUE) %>% 
      handle_brush(zoom_brush)
  }) %>% bind_shiny('graph_plot1', 'ui_plot1')
})

So, as soon as a brush is drawn, the domains reactive is changed, which in turn changes the domain of the x scale_numeric. If still have the following challenges:

  • Inside zoom_brush I get the coordinates of the brush, but in the pixel coordinate system of the plot not the domain coordinate system. How can I translate the pixels to the domain scale? In d3 I can simply use the range to scale transform functions, but I don't see how these are available in ggvis (via vega).
  • The handle_brush function only supports setting a on_move event handler. In this case I only want to trigger the zoom if the brush finishes, so the onmouseup event in the context of the brush. I fear that this is simply not possible right now?
  • Only when I set clamp = TRUE do I get an effective zoom. In not, the points outiside the domain are still shown and only the axes are set to the new domain. Is there an easy fix for this? Or should I make the dataset a reactive, and subset it based on the domain that was set by the brush?

I run the following R version and package versions.

> sessionInfo()
R version 3.1.1 (2014-07-10)
Platform: x86_64-apple-darwin10.8.0 (64-bit)

locale:
[1] C

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] ggvis_0.4.1  shiny_0.12.0

loaded via a namespace (and not attached):
 [1] DBI_0.3.1       R6_2.0.1        Rcpp_0.11.6     assertthat_0.1  digest_0.6.8    dplyr_0.4.1     htmltools_0.2.6 httpuv_1.3.2   
 [9] jsonlite_0.9.16 lazyeval_0.1.10 magrittr_1.5    mime_0.3        parallel_3.1.1  tools_3.1.1     xtable_1.7-4   
Paul Hiemstra
  • 59,984
  • 12
  • 142
  • 149
  • If you don't need to rely on `ggvis` perhaps [this example](http://shiny.rstudio.com/gallery/plot-interaction-zoom.html) would work? – JasonAizkalns Nov 05 '15 at 15:06
  • @jason thanks for the feedback. I am aware of this option, and this question is specifically aimed at ggvis. – Paul Hiemstra Nov 05 '15 at 15:27

1 Answers1

1

I think you need to subset your data: ggvis doesn't yet appear clever enough to ignore out of scale points. The following server.R works for me:

## server.R
shinyServer(function(input, output, session) {

  domains <- reactiveValues(x = c(NA, NA), y = c(NA, NA))

  mtcars_reactive <- reactive({
    if (anyNA(domains$x))
      mtcars
    else
      mtcars[mtcars$disp >= domains[["x"]][1] & mtcars$disp <= domains[["x"]][2], ]
  })

  zoom_brush = function(items, page_loc, session, ...) { # plot_loc
    print(items)
    message("page_loc")
    print(page_loc)
    print(session)
    domains$x = c(200, 400)
  }

  reactive({
    mtcars_reactive() %>%
      ggvis(~disp, ~mpg) %>%
      layer_points() %>%
      handle_brush(zoom_brush)
  }) %>% bind_shiny('graph_plot1', 'ui_plot1')

})
Jack Wasey
  • 3,360
  • 24
  • 43