OSMnx可视化A*算法路径遇阻:节点、边及路径无法显示求助
问题描述
我是编程新手,这学期修读高阶大学课程,现尝试使用OSMnx在地图上展示A*算法找到的路径,但在显示图中的节点、边及路径时遇到诸多问题。以下是相关代码,恳请协助解决节点等元素的显示问题:
相关代码文件
visualisation.py
import osmnx as ox import matplotlib.pyplot as plt from coordinates import letter_to_coord def visualise_map(graph, start, goal, path): G = ox.graph_from_address('address', dist=800) fig, ax = ox.plot_graph(G) for node in graph: coord = letter_to_coord.get(node, None) if coord is not None and isinstance(coord, tuple): ax.scatter(coord[1], coord[0], c='red') ax.annotate(node, (coord[1], coord[0]), fontsize=12) for u, v, *_ in G.edges: u_coord = letter_to_coord.get(u, None) v_coord = letter_to_coord.get(v, None) if u_coord is not None and v_coord is not None and isinstance(u_coord, tuple) and isinstance(v_coord, tuple): ax.plot([u_coord[1], v_coord[1]], [u_coord[0], v_coord[0]], c='k', linewidth=1, zorder=1) path_coords = [letter_to_coord.get(node, None) for node in path] path_coords = [coord for coord in path_coords if coord is not None and isinstance(coord, tuple)] path_lons = [coord[1] for coord in path_coords] path_lats = [coord[0] for coord in path_coords] ax.plot(path_lons, path_lats, c='g', linewidth=3, zorder=2) plt.show()
gui.py
import tkinter as tk from tkinter import ttk import matplotlib matplotlib.use('TkAgg') from astar import astar_search, graph from visualisation import visualise_map def display_path(): start = start_entry.get() goal = end_entry.get() path = astar_search(graph, start, goal) if path: path_text.delete('1.0', tk.END) path_text.insert(tk.END, f"Path found: {', '.join(path)}") visualise_map(graph, start, goal, path) else: path_text.delete('1.0', tk.END) path_text.insert(tk.END, "No path found") root = tk.Tk() root.title("Wheelchair Navigation") start_label = ttk.Label(root, text="Start:") start_label.grid(row=0, column=0, padx=10, pady=10) start_entry = ttk.Entry(root) start_entry.grid(row=0, column=1, padx=10, pady=10) end_label = ttk.Label(root, text="End:") end_label.grid(row=1, column=0, padx=10, pady=10) end_entry = ttk.Entry(root) end_entry.grid(row=1, column=1, padx=10, pady=10) display_button = ttk.Button(root, text="Find Path", command=display_path) display_button.grid(row=2, column=0, columnspan=2, padx=10, pady=10) path_text = tk.Text(root, height=5, width=50) path_text.grid(row=3, column=0, columnspan=2, padx=10, pady=10) root.mainloop()
astar.py
import heapq from visualisation import visualise_map from coordinates import letter_to_coord class Node: def __init__(self, position, cost, heuristic): self.position = position self.cost = cost self.heuristic = heuristic self.parent = None def __lt__(self, other): return (self.cost + self.heuristic) < (other.cost + other.heuristic) def astar_search(graph, start, goal): open_set = [] closed_set = set() start_node = Node(start, 0, heuristic(start, goal)) heapq.heappush(open_set, start_node) while open_set: current_node = heapq.heappop(open_set) if current_node.position == goal: path = [] while current_node: path.insert(0, current_node.position) current_node = current_node.parent return path closed_set.add(current_node.position) for neighbor in graph[current_node.position]: if neighbor not in closed_set: cost = current_node.cost + graph[current_node.position][neighbor] heuristic_val = heuristic(neighbor, goal) new_node = Node(neighbor, cost, heuristic_val) new_node.parent = current_node existing_node = next((node for node in open_set if node.position == neighbor), None) if existing_node and existing_node.cost <= cost: continue heapq.heappush(open_set, new_node) return None def heuristic(start, goal): node_coord = letter_to_coord.get(start) goal_coord = letter_to_coord.get(goal) if isinstance(node_coord, tuple) and isinstance(goal_coord, tuple): return abs(node_coord[0] - goal_coord[0]) + abs(node_coord[1] - goal_coord[1]) else: return 0 # Cost of each edge graph = { 'A': {'B': 45.5}, 'B': {'A': 45.5, 'C': 11.4, 'H': 23}, 'C': {'B': 11.4, 'D': 10.2, 'I': 24.5}, 'D': {'C': 10.2, 'E': 9.8, 'J': 24.8}, 'E': {'D': 9.8, 'F': 21.4, 'K': 24.7}, 'F': {'E': 21.4, 'G': 11.1}, 'G': {'F': 11.1, 'L': 41.3}, 'H': {'B': 23, 'I': 11}, 'I': {'H': 11, 'C': 24.5, 'J': 10.3}, 'J': {'I': 10.3, 'D': 24.8, 'K': 14.5}, 'K': {'J': 14.5, 'E': 24.7, 'L': 17}, 'L': {'K': 17, 'G': 41.3} }
注:letter_to_coord是自定义字典,将字母节点映射为EPSG:4326格式的经纬度元组。
问题解决与代码修正
核心问题点
- OSMnx绘图环境丢失:
ox.plot_graph(G)默认会直接显示并关闭绘图窗口,返回的ax对象无效,无法叠加自定义元素。 - 边绘制逻辑错误:遍历了OSMnx下载的地图边,而非自定义
graph中的边,导致无法展示自己定义的节点连接关系。 - 图层层级冲突:自定义元素的
zorder值过低,被OSMnx的底图遮挡。 - 地址参数无效:
ox.graph_from_address('address')中的占位符未替换为实际地址,无法下载正确的地图区域。
修正后的visualisation.py
import osmnx as ox import matplotlib.pyplot as plt from coordinates import letter_to_coord def visualise_map(graph, start, goal, path): # 替换为你的实际地址,确保下载对应区域的地图 G = ox.graph_from_address('北京市东城区王府井大街', dist=800) # 保留绘图环境,不自动显示/关闭窗口 fig, ax = ox.plot_graph(G, show=False, close=False) # 绘制自定义节点,提高zorder确保在底图上方 for node in graph: coord = letter_to_coord.get(node, None) if coord is not None and isinstance(coord, tuple): ax.scatter(coord[1], coord[0], c='red', s=60, zorder=10) ax.annotate(node, (coord[1], coord[0]), fontsize=12, zorder=11) # 绘制自定义图的边(遍历自己的graph字典) for u in graph: for v in graph[u]: u_coord = letter_to_coord.get(u, None) v_coord = letter_to_coord.get(v, None) if u_coord and v_coord and isinstance(u_coord, tuple) and isinstance(v_coord, tuple): ax.plot([u_coord[1], v_coord[1]], [u_coord[0], v_coord[0]], c='black', linewidth=2, zorder=5) # 绘制A*路径 if path: path_coords = [letter_to_coord.get(node) for node in path if letter_to_coord.get(node)] if path_coords: path_lons = [coord[1] for coord in path_coords] path_lats = [coord[0] for coord in path_coords] ax.plot(path_lons, path_lats, c='limegreen', linewidth=4, zorder=15) plt.show()
其他补充修正
- 移除循环导入:删除astar.py中的
from visualisation import visualise_map,避免模块循环依赖。 - 输入验证:在gui.py的
display_path函数中添加输入检查,确保用户输入的是A-L范围内的字母:def display_path(): start = start_entry.get().upper() goal = end_entry.get().upper() if not (start in graph and goal in graph): path_text.delete('1.0', tk.END) path_text.insert(tk.END, "输入无效,请输入A-L之间的字母") return # 原逻辑保留
内容的提问来源于stack exchange,提问作者niko
相关产品推荐
相关产品推荐

