北京天气预报 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.rdaima.com, www.rdaizuo.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**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值