You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Matplotlib 3D柱状图:解决柱状条悬浮、显示异常问题

Matplotlib 3D柱状图:解决柱状条悬浮、显示异常问题

嗨,我来帮你搞定这个3D柱状图的显示问题~ 你遇到的柱子悬浮、透明感异常、重叠错乱这些情况,主要是Matplotlib的3D渲染特性加上你的坐标处理方式导致的,咱们一步步来调整:

问题根源分析

  1. UTM坐标数值过大:UTM坐标通常是几万甚至几十万的大数值,Matplotlib的3D轴在处理这类大数值时,深度排序逻辑容易出错,导致柱子看起来像是悬浮或者重叠错位。
  2. 浮点数匹配精度问题:你用np.where(xx == current_x)直接匹配坐标,UTM坐标是浮点数,存在精度误差,很可能找不到对应位置,导致部分柱子高度为0或者位置偏移,出现“隐形”柱子的视觉异常。
  3. 3D渲染默认设置不足:默认的3D柱状图没有轮廓线,加上视角不合适,会让柱子看起来透明或者边界模糊。

具体解决方案

1. 坐标归一化,缩小数值范围

先把UTM坐标减去最小值,让数值范围大幅缩小,帮助Matplotlib更准确地计算3D深度:

# 归一化经纬度,降低数值量级
lon_normalized = lon - lon.min()
lat_normalized = lat - lat.min()

# 基于归一化后的坐标重新生成网格
xx = np.arange(lon_normalized.min(), lon_normalized.max() + resolution, resolution)
yy = np.arange(lat_normalized.max(), lat_normalized.min() - resolution, -resolution)
_xx, _yy = np.meshgrid(xx, yy)

2. 修复坐标匹配的精度问题

差值绝对值最小的方式匹配网格点,替代直接的浮点数相等判断,避免匹配失败:

_dz = np.zeros_like(_xx)
for i, datum in enumerate(data):
    current_x = lon_normalized[i]
    current_y = lat_normalized[i]
    # 找到最接近当前坐标的网格索引
    col = np.argmin(np.abs(xx - current_x))
    row = np.argmin(np.abs(yy - current_y))
    _dz[row, col] = datum

3. 优化3D渲染效果

通过调整视角、添加轮廓线、设置轴范围来改善显示:

fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(111, projection='3d')
# 固定z轴范围,确保所有柱子从z=0开始,避免悬浮感
ax.set_zlim(0, max(data) * 1.1)
# 调整视角,减少重叠带来的错乱(可以自行修改elev和azim的值)
ax.view_init(elev=30, azim=45)
# 添加白色轮廓线,让柱子边界更清晰,减少透明感
ax.bar3d(x, y, z, dx, dy, dz, color=rgba, edgecolor='white', linewidth=0.5)

4. 可选:用更高效的方式赋值数据(大数据量适用)

如果你的数据量很大,循环赋值会很慢,可以用scipygriddata来快速填充网格:

from scipy.interpolate import griddata

# 直接生成网格对应的data值,用最近邻插值
_dz = griddata((lon_normalized, lat_normalized), data, (_xx, _yy), method='nearest')
# 把无数据的NaN替换为0
_dz = np.nan_to_num(_dz)

完整优化后的代码

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm

df = pd.read_csv('example.csv')  # 注意这里要给文件名加引号哦
lat = df['lat']
lon = df['lon']
data = df['data']
resolution = 375

# 坐标归一化
lon_normalized = lon - lon.min()
lat_normalized = lat - lat.min()

# 生成网格
xx = np.arange(lon_normalized.min(), lon_normalized.max() + resolution, resolution)
yy = np.arange(lat_normalized.max(), lat_normalized.min() - resolution, -resolution)
_xx, _yy = np.meshgrid(xx, yy)

# 填充数据到网格
_dz = np.zeros_like(_xx)
for i, datum in enumerate(data):
    current_x = lon_normalized[i]
    current_y = lat_normalized[i]
    col = np.argmin(np.abs(xx - current_x))
    row = np.argmin(np.abs(yy - current_y))
    _dz[row, col] = datum

# 扁平化数据
x = _xx.flatten()
y = _yy.flatten()
z = np.zeros_like(x)
dx = np.full_like(x, resolution)
dy = np.full_like(x, resolution)
dz = _dz.flatten()

# 生成颜色映射
cmap = cm.plasma
rgba = [cmap(i/max(data)) for i in dz]

# 绘制优化后的3D柱状图
fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(111, projection='3d')
ax.set_zlim(0, max(data) * 1.1)
ax.view_init(elev=30, azim=45)
ax.bar3d(x, y, z, dx, dy, dz, color=rgba, edgecolor='white', linewidth=0.5)

# 添加轴标签(可选,提升可读性)
ax.set_xlabel('Normalized Longitude')
ax.set_ylabel('Normalized Latitude')
ax.set_zlabel('Data Value')

plt.show()

备注:内容来源于stack exchange,提问作者user29146195

火山引擎 最新活动