Làm thế nào để tạo hoạt ảnh cho một âm mưu phân tán?


82

Tôi đang cố tạo hoạt ảnh của một biểu đồ phân tán trong đó màu sắc và kích thước của các điểm thay đổi ở các giai đoạn khác nhau của hoạt ảnh. Đối với dữ liệu, tôi có hai ndarray numpy với giá trị x và giá trị y:

data.shape = (ntime, npoint)
x.shape = (npoint)
y.shape = (npoint)

Bây giờ tôi muốn vẽ một biểu đồ phân tán thuộc loại

pylab.scatter(x,y,c=data[i,:])

và tạo hoạt ảnh trên chỉ mục i. Làm thế nào để tôi làm điều này?


1
Có một ví dụ trong tài liệu matplotlib: Mô phỏng mưa .
Tầm quan

Câu trả lời:


141

Giả sử bạn có một biểu đồ phân tán scat = ax.scatter(...), thì bạn có thể

  • thay đổi vị trí

        scat.set_offsets(array)
    

    đâu arraylà một N x 2mảng có hình dạng của tọa độ x và y.

  • thay đổi kích thước

        scat.set_sizes(array)
    

    đâu arraylà mảng kích thước 1D tính bằng điểm.

  • thay đổi màu sắc

        scat.set_array(array)
    

    đâu arraylà mảng giá trị 1D sẽ được ánh xạ màu.

Đây là một ví dụ nhanh bằng cách sử dụng mô-đun hoạt ảnh .
Nó phức tạp hơn một chút so với hiện tại, nhưng điều này sẽ cung cấp cho bạn một khuôn khổ để thực hiện những điều kỳ diệu hơn.

(Mã được chỉnh sửa vào tháng 4 năm 2019 để tương thích với các phiên bản hiện tại. Đối với mã cũ hơn, hãy xem lịch sử sửa đổi )

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

class AnimatedScatter(object):
    """An animated scatter plot using matplotlib.animations.FuncAnimation."""
    def __init__(self, numpoints=50):
        self.numpoints = numpoints
        self.stream = self.data_stream()

        # Setup the figure and axes...
        self.fig, self.ax = plt.subplots()
        # Then setup FuncAnimation.
        self.ani = animation.FuncAnimation(self.fig, self.update, interval=5, 
                                          init_func=self.setup_plot, blit=True)

    def setup_plot(self):
        """Initial drawing of the scatter plot."""
        x, y, s, c = next(self.stream).T
        self.scat = self.ax.scatter(x, y, c=c, s=s, vmin=0, vmax=1,
                                    cmap="jet", edgecolor="k")
        self.ax.axis([-10, 10, -10, 10])
        # For FuncAnimation's sake, we need to return the artist we'll be using
        # Note that it expects a sequence of artists, thus the trailing comma.
        return self.scat,

    def data_stream(self):
        """Generate a random walk (brownian motion). Data is scaled to produce
        a soft "flickering" effect."""
        xy = (np.random.random((self.numpoints, 2))-0.5)*10
        s, c = np.random.random((self.numpoints, 2)).T
        while True:
            xy += 0.03 * (np.random.random((self.numpoints, 2)) - 0.5)
            s += 0.05 * (np.random.random(self.numpoints) - 0.5)
            c += 0.02 * (np.random.random(self.numpoints) - 0.5)
            yield np.c_[xy[:,0], xy[:,1], s, c]

    def update(self, i):
        """Update the scatter plot."""
        data = next(self.stream)

        # Set x and y data...
        self.scat.set_offsets(data[:, :2])
        # Set sizes...
        self.scat.set_sizes(300 * abs(data[:, 2])**1.5 + 100)
        # Set colors..
        self.scat.set_array(data[:, 3])

        # We need to return the updated artist for FuncAnimation to draw..
        # Note that it expects a sequence of artists, thus the trailing comma.
        return self.scat,


if __name__ == '__main__':
    a = AnimatedScatter()
    plt.show()

nhập mô tả hình ảnh ở đây

Nếu bạn đang sử dụng OSX và sử dụng phần phụ trợ OSX, bạn sẽ cần phải thay đổi blit=Truethành blit=Falsetrong phần FuncAnimationkhởi tạo bên dưới. Phần phụ trợ OSX không hoàn toàn hỗ trợ blush. Hiệu suất sẽ bị ảnh hưởng, nhưng ví dụ này sẽ chạy chính xác trên OSX khi bị tắt tính năng thổi.


Đối với một ví dụ đơn giản hơn, chỉ cập nhật màu sắc, hãy xem phần sau:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation

def main():
    numframes = 100
    numpoints = 10
    color_data = np.random.random((numframes, numpoints))
    x, y, c = np.random.random((3, numpoints))

    fig = plt.figure()
    scat = plt.scatter(x, y, c=c, s=100)

    ani = animation.FuncAnimation(fig, update_plot, frames=xrange(numframes),
                                  fargs=(color_data, scat))
    plt.show()

def update_plot(i, data, scat):
    scat.set_array(data[i])
    return scat,

main()

Xin chào Joe Tôi đã thử ví dụ đầu tiên của bạn nhưng nó không hoạt động trong khi ví dụ thứ hai thì có. Có lẽ tôi sẽ cố gắng gỡ lỗi tùy chọn đầu tiên, điều này sẽ giúp tôi nâng cao kiến ​​thức về python của mình. Cảm ơn bạn
Nicola Vianello 27/02/12

1
Thật không may, ví dụ đầu tiên không hiển thị cho tôi hoặc bằng cách sử dụng matplotlib 1.3.1 trên OS X. Tôi nhận được khung hình không có điểm nào được hiển thị. Ví dụ thứ hai hoạt động.
JoshAdel

8
LÀM THẾ NÀO TRONG THẾ GIỚI, bạn đã tìm ra thứ .set_array()sẽ cập nhật màu chấm ?!
Lucas

1
Ví dụ đầu tiên là không làm việc bạn phải thay đổi dòng self.Scat.set_offsets(data[:2, :]) để self.scat.set_offsets(data[:2, :].reshape(self.numpoints, 2))
AN O'Nyme

2
Có chức năng nào thay đổi điểm đánh dấu của các điểm phân tán không?
Constantinos

13

Tôi đã viết celluloid để làm cho việc này dễ dàng hơn. Nó có thể dễ dàng nhất để hiển thị bằng ví dụ:

import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from celluloid import Camera

numpoints = 10
points = np.random.random((2, numpoints))
colors = cm.rainbow(np.linspace(0, 1, numpoints))
camera = Camera(plt.figure())
for _ in range(100):
    points += 0.1 * (np.random.random((2, numpoints)) - .5)
    plt.scatter(*points, c=colors, s=100)
    camera.snap()
anim = camera.animate(blit=True)
anim.save('scatter.mp4')

nhập mô tả hình ảnh ở đây

Nó sử dụng ArtistAnimationdưới mui xe. camera.snapchụp trạng thái hiện tại của hình được sử dụng để tạo khung trong hoạt ảnh.

Chỉnh sửa: Để định lượng bộ nhớ này sử dụng, tôi đã chạy nó thông qua memory_profiler .

Line #    Mem usage    Increment   Line Contents
================================================
    11     65.2 MiB     65.2 MiB   @profile
    12                             def main():
    13     65.2 MiB      0.0 MiB       numpoints = 10
    14     65.2 MiB      0.0 MiB       points = np.random.random((2, numpoints))
    15     65.2 MiB      0.1 MiB       colors = cm.rainbow(np.linspace(0, 1, numpoints))
    16     65.9 MiB      0.6 MiB       fig = plt.figure()
    17     65.9 MiB      0.0 MiB       camera = Camera(fig)
    18     67.8 MiB      0.0 MiB       for _ in range(100):
    19     67.8 MiB      0.0 MiB           points += 0.1 * (np.random.random((2, numpoints)) - .5)
    20     67.8 MiB      1.9 MiB           plt.scatter(*points, c=colors, s=100)
    21     67.8 MiB      0.0 MiB           camera.snap()
    22     70.1 MiB      2.3 MiB       anim = camera.animate(blit=True)
    23     72.1 MiB      1.9 MiB       anim.save('scatter.mp4')

Để tóm tắt điều này:

  • Tạo 100 ô được sử dụng 1,9 MiB.
  • Tạo hoạt ảnh được sử dụng 2.3 MiB.
  • Phương pháp tạo hoạt ảnh này sử dụng tổng cộng 4,2 MiB bộ nhớ.

Vì điều này sử dụng ArtistAnimation, nó sẽ tạo ra 100 ô phân tán trong bộ nhớ, điều này khá kém hiệu quả. Chỉ sử dụng điều này nếu hiệu suất không quan trọng đối với bạn.
Tầm quan

1
Cấu hình bộ nhớ là một ý tưởng hay. Bạn đã làm như vậy cho FuncAnimation? Sự khác biệt là gì?
Tầm quan

1
Làm cách nào để bạn phân tán hoạt ảnh (như được sử dụng để lưu nó vào tệp)?
argentum2f

5

Đây là điều. Tôi đã từng sử dụng Qt và Matlab và tôi không quen lắm với hệ thống hoạt ảnh trên matplotlib.

Nhưng tôi đã tìm ra cách có thể tạo ra bất kỳ loại hoạt ảnh nào bạn muốn giống như trong matlab. Nó thực sự mạnh mẽ. Không cần phải kiểm tra các tham chiếu mô-đun và bạn có thể vẽ bất cứ thứ gì bạn muốn. Vì vậy, tôi hy vọng nó có thể giúp ích.

Ý tưởng cơ bản là sử dụng sự kiện thời gian bên trong PyQt (Tôi chắc chắn rằng hệ thống Gui khác trên Python như wxPython và TraitUi có cùng một cơ chế bên trong để thực hiện phản hồi sự kiện. Nhưng tôi không biết làm thế nào). Mỗi khi sự kiện Bộ đếm thời gian của PyQt được gọi, tôi làm mới toàn bộ khung vẽ và vẽ lại toàn bộ bức tranh, tôi biết tốc độ và hiệu suất có thể bị ảnh hưởng từ từ nhưng không nhiều lắm.

Đây là một ví dụ nhỏ về nó:

import sys
from PyQt4 import QtGui

from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

import numpy as np


class Monitor(FigureCanvas):
    def __init__(self):
        self.fig = Figure()
        self.ax = self.fig.add_subplot(111)

        FigureCanvas.__init__(self, self.fig)
        self.x = np.linspace(0,5*np.pi,400)
        self.p = 0.0
        self.y = np.sin(self.x+self.p)


        self.line = self.ax.scatter(self.x,self.y)

        self.fig.canvas.draw()

        self.timer = self.startTimer(100)


    def timerEvent(self, evt):
        # update the height of the bars, one liner is easier
        self.p += 0.1
        self.y = np.sin(self.x+self.p)
        self.ax.cla()
        self.line = self.ax.scatter(self.x,self.y)

        self.fig.canvas.draw()



if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    w = Monitor()
    w.setWindowTitle("Convergence")
    w.show()
    sys.exit(app.exec_())

Bạn có thể điều chỉnh tốc độ làm mới trong

        self.timer = self.startTimer(100)

Tôi cũng giống như bạn muốn sử dụng biểu đồ phân tán Hoạt hình để tạo hoạt ảnh sắp xếp. Nhưng tôi không thể tìm thấy một chức năng được gọi là "thiết lập". Vì vậy, tôi đã làm mới toàn bộ canva.

Hy vọng nó giúp..


Thực sự tốt đẹp! Tuy nhiên, tôi không nhận được bất kỳ thay đổi nào về tốc độ làm mới bằng cách điều chỉnh self.startTimergiá trị ... bất kỳ mẹo nào về điều đó? (Vâng, tôi biết nó được một thời gian ...)
H. Arponen

-1

Tại sao không thử cái này

import numpy as np
import matplotlib.pyplot as plt

x=np.random.random()
y=np.random.random()

fig, ax = plt.subplots()
ax.scatter(x,y,color='teal')
ax.scatter(y,x,color='crimson')
ax.set_xlim([0,1])
ax.set_ylim([0,1])

for i in np.arange(50):
    x=np.random.random()
    y=np.random.random()
    bha=ax.scatter(x,y)
    plt.draw()
    plt.pause(0.5)
    bha.remove()

plt.show()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.