绘制双曲格点图时遇NetworkXError:节点无位置的技术问询
双曲格点模拟程序的NetworkX节点位置错误修复
问题描述
开发基于Python的双曲格点模拟程序,用于研究双曲格点密度、曲率与AdS空间、AdS/CFT对偶的关系,使用matplotlib、numpy、networkx库。运行时出现NetworkXError提示“节点无位置”,调整node_size、edge_color、with_labels参数无效。
错误栈信息
Traceback (most recent call last): File "C:\Users\zorty\Masaüstü\.venv\Lib\site-packages\networkx\drawing\nx_pylab.py", line 445, in draw_networkx_nodes xy = np.asarray([pos[v] for v in nodelist]) ~~~^^^ KeyError: (np.float64(0.70848), np.float64(0.0)) The above exception was the direct cause of the following exception: Traceback (most recent call last): File "c:\Users\zorty\Masaüstü\Project.py", line 51, in <module> nx.draw(G, pos, node_size=10, edge_color="blue", with_labels=False) File "C:\Users\zorty\Masaüstü\.venv\Lib\site-packages\networkx\drawing\nx_pylab.py", line 126, in draw draw_networkx(G, pos=pos, ax=ax, **kwds) File "C:\Users\zorty\Masaüstü\.venv\Lib\site-packages\networkx\drawing\nx_pylab.py", line 314, in draw_networkx draw_networkx_nodes(G, pos, **node_kwds) File "C:\Users\zorty\Masaüstü\.venv\Lib\site-packages\networkx\drawing\nx_pylab.py", line 447, in draw_networkx_nodes raise nx.NetworkXError(f"Node {err} has no position.") from err networkx.exception.NetworkXError: Node (np.float64(0.70848), np.float64(0.0)) has no position.
错误原因分析
- 递归终止逻辑缺陷:当递归深度达到
max_depth时,函数直接返回,未为该层节点添加pos属性。但这些节点在上一层递归中已通过G.add_edge被自动加入图中,导致绘图时找不到位置信息。 - 浮点数类型不匹配:节点标识使用numpy.float64元组,后续属性查找时可能出现匹配失效的问题。
修复后的完整代码
import numpy as np import matplotlib.pyplot as plt import networkx as nx import random from collections import deque # 双曲格点参数 p = 7 # 每个多边形的边数(七边形) q = 3 # 每个顶点连接的多边形数 depth = 4 # 递归深度 # 初始化图 G = nx.Graph() def hyperbolic_polygon_vertices(sides, center, radius): angles = np.linspace(0, 2 * np.pi, sides, endpoint=False) vertices = [] for angle in angles: x = center[0] + radius * np.cos(angle) y = center[1] + radius * np.sin(angle) vertices.append((float(x), float(y))) # 转换为Python原生float return vertices def add_hyperbolic_lattice(G, center, radius, depth, max_depth): # 先为当前节点添加位置属性,确保所有节点都有pos pos_x = float(radius * np.cos(center[0])) pos_y = float(radius * np.sin(center[1])) G.add_node(center, pos=(pos_x, pos_y)) # 达到最大深度时停止递归,不再生成子节点 if depth >= max_depth: return # 生成相邻节点 angle_offset = 2 * np.pi / q for i in range(q): angle = i * angle_offset new_radius = radius * 0.8 # 调整半径模拟双曲空间深度效果 new_center_x = float(center[0] + new_radius * np.cos(angle)) new_center_y = float(center[1] + new_radius * np.sin(angle)) new_center = (new_center_x, new_center_y) # 添加边并递归生成子节点 G.add_edge(center, new_center) add_hyperbolic_lattice(G, new_center, new_radius, depth + 1, max_depth) # 初始化中心节点 initial_center = (0.0, 0.0) # 使用Python原生float initial_radius = 0.3 add_hyperbolic_lattice(G, initial_center, initial_radius, 0, depth) # 绘制双曲格点 pos = nx.get_node_attributes(G, 'pos') nx.draw(G, pos, node_size=10, edge_color="blue", with_labels=False) plt.title("Hyperbolic Lattice (Poincaré Disk)") plt.show() # 按距离计算密度 def calculate_density_by_distance(G, center, max_distance): distances = nx.single_source_shortest_path_length(G, center) density_by_distance = {} for distance in range(1, max_distance + 1): nodes_in_ring = [node for node, dist in distances.items() if dist == distance] if nodes_in_ring: area = np.pi * ((distance + 1)**2 - distance**2) # 近似环面积 density_by_distance[distance] = len(nodes_in_ring) / area return density_by_distance # 计算并绘制密度-距离曲线 center_node = initial_center density_data = calculate_density_by_distance(G, center_node, max_distance=5) plt.plot(density_data.keys(), density_data.values()) plt.xlabel("Distance from Center") plt.ylabel("Density") plt.title("Density vs Distance in Hyperbolic Lattice") plt.show() # 分析边界连通性(AdS/CFT类比) distances = nx.single_source_shortest_path_length(G, center_node) max_distance = max(distances.values()) boundary_nodes = [node for node, dist in distances.items() if dist == max_distance] boundary_connectivity = np.mean([G.degree(node) for node in boundary_nodes]) print("Average connectivity at boundary (AdS/CFT analogy):", boundary_connectivity) # 模拟到边界的网络流(黑洞热力学类比) boundary_node = random.choice(boundary_nodes) try: flow_value, _ = nx.maximum_flow(G, center_node, boundary_node) print("Simulated flow value (energy transfer to boundary):", flow_value) except Exception as e: print(f"Error calculating flow: {e}")
关键修复点
- 调整递归逻辑:将
G.add_node移到递归终止条件之前,确保所有被加入图的节点都带有pos属性,包括达到最大深度的节点。 - 统一浮点数类型:将所有节点坐标转换为Python原生
float,避免numpy.float64元组导致的属性查找匹配问题。 - 优化错误捕获:在网络流计算中捕获具体异常信息,提升调试效率。
内容的提问来源于stack exchange,提问作者Elly_0
相关产品推荐
相关产品推荐

