R中的交互式绘图

Posted

技术标签:

【中文标题】R中的交互式绘图【英文标题】:Interactive Plots in R 【发布时间】:2021-06-16 08:56:41 【问题描述】:

使用 plotly 库,我在 R 中制作了以下绘图:

library(dplyr)
library(ggplot2)
library(plotly)

set.seed(123)
df <- data.frame(var1 = rnorm(1000,10,10),
                   var2 = rnorm(1000,5,5))

df <- df %>% mutate(var3 = ifelse(var1 <= 5 & var2 <= 5, "a", ifelse(var1 <= 10 & var2 <= 10, "b", "c"))) 


plot = df %>%
  ggplot() + geom_point(aes(x=var1, y= var2, color= var3))


ggplotly(plot)

这是一个简单的散点图 - 生成两个随机变量,然后点的颜色由某些标准决定(例如,如果 var1 和 var2 在特定范围内)。

从这里,我还可以汇总统计数据:

df$var3 = as.factor(df$var3)
summary = df %>%
    group_by(var3) %>%
    summarize(Mean_var1 = mean(var1), Mean_var2 = mean(var2), count=n())

# A tibble: 3 x 4
  var3  Mean_var1 Mean_var2 count
* <fct>     <dbl>     <dbl> <int>
1 a         -1.70     0.946   158
2 b          4.68     4.94    260
3 c         15.8      6.49    582

我的问题:是否可以在此图中添加一些按钮,以允许用户根据自定义选择为点着色?例如。像这样:

现在,用户可以在他们想要的任何范围内输入 - 点的颜色会发生变化,并且会生成一些摘要统计信息。

谁能告诉我如何在 R 中做到这一点?

我有这个想法 - 首先我会创建一个巨大的表,它会创建“var1”和“var2”的所有可能范围组合:

vec1 <- c(-20:40,1)
vec2 <-  c(-20:40,1)


a <- expand.grid(vec1, vec2)

for (i in seq_along(vec1))  
    for (j in seq_along(vec2)) 

df <- df %>% mutate(var3 = ifelse(var1 <= i & var2 <= i, "a", ifelse(var1 <= j & j <= 10, "b", "c"))) 




然后,根据用户想要的范围 - SQL 风格的语句将这些行从对应于这些范围的海量表中分离出来:

custom_df = df[df$var1 > -20 & df$var1 <10 & df$var1 > -20 & df$var2 <10 , ]    

然后,将对“custom_df”进行单独的抓取,并为“custom_df”记录汇总统计信息:

summary = custom_df %>%
    group_by(var3) %>%
    summarize(Mean_var1 = mean(var1), Mean_var2 = mean(var2), count=n())

但我不确定如何在 R 中巧妙而有效地做到这一点。

有人可以告诉我怎么做吗?

谢谢

【问题讨论】:

您在shiny寻找解决方案吗? 最初我试图只使用 plotly 来解决这个问题 - 但现在我认为这只能使用闪亮来解决。我正在尝试从这个网站 (mastering-shiny.org/action-dynamic.html) 学习一些基本的闪亮知识。你有什么建议? 这可能需要一些努力,这可能是目前还没有答案的原因。如果您没有得到答案,您也可以选择筹集小额赏金以让更多人关注它 这些链接真的很有用。如果你自学,对回答这些问题会有很大帮助 谢谢,现在可能会得到更多关注 【参考方案1】:

我已经构建了一个闪亮的小应用程序来满足您的大部分要求。根据您预定义的大型数据框df,用户可以定义以下内容:

    为变量var1var2 选择最小值和最大值。 选择标准来定义变量var3,用于显示不同颜色的数据点。现在是一个范围。 将绘图保存为 HTML 文件。 以表格形式显示的汇总统计信息。

您可以定义更多选项,为用户提供选择颜色等的选项。为此,也许你应该在谷歌上搜索如何使用scale_color_manual()

更新:添加了根据 var1 和 var2 范围值选择红色和绿色的用户选项。

library(shiny)
library(plotly)
library(dplyr)
library(DT)

### define a large df
set.seed(123)
df <- data.frame(var1 = rnorm(1000,10,10),
                 var2 = rnorm(1000,15,15))

ui <- fluidPage(
  titlePanel(p("My First Test App", style = "color:red")),
  sidebarLayout(
    sidebarPanel(
      p("Choose Variable limits"),

      # Horizontal line ----
      tags$hr(),
      uiOutput("var1a"), uiOutput("var1b"),
      uiOutput("var2a"), uiOutput("var2b"),
      uiOutput("criteria")

    ),
    mainPanel(
      DTOutput("summary"), br(),
      plotlyOutput("plot"),
      br(), br(), br(),
      uiOutput("saveplotbtn")
    )
  )
)

server <- function(input, output, session)
  
  output$var1a <- renderUI(
    tagList(
      numericInput("var11", "Variable 1 min",
                  min = min(df$var1), max = max(df$var1), value = min(df$var1))
    )
  )
  output$var1b <- renderUI(
    if (is.null(input$var11))
      low1 <- min(df$var1)
    else low1 <- max(min(df$var1),input$var11)  ## cannot be lower than var 1 minimum
    tagList(
      numericInput("var12", "Variable 1 max", min = low1, max = max(df$var1), value = max(df$var1))
    )
  )
  
  output$var2a <- renderUI(
    tagList(
      numericInput("var21", "Variable 2 min",
                   min = min(df$var2), max = max(df$var2), value = min(df$var2))
    )
  )
  output$var2b <- renderUI(
    if (is.null(input$var21))
      low2 <- min(df$var2)
    else low2 <- max(min(df$var2),input$var21)  ## cannot be lower than var 2 minimum
    tagList(
      numericInput("var22", "Variable 2 max", min = low2, max = max(df$var2), value = max(df$var2))
    )
  )
  
  output$criteria <- renderUI(
    req(input$var11,input$var12,input$var21,input$var22)
        
    tagList(
      sliderInput("crit11", "Variable 1 red color range:",
                  min = -10, max = 0, value = c(-10,0)),
      sliderInput("crit12", "Variable 2 red color range:",
                  min = -25, max = 0, value = c(-25,0)),
      sliderInput("crit21", "Variable 1 green color range:",
                  min = 0.1, max = 10, value = c(0.1,10)),
      sliderInput("crit22", "Variable 2 green color range:",
                  min = 0.1, max = 20, value = c(0.1,20))
    )

  )
  
  dat <- reactive(
    req(input$crit11,input$crit12,input$crit21,input$crit22)
    
    df <- df %>% filter(between(var1, input$var11, input$var12)) %>% 
                 filter(between(var2, input$var21, input$var22))
    
    # df1 <- df %>% mutate(var3 = ifelse(var1 <= i & var2 <= i, "a", ifelse(var1 <= j & var2 <= j , "b", "c")))
    
    df1 <- df %>% mutate(var3 = ifelse(between(var1, input$crit11[1], input$crit11[2]) & between(var2, input$crit12[1], input$crit12[2]), "a",
                                       ifelse(between(var1, input$crit21[1], input$crit21[2]) & between(var2, input$crit22[1], input$crit22[2]), "b", "c")))
    
  )
  
  summari <- reactive(
    req(dat())
    df1 <- dat()
    df1$var3 = as.factor(df1$var3)
    summary = df1 %>%
      group_by(var3) %>%
      dplyr::summarize(Mean_var1 = mean(var1), Mean_var2 = mean(var2), count=n())
  )
  
  output$summary <- renderDT(summari())
  
  rv <- reactiveValues()
  
  observe(
    req(dat())
    p <- ggplot(data=dat()) + geom_point(aes(x=var1, y= var2, color= var3))
    pp <- ggplotly(p)
    rv$plot <- pp
  )
  
  output$plot <- renderPlotly(
    rv$plot
  )
  
  output$saveplotbtn <-  renderUI(
    div(style="display: block; padding: 5px 350px 5px 50px;",
        downloadBttn("saveHTML",
                     HTML("HTML"),
                     style = "fill",
                     color = "default",
                     size = "lg",
                     block = TRUE,
                     no_outline = TRUE
        ) )
  )
  
  output$saveHTML <- downloadHandler(
    filename = function() 
      paste("myplot", Sys.Date(), ".html", sep = "")
    ,
    content = function(file) 
      htmlwidgets::saveWidget(as_widget(rv$plot), file, selfcontained = TRUE)  ## self-contained
    
  )



shinyApp(ui, server)

【讨论】:

非常感谢您的回答!我正在考虑用“变量 3 范围”代替“标准 1”和“标准 2”。是否可以有另一个框来记录每个范围组合的汇总统计信息?非常感谢您的帮助! 是否可以用文本框替换滑块?最终结果可以保存为html文件吗? 如果答案让您满意,请点击复选标记接受。如果你还没有这样做,你也应该考虑支持这个解决方案。 @iamericfletcher :我赞成该解决方案。我试图从这个解决方案中解决一些问题(我在 cmets 中提到了它们)。谢谢! @stats555,接受已回答您的 OP 的答案被认为是礼貌的。这有助于其他正在为相同/相似查询寻找解决方案的人。此外,人们可能愿意在您未来的查询中为您提供帮助。

以上是关于R中的交互式绘图的主要内容,如果未能解决你的问题,请参考以下文章

R:向交互式绘图添加“工具提示”(绘图)

R语言动态交互绘图|plotly包-交互式柱形图

r绘图基本

如何在R / Shiny中将相机方向固定在交互式3D绘图中

R语言与医学统计图形-31动态交互绘图

R和Shiny:当悬停在Shiny上的绘图上时显示ggplot2数据值