Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
376 views
in Technique[技术] by (71.8m points)

javascript - Update large plots in Shiny without Re-Rendering

General Goal

I would like to be able to use RShiny to quickly plot large amounts of data that comes from R, and then make small modifications or additions without re-rendering all of the plotted data.

Specific Task

  1. Plot a large number of points (<100 000) in a scatter plot. I am okay with a short (<5 sec) but perceivable delay in this task.
  2. In response to a mouse click, detect the nearest plotted point.
  3. Using some information queried from data related to this point, highlight a small number of other points (<10). I would like this to be instantaneous.

Current Approach

I currently use ggplot2 and RShiny to make apps to help with data analysis. In general I'm very pleased with this combination. So ideally the solution will allow me to still mostly use these tools.

Using only the built-in functionality of RShiny and ggplot2, I have no problem accomplishing my task, except that step 3 cannot be done independently, without redoing step 1. It is my understanding that it is not possible to update or overlay ggplot2 plots without re-rendering them in their entirety.

So, what I am looking for is one of the following to achieve my general goal, in descending order of preference:

  1. A way to overlay or modify ggplot2 plots without re-rendering.
  2. An extension or fork or similar R-based to ggplot2 that allows this.
  3. An alternative to ggplot2 that is similarly easy to integrate with RShiny and R data that can allow this. Maybe an some interface to an existing javascript library? I would still like to be able to manipulate and interact with my plot using all of the RShiny machinery I am familiar with.

I have some knowledge of js but do not feel like learning something like d3 to accomplish such a small task. (If it's possible to use a small bit of d3 or js to do this, that would be great though!) It would be fine to be able to efficiently draw svg on top of ggplot2 plots, but using the same coordinate system.

I am aware of this question, but the solution provided was specific to time-series data.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Here is a solution with plotly. It does re-render the entire plot, but it's fast so perhaps will still meet your requirements. I think you'll see that introducing Plotly should not majorly disrupt your workflow.

Note that I use Plotly's WebGL function for speed. The example below is 100000 points. I've also included an example of how you would convert your existing ggplot2object. For Plotly click events, see this.

library(shiny)
library(dplyr)
library(plotly)
library(ggplot2)

ui <- fluidPage(

  titlePanel("Highlight nearby points"),

  sidebarLayout(
    sidebarPanel(width=3,
      p("Click on a point. Nearby points will be highlighted.")
    ),

    mainPanel(
      plotlyOutput("plot")
    )
  )
)

# Data
df <- tibble(x = runif(1e+05,1,100), y = runif(1e+05,1,100))

server <- function(input, output, session) {

  output$plot <- renderPlotly({

    # Gather click data
    event.data <- event_data("plotly_click")

    # Plotly object
    p <- plot_ly(df, x = ~x, y = ~y, type = "scatter", mode = "markers") 

    # Alternative: use existing ggplot

    # gg <- ggplot(df, aes(x = x, y = y)) +
    #   geom_point()
    # 
    # p <- plotly_build(gg)

    # End alternative

    # Check for click data
    if(!is.null(event.data)) {

      # If click data exists, create new markers based on range criteria and use a different color
      d <- filter(df,
                  x < event.data$x+10 & x > event.data$x-10,
                  y < event.data$y+10 & y > event.data$y-10)
      p <- add_markers(p, data = d, color = I("red"))

    }

    # Use webGL for faster ploting of many points
    p %>% toWebGL()

  })
}

# Run the application 
shinyApp(ui = ui, server = server)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...