Как динамически отображать данные в ответ на сторожевые события - PullRequest
0 голосов
/ 31 декабря 2018

Я пытаюсь отслеживать каталог для новых файлов определенного типа и отображать их по мере их создания для создания анимации в реальном времени в python.

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

"""
Created on Mon Dec 31 11:11:33 2018
For plotting real time open-ifs output

"""
#general modules
import numpy as np
import os
import sys
import time
#monitoring modules
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
#data load modules
from iris import load_cube, Constraint
import warnings
warnings.simplefilter('ignore')
#plotting modules
import iris.plot as iplt
import matplotlib.pyplot as plt
import cartopy.crs as ccrs



#A custom handler class inherited from PatternMatchingEventHandler
#This will check new files and if of the correct type, plot them.
class PlottingHandler(PatternMatchingEventHandler):

    def setup_handler(self,load_function,title_function,format_specifier):
        #Must take in only a filename, and return only a datacube
        self.load_func=load_function
        #Must take in only a filename and return only a title
        self.title_func=title_function
        #Must take in only a filename and return a boolean value
        self.format_specifier=format_specifier

    #these methods setup and update the plot
    def setup_plot(self,cmap,proj):
        self.cmap=cmap
        self.proj=proj
        self.fig , _ =plt.subplots(1,1,figsize=(10,10))
        self.ax = plt.axes(projection=proj)
        plt.tight_layout()
        plt.show()

    def update_plot(self,file):
        self.ax.cla()
        cube=self.load_func(file)
        iplt.contourf(cube, 30, cmap=self.cmap,fig=self.fig)
        self.ax.coastlines(color='white')
        plt.clim([224.0, 273.0])
        self.fig.suptitle(self.title_func(file))
        self.fig.canvas.draw()
        self.fig.canvas.flush_events()
        plt.pause(0.1)

    #these methods execute in response to file changes:
    def on_created(self,event):
        #if the filename is of the correct type then we will plot the new file
        if self.format_specifier(event.src_path) ==True:
            print("plotting new file")
            self.update_plot(event.src_path)
        else:
            print("new file not of plottable type")



#RELEVANT FUNCTIONS:
#Loads data from file
def LoadTempCube(file):
    temp=load_cube(file, 'Temperature').extract(Constraint(air_pressure=50000.0))
    temp = temp.extract(Constraint(time=lambda cell: True))
    return temp
#Creates title of plot from file 
def SimpleTitle(file):
    title=file.rsplit('/',1)[-1]
    return title
#determines if file is one we want to plot
def is_NetCDFfile(file):
    file=file.rsplit('/',1)[-1]
    ExpID="ICMSHh3a5"
    conditions=[]
    conditions.append(file.startswith(ExpID))
    conditions.append(file.endswith(".nc"))
    return np.all(conditions)

#PARAMETERS:          
path="/network/aopp/chaos/pred/dorrington/raspberry_pis/dummy/"  
color_map = plt.get_cmap('inferno')
proj = ccrs.Mollweide()

#EXECUTABLE CODE:
if not os.path.isdir(path):
    print("invalid file path")
    sys.exit(0)

#enable interactive plotting:
plt.ion()
#the handler responds to events detected by the observer
handler=PlottingHandler()

#We pass the relevant functions to the handler...
handler.setup_handler(LoadTempCube,SimpleTitle,is_NetCDFfile)

#... and setup the plot
handler.setup_plot(color_map,proj)
plt.pause(0.1)
#We initialise the observer object, which monitors the folder for file changes   
observer=Observer()
#we tell the observer who to pass events to, and where to look for them...
observer.schedule(handler,path)

#...and we begin monitoring
print("start")
observer.start()
observer.join()

Это сработало так, как янадеялся, что в Spyder будет запущен в интерактивном режиме, но при попытке запустить его из терминала код просто закончится.Чтобы предотвратить это, я должен был добавить строку Observer.join (), но теперь наблюдатель не позволяет обновлять фигуру matplotlib.Я думаю, что это, вероятно, проблема, связанная с потоком, но я не уверен, как ее исправить.

...