如何将绘图复制到剪贴板以进行粘贴?

How to copy a plot into the clipboard for pasting?

在 运行 下面的可重现代码中,用户可以 select 通过单击呈现的 Shiny 顶部的单选按钮来查看实际数据或数据图屏幕(如编码所示,默认为数据)。在渲染屏幕的底部,您会看到一个“复制”按钮。通过select输入“数据”然后“复制”,您可以轻松地将数据粘贴到 XLS 中。

但是,如果用户改为 select 查看剧情,我希望用户也能够 copy/paste 以相同的方式查看剧情。如何做到这一点?

我试过在下面 observeEvent(...)capture.output(...) 函数(及其各种迭代)中插入 plotPNG(...),使用由条件 if input$view == 'Plot' 触发的条件, 但还没有运气。

library(shiny)
library(ggplot2)

ui <- fluidPage(
   radioButtons("view",
                label = "View data or plot",
                choiceNames = c('Data','Plot'),
                choiceValues = c('Data','Plot'),
                selected = 'Data',
                inline = TRUE
                ),
   conditionalPanel("input.view == 'Data'",tableOutput("DF")),
   conditionalPanel("input.view == 'Plot'",plotOutput("plotDF")),
   actionButton("copy","Copy",style = "width:20%;")
)
  
server <- function(input, output, session) {
  
  data <- data.frame(Period = c(1,2,3,4,5,6),Value = c(10,20,15,40,35,30))

  output$DF <- renderTable(data)
  output$plotDF <- renderPlot(ggplot(data, aes(Period,Value)) + geom_line())

  observeEvent(
    req(input$copy),
    writeLines(
      capture.output(
        write.table(
          x = data,
          sep = "\t",
          row.names = FALSE
          )
        ),
      "clipboard")
    )
 
}

shinyApp(ui, server)

你可以试试shinyscreenshot:你可以进一步调整它https://daattali.com/shiny/shinyscreenshot-demo/

这是一个例子:

library(shiny)
library(ggplot2)
library(shinyscreenshot)


ui <- fluidPage(
  radioButtons("view",
               label = "View data or plot",
               choiceNames = c('Data','Plot'),
               choiceValues = c('Data','Plot'),
               selected = 'Data',
               inline = TRUE
  ),
  div(
    id = "takemyscreenshot",
  conditionalPanel("input.view == 'Data'",tableOutput("DF")),
  conditionalPanel("input.view == 'Plot'",plotOutput("plotDF")),
  actionButton("go","Go",style = "width:20%;")
  )
)

server <- function(input, output, session) {
  
  observeEvent(input$go, {
    screenshot(id = "takemyscreenshot")
  })
  
  data <- data.frame(Period = c(1,2,3,4,5,6),Value = c(10,20,15,40,35,30))
  
  output$DF <- renderTable(data)
  output$plotDF <- renderPlot(ggplot(data, aes(Period,Value)) + geom_line())
  
  observeEvent(
    req(input$copy),
    writeLines(
      capture.output(
        write.table(
          x = data,
          sep = "\t",
          row.names = FALSE
        )
      ),
      "clipboard")
  )
  
}

shinyApp(ui, server)

已在 Edge 上测试。

library(shiny)
library(ggplot2)

js <- '
async function getImageBlobFromUrl(url) {
  const fetchedImageData = await fetch(url);
  const blob = await fetchedImageData.blob();
  return blob;
}
$(document).ready(function () {
  $("#copybtn").on("click", async () => {
    const src = $("#plotDF>img").attr("src");
    try {
      const blob = await getImageBlobFromUrl(src);
      await navigator.clipboard.write([
        new ClipboardItem({
          [blob.type]: blob
        })
      ]);
      alert("Image copied to clipboard!");
    } catch (err) {
      console.error(err.name, err.message);
      alert("There was an error while copying image to clipboard :/");
    }
  });
});
'

ui <- fluidPage(
  tags$head(
    tags$script(HTML(js))
  ),
  br(),
  actionButton("copybtn", "Copy", icon = icon("copy"), class = "btn-primary"),
  br(),
  plotOutput("plotDF")
)

server <- function(input, output, session){
  
  output[["plotDF"]] <- renderPlot({
    ggplot(
      iris, aes(x = Sepal.Length, y = Sepal.Width)
    ) + geom_point()
  })
  
}

shinyApp(ui, server)


编辑

警报不是很好。我建议改为 shinyToastify

library(shiny)
library(shinyToastify)
library(ggplot2)

js <- '
async function getImageBlobFromUrl(url) {
  const fetchedImageData = await fetch(url);
  const blob = await fetchedImageData.blob();
  return blob;
}
$(document).ready(function () {
  $("#copybtn").on("click", async () => {
    const src = $("#plotDF>img").attr("src");
    try {
      const blob = await getImageBlobFromUrl(src);
      await navigator.clipboard.write([
        new ClipboardItem({
          [blob.type]: blob
        })
      ]);
      Shiny.setInputValue("success", true, {priority: "event"});
    } catch (err) {
      console.error(err.name, err.message);
      Shiny.setInputValue("failure", true, {priority: "event"});
    }
  });
});
'

ui <- fluidPage(
  tags$head(
    tags$script(HTML(js))
  ),
  useShinyToastify(),
  br(),
  actionButton("copybtn", "Copy", icon = icon("copy"), class = "btn-primary"),
  br(),
  plotOutput("plotDF")
)

server <- function(input, output, session){
  
  output[["plotDF"]] <- renderPlot({
    ggplot(
      iris, aes(x = Sepal.Length, y = Sepal.Width)
    ) + geom_point()
  })
  
  observeEvent(input[["success"]], {
    showToast(
      session,
      input,
      text = tags$span(
        style = "color: white; font-size: 20px;", "Image copied!"
      ),
      type = "success",
      position = "top-center",
      autoClose = 3000,
      pauseOnFocusLoss = FALSE,
      draggable = FALSE,
      style = list(
        border = "4px solid crimson",
        boxShadow = "rgba(0, 0, 0, 0.56) 0px 22px 30px 4px"
      )
    )
  })

  observeEvent(input[["failure"]], {
    showToast(
      session,
      input,
      text = tags$span(
        style = "color: white; font-size: 20px;", "Failed to copy image!"
      ),
      type = "error",
      position = "top-center",
      autoClose = 3000,
      pauseOnFocusLoss = FALSE,
      draggable = FALSE,
      style = list(
        border = "4px solid crimson",
        boxShadow = "rgba(0, 0, 0, 0.56) 0px 22px 30px 4px"
      )
    )
  })
  
}

shinyApp(ui, server)