如何利用Geopandas与Neo4j数据绘制节点间关系图?
解决方案
要绘制节点间的GO关系(道路),你需要先获取每条关系对应的起点、终点坐标,再将这些坐标转换为地理线段,最后叠加到已有的节点地图上。具体步骤如下:
1. 修改Cypher查询,获取关系的完整坐标信息
原来的关系查询仅返回节点ID,需要补充查询起点和终点的经纬度,才能生成可绘制的线段:
MATCH (n1)-[:GO]-(n2) RETURN n1.id AS start_id, n1.latitude AS start_lat, n1.longitude AS start_lon, n2.id AS end_id, n2.latitude AS end_lat, n2.longitude AS end_lon
2. 处理关系数据,转换为地理线段
使用shapely的LineString类,将每条关系的起点、终点坐标组合成线段几何对象,再转换为GeoDataFrame格式。
3. 叠加绘制道路线段
在已有的节点地图轴上,添加道路线段的绘制,注意调整绘制顺序保证节点可见。
完整代码示例
from py2neo import Graph import pandas as pd import geopandas import matplotlib.pyplot as plt from shapely.geometry import LineString # 新增导入,用于创建线段 port = "7687" user = "****" pswd = "*****" try: graph = Graph('bolt://localhost:'+port, auth=(user, pswd)) print('SUCCESS: Connected to the Neo4j Database.') except Exception as e: print('ERROR: Could not connect to the Neo4j Database. See console for details.') raise SystemExit(e) # 1. 查询节点数据并处理 df_nodes = pd.DataFrame(graph.run("MATCH (n:Road) RETURN n.id, n.latitude, n.longitude").to_table(), columns=['ID','Latitude','Longitude']) # 将字符串坐标转为数值类型 df_nodes['Latitude'] = df_nodes['Latitude'].astype(float) df_nodes['Longitude'] = df_nodes['Longitude'].astype(float) gdf_nodes = geopandas.GeoDataFrame(df_nodes, geometry=geopandas.points_from_xy(df_nodes.Longitude, df_nodes.Latitude)) # 2. 查询关系数据并转换为线段 df_roads = pd.DataFrame( graph.run(""" MATCH (n1)-[:GO]-(n2) RETURN n1.id AS start_id, n1.latitude AS start_lat, n1.longitude AS start_lon, n2.id AS end_id, n2.latitude AS end_lat, n2.longitude AS end_lon """).to_table(), columns=['start_id', 'start_lat', 'start_lon', 'end_id', 'end_lat', 'end_lon'] ) # 转换坐标为数值类型 df_roads[['start_lat', 'start_lon', 'end_lat', 'end_lon']] = df_roads[['start_lat', 'start_lon', 'end_lat', 'end_lon']].astype(float) # 创建线段几何列 gdf_roads = geopandas.GeoDataFrame( df_roads, geometry=[LineString([(row['start_lon'], row['start_lat']), (row['end_lon'], row['end_lat'])]) for _, row in df_roads.iterrows()] ) # 3. 绘制完整地图:底图 → 道路 → 节点 world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres')) ax = world[world.continent == 'North America'].plot(color='white', edgecolor='black') # 先画道路,再画节点(确保节点不被道路遮挡) gdf_roads.plot(ax=ax, color='gray', linewidth=1) gdf_nodes.plot(ax=ax, color='red', markersize=5) plt.show()
关键说明
- 坐标类型转换:从Neo4j返回的经纬度默认是字符串,必须转换为
float类型才能创建有效的地理对象。 - 绘制顺序:先绘制道路再绘制节点,避免节点被道路遮挡,保证节点的可见性。
- 线段创建:通过
LineString将每对起点终点的经纬度组合成线段,这是GeoPandas识别并绘制道路的核心步骤。
内容的提问来源于stack exchange,提问作者Gaston Acuse
相关产品推荐
相关产品推荐

