基于Cartopy实现鼠标左键点击选国家并上色的功能需求与实现
在Cartopy地图上实现点击国家打印名称并上色的功能
已完成功能完善,当前代码支持对任意国家进行选择/取消选择操作:点击国家时会打印名称并上色,再次点击可恢复初始灰色。
import pandas as pd import matplotlib.pyplot as plt import matplotlib as mpl import matplotlib.animation as animation import cartopy import cartopy.crs as ccrs import cartopy.io.shapereader as shpreader from math import log from math import exp from matplotlib import colors from shapely.geometry.multipolygon import MultiPolygon # 模拟数据:1960-1963年部分国家可再生能源发电占比 Indicator_df = pd.DataFrame({ 'CountryName': ['United States'] * 4 + ['Argentina'] * 4, 'Year': [1960, 1961, 1962, 1963] * 2, 'Value': [5, 10, 20, 30] * 2 }) # 配置颜色映射和色标 norm = mpl.colors.Normalize(vmin=0, vmax=30) colors_in_map = [] logbase = exp(1) for i in range(30): val = log(i + 1, logbase) / log(31, logbase) colors_in_map.append((1 - val, val, 0)) cmap = colors.ListedColormap(colors_in_map) # 加载Natural Earth的国家边界数据 shpfilename = shpreader.natural_earth(resolution='110m', category='cultural', name='admin_0_countries') reader = shpreader.Reader(shpfilename) countries_map = reader.records() facecolor = 'gray' edgecolor = 'black' # 创建地图画布 fig, ax = plt.subplots(figsize=(12, 6), subplot_kw={'projection': ccrs.PlateCarree()}) # 存储国家几何与绘图对象的字典 geom_dict = {} country_to_geom_and_artist = {} def init_run(): """初始化绘制所有灰色国家,并构建查询字典""" for n, country in enumerate(countries_map): # 统一处理Polygon和MultiPolygon类型 if country.geometry.geom_type == "Polygon": geom = MultiPolygon([country.geometry]) else: geom = country.geometry # 添加国家几何到地图并记录绘图对象 feature_artist = ax.add_geometries(country.geometry, ccrs.PlateCarree(), facecolor=facecolor, edgecolor=edgecolor, label=repr(country.attributes['NAME_CIAWF'])) geom_dict[country.attributes['NAME_CIAWF']] = feature_artist country_to_geom_and_artist[country.attributes['NAME_CIAWF']] = (country.geometry, feature_artist) def run(data, cname='United States'): """根据年份更新指定国家的颜色""" year = 1960 + data year_df = Indicator_df[Indicator_df['Year'] == year] for i, row in year_df.iterrows(): geom = geom_dict[cname] value = row['Value'] # 计算颜色值(基于对数映射) greenamount = (log(float(value) + 1, logbase) / log(31, logbase)) facecolor = (1 - greenamount, greenamount, 0) # 更新国家区域颜色 geom._feature._kwargs['facecolor'] = facecolor ax.set_title(cname) # 添加颜色条 cax = fig.add_axes([0.92, 0.2, 0.02, 0.6]) cb = mpl.colorbar.ColorbarBase(cax, cmap=cmap, norm=norm, spacing='proportional') cb.set_label('可再生能源发电占比 %') # 初始化地图 init_run() run(0) # 处理鼠标点击事件 import shapely.geometry as sgeom clist = [] def onclick(event): if event.button == 1: # 响应左键点击 if event.inaxes and isinstance(event.inaxes, cartopy.mpl.geoaxes.GeoAxes): ax = event.inaxes # 将点击坐标转换为经纬度 target = ccrs.PlateCarree() lon, lat = target.transform_point(event.xdata, event.ydata, ax.projection) point = sgeom.Point(lon, lat) # 遍历所有国家,判断点击点是否在国家范围内 for country, (geom, artist) in country_to_geom_and_artist.items(): if geom.contains(point): print(f'点击了:{country}') # 切换选择状态并更新颜色 if country in clist: clist.remove(country) run(0, country) # 恢复初始灰色 else: clist.append(country) run(2, country) # 设置为1962年对应占比的颜色 plt.draw() # 重绘地图 break # 绑定点击事件 plt.connect('button_press_event', onclick) plt.rcParams["figure.figsize"] = (50,50) plt.show()
运行效果:
- 鼠标左键点击地图上任意国家,控制台会打印该国名称,同时国家区域会根据模拟的可再生能源占比数据上色(绿色越深代表占比越高)
- 再次点击已选择的国家,会取消选择并将国家区域恢复为初始灰色
内容的提问来源于stack exchange,提问作者user23319825
相关产品推荐
相关产品推荐

