6

I would like to dynamically and rapidly highlight points on a faceted in .

My problem: the graphic takes quite a lot of time to be recomputed each time (It often happens to me with plots).

Ideas At this moment I have only two:

  1. Find a way to “precalculate” once for all the original ggplot, and only modify some points in red.
  2. Find a way to perfectly the original ggplot with a ggplot limited to red points (which will be much lighter).

References: I found these topics:

but it doesn’t seem to apply to my issue. Please find below a reproducible example. Thank you very much for your help and support!

library(shiny); library(ggplot2); library(dplyr)
# Dataset
data_=do.call("rbind", replicate(1000, mtcars, simplify = FALSE))
# General graphic
p_0=ggplot(data=data_,aes(x=wt,y=mpg))+geom_point()+facet_wrap(~carb)

VERSION 1: Easy reading code but an important lag effect when updating the data

ui=fluidPage(
                fluidRow(
                    column(width = 12,
                    numericInput("choice", "Highlight in red when carb=",1,),
                    plotOutput("plot1"))
                )
                )

server=function(input, output) {
    p=reactive({return(
        p_0+geom_point(data=data_ %>% filter(carb==input$choice),aes(x=wt,y=mpg),color='red')
        )})
    output$plot1=renderPlot({p()})
}

shinyApp(ui, server)

VERSION 2: Better user experience but difficult reading code, difficult layout using absolute panel, and still a lag issue

ui=fluidPage(
    fluidRow(
        column(width = 12,
            numericInput("choice", "Highlight in red when carb=", 1,),
            absolutePanel(plotOutput("plot1"), top = 200, left = 0,width = 500, height = 500),
            absolutePanel(plotOutput("plot2"), top = 200, left = 0,width = 500, height = 500)
        )
    )
    )

server=function(input, output) {

    p=reactive({return(ggplot(data=data_,aes(x=wt,y=mpg))+geom_blank()+facet_wrap(~carb)+
        geom_point(data=data_ %>% filter(carb==input$choice),color='red',size=3)+
        theme_bw()+
        theme(legend.position="none")+
        theme(
          panel.background =element_rect(fill = "transparent"),
          plot.background = element_rect(fill = "transparent"),
          panel.grid.major = element_blank(),
          panel.grid.minor = element_blank()
        )
        )})
    output$plot1=renderPlot({p_0},bg="transparent")
    output$plot2=renderPlot({p()},bg="transparent")

}

shinyApp(ui, server)
massisenergy
  • 1,764
  • 3
  • 14
  • 25
L.Miner
  • 86
  • 5
  • If the amount of choices for the user is limited, you can cache image files and load them with `renderImage`. See [here](https://stackoverflow.com/questions/24192570/caching-plots-in-r-shiny). – Gregor de Cillia Mar 26 '18 at 18:39
  • Thank you very much for the trick, unfortunately I have a too high amount of potential graphics to apply this. For instance, I could let the opportunity to the user to highlight only one point: in “mtcars” it represents already 32 possibilities - the number of rows in fact. – L.Miner Mar 27 '18 at 08:32
  • You could try wrapping your plot code in ggplotly(), this should allow for hover over and highlighting features in your plots. – Pryore Dec 10 '18 at 13:46

1 Answers1

0

I think I've squeezed a small speed improvement by doing the following two things:

  • Changed the numeric input into a select input box with restricted choices.
  • Simplified the code to make only the colour palette into a reactive expression.

library(shiny); library(ggplot2); library(dplyr)
# Dataset
data_=do.call("rbind", replicate(1000, mtcars, simplify = FALSE))
# General graphic

ui=fluidPage(
  fluidRow(
    column(width = 12,
           selectInput("choice", "Highlight in red when carb=",1, choices = c(1:4,6,8)),
           plotOutput("plot1"))
  )
)

server=function(input, output) {

  cols <- reactive({
    cols <- c("1" = "black", "2" =  "black", "3" =  "black",
              "4" =  "black", "6" =   "black",   "8" =   "black")
    cols[input$choice] <- "red"
    return(cols)
  })

  output$plot1=renderPlot({
    ggplot(data_, aes(x=wt, y=mpg, color = as.character(carb))) +
      geom_point() +
      scale_colour_manual(values = cols()) +
      facet_wrap(~carb)
      })
}

shinyApp(ui, server)

RDavey
  • 1,530
  • 10
  • 27
  • Thank you, I find your code smarter - by using the colors this way - it's a little bit better than my version 1 since you don't produce the points twice. Unfortunately, on my side version 2 remains faster (using geom_blank enables to only display red points). – L.Miner Mar 11 '19 at 19:13
  • I wonder if you can reduce the amount of piped commands in the reactive expression in your version 2 code to speed things up? This was what I was aiming for in the code above. – RDavey Mar 18 '19 at 11:07