使用pyplot在地理位置上进行游戏中断

时间:2015-03-30 13:49:16

标签: python animation matplotlib

我正在制作一个标有纬度和经度的位置的散点图,它可以正常工作,因为它显示了静态图像中一段时间​​内的所有位置。但我想知道是否有任何简单的利用方式,我对每个位置都有unixtime - 所以我可以将这些动作显示为一个游戏中时光倒流 - 循环显示位置并显示动作的动画。

修改

我已经设置了一个动态更新的绘图,逐个绘制所有位置,现在我只需要在后台添加底图。代码来自this answer.

import matplotlib.pyplot as plt
import sqlite3 as lite
from operator import itemgetter

def getData():
    con = lite.connect('database.db')
    with con:
        cur = con.cursor()
        cur.execute('SELECT latitude, longitude, unixtime FROM Message WHERE latitude > 50 AND longitude > -30 AND longitude < 40 AND latitude < 80')
        all_rows = [[int(x[0]), int(x[1]), int(x[2])] for x in cur]
        all_rows = sorted(all_rows, key=itemgetter(2))
        return all_rows

plt.ion()
class DynamicUpdate():
    #Suppose we know the x range
    min_x = 0
    max_x = 10000

    def on_launch(self):
        #Set up plot
        self.figure, self.ax = plt.subplots()
        self.lines, = self.ax.plot([],[], 'o')
        #Autoscale on unknown axis and known lims on the other
        self.ax.set_autoscaley_on(True)
        self.ax.set_xlim(-50, 50)
        self.ax.set_ylim(40, 80)
        #Other stuff
        self.ax.grid()

    def on_running(self, xdata, ydata):
        #Update data (with the new _and_ the old points)
        self.lines.set_xdata(xdata)
        self.lines.set_ydata(ydata)
        #Need both of these in order to rescale
        self.ax.relim()
        self.ax.autoscale_view()
        #We need to draw *and* flush
        self.figure.canvas.draw()
        self.figure.canvas.flush_events()

    #Example
    def __call__(self):
        import numpy as np
        import time
        self.on_launch()
        xdata = []
        ydata = []
        all_rows = getData()
        for x in all_rows:
            a,b,f = zip(x)
            xdata.append(b)
            ydata.append(a)
            self.on_running(xdata, ydata)
        return xdata, ydata

d = DynamicUpdate()
d()

旧代码:

这显示静态数据

    map = Basemap(projection='merc', lat_0=59.45, lon_0=10.5,
        resolution = 'c', area_thresh = 1000,
    llcrnrlon=-30, llcrnrlat=50,
    urcrnrlon=40, urcrnrlat=80)

    map.drawcoastlines()
    map.fillcontinents(color='black')
    con = lite.connect('database.db')
    with con:
        cur = con.cursor()
        cur.execute('SELECT latitude, longitude FROM Message WHERE latitude > 50 AND longitude > -30 AND longitude < 40 AND latitude < 80')
        data = cur.fetchall()
        y,x = zip(*data)
        x,y = map(x,y)
        plt.scatter(x,y, s=0.07, alpha=0.6, color="#e74c3c", edgecolors='none')
        plt.show()

2 个答案:

答案 0 :(得分:1)

在matplotlib中进行动画的方法很少,matplotlib.animation提供了framework,但这可能有点牵扯。 Probabaly最简单的方法是使用plt.ion()。我不知道你如何使用cur.execute访问你的日期,但做了类似的工作:

map = Basemap(projection='merc', lat_0=59.45, lon_0=10.5,
    resolution = 'c', area_thresh = 1000,
llcrnrlon=-30, llcrnrlat=50,
urcrnrlon=40, urcrnrlat=80)

fig, ax = plt.subplots(1,1)
plt.ion()
plt.show()

map.drawcoastlines(ax=ax)
map.fillcontinents(color='black',ax=ax)
con = lite.connect('database.db')

with con:
    cur = con.cursor()
    i=0
    for unixtime in range(1406851200,1409529600):
        cur.execute('SELECT latitude, longitude FROM Message WHERE latitude > 50 AND longitude > -30 AND longitude < 40 AND latitude < 80 AND unixtime ==' + str(unixtime))
        data = cur.fetchall()
        y,x = zip(*data)
        x,y = map(x,y)
        pts = ax.scatter(x,y, s=0.07, alpha=0.6, color="#e74c3c", edgecolors='none')
        plt.draw()
        plt.pause(0.0001)
        #i += 1
        #plt.savefig('./out.{0:07d}.png'.format(i))
        pts.remove() 

答案 1 :(得分:1)

即使我已经得到了足够的答案,但我发现让剧情完全像我想要的那样是一件很麻烦的事情,并且仍在制作它的动画 - 所以我利用一些linux工具制作了一部电影。快照而不是。这就是我所做的,供将来参考以及其他有同样问题的人参考:

间隔拍摄动画,懒惰的方式

我简单地在整个时间段内对每小时的所有地理位置做了一个情节。这可以做到每分钟,每秒等:

    con = lite.connect('database/SAISREAL.db')
    with con:
        cur = con.cursor()
        i = 0
        for k in range(0,137*24): #This is the timespan - every hour for 137 days
            map = Basemap(projection='merc', lat_0=59.45, lon_0=10.5,
            resolution = 'c', area_thresh = 1000,
            llcrnrlon=-30, llcrnrlat=50,
            urcrnrlon=40, urcrnrlat=80)
            map.drawcoastlines()
            map.fillcontinents(color='#27ae60')
            start = 0+k*60*60 #This is again the timespan
            end = 0+(k+1)*60*60

好的 - 所以现在我已经确定了我将从中查询数据的时间跨度,以及绘制地图叠加层

            cur.execute('SELECT distinct userid, latitude, longitude FROM geodata WHERE unixtime > {start} AND unixtime < {end}'.format(start = start, end = end))
            data = cur.fetchall()
            if len(data)>0: #Simply check if there is data available
                i = i+1
                filename = ''
                if i<10:
                    filename = '0000'+str(i)
                elif i<100:
                    filename = '000'+str(i)
                elif i<1000:
                    filename = '00'+str(i)
                else:
                    filename = '0'+str(i)
                f,y,x = zip(*data)
                x,y = map(x,y)

当我将图像转换为电影时,以后会使用整个文件名的东西 - 重要的是它们按顺序命名,每个人都有相同的位数。

                plt.title( str(datetime.datetime.fromtimestamp(int(end)).strftime('%Y-%m-%d')) + ' kl '+str(datetime.datetime.fromtimestamp(int(end)).strftime('%H')))
                plt.scatter(x,y, s=8, alpha=0.7, color="#2980b9", edgecolors='none')

这里我只是用时间戳作为标题绘制信息。

                plt.savefig('Fisheriesplot/fishplot/'+str(filename)+'.png', format='png')
                plt.clf()

然后,保存图片。这提供了大约3000个.png图像 - 显然可以用其他文件格式来完成。

在我将它们制作成GIF或电影之前,我想要删除透明背景 - 使它们看起来更漂亮(帧之间的色彩偏移更少)

mkdir batch
for file in *.png ; do convert "${file}" -background black -alpha remove -flatten -alpha off "batch/${file}" ; done
cd batch

如果目标是制作 gif - 请跳过其余部分并执行此操作:convert -delay 10 -loop 0 *.png animaion.gif

选项1:用.png制作电影

ffmpeg -y -f image2 -framerate 20 -i %05d.png -vcodec png -b 8000k a20k.avi

这就是在文件夹中。根据需要设置bitrakte和framerate-注意这部电影可能很大。

选项2:将图片转换为其他格式,然后制作电影

mogrify -format jpg *.png

这是在与图片相同的文件夹中的终端中完成的。然后我想将所有jpg移动到他们自己的文件夹中:

mkdir jpgfolder
mv *.jpg jpgfolder

现在,最后我可以拍电影了:

cd jpgfolder
ffmpeg -y -f image2 -framerate 4 -i %05d.jpg -vcodec mpeg4 -b 800k a88k.avi

此处设置为4的帧速率应设置为您想要的任何值。请注意,%05d.jpg表示每个文件都有一个前导0,总共有五位数。如果是四位数,请写4等。

请注意,这不是最简化或最智能的方法,但它是一个解决方案,适合所有不想更改代码的人,而不是将其置于循环中。