Add shaded rectangle with select Box corners in Plotly R

北慕城南 提交于 2019-12-11 04:28:44

问题


I am trying to create an application where if a user employs the Box Select tool in Plotly, then a filled rectangle will appear alongside the Box Select. To accomplish this, I am trying to call Plotly.addTrace() to create a rectangle object (type: rect) that has the corners of the box the user selected.

I am able to obtain the coordinates of the corners of the box the user selected (in the code they are called xMin, xMax, yMin, and yMax). However, I then try to create a variable called drawRect that can be added to Plotly. This does nothing at this time, though.

I based some of the syntax off a post about Python Plotly (https://plot.ly/python/shapes/). However, I am working with Plotly in R. Is there any similar rectangle object that I could use in Plotly R?

Below is MWE showing my code.

library(ggplot2)
library(shiny)
library(plotly)
library(htmlwidgets)

ui <- basicPage(
  plotlyOutput("plot1")
)

server <- function(input, output) {

  p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point(alpha=0) + xlim(0,5) +ylim(-3,3)
  gp <- ggplotly(p)

  set.seed(3)
  myDF <- data.frame(X1=rnorm(10,-1), X2=rnorm(10,-1), X3=rnorm(10,-1), X4=rnorm(10,1), X5=rnorm(10,1), X6=rnorm(10,1))
  colNms <- colnames(myDF)
  nVar <- length(colNms)

  output$plot1 <- renderPlotly({
    gp %>% onRender("
    function(el, x, data) {

    var myDF = data.myDF
    var Traces = [];
    var dLength = myDF.length
    var vLength = data.nVar
    var cNames = data.colNms
    for (a=0; a<dLength; a++){
      xArr = [];
      yArr = [];
      for (b=0; b<vLength; b++){
        xArr.push(b)
        yArr.push(myDF[a][cNames[b]]);
      }
      var pcpLine = {
        x: xArr,
        y: yArr,
        mode: 'lines',
        line: {
          color: 'orange',
          width: 1
        },
        opacity: 0.9,
      }
      Traces.push(pcpLine);
    }
    Plotly.addTraces(el.id, Traces);

    el.on('plotly_selected', function(e) {
      var dLength = myDF.length
      var selectedPCP = []
      var xMin = e.range.x[0]
      var xMax = e.range.x[1]
      var yMin = e.range.y[0]
      var yMax = e.range.y[1]

      console.log([xMin, xMax, yMin, yMax])

      var Traces = []
      var drawRect = {
        type: 'rect',
        x0: xMin,
        y0: yMin,
        x1: xMax,
        y1: yMax,
        line: {
          color: 'green',
          width: 1
        },
        fillcolor: 'green'
      }
      Traces.push(drawRect);
      Plotly.addTraces(el.id, Traces);
    })
    }", data = list(myDF = myDF, nVar = nVar, colNms = colNms))})

    }
    shinyApp(ui, server)

回答1:


Basically, strange as it may sound to us old ggplot vets, "shapes" are not handled the same way as markers and lines (which are set in "traces"), but "shapes" (like rect) are set in the layout part of a plotly plot. Probably I would understand this better if I read more of the plotly book..

So I made two changes.

  • Changed the dragmode to "select" using layout at the begining.
  • Changed the Plotly.addTraces logic at the end of your onRender javascript to Plotly.relayout

As a sidenote I have been wondering for hours why it was called "relay-out", I just now realized as I was writing this that it is "re-layout" which makes complete sense.

So here is the code:

library(ggplot2)
library(shiny)
library(plotly)
library(htmlwidgets)

ui <- basicPage(
  plotlyOutput("plot1")
)

server <- function(input, output) {

  p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point(alpha=0) + xlim(0,5) +ylim(-3,3)
  gp <- ggplotly(p)

  set.seed(3)
  myDF <- data.frame(X1=rnorm(10,-1), X2=rnorm(10,-1), X3=rnorm(10,-1), X4=rnorm(10,1), X5=rnorm(10,1), X6=rnorm(10,1))
  colNms <- colnames(myDF)
  nVar <- length(colNms)

  output$plot1 <- renderPlotly({
    gp %>% layout(dragmode="select") %>%  
           onRender("
                    function(el, x, data) {

                    var myDF = data.myDF
                    var Traces = [];
                    var dLength = myDF.length
                    var vLength = data.nVar
                    var cNames = data.colNms
                    for (a=0; a<dLength; a++){
                    xArr = [];
                    yArr = [];
                    for (b=0; b<vLength; b++){
                    xArr.push(b)
                    yArr.push(myDF[a][cNames[b]]);
                    }
                    var pcpLine = {
                    x: xArr,
                    y: yArr,
                    mode: 'lines',
                    line: {
                    color: 'orange',
                    width: 1
                    },
                    opacity: 0.9,
                    }
                    Traces.push(pcpLine);
                    }
                    Plotly.addTraces(el.id, Traces);

                    el.on('plotly_selected', function(e) {
                    var dLength = myDF.length
                    var selectedPCP = []
                    var xMin = e.range.x[0]
                    var xMax = e.range.x[1]
                    var yMin = e.range.y[0]
                    var yMax = e.range.y[1]

                    console.log([xMin, xMax, yMin, yMax])

                    var Traces = []
                    var drawRect = {
                    type: 'rect',
                    x0: xMin,
                    y0: yMin,
                    x1: xMax,
                    y1: yMax,
                    line: {
                    color: 'green',
                    width: 1
                    },
                    fillcolor: 'green'
                    }
                    var update = {
                        shapes:[drawRect]
                     }
                    Plotly.relayout(el.id, update)
                    })
                    }", data = list(myDF = myDF, nVar = nVar, colNms = colNms))})

  }
shinyApp(ui, server)

And here is a screen shot of it working:



来源:https://stackoverflow.com/questions/43243156/add-shaded-rectangle-with-select-box-corners-in-plotly-r

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!