【问题标题】:Show Overlay Page onclick of ggiraph plot in Shiny R在 Shiny R 中显示 ggiraph 图的叠加页面 onclick
【发布时间】:2021-01-08 10:43:06
【问题描述】:

我是一个闪亮的 R 应用程序,我想在单击 {ggiraph} 散点图时显示一个包含附加信息的叠加页面。

我想在 R 中动态地将这个覆盖页面构造为 renderUI,这就是为什么我不想使用 {ggiraph} 的集成 onlick 函数。但是,如果有一个涉及 {ggiraph} 的onlick 函数的纯 javascript 解决方案的简单实现,那么我会感兴趣。但是,请记住,我想在所述覆盖页面中的 R 中显示 data.frame 的几列,所以如果是纯 javascript 解决方案,我猜该页面需要在 javascript 中构建为 HTML。

我当前的方法使用 {ggiraph} 的input$plot_selected 来对基础数据进行子集化,我用它来构建动态覆盖页面。由于这是一个响应式端点,我使用了一个 javascript mutationObserver 来跟踪 DOM 树的变化,一旦它被触发,它就会切换覆盖页面。理想情况下,我想听动态覆盖页面的变化。但是,我无法定位相应的节点。任何尝试都会产生错误:

TypeError: 参数 1 ('target') 到 MutationObserver.observe 必须是 Node的一个实例

我查看了这个 SO question 以及 mutationObserver 的文档以及提到的所有示例 here,但我没有看到为什么我的 javascript 无法使用的原因

target = document.getElementById('targetthis')

targetthis 是动态覆盖页面周围的硬编码 div。

但是,如果我以 document.body 为目标,它可以正常工作,但现在 任何更改 DOM 树都会切换覆盖页面。在我的示例中,有一个 selectInput,但 不应该 切换覆盖页面。我也很困惑mutationObserver 的配置只适用于childList,我认为它适用于characterData(因为覆盖页面的文本会动态变化)。

我看到的另一种可能性是启动图形的mutationObserver onclick 并在显示覆盖页面后断开它。在这种情况下,我可以使用document.body 作为目标。但对于手头的任务来说,它似乎过于复杂。

我将不胜感激。

这是一个可重现的例子:

library(shiny)
library(ggplot2)
library(ggiraph)

jsCode <- "
// select the target node
var target = document.getElementById('targetthis')  

// create an observer instance
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    if( document.getElementById('overlay')) {
    document.getElementById('overlay').style.display = 'block';
    }
  });    
});

// configuration of the observer:
// it works with childList although I would expect it to work with characterData
var config = {
  childList: true,
  subtree: true,
  // attruibutes: true,
  // characterData: true
};

// pass in the target node, as well as the observer options
// doesn't work if target is used instead of document.body
observer.observe(document.body, config); 
    
function off() {
  document.getElementById('overlay').style.display = 'none';
}
"

shinyApp(ui = fluidPage(
  
  tags$script(jsCode),

  # overlay css
  tags$head(
    tags$style(HTML("
#overlay {
  position: fixed;
  display: none;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0,0,0,0.5);
  z-index: 2;
  cursor: pointer;
}

#profile {
  color: black;
  background-color: white;
  position: absolute;
  top: 50%;
  left: 50%;
  font-size: 50px;
  transform: translate(-50%,-50%);
  -ms-transform: translate(-50%,-50%);
}

    "))
  ),

  sidebarLayout(

  sidebarPanel(
    # test input overlay page should not be shown when input changes
    selectInput("test",
                "This is a test input",
                choices = c("Model A", "Model B", "Model C"))
  ),
  mainPanel(
    # plot
    girafeOutput("plot"),
    # overlay html
    # this hard coded div contains the overlay page 
    div(id = "targetthis",
                 uiOutput("overlay_page")),
    )
)),

  server = function(input, output) {

    # dynamic overlay page
    # preferably I want to build this page inside R (and not javascriptto,)
    output$overlay_page <- renderUI({
      
      info <- subset(mtcars, rownames(mtcars) == input$plot_selected)
      
    tagList(div(id = "overlay",
                onclick = "off()",
                tags$table(id = "profile",
                           style="width:80%",
                  tags$tr(
                    tags$th(colspan = 3,
                            rownames(info))
                  ),
                  tags$tr(
                    tags$td(colnames(info)[1]),
                    tags$td(info[, 1])
                  ),
                  tags$tr(
                    tags$td(colnames(info)[2]),
                    tags$td(info[, 2])
                  ),
                  tags$tr(
                    tags$td(colnames(info)[3]),
                    tags$td(info[, 3])
                  ),
                  tags$tr(
                    tags$td(colnames(info)[4]),
                    tags$td(info[, 4])
                  )
                  )
      )
      )
    
    })

    # plot
    output$plot <- renderGirafe({

      
      data <- mtcars

      p <- ggplot(aes(x = wt,
                      y = mpg,
                      data_id = row.names(mtcars)
                      ),
                  data = data) +
        geom_point_interactive(size = 3) +
        theme_minimal()

      girafe(
        ggobj = p,
        options = list(
          opts_hover(css = "fill:red;cursor:pointer;"),
          opts_selection(type = "single")
        )
      )
    })

  }

)

【问题讨论】:

    标签: javascript r shiny ggiraph


    【解决方案1】:

    @VictorPerrier 在 Twitter 上评论说只使用带有modalDialog 的模态窗口,我完全没有想到。我玩弄了它,它几乎可以在没有一行 javascript 的情况下完成我想要它做的事情(参见下面的代码)。

    我将保留这个问题,以防有人有一个“真正的”覆盖页面解决方案(我的用例不需要它,但其他人可能正在寻找它)。当然,在使用了mutationObserver API 一段时间后,我真的很想知道,为什么我的方法不起作用。

    library(shiny)
    library(ggplot2)
    library(ggiraph)
    
    
    shinyApp(ui = fluidPage(
    
      sidebarLayout(
    
      sidebarPanel(
        # test input overlay page should not be shown when input changes
        selectInput("test",
                    "This is a test input",
                    choices = c("Model A", "Model B", "Model C"))
      ),
      mainPanel(
        # plot
        girafeOutput("plot")
    ))),
    
      server = function(input, output) {
    
        # dynamic overlay page
        # preferably I want to build this page inside R (and not javascriptto,)
        observeEvent(input$plot_selected, {
          
          info <- subset(mtcars, rownames(mtcars) == input$plot_selected)
          
          showModal(shiny::modalDialog(
          
          tags$table(id = "profile",
                     style="width:80%",
                     tags$tr(
                       tags$th(colspan = 3,
                               rownames(info)
                       )
                     ),
                     tags$tr(
                       tags$td(colnames(info)[1]),
                       tags$td(info[, 1])
                     ),
                     tags$tr(
                       tags$td(colnames(info)[2]),
                       tags$td(info[, 2])
                     ),
                     tags$tr(
                       tags$td(colnames(info)[3]),
                       tags$td(info[, 3])
                     ),
                     tags$tr(
                       tags$td(colnames(info)[4]),
                       tags$td(info[, 4])
                     )
          ),
          easyClose = TRUE,
          footer = NULL
          ))
        })
    
        # plot
        output$plot <- renderGirafe({
    
          data <- mtcars
    
          p <- ggplot(aes(x = wt,
                          y = mpg,
                          data_id = row.names(mtcars)
                          ),
                      data = data) +
            geom_point_interactive(size = 3) +
            theme_minimal()
    
          girafe(
            ggobj = p,
            options = list(
              opts_hover(css = "fill:red;cursor:pointer;"),
              opts_selection(type = "single")
            )
          )
        })
    
      }
    
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-07
      • 1970-01-01
      • 1970-01-01
      • 2022-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多