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

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格式的经纬度元组。


问题解决与代码修正

核心问题点

  1. OSMnx绘图环境丢失:ox.plot_graph(G)默认会直接显示并关闭绘图窗口,返回的ax对象无效,无法叠加自定义元素。
  2. 边绘制逻辑错误:遍历了OSMnx下载的地图边,而非自定义graph中的边,导致无法展示自己定义的节点连接关系。
  3. 图层层级冲突:自定义元素的zorder值过低,被OSMnx的底图遮挡。
  4. 地址参数无效: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()

其他补充修正

  1. 移除循环导入:删除astar.py中的from visualisation import visualise_map,避免模块循环依赖。
  2. 输入验证:在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 09:27:10