在R Shiny应用程序中渲染ggplot2和一个可绘制对象 [英] Rendering a ggplot2 and a plotly object in an R Shiny app

查看:91
本文介绍了在R Shiny应用程序中渲染ggplot2和一个可绘制对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个R shiny应用程序,它同时使用Rplotlyggplot2来生成和显示图形.

I have an R shiny app that uses both R's plotly and ggplot2 to produce and display figures.

因为在shiny中渲染plotly图形需要plotlyrenderPlotly函数,所以ggplot2图形被转换为renderPlotly部分中的plotly对象,这使它们有些混乱.

Because rendering plotly figures in shiny requires plotly's the renderPlotly function the ggplot2 figures get converted to plotly objects in the renderPlotly part, which messes them up a bit.

这是一个例子. 首先,生成一些数据:

Here's an example. First, generate some data:

set.seed(1)

meta.df <- data.frame(cell = c(paste0("c_",1:1000,"_1w"), paste0("c_",1:1000,"_2w"), paste0("c_",1:1000,"_3w")),
                      cluster = c(sample(c("cl1","cl2","cl3"),1000,replace=T)),
                      age = c(rep(1,1000),rep(2,1000),rep(3,1000)),
                      x = rnorm(3000), y = rnorm(3000))

expression.mat <- cbind(matrix(rnorm(20*1000,1,1), nrow=20, ncol=1000, dimnames=list(paste0("g",1:20),meta.df$cell[1:1000])),
                        matrix(rnorm(20*1000,2,1), nrow=20, ncol=1000, dimnames=list(paste0("g",1:20),meta.df$cell[1001:2000])),
                        matrix(rnorm(20*1000,3,1), nrow=20, ncol=1000, dimnames=list(paste0("g",1:20),meta.df$cell[2001:3000])))

这是应用程序代码:

library(shiny)
library(dplyr)
library(ggplot2)
library(ggpmisc)

server <- function(input, output, session)
{
  output$gene <- renderUI({
      selectInput("gene", "Select Gene to Display", choices = rownames(expression.mat))
  })
  
  output$group <- renderUI({
    if(input$plotType == "Distribution Plot"){
      selectInput("group", "Select Group", choices = c("cluster","age"))
    }
  })
  
  scatter.plot <- reactive({
    scatter.plot <- NULL
    if(!is.null(input$gene)){
      gene.idx <- which(rownames(expression.mat) == input$gene)
      plot.df <- suppressWarnings(meta.df %>% dplyr::left_join(data.frame(cell=colnames(expression.mat),value=expression.mat[gene.idx,]),by=c("cell"="cell")))
      scatter.plot <- suppressWarnings(plotly::plot_ly(marker=list(size=3),type='scatter',mode="markers",color=plot.df$value,x=plot.df$x,y=plot.df$y,showlegend=F,colors=colorRamp(c("lightgray","darkred"))) %>%
                                         plotly::layout(title=input$gene,xaxis=list(zeroline=F,showticklabels=F,showgrid=F),yaxis=list(zeroline=F,showticklabels=F,showgrid=F)) %>%
                                         plotly::colorbar(limits=c(min(plot.df$value,na.rm=T),max(plot.df$value,na.rm=T)),len=0.4,title="Scaled Expression"))
    }
    return(scatter.plot)
  })
  
  distribution.plot <- reactive({
    distribution.plot <- NULL
    if(!is.null(input$gene) & !is.null(input$group)){
      gene.idx <- which(rownames(expression.mat) == input$gene)
      plot.df <- suppressWarnings(meta.df %>% dplyr::left_join(data.frame(cell=colnames(expression.mat),value=expression.mat[gene.idx,]),by=c("cell"="cell")))
      if(input$group == "cluster"){
        distribution.plot <- suppressWarnings(plotly::plot_ly(x=plot.df$cluster,y=plot.df$value,split=plot.df$cluster,type='violin',box=list(visible=T),points=T,color=plot.df$cluster,showlegend=F) %>%
                                                plotly::layout(title=input$gene,xaxis=list(title=input$group,zeroline=F),yaxis=list(title="Scaled Expression",zeroline=F)))
      } else{
        plot.df <- plot.df %>% dplyr::mutate(time=age) %>% dplyr::arrange(time)
        plot.df$age <- factor(plot.df$age,levels=unique(plot.df$age))
        distribution.plot <- suppressWarnings(ggplot(plot.df,aes(x=time,y=value)) +
                                                geom_violin(aes(fill=age,color=age),alpha=0.3) +
                                                geom_boxplot(width=0.1,aes(color=age),fill=NA) +
                                                geom_smooth(mapping=aes(x=time,y=value,group=cluster),color="black",method='lm',size=1,se=T) +
                                                stat_poly_eq(mapping=aes(x=time,y=value,group=cluster,label=stat(p.value.label)),formula=y~x,parse=T,npcx="center",npcy="bottom") +
                                                scale_x_discrete(name=NULL,labels=levels(plot.df$cluster),breaks=unique(plot.df$time)) +
                                                facet_wrap(~cluster) + theme_minimal() + ylab(paste0("#",input$gene," Scaled Expressioh"))+theme(legend.title=element_blank()))
      }
    }
    return(distribution.plot)
  })
  
  output$out.plot <- plotly::renderPlotly({
    if(input$plotType == "Scatter Plot"){
      scatter.plot()
    } else if(input$plotType == "Distribution Plot"){
      distribution.plot()
    }
  })
}


ui <- fluidPage(
  titlePanel("Explorer"),
  sidebarLayout(
    sidebarPanel(
      tags$head(
        tags$style(HTML(".multicol {-webkit-column-count: 3; /* Chrome, Safari, Opera */-moz-column-count: 3; /* Firefox */column-count: 3;}")),
        tags$style(type="text/css", "#loadmessage {position: fixed;top: 0px;left: 0px;width: 100%;padding: 5px 0px 5px 0px;text-align: center;font-weight: bold;font-size: 100%;color: #000000;background-color: #CCFF66;z-index: 105;}"),
        tags$style(type="text/css",".shiny-output-error { visibility: hidden; }",".shiny-output-error:before { visibility: hidden; }")),
      conditionalPanel(condition="$('html').hasClass('shiny-busy')",tags$div("In Progress...",id="loadmessage")),
      selectInput("plotType", "Plot Type", choices = c("Scatter Plot","Distribution Plot")),
      uiOutput("gene"),
      uiOutput("group"),
    ),
    mainPanel(
      plotly::plotlyOutput("out.plot")
    )
  )
)

shinyApp(ui = ui, server = server)

如果用户选择Distribution Plot Plot Type和年龄" Group,然后用ggplot2ggpmisc生成图形.作为ggplot2对象,这些数字如下所示:

If the user chooses the Distribution Plot Plot Type and the "age" Group then the figure is generated with ggplot2 and ggpmisc. As ggplot2 objects these figures look like this:

但是作为plotly对象(我想像plotly::renderPlotly部分使用plotlyggplotly函数从ggplot2对象转换),它变为:

But as a plotly object (which I imagine the plotly::renderPlotly part converts from a ggplot2 object using plotly's ggplotly function) it becomes:

如您所见,底部的P值丢失了,图例为行为异常".

As you can see the P-values in the bottom are missing and the legend is 'misbehaving'.

首选解决方案是,如果对象是plotly对象,请使用plotly::renderPlotly函数;如果对象是ggplot2对象,请使用render,但是我不知道如何实现(认为很难解决并更正ggplot2对象在转换为plotly对象时所经历的修改).

The preferred solution is to have shiny use the plotly::renderPlotly function if the object is a plotly object and the render if it is a ggplot2 object but I don't know how to implement that (I think it'll be harder to work out and correct the modifications that the ggplot2 object undergoes in its conversion to a plotly object).

有什么主意吗?

推荐答案

我认为最简单的解决方案是定义2个输出,一个在plotly绘图之前,一个在ggplot绘图之前,并使用shinyjs进行显示/根据输入隐藏正确的图:

I think the easiest solution is to define 2 outputs, one fore the plotly plots and one for the ggplot plots and use shinyjs to show/hide the correct plot based on the inputs:

set.seed(1)

meta.df <- data.frame(cell = c(paste0("c_",1:1000,"_1w"), paste0("c_",1:1000,"_2w"), paste0("c_",1:1000,"_3w")),
                      cluster = c(sample(c("cl1","cl2","cl3"),1000,replace=T)),
                      age = c(rep(1,1000),rep(2,1000),rep(3,1000)),
                      x = rnorm(3000), y = rnorm(3000))

expression.mat <- cbind(matrix(rnorm(20*1000,1,1), nrow=20, ncol=1000, dimnames=list(paste0("g",1:20),meta.df$cell[1:1000])),
                        matrix(rnorm(20*1000,2,1), nrow=20, ncol=1000, dimnames=list(paste0("g",1:20),meta.df$cell[1001:2000])),
                        matrix(rnorm(20*1000,3,1), nrow=20, ncol=1000, dimnames=list(paste0("g",1:20),meta.df$cell[2001:3000])))

library(shiny)
library(dplyr)
library(ggplot2)
library(ggpmisc)
library(shinyjs)

server <- function(input, output, session)
{
  output$gene <- renderUI({
    selectInput("gene", "Select Gene to Display", choices = rownames(expression.mat))
  })
  
  output$group <- renderUI({
    if(input$plotType == "Distribution Plot"){
      selectInput("group", "Select Group", choices = c("cluster","age"))
    }
  })
  
  scatter.plot <- reactive({
    scatter.plot <- NULL
    if(!is.null(input$gene)){
      gene.idx <- which(rownames(expression.mat) == input$gene)
      plot.df <- suppressWarnings(meta.df %>% dplyr::left_join(data.frame(cell=colnames(expression.mat),value=expression.mat[gene.idx,]),by=c("cell"="cell")))
      scatter.plot <- suppressWarnings(plotly::plot_ly(marker=list(size=3),type='scatter',mode="markers",color=plot.df$value,x=plot.df$x,y=plot.df$y,showlegend=F,colors=colorRamp(c("lightgray","darkred"))) %>%
                                         plotly::layout(title=input$gene,xaxis=list(zeroline=F,showticklabels=F,showgrid=F),yaxis=list(zeroline=F,showticklabels=F,showgrid=F)) %>%
                                         plotly::colorbar(limits=c(min(plot.df$value,na.rm=T),max(plot.df$value,na.rm=T)),len=0.4,title="Scaled Expression"))
    }
    return(scatter.plot)
  })
  
  distribution.plot <- reactive({
    distribution.plot <- NULL
    if(!is.null(input$gene) & !is.null(input$group)){
      gene.idx <- which(rownames(expression.mat) == input$gene)
      plot.df <- suppressWarnings(meta.df %>% dplyr::left_join(data.frame(cell=colnames(expression.mat),value=expression.mat[gene.idx,]),by=c("cell"="cell")))
      if(input$group == "cluster"){
        distribution.plot <- suppressWarnings(plotly::plot_ly(x=plot.df$cluster,y=plot.df$value,split=plot.df$cluster,type='violin',box=list(visible=T),points=T,color=plot.df$cluster,showlegend=F) %>%
                                                plotly::layout(title=input$gene,xaxis=list(title=input$group,zeroline=F),yaxis=list(title="Scaled Expression",zeroline=F)))
      } else{
        plot.df <- plot.df %>% dplyr::mutate(time=age) %>% dplyr::arrange(time)
        plot.df$age <- factor(plot.df$age,levels=unique(plot.df$age))
        distribution.plot <- suppressWarnings(ggplot(plot.df,aes(x=time,y=value)) +
                                                geom_violin(aes(fill=age,color=age),alpha=0.3) +
                                                geom_boxplot(width=0.1,aes(color=age),fill=NA) +
                                                geom_smooth(mapping=aes(x=time,y=value,group=cluster),color="black",method='lm',size=1,se=T) +
                                                stat_poly_eq(mapping=aes(x=time,y=value,group=cluster,label=stat(p.value.label)),formula=y~x,parse=T,npcx="center",npcy="bottom") +
                                                scale_x_discrete(name=NULL,labels=levels(plot.df$cluster),breaks=unique(plot.df$time)) +
                                                facet_wrap(~cluster) + theme_minimal() + ylab(paste0("#",input$gene," Scaled Expressioh"))+theme(legend.title=element_blank()))
      }
    }
    return(distribution.plot)
  })
  
  output$out.plot_plotly <- plotly::renderPlotly({
    if(input$plotType == "Scatter Plot"){
      scatter.plot()
    } else {
      req(input$group)
      if (input$plotType == "Distribution Plot" && input$group != "age"){
        distribution.plot()
      }
    }
  })
  
  output$out.plot_plot <- renderPlot({
    req(input$group)
    if (input$plotType == "Distribution Plot" && input$group == "age") {
      distribution.plot()
    }
  })
  
  observeEvent(c(input$group, input$plotType), {
    req(input$group)
    if (input$group == "age" && input$plotType == "Distribution Plot") {
      hide("out.plot_plotly")
      show("out.plot_plot")
    } else {
      hide("out.plot_plot")
      show("out.plot_plotly")
    }
  })
}


ui <- fluidPage(
  titlePanel("Explorer"),
  useShinyjs(),
  sidebarLayout(
    sidebarPanel(
      tags$head(
        tags$style(HTML(".multicol {-webkit-column-count: 3; /* Chrome, Safari, Opera */-moz-column-count: 3; /* Firefox */column-count: 3;}")),
        tags$style(type="text/css", "#loadmessage {position: fixed;top: 0px;left: 0px;width: 100%;padding: 5px 0px 5px 0px;text-align: center;font-weight: bold;font-size: 100%;color: #000000;background-color: #CCFF66;z-index: 105;}"),
        tags$style(type="text/css",".shiny-output-error { visibility: hidden; }",".shiny-output-error:before { visibility: hidden; }")),
      conditionalPanel(condition="$('html').hasClass('shiny-busy')",tags$div("In Progress...",id="loadmessage")),
      selectInput("plotType", "Plot Type", choices = c("Scatter Plot","Distribution Plot")),
      uiOutput("gene"),
      uiOutput("group"),
    ),
    mainPanel(
      plotly::plotlyOutput("out.plot_plotly"),
      plotOutput("out.plot_plot")
    )
  )
)

shinyApp(ui = ui, server = server)

这篇关于在R Shiny应用程序中渲染ggplot2和一个可绘制对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆