代码之家  ›  专栏  ›  技术社区  ›  Mark

R plotly:如何通过在散点图中单击图例来观察隐藏的轨迹

  •  1
  • Mark  · 技术社区  · 7 年前

    我试图通过在plotly的交互式图例中取消选择用户隐藏在散点图中的哪些跟踪。

    SO 帖子,以及下面评论中链接的类似问题,这让我更接近解决方案

    目前的解决方案只是做了我需要的部分工作。我希望改进的两件事是: -如何查看单击了哪个绘图的图例(查看源“id”) -我现在可以看到一个图例条目被点击,但我需要能够看到它是被点击“打开”(显示跟踪)还是“关闭”

    我正在寻找的输出将如下所示: input$trace_plot1 :这是一个关闭和打开的所有记录道的列表,或每次单击时的单个记录道nr,但它告诉您特定记录道现在是“打开”还是“关闭”

    以下是我的尝试,它不会以某种方式对传说作出反应,只会对zooom作出反应:

    library(plotly)
    library(shiny)
    library(htmlwidgets)
    
    js <- c(
      "function(el, x){",
      "  el.on('plotly_legendclick', function(evtData) {",
      "    Shiny.setInputValue('trace', evtData.data[evtData.curveNumber].name);",
      "  });",
      "}")
    
    iris$group <- c(rep(1,50), rep(2, 50), rep(3,50))
    
    ui <- fluidPage(
      plotlyOutput("plot1"),
      plotlyOutput("plot2"),
      verbatimTextOutput("legendItem")
    
    )
    
    
    server <- function(input, output){
    
      output$plot1 <- renderPlotly({
        p <- plot_ly(source = 'plotly1', data = iris, x = ~Sepal.Length, y = ~Petal.Length, color = ~as.factor(group), type = 'scatter', mode = 'markers') %>%
          layout(showlegend = TRUE)
    
        p %>% onRender(js)
    
        })
    
      output$plot2 <- renderPlotly({
        p <- plot_ly(source = 'plotly2', data = iris, x = ~Sepal.Length, y = ~Petal.Length, color = ~as.factor(group), type = 'scatter', mode = 'markers') %>%
          layout(showlegend = TRUE)
    
        p %>% onRender(js)
    
      })
    
      output$legendItem <- renderPrint({
        d <- input$trace
        if (is.null(d)) "Clicked item appear here" else d
      })
    
      }
    
    shinyApp(ui = ui, server = server)
    

    library(plotly)
    library(shiny)
    library(htmlwidgets)
    
    js <- c(
      "function(el, x, inputName){",
      "  var id = el.getAttribute('id');",
      "  var d3 = Plotly.d3;",
      "  el.on('plotly_restyle', function(evtData) {",
      "    var out = {};",
      "    d3.select('#' + id + ' g.legend').selectAll('.traces').each(function(){",
      "      var trace = d3.select(this)[0][0].__data__[0].trace;",
      "      out[trace.name] = trace.visible;",
      "    });",
      "    Shiny.setInputValue(inputName, out);",
      "  });",
      "}")
    
    
    ui <- fluidPage(
      plotlyOutput("plot1"),
      plotlyOutput("plot2"),
      verbatimTextOutput("tracesPlot1"),
      verbatimTextOutput("tracesPlot2")
    )
    
    server <- function(input, output, session) {
    
    output$plot1 <- renderPlotly({
        p1 <- plot_ly()
        p1 <-  add_trace(p1, data = mtcars, x = ~disp, y = ~mpg, type = 'scatter', mode = 'markers', color = ~as.factor(cyl))
        p1 %>% onRender(js, data = "tracesPlot1")    
      })
    
      output$plot2 <- renderPlotly({
        p2 <- plot_ly()
        p2 <- add_trace(p2, data = mtcars, x = ~disp, y = ~mpg, type = 'scatter', mode = 'markers', color = ~as.factor(cyl))
        p2 %>% onRender(js, data = "tracesPlot2")  })
    
    
      output$tracesPlot1 <- renderPrint({ unlist(input$tracesPlot1)  })
    
      output$tracesPlot2 <- renderPrint({unlist(input$tracesPlot2)
      })
    
    }
    
    shinyApp(ui, server)
    
    0 回复  |  直到 7 年前
        1
  •  6
  •   Stéphane Laurent    7 年前

    library(plotly)
    library(shiny)
    library(htmlwidgets)
    
    js <- c(
      "function(el, x){",
      "  el.on('plotly_legendclick', function(evtData) {",
      "    Shiny.setInputValue('trace', evtData.data[evtData.curveNumber].name);",
      "  });",
      "  el.on('plotly_restyle', function(evtData) {",
      "    Shiny.setInputValue('visibility', evtData[0].visible);",
      "  });",
      "}")
    
    ui <- fluidPage(
      plotlyOutput("plot"),
      verbatimTextOutput("legendItem")
    )
    
    server <- function(input, output, session) {
    
      output$plot <- renderPlotly({
        p <- plot_ly()
        for(name in c("drat", "wt", "qsec"))
        {
          p = add_markers(p, x = as.numeric(mtcars$cyl), y = as.numeric(mtcars[[name]]), name = name)
        }
        p %>% onRender(js)
      })
    
      output$legendItem <- renderPrint({
        trace <- input$trace
        ifelse(is.null(trace), 
               "Clicked item will appear here",
               paste0("Clicked: ", trace, 
                      " --- Visibility: ", input$visibility)
        )
      })
    }
    
    shinyApp(ui, server)
    

    enter image description here


    编辑

    以前的解决方案在双击图例项时出现问题。这里有一个更好的解决方案:

    library(plotly)
    library(shiny)
    library(htmlwidgets)
    
    js <- c(
      "function(el, x){",
      "  var d3 = Plotly.d3;",
      "  el.on('plotly_restyle', function(evtData) {",
      "    var out = {};",
      "    d3.select('g.legend').selectAll('.traces').each(function(){",
      "      var trace = d3.select(this)[0][0].__data__[0].trace;",
      "      out[trace.name] = trace.visible;",
      "    });",
      "    Shiny.setInputValue('traces', out);",
      "  });",
      "}")
    
    
    ui <- fluidPage(
      plotlyOutput("plot"),
      verbatimTextOutput("legendItem")
    )
    
    server <- function(input, output, session) {
    
      output$plot <- renderPlotly({
        p <- plot_ly()
        for(name in c("drat", "wt", "qsec"))
        {
          p = add_markers(p, x = as.numeric(mtcars$cyl), y = as.numeric(mtcars[[name]]), name = name)
        }
        p %>% onRender(js)
      })
    
      output$legendItem <- renderPrint({
        input$traces
      })
    }
    
    shinyApp(ui, server)
    

    enter image description here


    如果有多个绘图,请在图例选择器中添加绘图id,并使用函数生成JavaScript代码:

    js <- function(i) { 
      c(
      "function(el, x){",
      "  var id = el.getAttribute('id');",
      "  var d3 = Plotly.d3;",
      "  el.on('plotly_restyle', function(evtData) {",
      "    var out = {};",
      "    d3.select('#' + id + ' g.legend').selectAll('.traces').each(function(){",
      "      var trace = d3.select(this)[0][0].__data__[0].trace;",
      "      out[trace.name] = trace.visible;",
      "    });",
      sprintf("    Shiny.setInputValue('traces%d', out);", i),
      "  });",
      "}")
    }
    

    那就做吧 p1 %>% onRender(js(1)) p2 %>% onRender(js(2)) ,然后您将在中获得有关轨迹可见性的信息 input$traces1 , input$traces2 , ....

    另一种方法是在 data 论据 onRender :

    js <- c(
      "function(el, x, inputName){",
      "  var id = el.getAttribute('id');",
      "  var d3 = Plotly.d3;",
      "  el.on('plotly_restyle', function(evtData) {",
      "    var out = {};",
      "    d3.select('#' + id + ' g.legend').selectAll('.traces').each(function(){",
      "      var trace = d3.select(this)[0][0].__data__[0].trace;",
      "      out[trace.name] = trace.visible;",
      "    });",
      "    Shiny.setInputValue(inputName, out);",
      "  });",
      "}")
    
    
    p1 %>% onRender(js, data = "tracesPlot1")
    p2 %>% onRender(js, data = "tracesPlot2")