我面临着一个特定的挑战,并提出了一个解决方案.不过,我不确定这是不是一个优雅的解决方案.要求改进.

Challenge

I am developing a shiny app using with a page with multiple boxes. Each box may contain a plolty plot or a DT table. I am providing an actionButton in the footer of each box which allows a modalDialog to be opened, displaying a larger version of the plot.

我发现了Joe cheng here的一个旧注释,它显示了一种将相同的renderPlot调用链接到两个输出对象的方法.只要我在我的UI文件中调用一个对象,在modalDialog函数中调用另一个对象,它就可以工作.

然而,我想要控制绘图中的各种字体大小:在zoom 的绘图中,我希望使用比正常渲染的大字体更大的字体.我也不想冒险涉足Java脚本解决方案.

一个人可以通过复制renderPlotly个不同字体大小的函数来强迫自己完成这一任务.但我想重用现有的renderPlotly个函数;在我的例子中,该函数相当长.

Solution

  • 创建一个函数,我将其命名为renderDynamic,它以字体大小列表作为参数
  • 该函数返回renderPlotly个对象

使用虹膜作为数据集:

renderDynamic <- function(pars = list(tick_font_size = 14, title_font_size = 18)) {   
  tick_font_size <- pars[[1]]
  title_font_size <- pars[[2]]

  return(
   renderPlotly({
     plot <- plot_ly(data = iris, x = ~Sepal.Length, y = ~Sepal.Width, 
                                type = 'scatter', mode = 'markers', 
                                color = ~Species, 
                                marker = list(size = 10, opacity = 0.7))) %>%
       layout(
         xaxis = list(
           tickfont = list(size = tick_font_size),
           titlefont = list(size = title_font_size)),
         yaxis = list(
           tickfont = list(size = tick_font_size),
           titlefont = list(size = title_font_size))
     plot
    })
   )
})

output$plot_normal <- renderDynamic(pars = list(tick_font_size = 15, title_font_size = 18, slider_font_size = 15))
output$plot_zoom <- renderDynamic(pars = list(tick_font_size = 22, title_font_size = 22, slider_font_size = 18))

有什么 idea 吗?

推荐答案

我们可以通过plotlyProxy()修改现有的绘图对象,而无需重新渲染.在本例中,我们需要调用relayout--这比重新呈现整个小部件更快:

library(shiny)
library(plotly)

ui <- fluidPage(column(4, plotlyOutput("plot_normal")),
                actionButton("zoom", "zoom"))

server <- function(input, output, session) {
  # render plot once for both outputs
  output$plot_zoom <- output$plot_normal <- renderPlotly({
    plot <- plot_ly(
      data = iris,
      x = ~ Sepal.Length,
      y = ~ Sepal.Width,
      type = 'scatter',
      mode = 'markers',
      color = ~ Species,
      marker = list(size = 10, opacity = 0.7)
    ) %>% layout(
      xaxis = list(
        tickfont = list(size = 15),
        titlefont = list(size = 18)
      ),
      yaxis = list(
        tickfont = list(size = 15),
        titlefont = list(size = 18)
      )
    )
  })
  
  zoom_proxy <- plotlyProxy("plot_zoom", session)
  
  outputOptions(output, "plot_zoom", suspendWhenHidden = FALSE)
  
  observeEvent(input$zoom, {
    showModal(modalDialog(plotlyOutput("plot_zoom", height = "75vh"), size = "l", easyClose = TRUE))
    # modify plot shown in modalDialog
    plotlyProxyInvoke(zoom_proxy, "relayout", list(
      xaxis = list(
        tickfont = list(size = 22),
        titlefont = list(size = 22)
      ),
      yaxis = list(
        tickfont = list(size = 22),
        titlefont = list(size = 22)
      )
    ))
  })
}

shinyApp(ui, server)

result

顺便说一句:你知道是bslib::card()还是bs4Dash::box()?两者都是可扩展的--但是,我不确定它们是否可以与{shinydashboard}一起使用.

PS:在library(DT)中有一个等同的功能,称为dataTableProxy().


Edit:上述方法的模块化版本:

library(shiny)
library(plotly)

# plots could be generated in the server() function and wrapped in reactive({}) if needed
plot1 <- plot_ly(
  data = iris,
  x = ~ Sepal.Length,
  y = ~ Sepal.Width,
  type = 'scatter',
  mode = 'markers',
  color = ~ Species,
  marker = list(size = 10, opacity = 0.7)
) %>% layout(
  xaxis = list(
    tickfont = list(size = 15),
    titlefont = list(size = 18)
  ),
  yaxis = list(
    tickfont = list(size = 15),
    titlefont = list(size = 18)
  )
)

plot2 <- plot_ly(x = 1:10, y = 1:10, type = "scatter", mode = "lines")

plotUI <- function(id) {
  tagList(
    column(5, plotlyOutput(NS(id, "plot_normal"))),
    column(1, actionButton(NS(id, "zoom"), "zoom"))
  )
}

plotServer <- function(id, plotly_object) {
  moduleServer(id, function(input, output, session) {
    # render plot once for both outputs
    output$plot_zoom <- output$plot_normal <- renderPlotly({
      plotly_object
    })
    
    outputOptions(output, "plot_zoom", suspendWhenHidden = FALSE)
    
    zoom_proxy <- plotlyProxy("plot_zoom", session)
    
    observeEvent(input$zoom, {
      showModal(modalDialog(plotlyOutput(NS(id, "plot_zoom"), height = "75vh"), size = "l", easyClose = TRUE))
      # modify plot shown in modalDialog
      plotlyProxyInvoke(zoom_proxy, "relayout", list(
        xaxis = list(
          tickfont = list(size = 22),
          titlefont = list(size = 22)
        ),
        yaxis = list(
          tickfont = list(size = 22),
          titlefont = list(size = 22)
        )
      ))
    })
  })
}

plotApp <- function() {
  ui <- fluidPage(
    plotUI("my1stplot"),
    plotUI("my2ndplot")
  )
  server <- function(input, output, session) {
    plotServer(id = "my1stplot", plotly_object = plot1)
    plotServer(id = "my2ndplot", plotly_object = plot2)
  }
  shinyApp(ui, server)  
}

plotApp()

R相关问答推荐

如何将具有重复名称的收件箱合并到R中的另一列中,而结果不同?

将Multilinetring合并到一个线串中,使用sf生成规则间隔的点

在特定列上滞后n行,同时扩展框架的长度

整数成随机顺序与约束R?

如何动态更新selectizeInput?

Ggplot2中的重复注记

为什么我的基准测试会随着样本量的增加而出现一些波动?

我如何才能找到FAMILY=POISSON(LINK=&Q;LOG&Q;)中的模型预测指定值的日期?

将文件保存到新文件夹时,切换r设置以不必创建目录

合并DFS列表并将索引提取为新列

LOF中的插图短文字幕

使用RSelenium在R中抓取Reddit时捕获多个标签

更新R中的数据表(使用data.table)

远离理论值的伽马密度曲线下面积的近似

将工作目录子文件夹中的文件批量重命名为顺序

为什么不能使用lApply在包装函数中调用子集

如何使用循环从R中的聚合函数创建列,而不会在名称中给出&q;$&q;?

如何创建直方图与对齐的每月箱?

根据用户输入更改标记大小和 colored颜色 (R)

R:改进实现简单模型