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

Matplotlib pick_event在GeoDataFrame中无法触发的问题求助

问题:GeoPandas点图层无法触发Matplotlib pick_event事件

我通过GeoPandas绘制英国地图,并在地图上叠加parkrun跑步地点的坐标点,希望实现交互式选中这些坐标点后展示对应地点的信息,但调用fig.canvas.mpl_connect('pick_event', onclick)后功能完全无法正常工作,恳请帮忙排查原因。

可复现代码

import pandas as pd
import geopandas as gpd
import numpy as np
import matplotlib.pyplot as plt

##### Create hardcoded dataset ######
df = pd.DataFrame.from_dict({0: {'parkrun_name': 'Beeston',
  'location_name': 'Weirfields Recreation Ground',
  'longitude': -1.201737,
  'latitude': 52.913592,
  'Run Date': '12/11/2022',
  'Run Number': 370.0,
  'Pos': 107.0,
  'Time': '26:05',
  'Age Grade': '49.46%',
  'PB?': np.nan},
 1: {'parkrun_name': 'Colwick',
  'location_name': 'Colwick Country Park, Nottingham',
  'longitude': -1.09786,
  'latitude': 52.945171,
  'Run Date': '22/10/2022',
  'Run Number': 511.0,
  'Pos': 127.0,
  'Time': '29:44',
  'Age Grade': '43.39%',
  'PB?': np.nan},
 2: {'parkrun_name': 'Exmouth',
  'location_name': 'Exmouth',
  'longitude': -3.412392,
  'latitude': 50.614697,
  'Run Date': '24/12/2022',
  'Run Number': 189.0,
  'Pos': 197.0,
  'Time': '25:44',
  'Age Grade': '50.13%',
  'PB?': 'PB'},
}, orient='index')

###### Read in the UK Map File ######
uk = gpd.read_file("uk.geojson")

###### Convert df to geodf ######
gdf = gpd.GeoDataFrame(
    df, geometry=gpd.points_from_xy(df.longitude, df.latitude)
)
gdf.crs = "EPSG:4326"
gdf = gdf.to_crs(uk.crs)
###### Plot interactive map ######
%matplotlib widget

fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111)
uk.plot(ax=ax, alpha=0.8)

def onclick(event):
    ax = plt.gca()
    # ax.set_title(f"You selected {event.x}, {event.y}")
    
    line = event.artist
    xdata, ydata = line.get_data()
    ind = event.ind
    
    tx = f"{np.array([xdata[ind], ydata[ind]]).T}"
    
    ax.set_title(f"{tx}")
    
gdf[gdf['Run Date'].isna()].plot(ax=ax, color='black', marker='.', markersize=8, alpha=0.2, picker=20)
gdf[gdf['Run Date'].notna()].plot(ax=ax, color='#AAFF00', marker='.', markersize=50, picker=20)

ax.set_xlim(-7,2)
ax.set_ylim(49,60)

cid = fig.canvas.mpl_connect('pick_event', onclick)

问题排查与解决方案

核心问题1:坐标范围不匹配

你将gdf转换为了UK地图的CRS(通常是OSGB36,单位为米),但后续设置的ax.set_xlim(-7,2)和ax.set_ylim(49,60)是WGS84经纬度范围,这会导致所有点被移出可视区域,自然无法点击触发事件。

核心问题2:事件处理函数适配错误

GeoPandas绘制的点图层是PathCollection对象,而非代码中假设的Line2D对象,因此调用line.get_data()会报错(在widget环境下可能不显示错误信息),需要改用get_offsets()获取点坐标,再结合索引匹配原始数据。

修改后的代码

###### Plot interactive map ######
%matplotlib widget

fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111)
# 保持CRS一致,将UK地图转换为WGS84与gdf匹配
uk = uk.to_crs("EPSG:4326")
uk.plot(ax=ax, alpha=0.8)

# 存储每个图层对应的子集数据,方便点击时查询
layer_data = []
# 绘制无Run Date的点
na_layer = gdf[gdf['Run Date'].isna()].plot(ax=ax, color='black', marker='.', markersize=8, alpha=0.2, picker=20)
layer_data.append(gdf[gdf['Run Date'].isna()])
# 绘制有Run Date的点
not_na_layer = gdf[gdf['Run Date'].notna()].plot(ax=ax, color='#AAFF00', marker='.', markersize=50, picker=20)
layer_data.append(gdf[gdf['Run Date'].notna()])

# 对应WGS84的坐标范围,无需修改
ax.set_xlim(-7,2)
ax.set_ylim(49,60)

def onclick(event):
    ax = plt.gca()
    # 获取点击的图层索引
    layer_idx = [na_layer, not_na_layer].index(event.artist)
    # 获取点击的点索引
    point_idx = event.ind[0]
    # 获取对应的数据行
    selected_row = layer_data[layer_idx].iloc[point_idx]
    # 设置标题显示地点信息
    ax.set_title(f"选中地点:{selected_row['parkrun_name']}\n跑步日期:{selected_row['Run Date']}")

cid = fig.canvas.mpl_connect('pick_event', onclick)

关键修改说明

  1. 将UK地图转换为WGS84(EPSG:4326),与gdf保持CRS一致,确保坐标范围匹配,点能显示在可视区域内。
  2. 存储每个绘制图层对应的子集数据,方便点击时快速查询。
  3. 修改onclick函数,通过图层索引和点索引匹配原始数据,展示具体的地点信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 07:35:20