Example #1
0
 def select(self, jd=None, runid=0, ints=0, ntrac=0, database=None):
     """ Retrive trajectories from database """
     if not jd: jd = ints
     if not hasattr(self, 'db'):
         self.db = DB(self.projname, self.casename, database=database)
     res = self.db.select(jd, runid, ints, ntrac)
     if len(res) > 0:
         for n, a in enumerate(['runid', 'ints', 'ntrac', 'x', 'y', 'z']):
             self.__dict__[a] = np.array(res[n])
Example #2
0
 def select(self,jd=None, runid=0, ints=0, ntrac=0, database=None):
     """ Retrive trajectories from database """
     if not jd: jd = ints
     if not hasattr(self, 'db'):
         self.db = DB(self.projname, self.casename,database=database)
     res = self.db.select(jd, runid, ints, ntrac)
     if len(res) > 0:
         for n,a in enumerate(['runid','ints','ntrac','x','y','z']):
             self.__dict__[a] = np.array(res[n])
Example #3
0
 def insert(self, database="traj"):
     """Insert current trajectories into database"""
     DB.insert(db)
Example #4
0
class Traj(object):
    """Main class for trajectory post-processing"""
    def __init__(self, projname, casename=None, **kwargs):
        """ Setup variables and make sure everything needed is there """
        self.projname = projname
        self.basedir =  os.path.dirname(os.path.abspath(__file__))
        self.inkwargs = kwargs
        if casename is None:
            self.casename = projname
        else:
            self.casename = casename
        self._load_presets('projects',kwargs)

        self.setup_njord()

    def _load_presets(self, filepref, kwargs):
        """Read and parse the config file"""
        cfg = ConfigParser.ConfigParser()
        files = ["%s/%s.cfg" % (os.curdir, filepref),
                 "%s/.%s.cfg" % (os.path.expanduser("~"), filepref),
                 "%s/%s.cfg" % (self.basedir, filepref)]
        for fnm in files:
            cfg.read(fnm)
            if self.projname in cfg.sections():
                self.config_file = fnm
                break
        else:
            print "Project not included in config file"
            print "Geo-reference functionality will be limited"
            return
        
        def splitkey(key, val):
            if key in self.inkwargs.keys():
                self.__dict__[key] = self.inkwargs[key]
                del self.inkwargs[key]
            else:
                self.__dict__[key] = val
            
        for key,val in cfg.items(self.projname):
            try:
                splitkey(key, json.loads(val))
            except ValueError:
                splitkey(key, val)
                
    def setup_njord(self):
        self.gcm = (__import__("njord." + self.njord_module,
                             fromlist=["njord"]).__dict__[self.njord_class])()
        self.gcm.add_landmask()
        self.landmask = self.gcm.landmask
        self.llon = self.gcm.llon
        self.llat = self.gcm.llat
       
    def trajsloaded(aFunc):
        """Decorator function to check if trajs are loaded."""
        def bFunc( *args, **kw ):
            if not "x" in dir(args[0]):
                raise NameError, "Trajectory data not loaded."
            return aFunc( *args, **kw )
        bFunc.__name__ = aFunc.__name__
        bFunc.__doc__ = aFunc.__doc__
        return bFunc

    def add_mp(self, map_region=None):
        if map_region is not None:
            self.map_region = map_region
            if hasattr(self,'mp'): del self.mp
        try:
            import projmap
        except:
            raise ImportError("Module PROJMAP not available")            
        if not hasattr(self,'mp'):
            self.mp = projmap.Projmap(self.map_region)
            self.mpxll,self.mpyll = self.mp(self.llon,self.llat)

    @trajsloaded
    def ijll(self):
        """Add vectors with lat-lon positions of particles."""
        from scipy.ndimage.interpolation import map_coordinates
        self.lon = map_coordinates(self.llon, [self.y,self.x])
        self.lat = map_coordinates(self.llat, [self.y,self.x])
        self.lon[self.lon<-180] = self.lon[self.lon<-180] + 360
        self.lon[self.lon> 180] = self.lon[self.lon> 180] - 360
        self.lon[self.lon==0] = np.nan
        self.lat[self.lat==0] = np.nan

    @trajsloaded
    def ij2utm(self,ps=None):
        """Add vectors with UTM (km in cartesian grid) positions of particles."""
        from scipy.ndimage.interpolation import map_coordinates
        self.gcm.add_utmxy()
        self.utmx = map_coordinates(self.gcm.utmx, [self.y,self.x])
        self.utmy = map_coordinates(self.gcm.utmy, [self.y,self.x])

    @trajsloaded
    def grid(self,weights=[]):
        """Create a field with number of particles in each gridcell"""
        xy = np.vstack( (self.x.astype(np.int), self.y.astype(np.int)) )
        if len(weights) == 0: weights = np.ones(xy.shape[1])
        flat_coord = np.ravel_multi_index(xy, (self.imt, self.jmt))
        sums = np.bincount(flat_coord, weights)
        fld = np.zeros((self.imt, self.jmt))
        fld.flat[:len(sums)] = sums
        return fld.T

    @trajsloaded
    def calc_dists(self):
        """Calculate distance and speed between all positions along all trajs."""
        if not hasattr(self, 'lon'): self.ijll()
        self.dists = self.lon * np.nan
        self.speed = self.lon * np.nan
        for jd1,jd2 in zip(self.jdvec[:-1], self.jdvec[1:]):
            mask1 = self.jd == jd1
            mask2 = self.jd == jd2
            print jd1,jd2
            ntracmax = max(self.ntrac[mask1].max(), self.ntrac[mask2].max())
            lonvecs = np.zeros((2, ntracmax+1)) * np.nan
            latvecs = np.zeros((2, ntracmax+1)) * np.nan
            lonvecs[0,self.ntrac[mask1]] = self.lon[mask1]
            lonvecs[1,self.ntrac[mask2]] = self.lon[mask2]
            latvecs[0,self.ntrac[mask1]] = self.lat[mask1]
            latvecs[1,self.ntrac[mask2]] = self.lat[mask2]
            self.dists[mask2] = lldist.ll2dist(lonvecs,latvecs)[self.ntrac[mask2]]
            self.speed[mask2] = self.dists[mask2]/(jd2-jd1)/24/60/60

    @trajsloaded
    def field(self,fieldname):
        t = self.ints - self.ints.min()
        ifloor = np.floor(self.i).astype(int)
        jfloor = np.floor(self.y).astype(int)
        iceil  = np.ceil(self.x).astype(int)
        jceil  = np.ceil(self.y).astype(int)
        b1 = fld[t,ifloor,jfloor]
        b2 = fld[t,iceil,jfloor] - b1
        b3 = fld[t,ifloor,jceil] - b1
        b4 = b1 - fld[t,iceil,jfloor] - fld[t,ifloor,jceil] + fld[t,iceil,jceil]
        x = self.x - ifloor
        y = self.y - jfloor
        self.__dict__[fieldname] = b1 + b2*x + b3*y + b4*x*y

    @trajsloaded
    def permanent_mask(self, mask):
        """Delete masked particle positions from all vectors."""
        for v in vars(self):
            try:
                if len(self.__dict__[v]) == len(mask):
                    self.__dict__[v] = self.__dict__[v][mask]
            except:
                pass
        self.jdvec = np.unique(self.jd)

    @trajsloaded
    def mask_by_ntracvec(self, ntracvec, extra_vars=[]):
        """ Create a subset of trajectories based on a vector of ntrac's"""
        ntracvec = np.array(ntracvec)
        ntracmax = ntracvec.max()
        convec = np.zeros((ntracmax+1)).astype(np.bool)
        convec[ntracvec] = True
        mask = convec.copy()
        nmask = self.ntrac <= ntracmax
        ntracmask = (self.ntrac[:] * 0).astype(np.bool)

        for jd in self.jdvec:
            tmask = (self.jd == jd) & nmask
            convec[:] = False
            convec[self.ntrac[tmask]] = True
            tempmask = ntracmask[tmask]
            tempmask[np.nonzero((convec & mask))[0]-1] = True
            ntracmask[tmask] = tempmask
        subvars = ['ntrac','jd','x','y','z'] + extra_vars
        for v in subvars:
            self.__dict__[v] = self.__dict__[v][ntracmask]


    @trajsloaded
    def insert(self, database="traj"):
        """Insert current trajectories into database"""
        DB.insert(db)
  
    def select(self,jd=None, runid=0, ints=0, ntrac=0, database=None):
        """ Retrive trajectories from database """
        if not jd: jd = ints
        if not hasattr(self, 'db'):
            self.db = DB(self.projname, self.casename,database=database)
        res = self.db.select(jd, runid, ints, ntrac)
        if len(res) > 0:
            for n,a in enumerate(['runid','ints','ntrac','x','y','z']):
                self.__dict__[a] = np.array(res[n])

    @trajsloaded
    def scatter(self,mask=None, ntrac=None, jd=None, k1=None, k2=None,
                c="g", clf=True, coord="latlon", land="nice", map_region=None):
        """Plot particle positions on a map

                 mask: Boolean vector inidcating which particles to plot
                ntrac: Particle ID
                   jd: Julian date to plot, has to be included in jdvec.
                   k1: only plot particle deeper than k1
                   k2: only plot particle shallower than k1
                    c: color of particles
                  clf: Clear figure  if True
                coord: Use lat-lon coordinates if set to "latlon" (default),
                           i-j coordinates if set to "ij" 
                 land: Use landmask from basemap if set to "nice" (default),
                           landmask from model if set to "model". 
           map_region: Use other map_regions than set by config file

        """
        if (not hasattr(self,'mp'))  & (coord=="latlon"):
            self.add_mp(map_region)
        if (not hasattr(self,'lon')) & (coord=="latlon"):
            self.ijll()
        if mask is None:
            mask = self.ntrac==self.ntrac
            if jd is not None:
                mask = mask & (self.jd==jd)
            if ntrac is not None:
                mask = mask & (self.ntrac==ntrac)

        figpref.current()
        if clf: pl.clf()
    
        if coord is "latlon":
            x,y = self.mp(self.lon[mask],self.lat[mask])
            scH = self.mp.scatter(x, y, 5, c)
        else:
            scH = pl.scatter(self.x[mask], self.y[mask], 5, c)
    
        if land is "nice":
            land = self.gcm.mp.nice()
        elif coord is "latlon":
            self.mp.pcolormesh(self.mpxll,
                               self.mpyll,
                               np.ma.masked_equal(self.landmask, False),
                               cmap=GrGr())
        else:
            pl.pcolormesh(np.arange(self.gcm.i1, self.gcm.i2+1),
                          np.arange(self.gcm.j1, self.gcm.j2+1),
                          np.ma.masked_equal(self.landmask, False),
                          cmap=GrGr())
        if (ntrac is not None) & (coord is "latlon"):
            self.mp.plot(x,y,'-w',lw=0.5)

        """ 
        xl,yl = self.mp(
            [self.llon[0,0], self.llon[0,-1], self.llon[-1,-1],
             self.llon[-1,0],self.llon[0,0]],
            [self.llat[0,0], self.llat[0,-1], self.llat[-1,-1],
             self.llat[-1,0], self.llat[0,0]]
             )
        #self.mp.plot(xl,yl,'0.5')
        """
        if jd: pl.title(pl.num2date(jd).strftime("%Y-%m-%d %H:%M"))
        return scH
        
    @trajsloaded
    def movie(self,di=10, coord='latlon',land="nice"):
        mv = anim.Movie()
        for jd in self.jdvec:
            print self.jdvec[-1] - jd
            if jd/di == float(jd)/di:
                self.scatter(jd=jd, coord=coord, land=land)
                mv.image()
        mv.video(self.projname+self.casename+"_mov.mp4")

    @trajsloaded
    def double_movie(tr1,tr2,di=10):
        mv = anim.Movie()
        ints = np.intersect1d(tr1.ints,tr2.ints).sort()
        for i in ints:
            if i/di == float(i)/di:
                tr1.scatter(ints=i,c="b",clf=True)
                tr2.scatter(ints=i,c="r",clf=False)
                mv.image()
        mv.video(tr1.projname + tr1.casename + "_" +
                 tr2.projname + tr2.casename + "_mov.mp4")

    @trajsloaded
    def export(self,filename='',filetype="mat"):
        """Export trajecotires to a MATLAB .mat file"""  
        import scipy.io as sio

        if type(self.intstart) == int:
            intstart = self.intstart
        else:
            instart = self.intstart.min()            
        if not filename:
            filename = ( "%s_%s_%i_%i_%i_%i_%i.%s" %
                         (self.projname, self.casename, intstart,
                          self.ints.min(), self.ints.max(),
                          self.ntrac.min(), self.ntrac.max(), filetype)
                         )
        sio.savemat(filename, {'jd':    self.jd,
                               'ntrac': self.ntrac,
                               'x':     self.x,
                               'y':     self.y})

            
        

    def zip(self,xarr,yarr):
        """
        Transform data in a ziplike fashion. Matrices will be flatten with ravel 

        Example:

        >>> xarr = np.array([1,2,3])
        >>> yarr = np.array([5,6,7])
        >>> self.zip(xarr, yarr)
        array([[1, 5],
               [2, 6],
               [3, 7]])

        """
        return np.vstack((np.ravel(xarr), np.ravel(yarr))).T

    trajsloaded = staticmethod(trajsloaded)
Example #5
0
from fastapi import FastAPI, Request, Form, Cookie
from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from typing import Optional
from postgresql import DB
import uvicorn

app = FastAPI()
database = DB()

app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")


@app.on_event("shutdown")
def shutdown_event():
    database.db.close()


@app.get("/")
async def main(request: Request):
    return templates.TemplateResponse("main.html", {"request": request})


@app.get("/about")
async def main(request: Request):
    return templates.TemplateResponse("about.html", {"request": request})


@app.get("/sing_up")
Example #6
0
 def insert(self, database="traj"):
     """Insert current trajectories into database"""
     DB.insert(db)
Example #7
0
class Traj(object):
    """Main class for trajectory post-processing"""
    def __init__(self, projname, casename=None, **kwargs):
        """ Setup variables and make sure everything needed is there """
        self.projname = projname
        self.basedir = os.path.dirname(os.path.abspath(__file__))
        self.inkwargs = kwargs
        if casename is None:
            self.casename = projname
        else:
            self.casename = casename
        self._load_presets('projects', kwargs)

        self.setup_njord()

    def _load_presets(self, filepref, kwargs):
        """Read and parse the config file"""
        cfg = ConfigParser.ConfigParser()
        files = [
            "%s/%s.cfg" % (os.curdir, filepref),
            "%s/.%s.cfg" % (os.path.expanduser("~"), filepref),
            "%s/%s.cfg" % (self.basedir, filepref)
        ]
        for fnm in files:
            cfg.read(fnm)
            if self.projname in cfg.sections():
                self.config_file = fnm
                break
        else:
            print "Project not included in config file"
            print "Geo-reference functionality will be limited"
            return

        def splitkey(key, val):
            if key in self.inkwargs.keys():
                self.__dict__[key] = self.inkwargs[key]
                del self.inkwargs[key]
            else:
                self.__dict__[key] = val

        for key, val in cfg.items(self.projname):
            try:
                splitkey(key, json.loads(val))
            except ValueError:
                splitkey(key, val)

    def setup_njord(self):
        self.gcm = (__import__("njord." + self.njord_module,
                               fromlist=["njord"
                                         ]).__dict__[self.njord_class])()
        self.gcm.add_landmask()
        self.landmask = self.gcm.landmask
        self.llon = self.gcm.llon
        self.llat = self.gcm.llat

    def trajsloaded(aFunc):
        """Decorator function to check if trajs are loaded."""
        def bFunc(*args, **kw):
            if not "x" in dir(args[0]):
                raise NameError, "Trajectory data not loaded."
            return aFunc(*args, **kw)

        bFunc.__name__ = aFunc.__name__
        bFunc.__doc__ = aFunc.__doc__
        return bFunc

    def add_mp(self, map_region=None):
        if map_region is not None:
            self.map_region = map_region
            if hasattr(self, 'mp'): del self.mp
        try:
            import projmap
        except:
            raise ImportError("Module PROJMAP not available")
        if not hasattr(self, 'mp'):
            self.mp = projmap.Projmap(self.map_region)
            self.mpxll, self.mpyll = self.mp(self.llon, self.llat)

    @trajsloaded
    def ijll(self):
        """Add vectors with lat-lon positions of particles."""
        from scipy.ndimage.interpolation import map_coordinates
        self.lon = map_coordinates(self.llon, [self.y, self.x])
        self.lat = map_coordinates(self.llat, [self.y, self.x])
        self.lon[self.lon < -180] = self.lon[self.lon < -180] + 360
        self.lon[self.lon > 180] = self.lon[self.lon > 180] - 360
        self.lon[self.lon == 0] = np.nan
        self.lat[self.lat == 0] = np.nan

    @trajsloaded
    def ij2utm(self, ps=None):
        """Add vectors with UTM (km in cartesian grid) positions of particles."""
        from scipy.ndimage.interpolation import map_coordinates
        self.gcm.add_utmxy()
        self.utmx = map_coordinates(self.gcm.utmx, [self.y, self.x])
        self.utmy = map_coordinates(self.gcm.utmy, [self.y, self.x])

    @trajsloaded
    def grid(self, weights=[]):
        """Create a field with number of particles in each gridcell"""
        xy = np.vstack((self.x.astype(np.int), self.y.astype(np.int)))
        if len(weights) == 0: weights = np.ones(xy.shape[1])
        flat_coord = np.ravel_multi_index(xy, (self.imt, self.jmt))
        sums = np.bincount(flat_coord, weights)
        fld = np.zeros((self.imt, self.jmt))
        fld.flat[:len(sums)] = sums
        return fld.T

    @trajsloaded
    def calc_dists(self):
        """Calculate distance and speed between all positions along all trajs."""
        if not hasattr(self, 'lon'): self.ijll()
        self.dists = self.lon * np.nan
        self.speed = self.lon * np.nan
        for jd1, jd2 in zip(self.jdvec[:-1], self.jdvec[1:]):
            mask1 = self.jd == jd1
            mask2 = self.jd == jd2
            print jd1, jd2
            ntracmax = max(self.ntrac[mask1].max(), self.ntrac[mask2].max())
            lonvecs = np.zeros((2, ntracmax + 1)) * np.nan
            latvecs = np.zeros((2, ntracmax + 1)) * np.nan
            lonvecs[0, self.ntrac[mask1]] = self.lon[mask1]
            lonvecs[1, self.ntrac[mask2]] = self.lon[mask2]
            latvecs[0, self.ntrac[mask1]] = self.lat[mask1]
            latvecs[1, self.ntrac[mask2]] = self.lat[mask2]
            self.dists[mask2] = lldist.ll2dist(lonvecs,
                                               latvecs)[self.ntrac[mask2]]
            self.speed[mask2] = self.dists[mask2] / (jd2 - jd1) / 24 / 60 / 60

    @trajsloaded
    def field(self, fieldname):
        t = self.ints - self.ints.min()
        ifloor = np.floor(self.i).astype(int)
        jfloor = np.floor(self.y).astype(int)
        iceil = np.ceil(self.x).astype(int)
        jceil = np.ceil(self.y).astype(int)
        b1 = fld[t, ifloor, jfloor]
        b2 = fld[t, iceil, jfloor] - b1
        b3 = fld[t, ifloor, jceil] - b1
        b4 = b1 - fld[t, iceil, jfloor] - fld[t, ifloor, jceil] + fld[t, iceil,
                                                                      jceil]
        x = self.x - ifloor
        y = self.y - jfloor
        self.__dict__[fieldname] = b1 + b2 * x + b3 * y + b4 * x * y

    @trajsloaded
    def permanent_mask(self, mask):
        """Delete masked particle positions from all vectors."""
        for v in vars(self):
            try:
                if len(self.__dict__[v]) == len(mask):
                    self.__dict__[v] = self.__dict__[v][mask]
            except:
                pass
        self.jdvec = np.unique(self.jd)

    @trajsloaded
    def mask_by_ntracvec(self, ntracvec, extra_vars=[]):
        """ Create a subset of trajectories based on a vector of ntrac's"""
        ntracvec = np.array(ntracvec)
        ntracmax = ntracvec.max()
        convec = np.zeros((ntracmax + 1)).astype(np.bool)
        convec[ntracvec] = True
        mask = convec.copy()
        nmask = self.ntrac <= ntracmax
        ntracmask = (self.ntrac[:] * 0).astype(np.bool)

        for jd in self.jdvec:
            tmask = (self.jd == jd) & nmask
            convec[:] = False
            convec[self.ntrac[tmask]] = True
            tempmask = ntracmask[tmask]
            tempmask[np.nonzero((convec & mask))[0] - 1] = True
            ntracmask[tmask] = tempmask
        subvars = ['ntrac', 'jd', 'x', 'y', 'z'] + extra_vars
        for v in subvars:
            self.__dict__[v] = self.__dict__[v][ntracmask]

    @trajsloaded
    def insert(self, database="traj"):
        """Insert current trajectories into database"""
        DB.insert(db)

    def select(self, jd=None, runid=0, ints=0, ntrac=0, database=None):
        """ Retrive trajectories from database """
        if not jd: jd = ints
        if not hasattr(self, 'db'):
            self.db = DB(self.projname, self.casename, database=database)
        res = self.db.select(jd, runid, ints, ntrac)
        if len(res) > 0:
            for n, a in enumerate(['runid', 'ints', 'ntrac', 'x', 'y', 'z']):
                self.__dict__[a] = np.array(res[n])

    @trajsloaded
    def scatter(self,
                mask=None,
                ntrac=None,
                jd=None,
                k1=None,
                k2=None,
                c="g",
                clf=True,
                coord="latlon",
                land="nice",
                map_region=None):
        """Plot particle positions on a map

                 mask: Boolean vector inidcating which particles to plot
                ntrac: Particle ID
                   jd: Julian date to plot, has to be included in jdvec.
                   k1: only plot particle deeper than k1
                   k2: only plot particle shallower than k1
                    c: color of particles
                  clf: Clear figure  if True
                coord: Use lat-lon coordinates if set to "latlon" (default),
                           i-j coordinates if set to "ij" 
                 land: Use landmask from basemap if set to "nice" (default),
                           landmask from model if set to "model". 
           map_region: Use other map_regions than set by config file

        """
        if (not hasattr(self, 'mp')) & (coord == "latlon"):
            self.add_mp(map_region)
        if (not hasattr(self, 'lon')) & (coord == "latlon"):
            self.ijll()
        if mask is None:
            mask = self.ntrac == self.ntrac
            if jd is not None:
                mask = mask & (self.jd == jd)
            if ntrac is not None:
                mask = mask & (self.ntrac == ntrac)

        figpref.current()
        if clf: pl.clf()

        if coord is "latlon":
            x, y = self.mp(self.lon[mask], self.lat[mask])
            scH = self.mp.scatter(x, y, 5, c)
        else:
            scH = pl.scatter(self.x[mask], self.y[mask], 5, c)

        if land is "nice":
            land = self.gcm.mp.nice()
        elif coord is "latlon":
            self.mp.pcolormesh(self.mpxll,
                               self.mpyll,
                               np.ma.masked_equal(self.landmask, False),
                               cmap=GrGr())
        else:
            pl.pcolormesh(np.arange(self.gcm.i1, self.gcm.i2 + 1),
                          np.arange(self.gcm.j1, self.gcm.j2 + 1),
                          np.ma.masked_equal(self.landmask, False),
                          cmap=GrGr())
        if (ntrac is not None) & (coord is "latlon"):
            self.mp.plot(x, y, '-w', lw=0.5)
        """ 
        xl,yl = self.mp(
            [self.llon[0,0], self.llon[0,-1], self.llon[-1,-1],
             self.llon[-1,0],self.llon[0,0]],
            [self.llat[0,0], self.llat[0,-1], self.llat[-1,-1],
             self.llat[-1,0], self.llat[0,0]]
             )
        #self.mp.plot(xl,yl,'0.5')
        """
        if jd: pl.title(pl.num2date(jd).strftime("%Y-%m-%d %H:%M"))
        return scH

    @trajsloaded
    def movie(self, di=10, coord='latlon', land="nice"):
        mv = anim.Movie()
        for jd in self.jdvec:
            print self.jdvec[-1] - jd
            if jd / di == float(jd) / di:
                self.scatter(jd=jd, coord=coord, land=land)
                mv.image()
        mv.video(self.projname + self.casename + "_mov.mp4")

    @trajsloaded
    def double_movie(tr1, tr2, di=10):
        mv = anim.Movie()
        ints = np.intersect1d(tr1.ints, tr2.ints).sort()
        for i in ints:
            if i / di == float(i) / di:
                tr1.scatter(ints=i, c="b", clf=True)
                tr2.scatter(ints=i, c="r", clf=False)
                mv.image()
        mv.video(tr1.projname + tr1.casename + "_" + tr2.projname +
                 tr2.casename + "_mov.mp4")

    @trajsloaded
    def export(self, filename='', filetype="mat"):
        """Export trajecotires to a MATLAB .mat file"""
        import scipy.io as sio

        if type(self.intstart) == int:
            intstart = self.intstart
        else:
            instart = self.intstart.min()
        if not filename:
            filename = ("%s_%s_%i_%i_%i_%i_%i.%s" %
                        (self.projname, self.casename, intstart,
                         self.ints.min(), self.ints.max(), self.ntrac.min(),
                         self.ntrac.max(), filetype))
        sio.savemat(filename, {
            'jd': self.jd,
            'ntrac': self.ntrac,
            'x': self.x,
            'y': self.y
        })

    def zip(self, xarr, yarr):
        """
        Transform data in a ziplike fashion. Matrices will be flatten with ravel 

        Example:

        >>> xarr = np.array([1,2,3])
        >>> yarr = np.array([5,6,7])
        >>> self.zip(xarr, yarr)
        array([[1, 5],
               [2, 6],
               [3, 7]])

        """
        return np.vstack((np.ravel(xarr), np.ravel(yarr))).T

    trajsloaded = staticmethod(trajsloaded)