北京天气预报 R Shiny 应用

# 北京天气预报 R Shiny 应用

# 日期:2025年

# 加载必要的库

library(shiny)

library(shinydashboard)

library(DT)

library(plotly)

library(dplyr)

library(ggplot2)

library(lubridate)

library(jsonlite)

library(httr)

library(shinycssloaders)

# 模拟天气数据函数(实际应用中应该调用真实的天气API)

generate_weather_data <- function() {

  # 生成未来7天的模拟天气数据

  dates <- seq(from = Sys.Date(), by = "day", length.out = 7)


  weather_data <- data.frame(

    date = dates,

    weekday = weekdays(dates),

    temperature_high = round(runif(7, 15, 35), 1),

    temperature_low = round(runif(7, 5, 20), 1),

    humidity = round(runif(7, 30, 90), 0),

    wind_speed = round(runif(7, 5, 25), 1),

    pressure = round(runif(7, 1010, 1030), 0),

    visibility = round(runif(7, 8, 20), 1),

    uv_index = sample(1:10, 7, replace = TRUE),

    weather_condition = sample(c("晴朗", "多云", "阴天", "小雨", "中雨", "雷阵雨", "雾霾"), 7, replace = TRUE),

    air_quality = sample(c("优", "良", "轻度污染", "中度污染", "重度污染"), 7, replace = TRUE, prob = c(0.3, 0.4, 0.2, 0.08, 0.02))

  )


  # 确保最低温度小于最高温度

  weather_data$temperature_low <- pmin(weather_data$temperature_low, weather_data$temperature_high - 5)


  return(weather_data)

}

# 获取天气图标

get_weather_icon <- function(condition) {

  icons <- list(

    "晴朗" = "☀️",

    "多云" = "⛅",

    "阴天" = "☁️",

    "小雨" = "🌦️",

    "中雨" = "🌧️",

    "雷阵雨" = "⛈️",

    "雾霾" = "🌫️"

  )

  return(icons[[condition]] %||% "🌤️")

}

# 获取空气质量颜色

get_aqi_color <- function(quality) {

  colors <- list(

    "优" = "#00e400",

    "良" = "#ffff00",

    "轻度污染" = "#ff7e00",

    "中度污染" = "#ff0000",

    "重度污染" = "#8f3f97"

  )

  return(colors[[quality]] %||% "#999999")

}

# UI 界面设计

ui <- dashboardPage(

  # 页面头部

  dashboardHeader(

    title = tags$div(

      style = "font-family: 'Microsoft YaHei'; font-weight: bold;",

      "🌤️ 北京天气预报系统"

    )

  ),


  # 侧边栏

  dashboardSidebar(

    width = 250,

    sidebarMenu(

      menuItem("🏠 天气概览", tabName = "overview", icon = icon("home")),

      menuItem("📊 详细数据", tabName = "details", icon = icon("chart-bar")),

      menuItem("📈 趋势分析", tabName = "trends", icon = icon("line-chart")),

      menuItem("🗺️ 天气地图", tabName = "map", icon = icon("map")),

      menuItem("⚙️ 设置", tabName = "settings", icon = icon("cog")),


      br(),

      div(style = "padding: 20px;",

          h4("📍 当前位置", style = "color: white; margin-bottom: 10px;"),

          p("北京市", style = "color: #ecf0f1; font-size: 16px;"),

          p("海淀区", style = "color: #bdc3c7; font-size: 14px;"),

          br(),

          actionButton("refresh_data", "🔄 刷新数据",

                      class = "btn-primary",

                      style = "width: 100%; background: linear-gradient(45deg, #3498db, #2980b9);")

      )

    )

  ),


  # 主体内容

  dashboardBody(

    # 自定义CSS样式

    tags$head(

      tags$style(HTML("

        .content-wrapper, .right-side {

          background-color: #f4f7fc;

        }

        .box {

          border-radius: 8px;

          box-shadow: 0 2px 10px rgba(0,0,0,0.1);

        }

        .weather-card {

          background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

          color: white;

          border-radius: 15px;

          padding: 20px;

          margin: 10px;

          text-align: center;

          box-shadow: 0 4px 15px rgba(0,0,0,0.2);

        }

        .weather-icon {

          font-size: 48px;

          margin-bottom: 10px;

        }

        .temperature {

          font-size: 32px;

          font-weight: bold;

          margin: 10px 0;

        }

        .weather-condition {

          font-size: 18px;

          margin-bottom: 15px;

        }

        .weather-details {

          display: flex;

          justify-content: space-around;

          flex-wrap: wrap;

        }

        .detail-item {

          text-align: center;

          margin: 5px;

        }

        .detail-value {

          font-size: 16px;

          font-weight: bold;

        }

        .detail-label {

          font-size: 12px;

          opacity: 0.8;

        }

        .air-quality-badge {

          display: inline-block;

          padding: 5px 15px;

          border-radius: 20px;

          color: white;

          font-weight: bold;

          margin-top: 10px;

        }

      "))

    ),


    tabItems(

      # 天气概览页面

      tabItem(tabName = "overview",

              fluidRow(

                # 今日天气卡片

                column(12,

                      h2("📅 今日天气", style = "color: #2c3e50; margin-bottom: 20px;"),

                      div(id = "today_weather", class = "weather-card",

                          withSpinner(uiOutput("today_weather_card"), type = 6, color = "#3498db")

                      )

                )

              ),


              br(),


              fluidRow(

                # 核心指标卡片

                column(3,

                      valueBoxOutput("temp_box", width = NULL)

                ),

                column(3,

                      valueBoxOutput("humidity_box", width = NULL)

                ),

                column(3,

                      valueBoxOutput("wind_box", width = NULL)

                ),

                column(3,

                      valueBoxOutput("aqi_box", width = NULL)

                )

              ),


              br(),


              fluidRow(

                # 7天预报

                column(12,

                      box(

                        title = "📅 7天天气预报", status = "primary", solidHeader = TRUE, width = NULL,

                        withSpinner(uiOutput("week_forecast"), type = 6, color = "#3498db")

                      )

                )

              )

      ),


      # 详细数据页面

      tabItem(tabName = "details",

              fluidRow(

                column(12,

                      h2("📊 详细天气数据", style = "color: #2c3e50; margin-bottom: 20px;")

                )

              ),


              fluidRow(

                column(12,

                      box(

                        title = "🗃️ 天气数据表", status = "info", solidHeader = TRUE, width = NULL,

                        withSpinner(DT::dataTableOutput("weather_table"), type = 6, color = "#3498db")

                      )

                )

              ),


              fluidRow(

                column(6,

                      box(

                        title = "🌡️ 温度统计", status = "warning", solidHeader = TRUE, width = NULL,

                        withSpinner(plotlyOutput("temp_stats"), type = 6, color = "#f39c12")

                      )

                ),

                column(6,

                      box(

                        title = "💨 风速&湿度分析", status = "success", solidHeader = TRUE, width = NULL,

                        withSpinner(plotlyOutput("wind_humidity"), type = 6, color = "#27ae60")

                      )

                )

              )

      ),


      # 趋势分析页面

      tabItem(tabName = "trends",

              fluidRow(

                column(12,

                      h2("📈 天气趋势分析", style = "color: #2c3e50; margin-bottom: 20px;")

                )

              ),


              fluidRow(

                column(12,

                      box(

                        title = "🌡️ 温度变化趋势", status = "primary", solidHeader = TRUE, width = NULL,

                        withSpinner(plotlyOutput("temperature_trend"), type = 6, color = "#3498db")

                      )

                )

              ),


              fluidRow(

                column(6,

                      box(

                        title = "💧 湿度趋势", status = "info", solidHeader = TRUE, width = NULL,

                        withSpinner(plotlyOutput("humidity_trend"), type = 6, color = "#17a2b8")

                      )

                ),

                column(6,

                      box(

                        title = "🌪️ 风速&气压变化", status = "warning", solidHeader = TRUE, width = NULL,

                        withSpinner(plotlyOutput("wind_pressure_trend"), type = 6, color = "#ffc107")

                      )

                )

              )

      ),


      # 天气地图页面

      tabItem(tabName = "map",

              fluidRow(

                column(12,

                      h2("🗺️ 北京天气地图", style = "color: #2c3e50; margin-bottom: 20px;")

                )

              ),


              fluidRow(

                column(12,

                      box(

                        title = "🌍 实时天气雷达图", status = "success", solidHeader = TRUE, width = NULL, height = "600px",

                        div(style = "text-align: center; padding: 50px;",

                            h3("🚧 天气雷达图功能开发中", style = "color: #7f8c8d;"),

                            p("此功能需要接入真实的天气雷达API", style = "color: #95a5a6;"),

                            img(src = "https://via.placeholder.com/400x300/3498db/ffffff?text=Weather+Radar",

                                style = "border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.2);")

                        )

                      )

                )

              )

      ),


      # 设置页面

      tabItem(tabName = "settings",

              fluidRow(

                column(12,

                      h2("⚙️ 应用设置", style = "color: #2c3e50; margin-bottom: 20px;")

                )

              ),


              fluidRow(

                column(6,

                      box(

                        title = "🌐 API配置", status = "primary", solidHeader = TRUE, width = NULL,

                        textInput("api_key", "天气API密钥:", value = "demo_key_12345"),

                        selectInput("api_provider", "API服务商:",

                                    choices = list("OpenWeatherMap" = "openweather",

                                                    "和风天气" = "qweather",

                                                    "中国天气网" = "weather.com.cn"),

                                    selected = "openweather"),

                        numericInput("update_interval", "数据更新间隔(分钟):", value = 30, min = 5, max = 120),

                        actionButton("save_settings", "💾 保存设置", class = "btn-success")

                      )

                ),

                column(6,

                      box(

                        title = "🎨 显示设置", status = "info", solidHeader = TRUE, width = NULL,

                        selectInput("temp_unit", "温度单位:",

                                    choices = list("摄氏度 (°C)" = "celsius",

                                                    "华氏度 (°F)" = "fahrenheit"),

                                    selected = "celsius"),

                        selectInput("wind_unit", "风速单位:",

                                    choices = list("公里/小时" = "kmh",

                                                    "米/秒" = "ms",

                                                    "英里/小时" = "mph"),

                                    selected = "kmh"),

                        checkboxInput("show_animations", "启用动画效果", value = TRUE),

                        checkboxInput("dark_mode", "深色模式", value = FALSE),

                        actionButton("reset_settings", "🔄 重置设置", class = "btn-warning")

                      )

                )

              ),


              fluidRow(

                column(12,

                      box(

                        title = "ℹ️ 关于应用", status = "success", solidHeader = TRUE, width = NULL,

                        h4("北京天气预报系统 v1.0"),

                        p("这是一个基于R Shiny开发的天气预报应用,提供北京地区的详细天气信息。"),

                        h5("主要功能:"),

                        tags$ul(

                          tags$li("实时天气数据展示"),

                          tags$li("7天天气预报"),

                          tags$li("详细气象数据分析"),

                          tags$li("天气趋势图表"),

                          tags$li("交互式数据可视化")

                        ),

                        hr(),

                        p("数据来源:模拟数据(演示版本)", style = "color: #7f8c8d; font-style: italic;"),

                        p("开发者:AI助手 | 最后更新:2025年", style = "color: #95a5a6; font-size: 12px;")

                      )

                )

              )

      )

    )

  )

)

# Server 服务器逻辑

server <- function(input, output, session) {


  # 响应式数据

  weather_data <- reactive({

    # 当刷新按钮被点击时重新生成数据

    input$refresh_data

    generate_weather_data()

  })


  # 今日天气卡片

  output$today_weather_card <- renderUI({

    data <- weather_data()

    today <- data[1, ]


    tagList(

      div(class = "weather-icon", get_weather_icon(today$weather_condition)),

      div(class = "temperature",

          paste0(today$temperature_high, "°C / ", today$temperature_low, "°C")),

      div(class = "weather-condition", today$weather_condition),

      div(class = "air-quality-badge",

          style = paste0("background-color: ", get_aqi_color(today$air_quality)),

          paste("空气质量:", today$air_quality)),

      br(),

      div(class = "weather-details",

          div(class = "detail-item",

              div(class = "detail-value", paste0(today$humidity, "%")),

              div(class = "detail-label", "湿度")

          ),

          div(class = "detail-item",

              div(class = "detail-value", paste0(today$wind_speed, " km/h")),

              div(class = "detail-label", "风速")

          ),

          div(class = "detail-item",

              div(class = "detail-value", paste0(today$pressure, " hPa")),

              div(class = "detail-label", "气压")

          ),

          div(class = "detail-item",

              div(class = "detail-value", today$uv_index),

              div(class = "detail-label", "紫外线指数")

          )

      )

    )

  })


  # 温度指标卡

  output$temp_box <- renderValueBox({

    data <- weather_data()

    today <- data[1, ]

    valueBox(

      value = paste0(today$temperature_high, "°C"),

      subtitle = "今日最高温度",

      icon = icon("thermometer-half"),

      color = "red"

    )

  })


  # 湿度指标卡

  output$humidity_box <- renderValueBox({

    data <- weather_data()

    today <- data[1, ]

    valueBox(

      value = paste0(today$humidity, "%"),

      subtitle = "相对湿度",

      icon = icon("tint"),

      color = "blue"

    )

  })


  # 风速指标卡

  output$wind_box <- renderValueBox({

    data <- weather_data()

    today <- data[1, ]

    valueBox(

      value = paste0(today$wind_speed, " km/h"),

      subtitle = "风速",

      icon = icon("wind"),

      color = "green"

    )

  })


  # 空气质量指标卡

  output$aqi_box <- renderValueBox({

    data <- weather_data()

    today <- data[1, ]

    color_map <- list("优" = "green", "良" = "yellow", "轻度污染" = "orange",

                      "中度污染" = "red", "重度污染" = "purple")

    valueBox(

      value = today$air_quality,

      subtitle = "空气质量",

      icon = icon("leaf"),

      color = color_map[[today$air_quality]] %||% "gray"

    )

  })


  # 7天预报

  output$week_forecast <- renderUI({

    data <- weather_data()


    cards <- lapply(1:nrow(data), function(i) {

      day <- data[i, ]

      column(

        width = 12/7,

        div(

          style = "background: linear-gradient(135deg, #74b9ff, #0984e3);

                  color: white; border-radius: 10px; padding: 15px;

                  margin: 5px; text-align: center; min-height: 200px;",

          h5(day$weekday, style = "margin-bottom: 10px;"),

          div(style = "font-size: 24px; margin: 10px 0;", get_weather_icon(day$weather_condition)),

          p(day$weather_condition, style = "font-size: 14px; margin: 5px 0;"),

          p(paste0(day$temperature_high, "°/", day$temperature_low, "°"),

            style = "font-size: 16px; font-weight: bold; margin: 10px 0;"),

          p(paste0("💧 ", day$humidity, "%"), style = "font-size: 12px; margin: 2px 0;"),

          p(paste0("💨 ", day$wind_speed, " km/h"), style = "font-size: 12px; margin: 2px 0;")

        )

      )

    })


    do.call(fluidRow, cards)

  })


  # 天气数据表

  output$weather_table <- DT::renderDataTable({

    data <- weather_data()


    # 格式化数据表

    formatted_data <- data %>%

      mutate(

        日期 = format(date, "%Y-%m-%d"),

        星期 = weekday,

        天气 = paste0(get_weather_icon(weather_condition), " ", weather_condition),

        最高温 = paste0(temperature_high, "°C"),

        最低温 = paste0(temperature_low, "°C"),

        湿度 = paste0(humidity, "%"),

        风速 = paste0(wind_speed, " km/h"),

        气压 = paste0(pressure, " hPa"),

        能见度 = paste0(visibility, " km"),

        紫外线 = uv_index,

        空气质量 = air_quality

      ) %>%

      select(日期, 星期, 天气, 最高温, 最低温, 湿度, 风速, 气压, 能见度, 紫外线, 空气质量)


    DT::datatable(

      formatted_data,

      options = list(

        pageLength = 10,

        scrollX = TRUE,

        dom = 'Bfrtip',

        buttons = c('copy', 'csv', 'excel', 'pdf', 'print')

      ),

      class = "display nowrap compact",

      escape = FALSE

    )

  })


  # 温度统计图

  output$temp_stats <- renderPlotly({

    data <- weather_data()


    p <- ggplot(data, aes(x = date)) +

      geom_ribbon(aes(ymin = temperature_low, ymax = temperature_high),

                  fill = "#3498db", alpha = 0.3) +

      geom_line(aes(y = temperature_high, color = "最高温"), size = 1.2) +

      geom_line(aes(y = temperature_low, color = "最低温"), size = 1.2) +

      geom_point(aes(y = temperature_high, color = "最高温"), size = 3) +

      geom_point(aes(y = temperature_low, color = "最低温"), size = 3) +

      scale_color_manual(values = c("最高温" = "#e74c3c", "最低温" = "#3498db")) +

      labs(title = "温度变化", x = "日期", y = "温度 (°C)", color = "类型") +

      theme_minimal() +

      theme(

        plot.title = element_text(hjust = 0.5, size = 16, color = "#2c3e50"),

        legend.position = "bottom"

      )


    ggplotly(p, tooltip = c("x", "y", "colour"))

  })


  # 风速湿度分析

  output$wind_humidity <- renderPlotly({

    data <- weather_data()


    p <- ggplot(data, aes(x = wind_speed, y = humidity,

                          color = weather_condition, size = pressure)) +

      geom_point(alpha = 0.7) +

      geom_smooth(method = "lm", se = FALSE, color = "#95a5a6") +

      scale_size_continuous(range = c(3, 8)) +

      labs(title = "风速与湿度关系",

          x = "风速 (km/h)", y = "湿度 (%)",

          color = "天气状况", size = "气压 (hPa)") +

      theme_minimal() +

      theme(

        plot.title = element_text(hjust = 0.5, size = 16, color = "#2c3e50"),

        legend.position = "bottom"

      )


    ggplotly(p, tooltip = c("x", "y", "colour", "size"))

  })


  # 温度趋势

  output$temperature_trend <- renderPlotly({

    data <- weather_data()


    p <- plot_ly(data, x = ~date, type = 'scatter', mode = 'lines+markers') %>%

      add_trace(y = ~temperature_high, name = '最高温度',

                line = list(color = '#e74c3c', width = 3),

                marker = list(size = 8)) %>%

      add_trace(y = ~temperature_low, name = '最低温度',

                line = list(color = '#3498db', width = 3),

                marker = list(size = 8)) %>%

      layout(

        title = list(text = "未来7天温度趋势", font = list(size = 18, color = '#2c3e50')),

        xaxis = list(title = "日期"),

        yaxis = list(title = "温度 (°C)"),

        hovermode = 'x unified',

        showlegend = TRUE

      )


    p

  })


  # 湿度趋势

  output$humidity_trend <- renderPlotly({

    data <- weather_data()


    p <- plot_ly(data, x = ~date, y = ~humidity, type = 'scatter', mode = 'lines+markers',

                line = list(color = '#17a2b8', width = 3),

                marker = list(size = 8, color = '#17a2b8')) %>%

      layout(

        title = list(text = "湿度变化趋势", font = list(size = 16, color = '#2c3e50')),

        xaxis = list(title = "日期"),

        yaxis = list(title = "湿度 (%)"),

        hovermode = 'x'

      )


    p

  })


  # 风速气压趋势

  output$wind_pressure_trend <- renderPlotly({

    data <- weather_data()


    p <- plot_ly(data, x = ~date) %>%

      add_trace(y = ~wind_speed, name = '风速', type = 'scatter', mode = 'lines+markers',

                yaxis = 'y', line = list(color = '#27ae60', width = 2),

                marker = list(size = 6)) %>%

      add_trace(y = ~pressure, name = '气压', type = 'scatter', mode = 'lines+markers',

                yaxis = 'y2', line = list(color = '#f39c12', width = 2),

                marker = list(size = 6)) %>%

      layout(

        title = list(text = "风速与气压变化", font = list(size = 16, color = '#2c3e50')),

        xaxis = list(title = "日期"),

        yaxis = list(title = "风速 (km/h)", side = 'left'),

        yaxis2 = list(title = "气压 (hPa)", side = 'right', overlaying = 'y'),

        hovermode = 'x unified',

        showlegend = TRUE

      )


    p

  })


  # 设置保存

  observeEvent(input$save_settings, {

    showNotification("设置已保存!", type = "success", duration = 3)

  })


  # 设置重置

  observeEvent(input$reset_settings, {

    showNotification("设置已重置!", type = "warning", duration = 3)

  })

}

# 启动应用

shinyApp(ui = ui, server = server)

www.rdaizuo.com

www.daixie.it.com

www.rcodedaixie.com


**专业R语言辅导 | Python编程 | 数据分析 Data analysis | 统计分析 Statistics | 数据挖掘 Data mining | 机器学习 Machine learning | 留学生作业代做代写|6.864|9.520|6-867|CS229|CS231n|CS236|CS224n|STATS 202|STATS 203|STAT 110|STAT 104|CS109|BIOS221|10-701|10-605|10-607|10-601|10-603|10-604|STAT 705|STAT 707|COMS4771|COMS5771|COMS5733|COMS4733|STAT4203|STAT4204|STAT4205|STAT4206|STAT 133|STAT 134|DATA C88|CS 265|STAT 101A|STAT 100A|CS273A|CSE250A|COGS118A|CS-GY.6923|BUSF-GB.2397|CS 542|STAT 581|MLMI 201|MLMI 202|COMP0087|COMP0088|COMP01011|COMP3008|INFR11136|INFR11218|DATA1001|CSC311H1|CSC411|CSC413|CSC414|CSC412|STA302|STA2453H|STAT 302|DSCI511|DSCI512|DSCI513|DSCI514|STAT 540|STAT 541|CPSC 587|STAT 517|COMP 551|COMP 520|STAT 520|STAT 521|STAT 4500|STAT 5805|STAT 5806|STAT 4600|COMP5805|COMP90051|COMP90053|COMP90054|COMP90057|MATH90010|MATH90011|MATH90012|STAT30001|COMP1730|STAT3001|STAT3002|STAT3003|STAT3004|STAT3005|STAT3006|MATH3001|COMP5311|COMP5312|COMP5313|COMP5314|COMP5315|COMP5316|COMP5317|COMP5318|STAT5001|STAT5002|STAT5003|STAT5004|FIT5097|FIT5098|FIT5099|FIT5100|MTH5001|MTH5002|MTH5003**

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容