R shiny ggplot - 如何不让年份标签超出网格?

Posted

技术标签:

【中文标题】R shiny ggplot - 如何不让年份标签超出网格?【英文标题】:R shiny ggplot - How not to let the year labels go beyond the grid? 【发布时间】:2021-11-12 19:34:15 【问题描述】:

我和我的朋友正在使用 ggplot 学习 R 语言。我们发现 x 轴标签超出了网格范围。

简单的数据文件在这里:https://drive.google.com/file/d/1pZQe89wxw14lirW2mRIgi9h29yPyc7Fs/view?usp=sharing

我们删除了滑动条和 x 轴中年份的小数点(使用 scale_x_discrete(limits=c(input$year[1]:input$year[2]))

但是又出现了一个问题:为什么2020的x轴标签会超出网格?

PS:没有2020年和2021年所有项目的数据。

有两种解决方法:1.覆盖网格中的x轴标签。 2. 不允许用户在滑动条上选择没有数据的年份。

我可以知道如何为这两种方式编写代码吗?

这里是源代码:

library(shiny)
library(shinydashboard)
library(dplyr)
library(tidyverse)
library(reshape)
library(scales)



ecd <- read.csv("ecd-figures.csv")

c(
  "No of case" = "no_of_case",
  "Minor Case" = "minor_case",
  "All Non Fatal Case" = "all_non_fatal_case",
  "Fatal Case" = "fatal_case"
) -> vec

ui <- fluidPage(sidebarLayout(
  sidebarPanel
  (
    checkboxGroupInput("feature",
                       "Feature",
                       vec),
    sliderInput(
      "year",
      "Year",
      min = 2015,
      max = 2021,
      value = c(2015, 2021),
      sep = "",
      step = 1
    )
  ),
  
  mainPanel(tabsetPanel(
    tabPanel("Plot", plotOutput("correlation_plot")),
    tabPanel("Table", tableOutput("ecd"))
  ))
))



server <- function(input, output) 
  yearrange <- reactive(
    ecd %>% subset(year %in% input$year[1]:input$year[2]) %>% select(c(year, input$feature))
  )
  
  output$correlation_plot <- renderPlot(
    
    ecdsubset <- yearrange()
    ecdsubset <- melt(ecdsubset, id = "year")
    validate(need(input$feature, 'Check at least one item.'))
    ggplot(ecdsubset,aes(x=year,y=value,color=variable))+geom_line(size=1)+
      scale_x_discrete(limits=c(input$year[1]:input$year[2]))
    
  )
  output$ecd <- renderTable(
    yearrange()
  )
  


shinyApp(ui, server)

这是输出。

非常感谢。

【问题讨论】:

【参考方案1】:

对于 1) 删除 scale_x_discrete

对于 2) 您可以从数据中获取这些值,而不是硬编码 minmaxvalue

library(shiny)
library(shinydashboard)
library(dplyr)
library(tidyverse)
library(reshape)
library(scales)


ecd <- read.csv("ecd-figures.csv")

c(
  "No of case" = "no_of_case",
  "Minor Case" = "minor_case",
  "All Non Fatal Case" = "all_non_fatal_case",
  "Fatal Case" = "fatal_case"
) -> vec

ui <- fluidPage(sidebarLayout(
  sidebarPanel
  (
    checkboxGroupInput("feature",
                       "Feature",
                       vec),
    sliderInput(
      "year",
      "Year",
      min = min(ecd$year),
      max = max(ecd$year),
      value = range(ecd$year),
      sep = "",
      step = 1
    )
  ),
  
  mainPanel(tabsetPanel(
    tabPanel("Plot", plotOutput("correlation_plot")),
    tabPanel("Table", tableOutput("ecd"))
  ))
))



server <- function(input, output) 
  yearrange <- reactive(
    ecd %>% subset(year %in% input$year[1]:input$year[2]) %>% select(c(year, input$feature))
  )
  
  output$correlation_plot <- renderPlot(
    
    ecdsubset <- yearrange()
    ecdsubset <- melt(ecdsubset, id = "year")
    validate(need(input$feature, 'Check at least one item.'))
    ggplot(ecdsubset,aes(x=year,y=value,color=variable))+geom_line(size=1)
    
  )
  output$ecd <- renderTable(
    yearrange()
  )
  


shinyApp(ui, server)

【讨论】:

for 1),问题是,如果我使用scale_x_continuous,小数点会重新出现.....例如2015.00、2015.25、2015.50、2015.75、2016.00。毫无意义。 我没有使用我的代码得到小数。也许您想将year 更改为因子? 应该是这个? validate(need(input$feature, 'Check at least one item.')) ecd$year &lt;- as.factor(ecd$year) ggplot(ecdsubset,aes(x=year,y=value,color=variable))+geom_line(size=1)+ scale_x_continuous(limits=c(input$year[1]:input$year[2])) 失败了..... 我已经更新了答案并添加了一张图片来展示我的结局。 嗯.....但是一旦我选择了一个更窄的范围,比如 2016 年到 2017 年,年份标签就是十进制形式,如下所示:drive.google.com/file/d/1MleXuwpQPAcNiBuNpFCxg3Bi23milYy2/…【参考方案2】:

除了 Ronak Shah 的回答之外,将此代码放到服务器部分 yeararrange

 mutate(across(where(is.numeric), as.integer)) %>% 

完整代码:

library(shiny)
library(shinydashboard)
library(dplyr)
library(tidyverse)
library(reshape)
library(scales)

ecd <- read.csv("ecd-figures.csv")

c(
    "No of case" = "no_of_case",
    "Minor Case" = "minor_case",
    "All Non Fatal Case" = "all_non_fatal_case",
    "Fatal Case" = "fatal_case"
) -> vec

ui <- fluidPage(sidebarLayout(
    sidebarPanel
    (
        checkboxGroupInput("feature",
                           "Feature",
                           vec),
        sliderInput(
            "year",
            "Year",
            min = min(ecd$year),
            max = max(ecd$year),
            range = c(min(ecd$year), max(ecd$year)),
            sep="",
            step = 1
        )
    ),
    
    mainPanel(tabsetPanel(
        tabPanel("Plot", plotOutput("correlation_plot")),
        tabPanel("Table", tableOutput("ecd"))
    ))
))



server <- function(input, output) 
    yearrange <- reactive(
        ecd %>% 
            mutate(across(where(is.numeric), as.integer)) %>% 
            subset(year %in% input$year[1]:input$year[2]) %>% 
            select(c(year, input$feature))
    )
    
    output$correlation_plot <- renderPlot(
        
        ecdsubset <- yearrange()
        ecdsubset <- melt(ecdsubset, id = "year")
        validate(need(input$feature, 'Check at least one item.'))
        ggplot(ecdsubset,aes(x=year,y=value,color=variable))+geom_line(size=1)+
            theme(legend.position = "none") +
            scale_x_discrete(limits=c(input$year[1]:input$year[2]))
        
    )
    output$ecd <- renderTable(
        yearrange()
    )
    


shinyApp(ui, server)

【讨论】:

先谢谢你。只要使用scale_x_discrete,您的建议就会起作用。但正如 Ronak Shah 提到的,我应该更好地使用 scale_x_continuous。也正因为如此,小数点还在……drive.google.com/file/d/1MleXuwpQPAcNiBuNpFCxg3Bi23milYy2/…【参考方案3】:

我最终采用了 Joshua Cook 的解决方案,即为标签中断编写一个额外的函数。完整代码:

library(shiny)
library(shinydashboard)
library(dplyr)
library(tidyverse)
library(reshape)
library(scales)



ecd <- read.csv("ecd-figures.csv")

c(
  "No of case" = "no_of_case",
  "Minor Case" = "minor_case",
  "All Non Fatal Case" = "all_non_fatal_case",
  "Fatal Case" = "fatal_case"
) -> vec

ui <- fluidPage(sidebarLayout(
  sidebarPanel
  (
    checkboxGroupInput("feature",
                       "Feature",
                       vec),
    sliderInput(
      "year",
      "Year",
      min = min(ecd$year),
      max = max(ecd$year),
      value = range(ecd$year),
      sep = "",
      step = 1
    )
  ),
  
  mainPanel(tabsetPanel(
    tabPanel("Plot", plotOutput("correlation_plot")),
    tabPanel("Table", tableOutput("ecd"))
  ))
))



server <- function(input, output) 
  yearrange <- reactive(
    ecd %>%
      subset(year %in% input$year[1]:input$year[2]) %>%
      select(c(year, input$feature))
  )
  
  integer_breaks <- function(n = 5, ...) 
    fxn <- function(a) 
      breaks <- floor(pretty(a, n, ...))
      names(breaks) <- attr(breaks, "labels")
      breaks
    
    return(fxn)
  
  
  
  output$correlation_plot <- renderPlot(
    ecdsubset <- yearrange()
    ecdsubset <- melt(ecdsubset, id = "year")
    validate(need(input$feature, 'Check at least one item.'))
    ggplot(ecdsubset, aes(x = year, y = value, color = variable)) + geom_line(size = 1) + scale_x_continuous(breaks = integer_breaks())
    
    
  )
  output$ecd <- renderTable(
    yearrange()
  )
  


shinyApp(ui, server)

我不明白的是,...integer_breaks &lt;- function(n = 5, ...) 中是什么意思?谢谢你的建议。

【讨论】:

以上是关于R shiny ggplot - 如何不让年份标签超出网格?的主要内容,如果未能解决你的问题,请参考以下文章

使用Shiny滑块控制ggplot上的输出

R闪亮:如何将滑块和单选按钮链接到ggplot

Shiny R仅绘制滑块范围的极值

在 R Shiny 的表中插入 ggplot barplot

将 ggplot 与 r-shiny 一起使用时出错

R Shiny 服务器未呈现正确的 ggplot 字体系列