Анимация нескольких точек на базовой карте Matplotlib с течением времени

Я пытаюсь создать анимированный сюжет серии точек с позициями широты и долготы на карте matplotlib.basemap. Каждая точка имеет ряд позиций для ряда дней, которые я прочитал в pandas DataFrame.

Я попытался изменить используемую процедуру ЗДЕСЬ сделать это, но я получаю сообщение об ошибке global name 'points' is not defined. Я пытался объявить это глобальным в подпрограмме init, но это не помогло.

Как я могу это сделать?

Пример данных:

day,id,      lon,      lat
156, 1, 67.53453, -4.00454
156, 2, 66.73453,  0.78454
156, 3, 68.23453, -1.01454
157, 1, 67.81453, -4.26454
157, 2, 66.42653,  0.91454
157, 3, 69.11253, -1.01454
158, 1, 68.12453, -3.26454
158, 2, 67.10053,  1.01454
158, 3, 68.01253, -2.61454

Процедура вызова:

if datafile != None:
    data = readdata(datafile)
    dates = np.unique(data.daynr).values

    x,y = m(0,0)
    point = m.plot(x,y, 'ro', markersize=5)[0]
    points = list()

    anim = animation.FuncAnimation(plt.gcf(), animate,
                                   init_func=init, frames=20,
                                   interval=500, blit=True)

    # Add current date/time or something to make unique
    anim.save('movement.mp4', fps=15,
              extra_args=['-vcodec', 'libx264'])

init, animate и процедуры чтения данных:

def init():
    for pt in points:
        pt.set_data([], [])
    return points

def animate(i):
    lons = data.lons[data.daynr==dates[i]]
    lats = data.lats[data.daynr==dates[i]]

    i = 0
    for lon,lat, pt in zip(points, lons, lats):
        x, y = map(lon,lat)
        pt.set_data(x, y)
        i = i + 1
    return points

def readdata(datafile):
    dtypes = np.dtype([
                    ('daynr',int),      #00 - Simulation day number
                    ('id',int),         #01 - Id
                    ('lon',float),      #02 - Longitude
                    ('lat',float),      #03 - Latitude
                    ])
    f = open(datafile, 'rb')
    data = pd.read_csv(f, index_col=False, names=dtypes.names,
                           dtype=dtypes, header=None)
    f.close()
    return data

person ryanjdillon    schedule 21.01.2014    source источник
comment
На какой строке прерывается ваша программа?   -  person waitingkuo    schedule 21.01.2014
comment
Вы все коды в один файл поместили?   -  person waitingkuo    schedule 21.01.2014
comment
У меня есть. У меня есть (в противном случае работающая) функция построения графика с необязательным параметром datafile=None, и первая процедура выше вызывается, если она существует.   -  person ryanjdillon    schedule 22.01.2014


Ответы (1)


Итак... моя первая проблема заключалась в том, что я не осознавал, что переменные внутри функции в python не считаются "глобальными" функциями, которые вызываются внутри нее.

Чтобы обойти это, я сделал свои функции init() и animate(i) «подфункциями», которые затем позволили переменным, объявленным в родительской функции, обрабатываться как глобальные подфункциями init() и animate(i) (см. код ниже).

Я нашел эту статью в блоге очень полезной для прийти к моему решению.

Как и этот вопрос SO.

ПРИМЕЧАНИЕ. Я немного отредактировал свой код для целей этого ответа, поэтому, пожалуйста, прокомментируйте, если это не работает должным образом для вас.

Моя функция построения графика и процедура вызова:

import pandas as pd
import numpy as np
import pyproj
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap


def makeplot(plot_data=False):
''' plot function with optional data animation
    if data is supplied (as a `pandas` DataFrame), subfuntions `init()` 
    and `animate(i)` will animate recurring, multiple position values 
    per unique day and save to file.'''

    def init():
        # initialize each plot point created in the list `points`
        for pt in points:
            pt.set_data([], [])
        return points

    def animate(i):
        #Only routine if `i` doesn't exceed number of unique days to animate
        if i < len(data_dates):
            print 'Animation frame:', i, '; Simulation Day:', data_dates[i]

            lons = data.lons[data.daynr==dates[i]].values
            lats = data.lats[data.daynr==dates[i]].values

            j = 0
            for pt,lon,lat in zip(points, lons, lats):
                x, y = m(lon,lat)
                pt.set_data(x, y)
                j = j + 1
        return points

    # Define ellipsoid object for distance measurements
    g = pyproj.Geod(ellps='WGS84') # Use WGS84 ellipsoid
    r_equator = g.a # earth's radius at equator
    r_poles = g.b   # earth's radius through poles

    lon0, lat0, map_width, map_height = center_map(poly_lons, poly_lats, 1.1)

    m = Basemap(width=map_width,height=map_height,
                rsphere=(r_equator, r_poles),\
                resolution='f', projection='laea',\
                lat_ts=lat0,\
                lat_0=lat0,lon_0=lon0)

    # Draw parallels and meridians.
    m.drawparallels(np.arange(-80.,81.,5.), labels=[1,0,0,0], fontsize=10)
    m.drawmeridians(np.arange(-180.,181.,10.), labels=[0,0,0,1], fontsize=10)
    m.drawmapboundary(fill_color='white')
    m.drawcoastlines(linewidth=0.2)
    m.fillcontinents(color='gray', lake_color='white') #aqua

    # Animate if position data is supplied with plotting function
    if plot_data == True:
        # Automatically determine frame number
        f_num = len(data_dates)
        # Declare list of point objects
        points = list()

        # Create a placeholder plot point
        x,y = m(0,0)
        # Fill list with same number of placeholders as points to animate
        for i in range(len(data.lons)):
            points.append(m.plot(x,y, 'ro', markersize=5)[0])

        anim = animation.FuncAnimation(plt.gcf(), animate,
                                       init_func=init, frames=f_num,
                                       interval=500, blit=True)

        # Save animation to file
        anim.save('plot_animation.mp4', fps=f_num,
                  extra_args=['-vcodec', 'libx264'])

    plt.show()

if __name__ == '__main__':

    # WGS84 datum
    wgs84 = pyproj.Proj(init='EPSG:4326')

    # CSV data with columns 'daynr', 'lons', and 'lats'
    datafile = '/home/dude/datalocations/data.csv'
    data = readwhales(whale_datafile)
    data_dates = np.unique(data.daynr).values

    makeplot(plot_data=True)
person ryanjdillon    schedule 27.01.2014