Python Matplotlib: Анимация вращающейся коллекции PatchCollection - PullRequest
0 голосов
/ 14 июля 2020

Я пытаюсь создать анимацию, в которой PatchCollection вращается вокруг начала координат. Самый простой способ - использовать FuncAnimation.

В соответствии с ответом на matplotlib изменить патч в PatchCollection Я использую расширение класса PatchCollection, которое позволяет мне для обновления позиций отдельных патчей.

Функция анимации просто вызывает один из методов класса и возвращает обновленную коллекцию:

fig, ax = plt.subplots(1)

grid = HexagonalGrid()

ax.add_collection(grid)

def animate(frame):
    grid.rotateGrid(0.1)
    return (grid,)
    
anim = anim.FuncAnimation(fig, animate, blit=True)

При использовании RegularPolygon патчей все работает отлично:

class HexagonalGrid(UpdateablePatchCollection):    
    def __init__(self, latticeParameter = 5):
        self.patches = self._initiatePatches(hexRadius)
        UpdateablePatchCollection.__init__(self, self.patches, match_original=True, animated=True)

    def _initiatePatches(self, hexRadius):
        patches = []
        for :
            #calculates the correct starting position for each patch
            patches.append(self._createHex(x,y,hexRadius))
        
    def _createHex(self, x,y, hexRadius):
        return matplotlib.patches.RegularPolygon(
            (x, y),
            numVertices = 6,
            radius = hexRadius,
            orientation = 0,
            fc = (0.1, 0.1, 0.1, 0.1), # fill colour RGBA (black and transparent)
            ec = 'black' # edge colour
        )

        def rotateGrid(self, angle):
        for patch in self.patches:
            x, y = patch.xy
            xNew = x * math.cos(angle) - y * math.sin(angle)
            yNew = x * math.sin(angle) + y * math.cos(angle)
            patch.xy = (xNew, yNew)
            patch.orientation = patch.orientation + angle

Но при попытке сделать это с Rectangle патчами, которые являются тем же классом, за исключением следующих функций:

    def _createRectangle(self, x, y, width, height):
        return matplotlib.patches.Rectangle(
            (x, y),
            width,
            height,
            fc=(0.1, 0.1, 0.1, 0.1),
            ec='black',
            animated=True
        )

    def rotateGrid(self, angle):
    for patch in self.patches:
        x, y = patch.xy
        xNew = x * math.cos(angle) - y * math.sin(angle)
        yNew = x * math.sin(angle) + y * math.cos(angle)
        patch.xy = (xNew, yNew)
        patch.angle = patch.angle + angle

Прямоугольники не вращаются вместе с сеткой

Пример

(Для ясности: я ожидал, что прямоугольники тоже будут повернуты на 45 градусов)

Я уже пробовал заменить поворот на patch.set_transform(patch.get_transform() + matplotlib.transforms.Affine2D().rotate(angle)) но это имело очень странное поведение, перемещая и увеличивая участки.

Кто-нибудь знает, как заставить прямоугольники вращаться?

1 Ответ

0 голосов
/ 15 июля 2020

После некоторого исследования исходного кода matplotlib я выяснил, в чем проблема. Если кто-то еще столкнется с той же или подобной проблемой, прочтите решение ниже и посмотрите, поможет ли оно вам!

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

Поскольку я хотел изменить существующее преобразование, я использовал геттер Rectangle.get_transform(), к которому я добавил другое преобразование. По какой-то причине метод получения преобразования Rectangle (но это может быть случай для всех Patches) не возвращает установленное значение. То есть:

t = some_transformation
rect = Rectangle(x,y,width,height)
rect.set_transform(t)
print(rect.get_transform() == t) 

печатает False

Правильный геттер для использования в этом случае будет rect.get_data_transform(), после чего могут быть добавлены последующие преобразования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...