ggplot+coord_map自定义tooltip:nearPoint匹配偏移问题求助
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
- Extract Transformed Data:
ggplot_build()gives us the data after projection, which hasx/yvalues that exactly match the plot’s coordinate space. - Merge Metadata: We link the transformed data back to the original
regionandsubregionlabels using thegroupcolumn, so we can still display those details in the tooltip. - Simplified Tooltip Placement: Instead of calculating percentages, we use
hover$coords_imgto get the exact pixel position of the mouse on the plot—this makes tooltip placement precise without extra math. - 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

