上面代码运行后提示python里面不包含openrouteservice 的模块,需要按照以下代码的调用格式进行改进:
import requests
import json
import folium
import pandas as pd
import numpy as np
from datetime import datetime
import webbrowser
import os
import math
class OpenRouteService:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://api.openrouteservice.org"
def get_directions(self, coordinates, profile='driving-car'):
"""获取路径规划"""
headers = {
'Authorization': self.api_key,
'Content-Type': 'application/json'
}
body = {
"coordinates": coordinates,
"instructions": "false",
"geometry": "true"
}
print("正在调用OpenRouteService API...")
try:
response = requests.post(
f"{self.base_url}/v2/directions/{profile}/geojson",
json=body,
headers=headers,
timeout=30
)
if response.status_code == 200:
print("API调用成功!")
return response.json()
else:
print(f"API调用失败: {response.status_code}")
print(f"错误信息: {response.text}")
return None
except Exception as e:
print(f"API请求异常: {e}")
return None
def parse_route_data(ors_result, timestamps):
"""解析路由数据并计算速度"""
if not ors_result or 'features' not in ors_result or not ors_result['features']:
print("未找到有效的路径数据")
return None, None, None, None
feature = ors_result['features'][0]
geometry = feature['geometry']
properties = feature.get('properties', {})
# 提取路径坐标
route_coords = []
if geometry['type'] == 'LineString':
# 转换坐标顺序: [经度, 纬度] -> (纬度, 经度)
route_coords = [(coord[1], coord[0]) for coord in geometry['coordinates']]
# 检查是否有segments数据
if 'segments' not in properties or not properties['segments']:
print("警告: 返回的数据中没有segments信息,使用简化计算")
# 使用简化方法计算距离和速度
return calculate_simple_speed(route_coords, timestamps)
# 提取分段信息
segments = properties['segments'][0]
total_distance = segments.get('distance', 0) # 米
total_duration = segments.get('duration', 0) # 秒
# 计算平均速度
if total_duration > 0:
avg_speed = (total_distance / total_duration) * 3.6 # km/h
else:
avg_speed = 0
print(f"路径总距离: {total_distance:.2f} 米")
print(f"路径总时间: {total_duration:.2f} 秒")
print(f"平均速度: {avg_speed:.2f} km/h")
# 计算分段速度(如果有多个分段)
step_speeds = []
step_distances = []
if 'steps' in segments:
for step in segments['steps']:
distance = step.get('distance', 0)
duration = step.get('duration', 0)
if duration > 0:
speed = (distance / duration) * 3.6
else:
speed = 0
step_speeds.append(speed)
step_distances.append(distance)
else:
# 如果没有steps,使用总距离和总时间
if total_duration > 0:
step_speeds.append(avg_speed)
step_distances.append(total_distance)
return route_coords, step_speeds, step_distances, avg_speed
def calculate_simple_speed(route_coords, timestamps):
"""简化计算速度(当API返回数据不完整时使用)"""
if not route_coords or len(route_coords) < 2:
return None, None, None, 0
# 计算总距离(使用Haversine公式计算实际地理距离)
total_distance = 0
for i in range(len(route_coords) - 1):
# 使用Haversine公式计算两点间距离
lat1, lon1 = route_coords[i]
lat2, lon2 = route_coords[i + 1]
distance = haversine_distance(lon1, lat1, lon2, lat2)
total_distance += distance
# 计算总时间
total_duration = (timestamps[-1] - timestamps[0]).total_seconds()
# 计算平均速度
if total_duration > 0:
avg_speed = (total_distance / total_duration) * 3.6 # km/h
else:
avg_speed = 0
print(f"简化计算 - 路径总距离: {total_distance:.2f} 米")
print(f"简化计算 - 路径总时间: {total_duration:.2f} 秒")
print(f"简化计算 - 平均速度: {avg_speed:.2f} km/h")
# 创建简化的分段数据
step_speeds = [avg_speed] # 使用平均速度作为分段速度
step_distances = [total_distance] # 使用总距离作为分段距离
return route_coords, step_speeds, step_distances, avg_speed
def haversine_distance(lon1, lat1, lon2, lat2):
"""使用Haversine公式计算两点间距离(米)"""
R = 6371000 # 地球半径(米)
dlat = math.radians(lat2 - lat1)
dlon = math.radians(lon2 - lon1)
a = (math.sin(dlat / 2) * math.sin(dlat / 2) +
math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) *
math.sin(dlon / 2) * math.sin(dlon / 2))
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
return R * c
def create_visualization(original_points, route_coords, step_speeds, person_id, output_dir="./output"):
"""创建可视化地图并保存结果"""
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# 创建地图 - 郑州大学为中心
center_lat = 34.817 # 郑州大学大致纬度
center_lon = 113.536 # 郑州大学大致经度
m = folium.Map(location=[center_lat, center_lon], zoom_start=15)
# 添加原始点标记
for i, point in enumerate(original_points):
folium.Marker(
location=[point[1], point[0]], # (纬度, 经度)
popup=f"人员 {person_id}<br>点 {i + 1}<br>经度: {point[0]:.6f}<br>纬度: {point[1]:.6f}",
icon=folium.Icon(color='red', icon='user')
).add_to(m)
# 添加路径
if route_coords:
# 根据速度给路径着色
avg_speed = np.mean(step_speeds) if step_speeds else 0
if avg_speed < 1:
color = 'gray'
elif avg_speed < 3:
color = 'blue'
elif avg_speed < 5:
color = 'green'
elif avg_speed < 10:
color = 'orange'
else:
color = 'red'
folium.PolyLine(
route_coords,
color=color,
weight=6,
opacity=0.7,
popup=f"人员 {person_id} 轨迹<br>平均速度: {avg_speed:.1f} km/h"
).add_to(m)
# 添加起点终点标记
folium.Marker(
location=route_coords[0],
popup="起点",
icon=folium.Icon(color='green', icon='play')
).add_to(m)
folium.Marker(
location=route_coords[-1],
popup="终点",
icon=folium.Icon(color='red', icon='stop')
).add_to(m)
# 添加郑州大学标记
folium.Marker(
location=[34.817, 113.536],
popup="郑州大学",
icon=folium.Icon(color='purple', icon='education')
).add_to(m)
# 保存地图
map_file = os.path.join(output_dir, f"route_visualization_{person_id}.html")
m.save(map_file)
print(f"地图已保存至: {map_file}")
return map_file
def save_results_to_csv(original_points, route_coords, step_speeds, step_distances, timestamps, person_id,
output_dir="./output"):
"""保存结果到CSV文件"""
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# 保存原始点数据
original_data = []
for i, point in enumerate(original_points):
original_data.append({
'person_id': person_id,
'point_id': i + 1,
'longitude': point[0],
'latitude': point[1],
'timestamp': timestamps[i] if i < len(timestamps) else None
})
df_original = pd.DataFrame(original_data)
original_csv = os.path.join(output_dir, f"original_points_{person_id}.csv")
df_original.to_csv(original_csv, index=False, encoding='utf-8-sig')
print(f"原始点数据已保存至: {original_csv}")
# 保存路径点数据
if route_coords:
route_data = []
for i, coord in enumerate(route_coords):
route_data.append({
'person_id': person_id,
'route_point_id': i + 1,
'latitude': coord[0],
'longitude': coord[1]
})
df_route = pd.DataFrame(route_data)
route_csv = os.path.join(output_dir, f"route_points_{person_id}.csv")
df_route.to_csv(route_csv, index=False, encoding='utf-8-sig')
print(f"路径点数据已保存至: {route_csv}")
# 保存分段速度数据
if step_speeds and step_distances:
speed_data = []
for i, (speed, distance) in enumerate(zip(step_speeds, step_distances)):
speed_data.append({
'person_id': person_id,
'segment_id': i + 1,
'distance_m': distance,
'speed_kmh': speed,
'start_time': timestamps[i] if i < len(timestamps) else None,
'end_time': timestamps[i + 1] if i + 1 < len(timestamps) else None
})
df_speed = pd.DataFrame(speed_data)
speed_csv = os.path.join(output_dir, f"segment_speeds_{person_id}.csv")
df_speed.to_csv(speed_csv, index=False, encoding='utf-8-sig')
print(f"分段速度数据已保存至: {speed_csv}")
def open_map_in_browser(map_file):
"""在浏览器中打开地图"""
try:
webbrowser.open('file://' + os.path.abspath(map_file))
print("正在浏览器中打开地图...")
except Exception as e:
print(f"无法在浏览器中打开地图: {e}")
print(f"请手动打开文件: {os.path.abspath(map_file)}")
def parse_timestamp(timestamp_str):
"""解析时间戳字符串"""
try:
# 处理毫秒时间戳
if '.' in timestamp_str:
return datetime.strptime(timestamp_str, '%Y-%m-%dT%H:%M:%S.%f')
else:
return datetime.strptime(timestamp_str, '%Y-%m-%dT%H:%M:%S')
except Exception as e:
print(f"时间解析错误: {e}")
return datetime.now()
def process_person_trajectory(person_data, api_key):
"""处理单个人的轨迹数据"""
# 按时间排序
person_data.sort(key=lambda x: x['timestamp'])
# 提取坐标和时间
coordinates = [[point['longitude'], point['latitude']] for point in person_data]
timestamps = [point['timestamp'] for point in person_data]
person_id = person_data[0]['person_id'] if person_data else "unknown"
print(f"\n处理人员 {person_id} 的轨迹数据...")
print(f"数据点数: {len(coordinates)}")
ors = OpenRouteService(api_key)
# 获取路径规划
result = ors.get_directions(coordinates)
if result:
# 解析数据
route_coords, step_speeds, step_distances, avg_speed = parse_route_data(result, timestamps)
if route_coords:
# 创建可视化
map_file = create_visualization(coordinates, route_coords, step_speeds, person_id)
# 保存结果到CSV
save_results_to_csv(coordinates, route_coords, step_speeds, step_distances, timestamps, person_id)
# 在浏览器中打开地图
open_map_in_browser(map_file)
print(f"\n=== 人员 {person_id} 处理完成 ===")
print(f"• 可视化地图: {os.path.abspath(map_file)}")
print(f"• 数据文件保存在: {os.path.abspath('./output')} 目录")
return True
else:
print(f"无法解析人员 {person_id} 的路径数据")
return False
else:
print(f"无法获取人员 {person_id} 的路径规划结果")
return False
# 使用示例 - 郑州大学轨迹分析
def zhengzhou_university_example():
# 替换为你的实际API密钥
api_key = "eyJvcmciOiI1YjNjZTM1OTc4NTExMTAwMDFjZjYyNDgiLCJpZCI6IjdjMjYxY2Q2NzgyNjRlYjViOWRiODBlOTIxZTE3NDA1IiwiaCI6Im11cm11cjY0In0="
if api_key == "YOUR_OPENROUTESERVICE_API_KEY":
print("请先设置你的OpenRouteService API密钥!")
return
# 郑州大学实际点位数据
raw_data = [
"郑州大学点,2024-7-13T11:55:10,0000897851,113.529859103333,34.81229556",
"郑州大学点,2024-7-13T12:00:33,0000897851,113.5240264075,34.813994935"
]
# 解析数据
person_data = []
for line in raw_data:
parts = line.split(',')
if len(parts) >= 5:
person_data.append({
'location': parts[0],
'timestamp': parse_timestamp(parts[1]),
'person_id': parts[2],
'longitude': float(parts[3]),
'latitude': float(parts[4])
})
# 按人员ID分组处理(这里只有一个人员)
persons = {}
for data in person_data:
person_id = data['person_id']
if person_id not in persons:
persons[person_id] = []
persons[person_id].append(data)
# 处理每个人的轨迹
success_count = 0
for person_id, data in persons.items():
if process_person_trajectory(data, api_key):
success_count += 1
print(f"\n=== 总体处理完成 ===")
print(f"成功处理 {success_count}/{len(persons)} 个人员的轨迹数据")
print(f"所有结果保存在: {os.path.abspath('./output')} 目录")
if __name__ == "__main__":
zhengzhou_university_example()
# 添加暂停,确保能看到输出
input("按Enter键退出...")