10

如何使用Matplotlib将 2D 数组绘制为图像,其 y 比例相对于两个 y 值的幂?

例如,我的数组的第一行在图像中的高度为 1,第二行的高度为 4,依此类推(单位无关)用文字解释并不简单,所以请看这张图片(那是我想要的结果):

替代文字 http://support.sas.com/rnd/app/da/new/802ce/iml/chap1/images/wavex1k.gif

如您所见,第一行比上一行小 2 倍,依此类推。

对于那些对我为什么要这样做感兴趣的人:

我有一个相当大的浮点数组(10、700000),代表声音文件的离散小波变换系数。我正在尝试使用这些系数绘制比例图。我可以复制数组 x 次,直到获得所需的图像行大小,但内存无法容纳这么多信息......

4

4 回答 4

8

您是否尝试过转换轴?例如:

ax = subplot(111)
ax.yaxis.set_ticks([0, 2, 4, 8])
imshow(data)

这意味着不存在坐标的数据中必须存在间隙,除非有办法提供变换函数而不仅仅是列表(从未尝试过)。

编辑

我承认这只是一个线索,而不是一个完整的解决方案。这是我更详细的意思。

假设您将数据放在一个数组中,a. 您可以使用这样的转换:

class arr(object):
    @staticmethod
    def mylog2(x):
        lx = 0
        while x > 1:
            x >>= 1
            lx += 1
        return lx
    def __init__(self, array):
        self.array = array
    def __getitem__(self, index):
        return self.array[arr.mylog2(index+1)]
    def __len__(self):
        return 1 << len(self.array)

基本上,它将使用mylog2函数转换数组或列表的第一个坐标(您可以根据需要进行转换 - 它是自制的 log2 的简化版)。优点是,您可以在需要时将其重新用于另一个转换,并且您也可以轻松控制它。

然后将您的数组映射到这个数组,它不会复制,而是实例中的本地引用:

b = arr(a)

现在您可以显示它,例如:

ax = subplot(111)
ax.yaxis.set_ticks([16, 8, 4, 2, 1, 0])
axis([-0.5, 4.5, 31.5, 0.5])
imshow(b, interpolation="nearest")

这是一个示例(带有包含随机值的数组):

替代文字 http://img691.imageshack.us/img691/8883/clipboard01f.png

于 2009-11-05T09:48:03.663 回答
4

我发现使用 matplotlib 制作比例图的最佳方法是使用imshow,类似于specgram. 使用矩形很慢,因为您必须为每个值制作单独的字形。同样,您不希望将事物烘焙到统一的 NumPy 数组中,因为您可能会很快耗尽内存,因为您的最高级别将大约是信号的一半。

这是一个使用 SciPy 和PyWavelets的示例:

from pylab import *
import pywt
import scipy.io.wavfile as wavfile

# Find the highest power of two less than or equal to the input.
def lepow2(x):
    return 2 ** floor(log2(x))

# Make a scalogram given an MRA tree.
def scalogram(data):
    bottom = 0

    vmin = min(map(lambda x: min(abs(x)), data))
    vmax = max(map(lambda x: max(abs(x)), data))

    gca().set_autoscale_on(False)

    for row in range(0, len(data)):
        scale = 2.0 ** (row - len(data))

        imshow(
            array([abs(data[row])]),
            interpolation = 'nearest',
            vmin = vmin,
            vmax = vmax,
            extent = [0, 1, bottom, bottom + scale])

        bottom += scale

# Load the signal, take the first channel, limit length to a power of 2 for simplicity.
rate, signal = wavfile.read('kitten.wav')
signal = signal[0:lepow2(len(signal)),0]
tree = pywt.wavedec(signal, 'db5')

# Plotting.
gray()
scalogram(tree)
show()

您可能还希望按级别自适应地缩放值。

这对我来说效果很好。我唯一的问题是 matplotlib 在级别之间创建了一个细细的空间。我仍在寻找解决此问题的方法。

PS - 尽管这个问题现在已经很老了,但我想我会在这里回答,因为当我在寻找使用 MPL 创建尺度图的方法时,这个页面出现在 Google 上。

于 2011-07-22T10:42:02.993 回答
3

您可以查看matplotlib.image.NonUniformImage。但这只会有助于轴不均匀 - 我认为你不能像你想要的那样自适应地绘制(我认为图像中的每个点总是会有相同的区域 - 所以你要必须多次使用更宽的行)。有什么理由需要绘制整个数组吗?显然,完整的细节不会出现在任何情节中 - 所以我建议对原始矩阵进行大量下采样,以便您可以根据需要复制行以获得图像而不会耗尽内存。

于 2009-11-05T09:12:50.747 回答
2

如果您希望两者都能够缩放节省内存,则可以“手动”进行绘图。Matplotlib 允许您绘制矩形(它们将是您的“矩形像素”):

from matplotlib import patches
axes = subplot(111)
axes.add_patch(patches.Rectangle((0.2, 0.2), 0.5, 0.5))

请注意,轴的范围不是由 add_patch() 设置的,但您可以自己将它们设置为您想要的值(axes.set_xlim,...)。

PS:在我看来,thrope 的响应(matplotlib.image.NonUniformImage)实际上可以做你想做的事,比这里描述的“手动”方法更简单!

于 2009-11-05T10:53:44.340 回答