Как питонически передать numpy.array методу объектов в numpy.array - PullRequest
2 голосов
/ 26 марта 2019

У меня есть двумерный массив NumPy txtStrs, содержащий строки, которые я пишу в виде текста на ось фигуры matplotlib ax, используя, например,

ax.text( posX, posY, txtStrs[0,0] )

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

Когда я теперь хочу обновить тексты, я использовал два цикла for

    import numpy as np
    import matplotlib.pyplot as plt
    siz = 20

    txtStrs = np.empty( (siz, siz), dtype = str )
    txtObjs = np.empty( (siz, siz), dtype = object )

    plt.figure()
    ax = plt.gca()
    for x in range(siz):
        for y in range(siz)):
            txtObjs[x,y] = ax.text( x, y, "" )

    #Fill txtStrs with some string values

    for x in range(siz):
        for y in range(siz)):
            txtObjs[x,y].set_text( txtStrs[x,y] )

Последний цикл for кажется ненужным и не совсем питоническиммне.Если бы мне не нужно было вызывать метод set_text, я мог бы использовать внутренние обновления numpy для обновления.

Мой вопрос: есть ли другой способ передать txtStrs в txtObjs,например, используя векторизацию, списочное понимание или что-то еще?

Ответы [ 2 ]

2 голосов
/ 26 марта 2019

Петли Pythonic!

И использование метода set_text объекта matplotlib.text также допустимо для Python. Вот как мы работаем с объектами - используйте их методы.

С numpy мы стараемся избегать циклов, но это значительно экономит время, если массив содержит числовые (или строковые) dtypes. Затем он может выполнить итерацию в скомпилированном коде, используя предоставленные методы массива. Ваш массив txtObjs является объектом типа d, и большинство операций с таким массивом включает итерацию уровня Python, даже если он скрыт. Как и список, массив объектов содержит указатели на объекты в других местах памяти. Он должен ссылаться на каждый объект и использовать свои собственные методы.

Итерация для массивов объектов немного медленнее, чем итерация для списков, хотя многомерный характер массивов может сделать итерацию более привлекательной.

Понимание списка - это аккуратный способ написания цикла for - если вы возвращаете новый список. Это не относится к модификациям на месте. То же самое касается некоторых простых функций, которые «векторизуют» (скрывают) итерации.

Если txtObjs и txtStrs являются списками одинакового размера, то

for a, b in zip(txtObjs, txtStrs):
    a.set_text(b)

должен обновить все text объекты.

Для двумерных массивов:

for a, b in zip(txtObjs.ravel(), txtStrs.ravel()):

тоже должно работать. Двумерная форма этих массивов мешает простой передаче значений, хотя это может быть удобно при установке начальных координат.

2 голосов
/ 26 марта 2019

Вот кое-что, что уменьшит эти два цикла до одного, но я не думаю, что есть «apply», «forEach» или что-то в этом роде.

for (x, y), text_obj in np.ndenumerate(txtObjs):
    text_obj.set_text(txtStrs[x, y])

Используется ndenumerate , который представляет собой аккуратный способ перебора n-мерного массива numpy.

...