Source

Fat x Fast / FatxFast / utils / graphifier.py

Full commit

# This file is part of FatxFast.
#
#    FatxFast is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    FatxFast is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with FatxFast.  If not, see <http://www.gnu.org/licenses/>.

# Versioning based on: 
# http://en.wikipedia.org/wiki/Versioning#Designating_development_stage
__author__ = "dryatu (c) 2013"
__version__ = "1.2.5"

import matplotlib.pyplot as plt                                                 
import matplotlib.animation as animation

import time
import sys

class Graphifier(object):

    def __init__(self, max_frames, ylim):
        plt.ion()
        self.max_frames = max_frames
        self.ylim = ylim 
        self.lines = []
        self._queue = []
        self._running = False

    def add_animated_line(self, object_to_follow, attribute_to_follow, 
        further_attr, layout="g-"):
        """Public interface for adding lines to the graph
        Inserts called function to a queue for thread safety"""
        self._queue.append((self._add_animated_line, 
            (object_to_follow, attribute_to_follow, further_attr, layout)))

    def _add_animated_line(self, object_to_follow, 
        attribute_to_follow, further_attr=None, layout="g-"):
        lines = plt.plot([], [], layout)
        self.lines.append({"line":lines[0],
            "link":object_to_follow,
            "attr":attribute_to_follow,
            "further_attr":further_attr})

    def is_running(self):
        return self._running

    def run(self):
        """Starts the graphing process. This is intended to be started within
        a separate thread. After running this other interface functions are
        available"""
        self.figure = plt.figure(figsize=(10,8), facecolor=(0.4,0.4, 0.4))   
        plt.ylim(self.ylim)
        frame = 0
        self._running = True
        while self._running:
            
            for que_item in list(self._queue):
                que_item[0](*que_item[1])
                self._queue.remove(que_item)
            for line in self.lines:
                self._update(frame, line)
            frame += 1
            time.sleep(0.033)

        plt.close("all")
        plt.clf()
        plt.close("all")

    def stop(self):
        """Prepares for shutdown"""
        del self._queue[:]
        del self.lines[:]
        self._running = False

    def _update(self, frame, line):
        xes = xrange(frame-self.max_frames, frame)

        lower_limit = frame-self.max_frames
        if frame < self.max_frames:
            lower_limit = -1
        
        plt.xlim(lower_limit, frame)
        value = getattr(line["link"], line["attr"])
        
        if line["further_attr"]:
            value = getattr(value, line["further_attr"])
        
        values_cache = list(line["line"].get_data()[1])
        values_cache.append(value)

        if len(values_cache)-1 == self.max_frames:
            values_cache.pop(0)
        elif (len(values_cache) < self.max_frames or 
            len(values_cache) > self.max_frames):
            values_cache = [0]*self.max_frames
        
        line["line"].set_data(xes, values_cache)
        plt.draw()