我正在制作一个标有纬度和经度的位置的散点图,它可以正常工作,因为它显示了静态图像中一段时间内的所有位置。但我想知道是否有任何简单的利用方式,我对每个位置都有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()
答案 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等。
请注意,这不是最简化或最智能的方法,但它是一个解决方案,适合所有不想更改代码的人,而不是将其置于循环中。