有没有办法在 R 中创建 Plotly 图表的全屏弹出窗口?

问题描述 投票:0回答:2

我创建了一个闪亮的仪表板,其中有许多选项卡,每个选项卡都并排设置了一些绘图图表。因为它们是并排的,所以如果不放大浏览器以使图表填满页面,就很难详细查看单个图表(即使如此,由于某种原因,图表在放大时会上下摆动)。

我在想 Plotly 中肯定有一种方法可以创建一个按钮来创建一个可以全屏显示的图表弹出窗口?然而,我在谷歌上搜索过,找不到任何与plotly相关的内容。

我确实找到了这个... Shiny:在弹出窗口中绘制结果

这种弹窗就够了。但在本例中,图表仅在弹出窗口本身上创建(并且是图像而不是交互式绘图)。在这种情况下,我想做的是镜像主页上的图表,但我知道您从 UI 的两个不同部分调用相同的输出在 Shiny 中不起作用。

有人对如何解决这个问题有任何想法吗?

r charts shiny popup plotly
2个回答
12
投票
  1. 无需使用模态或任何其他附加组件。
  2. 无需渲染两次。
  3. 我们可以纯粹从前端解决这个问题,不需要任何服务器处理。

我们可以通过一些 CSS 和 js 技巧来做到这一点:

library(shiny)
library(plotly)
ui <- fluidPage(
    htmltools::htmlDependencies(icon("")),
    tags$style(
        '
        .plot-zoom {
            position: absolute;
            border: none;
            background-color: transparent;
            bottom: 0;
            right: 0;

        }
        .full-screen {
            position: fixed;
            height: 98vh !important;
            width: 98vw !important;
            left: 0;
            top: 0;
            z-index: 9999;
            overflow: hidden;
        }
        '
    ),
    div(
        class = "plotly-full-screen",
        column(6, plotlyOutput("p2")),
        column(6, plotlyOutput("p1")),
    ),
    tags$script(HTML(
        "
        function plotZoom(el){
            el = $(el);
            var parent = el.parent().parent();
            if(el.attr('data-full_screen') === 'false') {
                parent.addClass('full-screen').trigger('resize').fadeOut().fadeIn();
                el.attr('data-full_screen', 'true');
            } else {
                parent.removeClass('full-screen').trigger('resize').fadeOut().fadeIn();
                el.attr('data-full_screen', 'false');
            }
        }
        
        $(function(){
           $('.plotly-full-screen  .plotly.html-widget').append(
            `
            <div style='position: relative;'>
                <button onclick=plotZoom(this) class='plot-zoom' data-full_screen='false' title='Full screen'>
                    <i class='fa fa-expand-arrows-alt'></i>
                </button>
            </div>
            `); 
        })
        "
    ))
   
)

server <- function(input, output, session) {
    output$p1 <- output$p2 <- renderPlotly(plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length))
}

shinyApp(ui, server)

我在每个图的右下角添加了一个小按钮。单击时,绘图将放大到全屏,在全屏状态下,再次单击将返回正常视图。

如何使用

  • 您需要做的就是将绘图组件放置在具有
    class = "plotly-full-screen"
    的父组件或祖父母或曾祖...父组件中。
  • 如果您不喜欢按钮位置或颜色等,请更改
    .plot-zoom
    样式。
  • 另一个好处是当你使用情节截图按钮时,这个全屏按钮将不会被包含。
  • 在您的应用程序中包含
    style
    script
    标签。通常您希望样式靠近应用程序的顶部(头部),并将脚本放置在绘图标签之后。

变焦前

缩放后

享受吧!


0
投票

受上面启发,但使用绘图菜单栏加上一个额外的 csv 下载按钮。分享回来,因为它对我有帮助。

library(shiny)
library(plotly)

# SVG icons
icons <- list()
# Fullscreen (source : https://fontawesome.com/icons/expand?f=classic&s=solid)
icons$expand <- "M32 32C14.3 32 0 46.3 0 64v96c0 17.7 14.3 32 32 32s32-14.3 32-32V96h64c17.7 0 32-14.3 32-32s-14.3-32-32-32H32zM64 352c0-17.7-14.3-32-32-32s-32 14.3-32 32v96c0 17.7 14.3 32 32 32h96c17.7 0 32-14.3 32-32s-14.3-32-32-32H64V352zM320 32c-17.7 0-32 14.3-32 32s14.3 32 32 32h64v64c0 17.7 14.3 32 32 32s32-14.3 32-32V64c0-17.7-14.3-32-32-32H320zM448 352c0-17.7-14.3-32-32-32s-32 14.3-32 32v64H320c-17.7 0-32 14.3-32 32s14.3 32 32 32h96c17.7 0 32-14.3 32-32V352z"
# Download Data CSV (source : https://fontawesome.com/icons/file-csv?f=classic&s=solid)
icons$csv <- "M0 64C0 28.7 28.7 0 64 0H224V128c0 17.7 14.3 32 32 32H384V304H176c-35.3 0-64 28.7-64 64V512H64c-35.3 0-64-28.7-64-64V64zm384 64H256V0L384 128zM200 352h16c22.1 0 40 17.9 40 40v8c0 8.8-7.2 16-16 16s-16-7.2-16-16v-8c0-4.4-3.6-8-8-8H200c-4.4 0-8 3.6-8 8v80c0 4.4 3.6 8 8 8h16c4.4 0 8-3.6 8-8v-8c0-8.8 7.2-16 16-16s16 7.2 16 16v8c0 22.1-17.9 40-40 40H200c-22.1 0-40-17.9-40-40V392c0-22.1 17.9-40 40-40zm133.1 0H368c8.8 0 16 7.2 16 16s-7.2 16-16 16H333.1c-7.2 0-13.1 5.9-13.1 13.1c0 5.2 3 9.9 7.8 12l37.4 16.6c16.3 7.2 26.8 23.4 26.8 41.2c0 24.9-20.2 45.1-45.1 45.1H304c-8.8 0-16-7.2-16-16s7.2-16 16-16h42.9c7.2 0 13.1-5.9 13.1-13.1c0-5.2-3-9.9-7.8-12l-37.4-16.6c-16.3-7.2-26.8-23.4-26.8-41.2c0-24.9 20.2-45.1 45.1-45.1zm98.9 0c8.8 0 16 7.2 16 16v31.6c0 23 5.5 45.6 16 66c10.5-20.3 16-42.9 16-66V368c0-8.8 7.2-16 16-16s16 7.2 16 16v31.6c0 34.7-10.3 68.7-29.6 97.6l-5.1 7.7c-3 4.5-8 7.1-13.3 7.1s-10.3-2.7-13.3-7.1l-5.1-7.7c-19.3-28.9-29.6-62.9-29.6-97.6V368c0-8.8 7.2-16 16-16z"

dirty_js <- function(x) {
  structure(x, class = unique(c("JS_EVAL", oldClass(x))))
}

button_fullscreen <- function() {
  list(
    name = "fullscreen",
    title = "Toggle fullscreen",
    icon = list(
      path = icons$expand,
      transform = 'matrix(1 0 0 1 0 -1) scale(0.03571429)'
    ),
    attr = "full_screen",
    val = "false",
    click = dirty_js(
      "function(gd, ev) {
         var button = ev.currentTarget;
         var astr = button.getAttribute('data-attr');
         var val = button.getAttribute('data-val') || false;
      
         if(astr === 'full_screen') {
           if(val === 'false') {
             button.setAttribute('data-val', 'true');
             gd.classList.add('full-screen');
             Plotly.Plots.resize(gd);
           } else {
             button.setAttribute('data-val', 'false');
             gd.classList.remove('full-screen');
             Plotly.Plots.resize(gd);
           }
         }
      }"
    )
  )
}

dirty_csv <- function(data) {
  c(
    paste0(colnames(data), collapse = ","),
    apply(data, 1, paste0, collapse = ",")
  ) |> paste0(collapse = "\n") |> utils::URLencode(reserved = TRUE)
}

button_download <- function(data) {
  list(
    name = "datacsv",
    title = "Download plot data as csv",
    icon = list(
      path = icons$csv,
      transform = 'matrix(1 0 0 1 0 0) scale(0.03125)'
    ),
    click = dirty_js(
      "function(gd, ev) {
         var el = document.createElement('a');
         el.setAttribute('href', 'data:text/plain;charset=utf-8,%s');
         el.setAttribute('download', 'plot_data.csv');
         el.click();
      }" |> sprintf(dirty_csv(data))
    )
  )
}

ui <- fluidPage(
  tags$style(
    '
        .full-screen {
            position: fixed;
            height: 98vh !important;
            width: 98vw !important;
            left: 0;
            top: 0;
            z-index: 9999;
            overflow: hidden;
        }
        '
  ),
  div(
    column(6, plotlyOutput("p2")),
    column(6, plotlyOutput("p1")),
  )
  
)

server <- function(input, output, session) {
  
  p <- plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length)
  
  p <- config(
      p,
      modeBarButtonsToAdd = list(
        list(button_fullscreen(), button_download(p[["x"]][["visdat"]][[p[["x"]][["cur_data"]]]]()))
      ),
      modeBarButtonsToRemove = c("toImage", "hoverClosest","hoverCompare"),
      displaylogo = FALSE
    )
  
  output$p1 <- output$p2 <- renderPlotly(p)
}

shinyApp(ui, server)
© www.soinside.com 2019 - 2024. All rights reserved.