Как построить изображение с нелинейной осью y с помощью Matplotlib с помощью imshow?

Как я могу построить 2D-массив как изображение с библиотек matplotlib имея шкалу y относительно мощности двух значений y?

например, первая строка моего массива будет иметь высоту в изображении 1,вторая строка будет иметь высоту 4 и т. д. (единицы не имеют значения) Это не просто объяснить словами, поэтому посмотрите на это изображение, пожалуйста (это тот результат, который я хочу):

alt-текст http://support.sas.com/rnd/app/da/new/802ce/iml/chap1/images/wavex1k.gif

Как вы можете видеть, первая строка в 2 раза меньше, чем верхняя, и так далее.

для тех, кто интересуется, почему я пытаюсь сделать это:

У меня довольно большой массив (10, 700000) поплавков, представляющих дискретные коэффициенты вейвлет-преобразования звукового файла. Я пытаюсь построить scalogram, используя эти коэффициенты. Я мог бы скопировать массив x раз, пока не получу желаемый размер строки изображения, но память не может содержать столько информации...

4 ответов


вы пытались преобразовать ось? Например:

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")

вот пример (с массивом, содержащим случайные значения):

alt текст http://img691.imageshack.us/img691/8883/clipboard01f.png


вы можете посмотреть библиотек matplotlib.изображение.NonUniformImage. Но это помогает только с неоднородной осью-я не думаю, что вы сможете строить адаптивно, как хотите (я думаю, что каждая точка на изображении всегда будет иметь одну и ту же область - поэтому вам придется иметь более широкие строки несколько раз). Есть ли причина, по которой вам нужно построить полный массив? Очевидно, что полная деталь не будет отображаться в любом сюжете - поэтому я бы предложил сильно уменьшить исходная матрица, поэтому вы можете копировать строки по мере необходимости, чтобы получить изображение без исчерпания памяти.


лучший способ сделать scalogram с помощью 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 создает тонкое пространство между уровнями. Я все еще ищу способ исправить это.

P.S. - хотя этот вопрос довольно старый, я решил, что отвечу здесь, потому что эта страница появилась в Google, когда я искал метод создания scalograms с использованием MPL.


Если вы хотите, чтобы иметь возможность увеличить и сохранить память, вы можете сделать рисунок "вручную". Matplotlib позволяет рисовать прямоугольники (они будут вашими "прямоугольными пикселями"):

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

обратите внимание, что экстенты осей не задаются add_patch (), но вы можете установить их самостоятельно на нужные значения (оси.set_xlim,...).

PS: мне кажется, что ответ thrope (matplotlib.изображение.NonUniformImage) на самом деле можно делать, что хочешь, проще так что "ручной" метод, описанный здесь!