Matplotlib中imshow的非线性坐标轴

26

我正在生成基于对数轴的二维数组(例如,x像素坐标使用logspace(log10(0.95), log10(2.08), n)生成)。

我想使用普通的imshow显示图像,以其本地分辨率和缩放比例显示(我不需要拉伸它;数据本身已经是对数比例),但我想添加在对数轴上正确位置的刻度、标签和线条。我该如何做?

理想情况下,我只需使用类似axvline(1.5)的命令即可将线条放置在正确的位置(距离左侧58%的位置),但如果唯一的方法是手动在对数比例坐标和图像坐标之间进行转换,那也可以。

对于线性轴,使用extents=调用imshow可以实现我想要的效果,但我没有看到在对数轴上实现相同效果的方法。

示例:

from matplotlib.colors import LogNorm

x = logspace(log10(10), log10(1000), 5)
imshow(vstack((x,x)), extent=[10, 1000, 0, 100], cmap='gray', norm=LogNorm(), interpolation='nearest')
axvline(100, color='red')

这个例子无法正常工作,因为 extent= 仅适用于线性比例尺,因此当您在100处执行 axvline时,它不会出现在中心位置。我希望 x 轴显示 10、100、1000,axvline(100) 在 100 点处插入一条竖直线,同时像素仍然保持等间距。

你能提供一些可工作的代码或者你想要实现的图片吗?另一个问题是,你是否可以灵活地使用pcolor而不是imshow? - imsc
@imsc:增加了一个例子。我认为pcolor很好。 - endolith
3个回答

21

在我的看法中,更好的做法是使用 pcolor 和常规(未转换)x和y值。 pcolor 给你更多的灵活性,而常规的x和y轴会更少引起混淆。

import pylab as plt
import numpy as np
from matplotlib.colors import LogNorm
from matplotlib.ticker import LogFormatterMathtext

x=np.logspace(1, 3, 6)
y=np.logspace(0, 2,3)
X,Y=np.meshgrid(x,y)
z = np.logspace(np.log10(10), np.log10(1000), 5)
Z=np.vstack((z,z))

im = plt.pcolor(X,Y,Z, cmap='gray', norm=LogNorm())
plt.axvline(100, color='red')

plt.xscale('log')
plt.yscale('log')

plt.colorbar(im, orientation='horizontal',format=LogFormatterMathtext())
plt.show()

enter image description here

由于 pcolor 函数速度较慢,更快的解决方案是改用 pcolormesh 函数。

im = plt.pcolormesh(X,Y,Z, cmap='gray', norm=LogNorm())

1
这看起来像是可以解决我的问题。这里有一个更简单的例子,可以解决我试图解决的问题:https://gist.github.com/3124528 。所以pcolor就像是一个非常慢的imshow,它将每个像素绘制成一个矩形?没有办法使用imshow进行“xscale('log')”吗? - endolith
pcolormesh看起来是做同样事情的一种更快的方法。“pcolormesh使用了QuadMesh,这是对pcolor的一种更快的泛化,但有一些限制。” 不确定那些限制是什么,但它似乎能够正常工作。 - endolith
pcolormesh似乎是一个不错的选择。其中一个限制是它不能与掩码坐标数组一起使用。 - imsc
不幸的是,与imshow相比,这会导致结果图像中的插值错误。:/ 等等.....我刚刚尝试了带有extent的imshow,并跟随xscale('log'),它可以正常工作。 - endolith
你能把你的解决方案作为一个新答案吗? - imsc

11

实际上,它运行良好。我感到困惑。

之前我一直在遇到“图像不支持非线性轴”的错误,这就是为什么我提出了这个问题。但现在当我尝试它时,它可以工作:

import matplotlib.pyplot as plt
import numpy as np

x = np.logspace(1, 3, 5)
y = np.linspace(0, 2, 3)
z = np.linspace(0, 1, 4)
Z = np.vstack((z, z))

plt.imshow(Z, extent=[10, 1000, 0, 1], cmap='gray')
plt.xscale('log')

plt.axvline(100, color='red')

plt.show()

这比 pcolor()pcolormesh() 更好,因为

  1. 它不会无比缓慢且
  2. 当图像未以本机分辨率显示时,它可以进行漂亮的插值而不会出现误导性伪影。

2
我们发现如果删除 extent 就无法工作。也就是说,plt.imshow(Z,cmap='gray'); plt.xscale('log') 会引发错误。 - Developer
2
@开发者,可能是因为默认范围从0开始吧? - endolith
2
这在MPL2中停止工作了吗?很可能是:http://matplotlib.org/devdocs/users/whats_new.html#non-linear-scales-on-image-plots - endolith
8
这还有效吗?我没有收到任何错误信息,但是图像被对数比例拉伸变形了。就好像我希望所有的正方形大小都相同,但它们并不相同。 - Marses
2
我认为它不再起作用了,我的图像也被拉伸了。在@endolith提供的示例中,有4个不同的值应该随着x=31.6、100和316而改变。然而,在图像中,这些变化大约在250、500和750左右。显然有些地方出了问题!有人知道如何解决吗? - BayesianMonk
显示剩余3条评论

-2

要在横坐标上显示对数刻度的imshow:

ax = fig.add_subplot(nrow, ncol, i+1)
ax.set_xscale('log')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接