[英]Plotting mplot3d / axes3D xyz surface plot with log scale?
我一直在寻找解决这个简单问题的方法,但在任何地方都找不到! 有很多帖子详细介绍了 2D 中数据的 semilog/loglog 绘图,例如 plt.setxscale('log') 但是我对在 3d plot(mplot3d) 上使用对数刻度很感兴趣。
我手头没有确切的代码,所以不能在这里发布,但是下面的简单示例应该足以解释这种情况。 我目前正在使用 Matplotlib 0.99.1,但很快就会更新到 1.0.0 - 我知道我必须更新我的 mplot3d 实现代码。
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FixedLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = Axes3D(fig)
X = np.arange(-5, 5, 0.025)
Y = np.arange(-5, 5, 0.025)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet, extend3d=True)
ax.set_zlim3d(-1.01, 1.01)
ax.w_zaxis.set_major_locator(LinearLocator(10))
ax.w_zaxis.set_major_formatter(FormatStrFormatter('%.03f'))
fig.colorbar(surf)
plt.show()
上面的代码可以在 3D 中很好地绘制,但是三个尺度(X、Y、Z)都是线性的。 我的“Y”数据跨越了几个数量级(比如 9!),所以在对数刻度上绘制它会非常有用。 我可以通过获取“Y”的日志、重新创建 numpy 数组并在线性刻度上绘制 log(Y) 来解决此问题,但在真正的 Python 风格中,我正在寻找更智能的解决方案,它将数据绘制在一个对数刻度。
是否可以使用对数刻度生成我的 XYZ 数据的 3D 曲面图,理想情况下我希望 X 和 Z 在线性刻度上,而 Y 在对数刻度上?
任何帮助将不胜感激。 请原谅上面示例中的任何明显错误,如前所述,我没有确切的代码,因此根据我的记忆更改了 matplotlib 库示例。
谢谢
由于我遇到了同样的问题,而 Alejandros 的回答没有产生预期的结果,这是我目前发现的结果。
3D 轴的对数缩放是 matplotlib 中的一个持续问题。 目前,您只能使用以下内容重新标记轴:
ax.yaxis.set_scale('log')
然而,这不会导致轴被缩放为对数,而是标记为对数。 ax.set_yscale('log')
将导致 3D 异常
请参阅 github问题 209
因此,您仍然必须重新创建 numpy 数组
在 osx 中:运行 ax.zaxis._set_scale('log') (注意下划线)
你所要做的就是定义你想要的轴的比例。 例如,如果您希望 x 和 y 轴在对数刻度上,您应该编写:
ax.xaxis.set_scale('log')
ax.yaxis.set_scale('log')
并最终:
ax.zaxis.set_scale('log')
我想要一个符号图,并且由于我手动填充数据数组,因此我只是创建了一个自定义函数来计算日志,以避免在数据 < 1 时bar3d
中出现负条:
import math as math
def manual_log(data):
if data < 10: # Linear scaling up to 1
return data/10
else: # Log scale above 1
return math.log10(data)
由于我没有负值,所以我没有在这个函数中实现处理这个值,但是改变它应该不难。
我从第209期中汲取灵感,想出了一个简单易用的解决方案。 您定义一个小型格式化程序函数,您可以在其中设置自己的符号。
import matplotlib.ticker as mticker
# My axis should display 10⁻¹ but you can switch to e-notation 1.00e+01
def log_tick_formatter(val, pos=None):
return f"$10^{{{int(val)}}}$" # remove int() if you don't use MaxNLocator
# return f"{10**val:.2e}" # e-Notation
ax.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))
ax.zaxis.set_major_locator(mticker.MaxNLocator(integer=True))
set_major_locator
将指数设置为仅使用整数set_major_locator
而不使用 10^-1.5 等。 来源
Important!
如果您不使用set_major_locator
并且想要显示 10^-1.5,则删除 return 语句中的 cast int()
否则它仍将打印 10⁻¹ 而不是 10^-1.5。
自己试试吧!
from mpl_toolkits.mplot3d import axes3d
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
fig = plt.figure(figsize=(11,8))
ax1 = fig.add_subplot(121,projection="3d")
# Grab some test data.
X, Y, Z = axes3d.get_test_data(0.05)
# Now Z has a range from 10⁻³ until 10³, so 6 magnitudes
Z = (np.full((120, 120), 10)) ** (Z / 20)
ax1.plot_wireframe(X, Y, Z, rstride=10, cstride=10)
ax1.set(title="Linear z-axis (small values not visible)")
def log_tick_formatter(val, pos=None):
return f"$10^{{{int(val)}}}$"
ax2 = fig.add_subplot(122,projection="3d")
# You still have to take log10(Z) but thats just one operation
ax2.plot_wireframe(X, Y, np.log10(Z), rstride=10, cstride=10)
ax2.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))
ax2.zaxis.set_major_locator(mticker.MaxNLocator(integer=True))
ax2.set(title="Logarithmic z-axis (much better)")
plt.savefig("LinearLog.png", bbox_inches='tight')
plt.show()
由于问题209,没有解决办法。但是,您可以尝试这样做:
ax.plot_surface(X, np.log10(Y), Z, cmap='jet', linewidth=0.5)
如果在“Y”中有一个 0,它会出现警告但仍然有效。 由于此警告色图不起作用,因此请尽量避免使用 0 和负数。 例如:
Y[Y != 0] = np.log10(Y[Y != 0])
ax.plot_surface(X, Y, Z, cmap='jet', linewidth=0.5)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.