/usr/local/lib/python2.4/site-packages/dataplot/bike/models.py

Go to the documentation of this file.
00001 """Record of bike trips for data analysis.
00002 
00003 Demonstration app for dataplot.
00004 
00005 """
00006 
00007 import datetime,pdb,os
00008 #from django.db import models
00009 from dataplot import plotmodels as models
00010 from django.db import connection
00011 from django.db.models import Q
00012 from dataplot.bike.R import ThereAndBackPlot
00013 from dataplot import R,GenericPlot
00014 #GenericPlot.enable_caching=True
00015 try:
00016     from dataplot import matplotlib
00017 except ImportError: # no matplotlib support on this system
00018     matplotlib=None
00019 
00020 def tup_to_minutes(h,m,s):
00021     return h*60 + m + float(s)/60
00022 
00023 PAIRED_RIDES_SQL="""
00024 select x.date,x.hours,x.minutes,x.seconds,y.hours,y.minutes,y.seconds
00025 from bike_ride as x join bike_ride as y on x.date=y.date where
00026 x.origin_id=%s and x.destination_id=%s and
00027 y.origin_id=%s and y.destination_id=%s order by date;
00028 """
00029         
00030 class Location(models.Model):
00031     """Origin or destination of a bike ride.
00032 
00033     """
00034     short_name=models.CharField(
00035         max_length=100,
00036         blank=True,
00037         null=False,
00038         default='',
00039         )
00040     address=models.TextField(blank=True,null=False,default='')
00041 
00042     class Admin:
00043         pass
00044 
00045     def __str__(self):
00046         return self.short_name.capitalize()
00047 
00048     DATAPLOTS=(
00049         R.CorrScatter,
00050         )
00051 
00052     def CorrScatter_args(self):
00053         cursor = connection.cursor()
00054         cursor.execute(PAIRED_RIDES_SQL,[self.id,self.o.id,self.o.id,self.id])
00055         rows = cursor.fetchall()
00056         return {
00057             'x':[tup_to_minutes(*d[1:4]) for d in rows],
00058             'xlab':'%s->%s'%(self.short_name,self.o.short_name),
00059             'y':[tup_to_minutes(*d[4:7]) for d in rows],
00060             'ylab':'%s->%s'%(self.o.short_name,self.short_name),
00061             'main':"Correlation in ride times for rides on same day?",
00062             }
00063 
00064     def related_locations(self):
00065         return Location.objects.filter(
00066             Q(ride_origins__destination__id__exact=self.id)|
00067             Q(ride_destinations__origin__id__exact=self.id)).exclude(
00068             id=self.id).distinct()
00069 
00070     def related_locations_dict(self):
00071         #pdb.set_trace()
00072         li=[]
00073         for loc in self.related_locations():
00074             loc.compare(self)
00075             li.append({
00076             'from_here_to_there':Ride.objects.filter(
00077             origin__id__exact=self.id,
00078             destination__id__exact=loc.id,
00079             ).count(),
00080             'from_there_to_here':Ride.objects.filter(
00081             origin__id__exact=loc.id,
00082             destination__id__exact=self.id,
00083             ).count(),
00084             'l':loc,
00085             })
00086         return li
00087 
00088     h=4
00089     w=6
00090     def compare(self,o):
00091         """Initialize plots to summarize rides to another location.
00092 
00093         o: other location
00094 
00095         """
00096         self.o=o
00097         self.to_o=self.ride_origins.filter(destination__id__exact=o.id)
00098         self.from_o=self.ride_destinations.filter(origin__id__exact=o.id)
00099         pre='%s-to-%s-'%(self.short_name,o.short_name)
00100         self.hist=R.Histogram(
00101             pre+'hist',
00102             self.get_hist_args,
00103             h=self.h,
00104             w=self.w,
00105             )
00106         self.qqnorm=R.NormalQQPlot(
00107             pre+'qqnorm',
00108             self.get_qqnorm_args,
00109             h=self.h,
00110             w=self.w,
00111             )
00112         self.custom=ThereAndBackPlot(
00113             pre+'custom',
00114             self.get_there_and_back_args,
00115             )
00116 
00117     def get_there_and_back_args(self):
00118         """kwargs to pass to the R function for plotting.
00119 
00120         """
00121         rides=list(self.to_o)+list(self.from_o)
00122         values=[ride.there_and_back_dict() for ride in rides]
00123         # shortcut for making a dataframe for R
00124         df=R.values_to_df(values)
00125         return {'d':df}
00126 
00127     def get_hist_args(self):
00128         xlim=self.get_hist_xlim()
00129         breaks=range(xlim[0],xlim[1],3)
00130         minutes=[ride.get_minutes() for ride in self.to_o]
00131         return {
00132             'x':minutes,
00133             'main':'Rides from %s to %s'%(self,self.o),
00134             'xlab':'Ride length (minutes)',
00135             'xlim':xlim,
00136             'breaks':breaks,
00137             'freq':False,
00138             'ylim':[0,0.2],
00139             }
00140 
00141     def get_qqnorm_args(self):
00142         return {
00143             'y':[ride.get_minutes() for ride in self.to_o],
00144             'ylim':self.get_hist_xlim(),
00145             }
00146     
00147     def get_hist_xlim(self):
00148         minutes=[
00149             ride.get_minutes() for ride in self.to_o
00150             ]+[
00151             ride.get_minutes() for ride in self.from_o
00152             ]
00153         return [int(min(minutes)-1),int(max(minutes)+3)]
00154 
00155 class Bike(models.Model):
00156     """Parameters of bike -- different bikes may be different speeds.
00157 
00158     """
00159     short_name=models.CharField(
00160         max_length=100,
00161         blank=True,
00162         null=False,
00163         default='',
00164         )
00165     description=models.TextField(blank=True,null=False,default='')
00166 
00167     class Admin:
00168         pass
00169 
00170     def __str__(self):
00171         return self.short_name.capitalize()
00172 
00173 class RideManager(models.Manager):
00174     """Used for making global ride plots and importing data.
00175 
00176     """
00177 
00178     def create_from_file_default(self):
00179         """Create new bike rides based on default dataset.
00180 
00181         """
00182         self.create_from_file(os.path.join(
00183             os.path.dirname(__file__),'bikelog.txt'))
00184 
00185     def create_from_file(self,filename):
00186         """Create new bike rides based on records in a text file.
00187 
00188         """
00189         print "Loading data from %s"%filename
00190         lines=open(filename).readlines()
00191         for line in lines[1:]: # assume header line
00192             print line
00193             ride=Ride()
00194             ride.get_data_from_line(line)
00195             ride.save()
00196 
00197     def __init__(self):
00198         self.odoplot=R.TimeSeries(
00199             'allrides',
00200             self.get_odoplot_args,
00201             )
00202         if matplotlib:
00203             self.corr=matplotlib.Scatter(
00204                 'samedaycorr-matplotlib',
00205                 self.get_corr_args,
00206                 )
00207         self.corrr=R.SquareScatter(
00208             'samedaycorr-R',
00209             self.get_corr_args,
00210             default_kwargs={'fit_lty':1,'lty.x.y':2,'one.to.one':True}
00211             )
00212         #self.corrr.SAVE_DATA_ON_MAKEFILE=True
00213 
00214     def get_odoplot_args(self):
00215         """Get arguments for the time series plot.
00216 
00217         If no data present, create some from the default dataset.
00218 
00219         """
00220         qs=self.all()
00221         if not qs:
00222             self.create_from_file_default()
00223             qs=self.all()
00224         return {
00225             'd':[ride.date.strftime("%s") for ride in qs],
00226             'y':[ride.distance for ride in qs],
00227             'transform':'cumulative',
00228             'label.interval':'day',
00229             'main':'Cumulative distance rode by Toby Dylan Hocking over time',
00230             'ylab':'Distance (miles)',
00231             'xlab':'Day of ride',
00232             }
00233 
00234     def get_date_dict(self):
00235         """Sort rides based on date in a dictionary.
00236 
00237         """
00238         qs=self.all()
00239         di={}
00240         for ride in qs:
00241             k=ride.date
00242             if k not in di:
00243                 di[k]=[]
00244             di[k].append(ride.average_speed)
00245         return di
00246 
00247     def get_corr_args(self):
00248         """Arguments for making the daily correlation scatterplot.
00249         
00250         """
00251         tups=[li for li in self.get_date_dict().values() if len(li)==2]
00252         return {
00253             'x':[t[0] for t in tups],
00254             'y':[t[1] for t in tups],
00255             'main':"2 speeds (miles/hour) for rides on the same day",
00256             'xlab':'',
00257             'ylab':'',
00258             }
00259 
00260     def from_to(self,org,dest):
00261         """Shortcut for searching from and to by short_name.
00262 
00263         """
00264         return self.filter(
00265             origin__short_name__exact=org,
00266             destination__short_name__exact=dest,
00267             )
00268 
00269 class Ride(models.Model):
00270     """Ride and associated statistics.
00271 
00272     I can type these into Django's admin interface easily (data from
00273     my bike's navigational computer).
00274 
00275     """
00276     date=models.DateField(blank=False,null=False)
00277     bike=models.ForeignKey(Bike,blank=False,null=False)
00278     origin=models.ForeignKey(
00279         Location,blank=False,null=False,related_name='ride_origins')
00280     destination=models.ForeignKey(
00281         Location,blank=False,null=False,related_name='ride_destinations')
00282     distance=models.FloatField(blank=False,null=False)
00283     fastest_speed=models.FloatField(blank=False,null=False)
00284     average_speed=models.FloatField(blank=False,null=False)
00285     hours=models.IntegerField(blank=False,null=False)
00286     minutes=models.IntegerField(blank=False,null=False)
00287     seconds=models.IntegerField(blank=False,null=False)
00288     back_flats=models.IntegerField(blank=False,null=False)
00289     front_flats=models.IntegerField(blank=False,null=False)
00290 
00291     objects=RideManager()
00292     DO_NOT_CACHE_MANAGER_PLOTS=False
00293 
00294     MANAGER_DATAPLOTS=(
00295         (R.CorrScatter,{'get_plot_args':{'x':'fastest_speed','y':'average_speed'}}),
00296         )
00297 
00298     class Admin:
00299         list_display=[
00300             'date',
00301             'bike',
00302             'origin',
00303             'destination',
00304             'distance',
00305             'average_speed',
00306             'fastest_speed',
00307             ]
00308 
00309     def __str__(self):
00310         return "%s(%s->%s)=%s"%(
00311             self.date,
00312             self.origin,
00313             self.destination,
00314             self.distance,
00315             )
00316 
00317     def get_minutes(self):
00318         """Calculate ride time in minutes.
00319 
00320         This considers hours and seconds columns too.
00321 
00322         """
00323         return tup_to_minutes(self.hours,self.minutes,self.seconds)
00324 
00325     def there_and_back_dict(self):
00326         """Return a dict for input to there and back Rplot.
00327 
00328         """
00329         return {
00330             'date':self.date.strftime("%Y-%m-%d"),
00331             'from':self.origin.short_name,
00332             'to':self.destination.short_name,
00333             'm':self.get_minutes(),
00334             }
00335             
00336     def get_data_from_line(self,line):
00337         """Import 1 row of data from a line in a text file.
00338 
00339         The line looks something like:
00340         2007-06-06 road    sangamo home    9.783  30   15.1 0 39 7
00341         
00342         """
00343         # ordering of fields matches ordering of cols in text file
00344         for f, i in zip(self._meta.get_data_holders()[1:],line.split()):
00345             if f.rel:
00346                 # lookup of bikes and locations is by short_name
00347                 obj, created = f.rel.to.objects.get_or_create(short_name=i)
00348                 val=obj.id
00349             else:
00350                 val=i
00351             setattr(self,f.attname,val)
00352         # Set date object specially
00353         self.date=datetime.date(*[int(i) for i in self.date.split("-")])
00354 

Generated on Tue Apr 22 23:16:22 2008 for django-dataplot by  doxygen 1.4.6