Как динамически обновлять сюжет matplotlib, используя изображения вместо маркеров - PullRequest
0 голосов
/ 27 марта 2020

Я играю с динамическими c обновлениями сюжетов matplotlib.

Я хотел бы иметь возможность динамически обновлять график, основываясь на сборе некоторых данных, скажем, каждые 0,5 секунды. Однако вместо использования маркеров я хотел бы иметь возможность использовать изображение JPG. т.е. нанесите несколько изображений и переместите их вдоль оси.

Вот фиктивный код, который выполняет идею с использованием маркеров:

import matplotlib.pyplot as plt
import random
plt.ion()
class DynamicUpdate():
    #Suppose we know the x range
    min_x = 0
    max_x = 10

    def on_launch(self):
        self.figure, self.ax = plt.subplots()
        self.lines, = self.ax.plot([],[], 'o')
        self.ax.set_xlim(self.min_x, self.max_x)
        self.ax.set_ylim(0,500)
        self.ax.grid()

    def on_running(self, xdata, ydata):
        self.lines.set_xdata(xdata)
        self.lines.set_ydata(ydata)
        self.figure.canvas.draw()
        self.figure.canvas.flush_events()

    #Example
    def __call__(self):
        import numpy as np
        import time
        self.on_launch()
        xdata = np.arange(10)
        ydata = np.zeros(10)
        for it in range(100):
            ydata=[y+random.randint(1,10) for y in ydata]
            self.on_running(xdata, ydata)
            time.sleep(0.5)
        return xdata, ydata

d = DynamicUpdate()
d()
plt.show()

Я пытался использовать imshow() для добавления изображений на ось, но они отказываются обновляться и перемещаться по мере изменения данных.

Если у кого-то есть какие-нибудь яркие идеи, я был бы благодарен.

1 Ответ

0 голосов
/ 27 марта 2020

Кажется, это ведет себя так, как я хотел - изображения размещаются на оси и перемещаются вдоль, пока не будет выполнено определенное количество шагов.

Включает код для автоматической установки изображения на соответствующий размер на оси:

import matplotlib.pyplot as plt
import random
import matplotlib.image as image

plt.ion()

def get_ax_size(fig, ax):
    '''
    Returns the size of a given axis in pixels

    Args:
       fig (matplotlib figure)
       ax (matplotlib axes)

    '''
    bbox = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
    width, height = bbox.width, bbox.height
    width *= fig.dpi
    height *= fig.dpi
    return width, height


def get_extent(fig, ax, image_name, xsize, xpos, ypos):
    '''
    Places an image on a given axes whilst maintaining its aspect ratio

    Args:
        fig (matplotlib figure)
        ax (matplotlib axes)
        image_name (string): name of image to place on axes
        xsize(float): size of the x-dimension of object given as fraction of the axes length
        xpos(float): x-coordinate of image given as fraction of axes
        ypos(float): y-coordinate of image given as fraction of axes

    '''
    import matplotlib.image as image

    im = image.imread(image_name)

    xrange=ax.get_xlim()[1]-ax.get_xlim()[0]
    yrange=ax.get_ylim()[1]-ax.get_ylim()[0]

    ysize=(im.shape[0]/im.shape[1])*(xsize*get_ax_size(fig,ax)[0])/get_ax_size(fig,ax)[1]

    xsize *= xrange
    ysize *= yrange

    xpos = (xpos*xrange) + ax.get_xlim()[0]
    ypos = (ypos*yrange) + ax.get_ylim()[0]

    return (xpos,xpos+xsize,ypos,ypos+ysize)

class DynamicUpdate():

    def on_launch(self):
        self.figure, self.ax = plt.subplots()
        self.lines, = self.ax.plot([],[], 'o')
        self.im = []
        self.ax.set_xlim(0,10)
        self.ax.set_ylim(0,100)
        self.ax.grid()

    def on_running(self, xdata, ydata):
        global flags

        im = image.imread('Image.jpg')

        for flag in flags:
            flag.remove()
        flags = []
        for i,x in enumerate(xdata):
            extent=get_extent(self.figure,self.ax,'Image.jpg',0.1,x,ydata[i])
            print(extent)
            flags.append(self.ax.imshow(im,aspect='auto',extent=extent,interpolation='none', zorder=10 ))

        self.figure.canvas.draw()
        self.figure.canvas.flush_events()

    #Example
    def __call__(self):
        import numpy as np
        import time
        self.on_launch()
        xdata = np.arange(10)/10
        ydata = np.zeros(10)
        for it in range(100):
            if it < 10:
                ydata=[(y+random.randint(1,5))  for y in ydata]
            self.on_running(xdata, ydata/self.ax.get_ylim()[1]-self.ax.get_ylim()[0])
            time.sleep(0.2)
        return xdata, ydata

flags=[]
d = DynamicUpdate()
d()
plt.show()
...