如何为3D绘图的Lat-Long平面添加背景图并保持2D宽高比
需求:将2D背景图融合到3D散点图的经纬度平面(保留宽高比)
现有2D可视化代码(带高度约束的经纬度-温度图)
该代码基于高度范围筛选数据,在金星地图背景上绘制经纬度点,用颜色表示温度,并根据背景图宽高比设置画布尺寸:
import os import pandas as pd import matplotlib.pyplot as plt # 路径设置 combo_folder = '/home/dev/Desktop/Venus/Data/combo' # 约束参数 height_min = 40 height_max = 60 venus_radius = 6051.8 # 读取背景图并计算宽高比 image = plt.imread('/home/dev/Desktop/Venus/Images/venmap.gif') image_aspect_ratio = image.shape[1] / image.shape[0] # 根据宽高比设置画布尺寸 width = 30 height = width / image_aspect_ratio fig, ax = plt.subplots(figsize=(width, height)) # 绘制背景图 ax.imshow(image, extent=[0, 360, -90, 90], aspect='auto') # 遍历并绘制CSV数据 for filename in os.listdir(combo_folder): if filename.endswith('.csv'): file_path = os.path.join(combo_folder, filename) df = pd.read_csv(file_path) # 提取字段并计算高度 latitude = df['LATITUDE'] longitude = df['LONGITUDE'] temperature = df['TEMPERATURE_MEDIUM_TEMPERATURE_AT_BOUNDARY'] height = df['RADIUS'] - venus_radius # 高度范围筛选 mask = (height >= height_min) & (height <= height_max) latitude = latitude[mask] longitude = longitude[mask] temperature = temperature[mask] # 绘制散点图 scatter = ax.scatter(longitude, latitude, c=temperature, s=200, cmap='viridis', alpha=0.7) ax.set_xlabel('Longitude') ax.set_ylabel('Latitude') ax.set_title(f'Latitude and Longitude with Temperature (Height: {height_min} to {height_max})') # 添加温度色标 cbar = fig.colorbar(scatter, ax=ax, label='Temperature (°C)') plt.show()
现有3D可视化代码(经纬度-高度-温度散点图)
该代码在3D空间展示经纬度、高度与温度的关系,同样应用了高度范围约束:
import os import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # 路径设置 combo_folder = '/home/dev/Desktop/Venus/Data/combo' # 约束参数 height_min = 40 height_max = 60 venus_radius = 6051.8 # 创建3D画布 fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # 设置轴范围 ax.set_xlim(0, 360) ax.set_ylim(-90, 90) ax.set_zlim(0, 90) # 遍历并绘制CSV数据 for filename in os.listdir(combo_folder): if filename.endswith('.csv'): file_path = os.path.join(combo_folder, filename) df = pd.read_csv(file_path) # 提取字段并计算高度 latitude = df['LATITUDE'] longitude = df['LONGITUDE'] temperature = df['TEMPERATURE_MEDIUM_TEMPERATURE_AT_BOUNDARY'] height = df['RADIUS'] - venus_radius # 高度范围筛选 mask = (height >= height_min) & (height <= height_max) latitude = latitude[mask] longitude = longitude[mask] temperature = temperature[mask] height = height[mask] # 绘制3D散点图 scatter = ax.scatter(longitude, latitude, height, c=temperature, cmap='viridis', alpha=0.7) ax.set_xlabel('Longitude') ax.set_ylabel('Latitude') ax.set_zlabel('Height') ax.set_title(f'Latitude, Longitude, and Height with Temperature (Height: {height_min} to {height_max})') # 添加温度色标 cbar = fig.colorbar(scatter, ax=ax, label='Temperature (°C)') plt.show()
目标需求
- 保留2D绘图中基于背景图宽高比设置画布尺寸的逻辑
- 将金星背景图添加到3D散点图的**经纬度平面(z=0)**上
- 融合后保留3D散点的温度色标与交互功能
融合后的实现代码
import os import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # 路径设置 combo_folder = '/home/dev/Desktop/Venus/Data/combo' background_img_path = '/home/dev/Desktop/Venus/Images/venmap.gif' # 约束参数 height_min = 40 height_max = 60 venus_radius = 6051.8 # ---------------------- 保留2D图的宽高比设置逻辑 ---------------------- # 读取背景图并计算宽高比 image = plt.imread(background_img_path) image_aspect_ratio = image.shape[1] / image.shape[0] # 根据宽高比设置画布尺寸 width = 30 height = width / image_aspect_ratio fig = plt.figure(figsize=(width, height)) ax = fig.add_subplot(111, projection='3d') # ---------------------- 设置3D轴属性 ---------------------- ax.set_xlim(0, 360) ax.set_ylim(-90, 90) ax.set_zlim(0, 90) ax.set_xlabel('Longitude') ax.set_ylabel('Latitude') ax.set_zlabel('Height') ax.set_title(f'Latitude, Longitude, Height with Temperature (Height: {height_min} to {height_max})') # ---------------------- 在经纬度平面(z=0)添加背景图 ---------------------- # 创建覆盖经纬度范围的网格,固定z=0 x_range = [0, 360] y_range = [-90, 90] X, Y = plt.meshgrid(x_range, y_range) Z = X * 0 # z坐标固定为0 # 将背景图贴到z=0平面,匹配经纬度范围并保持图像比例 ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=image, shade=False, extent=[0, 360, -90, 90], aspect='auto') # ---------------------- 绘制筛选后的3D散点数据 ---------------------- scatter = None for filename in os.listdir(combo_folder): if filename.endswith('.csv'): file_path = os.path.join(combo_folder, filename) df = pd.read_csv(file_path) # 提取并计算所需字段 lat = df['LATITUDE'] lon = df['LONGITUDE'] temp = df['TEMPERATURE_MEDIUM_TEMPERATURE_AT_BOUNDARY'] height = df['RADIUS'] - venus_radius # 高度范围筛选 mask = (height >= height_min) & (height <= height_max) scatter = ax.scatter(lon[mask], lat[mask], height[mask], c=temp[mask], cmap='viridis', alpha=0.7, s=200) # ---------------------- 添加温度色标 ---------------------- if scatter is not None: cbar = fig.colorbar(scatter, ax=ax, label='Temperature (°C)') plt.show()
关键修改说明
- 保留宽高比逻辑:完全沿用2D图中读取背景图、计算宽高比并设置画布尺寸的代码,保证画布比例与背景图一致
- 3D平面贴背景图:使用
plot_surface在z=0的平面上绘制背景图,通过facecolors参数将图像作为纹理贴附,extent匹配经纬度范围,aspect='auto'避免图像拉伸变形 - 兼容原3D逻辑:保留了原3D散点的筛选与绘制逻辑,仅调整变量名避免冲突
- 鲁棒性处理:添加了色标绘制的判断,避免无数据时出现报错
内容的提问来源于stack exchange,提问作者Keshav Aggarwal
相关产品推荐
相关产品推荐

