Как анимировать диаграмму рассеяния по базовой карте в matplotlib?

Приведенный ниже код создает анимированную базовую карту, но не совсем ту, которую я хочу: я хочу, чтобы диаграмма рассеяния из предыдущего кадра исчезла, но она сохраняется до конца анимации.

Я подозреваю, что это как-то связано с тем, что я не понимаю, что такое базовая карта на самом деле является. Я понимаю, что вызываю его на широту/долготу, чтобы проецировать их на x/y, но я не совсем понимаю, что происходит, когда я вызываю event_map.scatter().

import random
import os
import numpy as np

import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
from matplotlib import animation
import pandas as pd
from IPython.display import HTML


# Enables animation display directly in IPython 
#(http://jakevdp.github.io/blog/2013/05/12/embedding-matplotlib-animations/)
from tempfile import NamedTemporaryFile

VIDEO_TAG = """<video controls>
 <source src="data:video/x-m4v;base64,{0}" type="video/mp4">
 Your browser does not support the video tag.
</video>"""

def anim_to_html(anim):
    if not hasattr(anim, '_encoded_video'):
        with NamedTemporaryFile(suffix='.mp4') as f:
            anim.save(f.name, fps=20, extra_args=['-vcodec', 'libx264'])
            video = open(f.name, "rb").read()
        anim._encoded_video = video.encode("base64")

    return VIDEO_TAG.format(anim._encoded_video)

def display_animation(anim):
    plt.close(anim._fig)
    return HTML(anim_to_html(anim))

animation.Animation._repr_html_ = anim_to_html



FRAMES = 20
POINTS_PER_FRAME = 30
LAT_MIN = 40.5
LAT_MAX = 40.95
LON_MIN = -74.15
LON_MAX = -73.85
FIGSIZE = (10,10)
MAP_BACKGROUND = '.95'
MARKERSIZE = 20

#Make Sample Data
data_frames = {}
for i in range(FRAMES):
    lats = [random.uniform(LAT_MIN, LAT_MAX) for x in range(POINTS_PER_FRAME)]
    lons = [random.uniform(LON_MIN, LON_MAX) for x in range(POINTS_PER_FRAME)]
    data_frames[i] = pd.DataFrame({'lat':lats, 'lon':lons})    


class AnimatedMap(object):
    """ An animated scatter plot over a basemap"""
    def __init__(self, data_frames):
        self.dfs = data_frames
        self.fig = plt.figure(figsize=FIGSIZE)
        self.event_map = Basemap(projection='merc', 
                resolution='i', area_thresh=1.0, # Medium resolution
                lat_0 = (LAT_MIN + LAT_MAX)/2, lon_0=(LON_MIN + LON_MAX)/2, # Map center 
                llcrnrlon=LON_MIN, llcrnrlat=LAT_MIN, # Lower left corner
                urcrnrlon=LON_MAX, urcrnrlat=LAT_MAX) # Upper right corner 
        self.ani = animation.FuncAnimation(self.fig, self.update, frames=FRAMES, interval=1000, 
                                           init_func=self.setup_plot, blit=True,
                                           repeat=False)

    def setup_plot(self):
        self.event_map.drawcoastlines() 
        self.event_map.drawcounties()
        self.event_map.fillcontinents(color=MAP_BACKGROUND) # Light gray
        self.event_map.drawmapboundary()
        self.scat = self.event_map.scatter(x = [], y=[], s=MARKERSIZE,marker='o', zorder=10) 
        return self.scat

    def project_lat_lons(self, i):
        df = data_frames[i]
        x, y = self.event_map(df.lon.values, df.lat.values)
        x_y = pd.DataFrame({'x': x, 'y': y}, index=df.index)
        df = df.join(x_y)
        return df

    def update(self, i):
        """Update the scatter plot."""
        df = self.project_lat_lons(i)
        self.scat = self.event_map.scatter(x = df.x.values, y=df.y.values,  marker='o', zorder=10)  
        return self.scat,


s = AnimatedMap(data_frames)
s.ani

person Dan    schedule 05.01.2014    source источник
comment
очевидно, что ухабистый - это тупой, по какой-то причине я не могу это исправить =(   -  person Dan    schedule 10.05.2014


Ответы (1)


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

def update(self, i):
    """Update the scatter plot."""
    df = self.project_lat_lons(i)
    new_offsets = np.vstack([df.x.values, df.y.values]).T
    self.scat.set_offsets(new_offsets)
    return self.scat,

Обратите внимание, что я не проверял это.

person jakevdp    schedule 20.01.2014