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

ggplot+coord_map自定义tooltip:nearPoint匹配偏移问题求助

Fixing nearPoints Offset with coord_map in Shiny + ggplot2

I get it—when using coord_map() (especially projections like polyconic), the nearPoints() function keeps mismatching the correct hover location because it’s comparing the plot’s transformed coordinates against your raw geographic (lat/long) data. The projection warps the coordinate system, so your original long/lat values don’t line up with what’s actually rendered on the screen. Here’s how to fix this:

The Root Cause

coord_map() applies a projection transformation to your data in the background, converting geographic coordinates to flat plot-ready coordinates. But nearPoints() uses your untransformed counties data, while input$plot_hover returns coordinates from the projected plot space. This mismatch is why the tooltips are offset.

Solution: Use Transformed Plot Data for nearPoints

We need to extract the exact data ggplot uses to render the map (after projection) and use that for the nearPoints() check. Here’s the revised working code:

library(ggplot2)
library(mapdata)
library(data.table)
library(shiny)

map.county <- map_data('county')
counties <- data.table(map.county)

ui <- fluidPage(
  titlePanel("NearPoints using a map"),
  div(
    style = "position:relative",
    plotOutput("county_map", hover = hoverOpts("plot_hover", delay = 100, delayType = "debounce")),
    uiOutput("hover_info")
  )
)

server <- function(input, output) {
  # Create plot and extract transformed data reactively
  map_plot <- reactive({
    # Build the base plot with projection
    p <- ggplot(counties, aes(x=long, y=lat, group = group)) +
      geom_polygon(colour = "grey") +
      coord_map("polyconic")
    
    # Extract the data ggplot actually renders (after projection)
    gb <- ggplot_build(p)
    transformed_data <- gb$data[[1]]
    
    # Merge back original region/subregion labels using group ID
    transformed_data <- merge(
      transformed_data, 
      unique(counties[, .(group, region, subregion)]), 
      by = "group"
    )
    
    # Return both plot and transformed data
    list(plot = p, data = transformed_data)
  })
  
  output$county_map <- renderPlot({
    map_plot()$plot
  })
  
  output$hover_info <- renderUI({
    hover <- input$plot_hover
    transformed_data <- map_plot()$data
    
    # Use transformed data for accurate nearPoints matching
    point <- nearPoints(transformed_data, hover, threshold = 5, maxpoints = 1, addDist = TRUE)
    if (nrow(point) == 0) return(NULL)
    
    # Use direct pixel coordinates for tooltip positioning
    style <- paste0(
      "position:absolute; z-index:100; background-color: rgba(245, 245, 245, 0.85); ",
      "left:", hover$coords_img$x + 10, "px; top:", hover$coords_img$y - 100, "px;"
    )
    
    wellPanel(
      style = style,
      p(HTML(paste0(
        "<b>Region:</b> ", point$region, "<br/>",
        "<b>County:</b> ", point$subregion, "<br/>"
      )))
    )
  })
}

shinyApp(ui = ui, server = server)

Key Changes Breakdown

  1. Extract Transformed Data: ggplot_build() gives us the data after projection, which has x/y values that exactly match the plot’s coordinate space.
  2. Merge Metadata: We link the transformed data back to the original region and subregion labels using the group column, so we can still display those details in the tooltip.
  3. Simplified Tooltip Placement: Instead of calculating percentages, we use hover$coords_img to get the exact pixel position of the mouse on the plot—this makes tooltip placement precise without extra math.
  4. Reactive Plot Object: Wrapping the plot and data in a reactive ensures it’s only built once (or when dependencies change), boosting performance.

This approach makes sure nearPoints() compares like-for-like coordinates, so the hover always matches the correct county—even with complex projections like polyconic.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:56:09