简体   繁体   English

使用Matplotlib绘制数据的动画散点图

[英]Animated scatterplot of data with Matplotlib

I tried to adapt animated scatter plot-example in such a way, so it shows real-time the results of an agent based-model I developed. 我尝试以这种方式调整动画散点图示例,因此它实时显示了我开发的基于代理的模型的结果。 However, the result shown in the graph are not that what I except them to be. 但是,图表中显示的结果并不是我除了它们之外的结果。 It goes wrong when updating the values, and strange patterns appear where the agents tend to cluster in a diagonal line. 更新值时出错,并且代理倾向于在对角线中聚集的地方出现奇怪的模式。 I added some simple code that illustrates this problem. 我添加了一些简单的代码来说明这个问题。 Does anyone has an idea what goes wrong? 有谁知道出了什么问题?

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

n = 25 ## nr of agents
x,y = 10, 10 ## matrix of x by y dimension
dataX, dataY, binaryRaster = [],[],[]

class AnimatedScatter(object):
    """An animated scatter plot using matplotlib.animations.FuncAnimation."""
    def __init__(self):
        global n
        self.numpoints = n
        self.stream = self.data_stream()
        self.fig, self.ax = plt.subplots()
        self.ax.set_title("My first Agent Based Model (ABM)",fontsize=14)
        self.ax.grid(True,linestyle='-',color='0.75')
        self.ani = animation.FuncAnimation(self.fig, self.update, interval=100, 
                                           init_func=self.setup_plot, blit=True,
                                           repeat=False)

    def setup_plot(self):
        """Initial drawing of the scatter plot."""
        global x,y
        dataX,dataY = next(self.stream)
        self.scat = self.ax.scatter(dataY, dataX, c="tomato", s=20, animated=True)
        self.ax.axis([0, y, x, 0])
        return self.scat,

    def data_stream(self):
        """Generate a random walk (brownian motion). Data is scaled to produce
        a soft "flickering" effect."""
        global x,y, n

        dataX,dataY = self.createRandomData()

        #printing results to ascii for validation
        lines = []
        binaryData = np.zeros((x,y), dtype=np.int)
        for i in range(n):
            binaryData[dataX,dataY] =1
        for i in range(x):
            line = ""
            for j in range(y):
                line += str(binaryData[i,j])+ ","
            line= line[:-1]+ "\n"
            lines.append(line)
        lines.append("\n")

        yx = np.array([dataY,dataX])
        cnt = 0
        while cnt < 10:
            dataX,dataY = self.createRandomData()
            yx = np.array([dataY,dataX])

            #printing results to ascii for validation
            binaryData = np.zeros((x,y), dtype=np.int)
            for i in range(n):
                binaryData[dataX,dataY] =1
            for i in range(x):
                line = ""
                for j in range(y):
                    line += str(binaryData[i,j])+ ","
                line= line[:-1]+ "\n"
                lines.append(line)
            lines.append("\n")

            cnt+=1
            yield yx

        #printing results to ascii for validation

        outNm = os.getcwd()+"\\ScatterValidation.txt"
        outfile = open(outNm, "w")
        outfile.writelines(lines)
        outfile.close()
        return

    def update(self, i):
        """Update the scatter plot."""
        data = next(self.stream)
        self.scat.set_offsets(data[:2, :])
        return self.scat,

    def show(self):
        plt.show()

    def createRandomData(self):
        """Positions n agents randomly on a raster of x by y cells.
        Each cell can only hold a single agent."""

        global x,y,n
        binaryData = np.zeros((x,y), dtype=np.int)
        newAgents = 0
        dataX,dataY = [],[]
        while newAgents < n:
            row = np.random.randint(0,x,1)[0]
            col = np.random.randint(0,y,1)[0]
            if binaryData[row][col] != 1:
                binaryData[row][col] = 1
                newAgents+=1

        for row in range(x):
            for col in range(y):
                if binaryData[row][col] == 1:
                    dataX.append(row)
                    dataY.append(col)
        return dataX, dataY

def main():
    global n, x, y, dataX, dataY, binaryRaster
    a = AnimatedScatter()
    a.show()
    return

if __name__ ==  "__main__":
    main()

You can fix your script in 2 ways, both involve changing the update function: 您可以通过两种方式修复脚本,两者都涉及更改update功能:

  1. Using a scatter call in the update function, is clearer I think 我认为在更新函数中使用分散调用更清晰
  2. Transposing the data array before calling set_offsets in update 在更新中调用set_offsets之前转置数据数组

Using a scatter call is the clearest fix, and you could increase the agents during your run: 使用分散调用是最明确的修复,您可以在运行期间增加代理:

def update(self, i):
    """Update the scatter plot."""
    dataX, dataY = next(self.stream)
    self.scat = self.ax.scatter(dataX, dataY, c="tomato", s=20, animated=True)
    return self.scat,

Transposing the offsets array will also work: 转置偏移数组也可以:

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

Offsets are given as a N tuples of 2 items each while the data array is given as 2 tuples with N items each, transposing the data array will fix your problem. 偏移量为每个2个项目的N个元组,而数据数组则为2个元组,每个元素包含N个项目,转置数据数组将解决您的问题。

Note: If you do not change the global variables, you do not need to specify the globals with a global statement, so in setup_plot , __init__ etc. you can remove the global n,x,y lines. 注意:如果不更改全局变量,则不需要使用全局语句指定全局变量,因此在setup_plot__init__等中,可以删除global n,x,y行。 I would put n , x and y as instance variables of your class, plus there is no need for dataX , dataY and binaryRasted to be defined at the top of your script. 我会将nxy作为类的实例变量,而且binaryRasted在脚本的顶部定义dataXdataYbinaryRasted

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM