I have a Shiny application that has two plots. If a user clicks on a point in the top plot, the x and y coordinate of that point are saved to a reactive Shiny variable (in the code below, it is called pointSel).
In the bottom plot, I would like the x and y coordinate from this pointSel to be plotted as a green point. I have this working currently (as seen in the script below). However, each time the pointSel object is updated, the second plot is plotted all over again. Instead, I am trying to keep the second plot background unplotted and to simply overlay a new green point on top of it.
I believe this would require two things:
1) The isolate() function applied to "data = pointSel()" in the onRender() function.
2) Some syntax that alerts to only add the green dot trace if the pointSel has been updated. I put tentative syntax for this in comments "$('#pointSel').on('click',function()".
Below is my code:
library(plotly)
library(GGally)
library(hexbin)
library(htmlwidgets)
library(tidyr)
library(shiny)
library(edgeR)
library(EDASeq)
library(dplyr)
library(data.table)
library(ggplot2)
ui <- shinyUI(fluidPage(
plotlyOutput("plot1"),
plotlyOutput("plot2")
))
server <- shinyServer(function(input, output) {
data <- data.frame(mpg=mtcars$mpg,qsec=mtcars$qsec)
output$plot1 <- renderPlotly({
p <- qplot(data$mpg,data$qsec)
pP <- ggplotly(p)
pP %>% onRender("
function(el, x, data) {
el.on('plotly_click', function(e) {
var pointSel = [e.points[0].x, e.points[0].y]
Shiny.onInputChange('pointSel', pointSel);
})}
", data = data)
})
pointSel <- reactive(input$pointSel)
output$plot2 <- renderPlotly({
p2 <- qplot(mpg,qsec,data=data, geom="point", alpha=I(0))
pP2 <- ggplotly(p2)
pP2 %>% onRender("
function(el, x, data) {
console.log('Whole bottom plot is being redrawn')
var myX = data[0]
var myY = data[1]
//$('#pointSel').on('click',function() {
var Traces = [];
var trace = {
x: [myX],
y: [myY],
mode: 'markers',
marker: {
color: 'green',
size: 10
}
};
Traces.push(trace);
Plotly.addTraces(el.id, Traces);
//})
}", data = pointSel())
})
})
shinyApp(ui, server)
Note: This is a similar problem to what I posted earlier and has a helpful answer (Shiny actionButton() output in onRender() function of htmlWidgets). I have been coming across variants of this problem (being unable to overlay aspects of a plot to a background plot in the onRender() function), and this current post is simply another variant of that problem. I am trying to find a similar answer for this situation! Thank you for any advice.
You can use define a custom message handler in your onRender
function and use it in server.R
to pass the selected point coordinates.
The onRender
function of the second plot could look like:
function(el, x, data) {
Shiny.addCustomMessageHandler('draw_point',
function(point) {
var Traces = [];
var trace = {
x: [point[0]],
y: [point[1]],
mode: 'markers',
marker: {
color: 'green',
size: 10
}
};
Traces.push(trace);
console.log(Traces);
Plotly.addTraces(el.id, Traces);
});
}
And in your server.R
you could do:
observe({
session$sendCustomMessage(type = "draw_point", input$pointSel)
})
Whenever a point is selected, the coordinates will be sent to the function defined in the onRender
and the point will be drawn.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With