You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于R实现可点击修改属性的交互式选举人团热力地图技术求助

Great question! I've built similar interactive map tools in Shiny before, and here's a solid solution that addresses your core needs: click-to-toggle region results, persist those changes, and calculate aggregated totals in real-time.

Solution Overview

We'll build a Shiny app using ggplot2 + plotly for interactive mapping, paired with Shiny's reactive values to track state result changes. This approach works because:

  • Plotly lets us capture click events and extract the exact region that was clicked
  • Reactive values in Shiny let us update the underlying data and automatically refresh the map/totals
  • We can easily integrate custom metrics (like electoral votes) for post-modification calculations
Step-by-Step Implementation

1. Install Required Packages

First, make sure you have these packages installed:

install.packages(c("shiny", "ggplot2", "maps", "plotly", "dplyr", "usdata"))

2. Full Shiny App Code

library(shiny)
library(ggplot2)
library(maps)
library(plotly)
library(dplyr)
library(usdata)

# Get base state map data
usa <- map_data("state")

# Get electoral college votes per state (clean up to match map region names)
electoral_votes <- usdata::electoral_college() %>%
  mutate(region = tolower(state)) %>%
  select(region, votes)

# Initialize state results with your default probabilities
set.seed(123) # For reproducibility
initial_results <- usa %>%
  distinct(region) %>%
  mutate(
    result = sample(
      c("Rep", "Dem", "Toss-Up"),
      size = n(),
      prob = c(0.30, 0.40, 0.30),
      replace = TRUE
    )
  ) %>%
  left_join(electoral_votes, by = "region")

# Merge initial results with map data
initial_map_data <- usa %>%
  left_join(initial_results, by = "region")

ui <- fluidPage(
  titlePanel("Interactive State Result Map"),
  fluidRow(
    column(8, plotlyOutput("state_map")),
    column(4,
           h3("Electoral Vote Totals"),
           verbatimTextOutput("vote_totals")
    )
  )
)

server <- function(input, output) {
  # Reactive value to store the current state of the map data (updates when clicks happen)
  current_map_data <- reactiveVal(initial_map_data)
  
  # Capture plotly click events
  observeEvent(event_data("plotly_click"), {
    clicked_state <- event_data("plotly_click")$customdata
    
    # Update the result for the clicked state (cycle through Rep → Dem → Toss-Up → Rep)
    updated_data <- current_map_data() %>%
      group_by(region) %>%
      mutate(
        result = case_when(
          region == clicked_state & result == "Rep" ~ "Dem",
          region == clicked_state & result == "Dem" ~ "Toss-Up",
          region == clicked_state & result == "Toss-Up" ~ "Rep",
          TRUE ~ result
        )
      ) %>%
      ungroup()
    
    # Update the reactive value with the new data
    current_map_data(updated_data)
  })
  
  # Render the interactive map
  output$state_map <- renderPlotly({
    p <- ggplot() +
      geom_map(
        data = current_map_data(),
        map = usa,
        aes(long, lat, map_id = region, fill = result, customdata = region),
        color = "black"
      ) +
      scale_fill_manual(
        values = c("Dem" = "blue", "Rep" = "red", "Toss-Up" = "grey"),
        name = "Result"
      ) +
      coord_map() +
      theme_void()
    
    # Convert ggplot to plotly (preserves interactivity)
    ggplotly(p) %>%
      layout(hovermode = "closest") %>%
      event_register("plotly_click")
  })
  
  # Calculate and display electoral vote totals
  output$vote_totals <- renderPrint({
    vote_summary <- current_map_data() %>%
      distinct(region, result, votes) %>%
      group_by(result) %>%
      summarize(total_votes = sum(votes, na.rm = TRUE)) %>%
      filter(result != "Toss-Up")
    
    cat("Democratic:", vote_summary$total_votes[vote_summary$result == "Dem"], "\n")
    cat("Republican:", vote_summary$total_votes[vote_summary$result == "Rep"], "\n")
  })
}

shinyApp(ui, server)

3. Key Features Explained

  • Reactive Data Storage: current_map_data() is a reactive value that holds the latest state of our map data. Every time a region is clicked, we update this value, which triggers an automatic refresh of both the map and vote totals.
  • Click Handling: The observeEvent() listens for plotly_click events. We extract the clicked region's name from customdata (added to the ggplot aes so Plotly can track it) and cycle the result value as needed.
  • Aggregated Calculation: We use distinct() to get one row per region, then group by result to sum up votes for each party.
  • Map Customization: The scale_fill_manual() matches your requested colors, and theme_void() cleans up the map to focus on the regions themselves.

4. Why This Solves Your Earlier Issues

  • When you tried Plotly/Leaflet before, you likely didn't tie click events to reactive data updates in Shiny. This is the missing piece—Shiny's reactive framework lets us persist changes and propagate them across the entire app.
  • mapedit is great for selecting features, but it's not designed for direct data modification in a Shiny workflow. This approach gives you full control over how clicks modify your data.
Customization Tips
  • Adjust the result cycle logic (e.g., only toggle between two options instead of three) by modifying the case_when() statement.
  • Add a reset button to revert all regions to their initial state by adding an actionButton() and updating current_map_data() back to initial_map_data.
  • Replace electoral vote data with your own custom metrics (since your actual use case isn't elections) by swapping out the electoral_votes data frame with your own dataset.

内容的提问来源于stack exchange,提问作者tifu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:58:00