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

Go to the documentation of this file.
00001 """Auto-define and -update mechanism for django-dataplot images.
00002 
00003 Comment out this line in your models.py:
00004 # from django.db import models
00005 
00006 Then add:
00007 from dataplot import plotmodels as models
00008 
00009 """
00010 from django.db.models.base import ModelBase
00011 from django.db.models import * # so we can use this as a models file
00012 from django.utils.functional import curry
00013 from copy import copy
00014 import dataplot
00015 import os,re
00016 import pdb
00017 
00018 class DataplotImproperlyConfigured(dataplot.PlotError): pass
00019 
00020 UNSAFE_FILE_CHARS=re.compile(r'[^a-zA-Z0-9]')
00021 
00022 def call_if_possible(i):
00023     if callable(i):
00024         return i()
00025     else:
00026         return i
00027 
00028 def get_plot_args(self,kwargs):
00029     """To be curried and used as a method for plotting.
00030 
00031     """
00032     new_plot_dict=dict(kwargs['plot_dict'])
00033     qsattr=kwargs.get('qs','plotable')
00034     if isinstance(self,Model):
00035         m=getattr(self,qsattr)
00036     else:
00037         m=getattr(kwargs['toset'],qsattr,kwargs['toset'].all)
00038     qs=m()
00039     for k,v in new_plot_dict.iteritems():
00040         try: # to get value list from fields
00041             vals=[getattr(row,v) for row in qs]
00042             new=[call_if_possible(val) for val in vals]
00043         except Exception, e: # field not specified
00044             try: # to get a named attribute
00045                 attr=getattr(self,v,v)
00046                 new=call_if_possible(attr)
00047             except: # not a named attribute, just keep the value
00048                 new=v
00049         new_plot_dict[k]=new
00050     try:
00051         # set default args if specified
00052         for k,v in kwargs['plot'].default_args_map.iteritems():
00053             new_plot_dict.setdefault(k,kwargs['plot_dict'][v])
00054     except: # no problem if no default args
00055         pass
00056     return new_plot_dict
00057 
00058 class ModelBase(ModelBase):
00059     """Extend ModelBase to initialize dataplots.
00060 
00061     """
00062     
00063     def __init__(self,*posargs,**kwargs):
00064         """automatic dataplot construction based on DATAPLOTS syntax
00065 
00066         """
00067         super(ModelBase,self).__init__(*posargs,**kwargs)
00068         # Need to reset manager since Django guesses poorly with inheritance
00069         # Also bad: default manager is shared across all models
00070         #  so if we don't reset we will end up setting attrs and methods
00071         #  across all default managers
00072         self.objects=self._default_manager=copy(self.objects)
00073         self.objects.model=self
00074         #print self,self.objects.model._meta.db_table,self._meta.db_table
00075         #print self.objects,self.ChangeManipulator.manager.model._meta.db_table,self._default_manager.model._meta.db_table
00076         toset_tups=[
00077             (self.objects,'MANAGER_DATAPLOTS'),
00078             (self,'DATAPLOTS'), # self is the model subclass
00079             ]
00080         for o,attr in toset_tups:
00081             for plotarg in getattr(self,attr,()):
00082                 dp=Dataplot(plotarg,o)
00083                 dp.defaults()
00084                 dp.set_method()
00085                 if attr!='DATAPLOTS': # only set plot for manager
00086                     # will set plot for model at instantiation
00087                     dp.set_attribute()
00088 
00089 class Model(Model):
00090     """Enables figure autosave with Django-dataplot.
00091 
00092     All attributes of this model which are instances of
00093     dataplot.GenericPlot will be resaved.
00094 
00095     """
00096     __metaclass__=ModelBase
00097 
00098     def __init__(self,*args,**kwargs):
00099         super(Model,self).__init__(*args,**kwargs)
00100         for plotarg in getattr(self,'DATAPLOTS',()):
00101             dp=Dataplot(plotarg,self) # self is the instance
00102             dp.defaults()
00103             dp.set_attribute()
00104 
00105     def save(self):
00106         """Save method which allows for maximum configurability.
00107 
00108         On a model with no custom save method, we will call django's
00109         save first, then try to make plots for this object.
00110 
00111         On a model with a custom save method, you should call
00112         make_plots and Model.save yourself, depending on when it is
00113         appropriate in terms of your data processing.
00114 
00115         """
00116         super(Model,self).save()
00117         self.DATAPLOT_CHECK_AUTOSAVE=True
00118         self.save_plots()
00119 
00120     def save_plots(self):
00121         force=not getattr(self,'DATAPLOT_CHECK_AUTOSAVE',False)
00122         self.make_model_plots(force)
00123         self.make_manager_plots(force)
00124 
00125     def make_model_plots(self,force=True):
00126         """Try to remake plots related to this model.
00127 
00128         """
00129         make_plots(self,force)
00130 
00131     @classmethod
00132     def make_manager_plots(cls,force=True):
00133         """Try to remake plots related to this model's manager.
00134 
00135         """
00136         make_plots(cls.objects,force)
00137 
00138 def make_plots(x,force):
00139     """Look for dataplots in attributes, and remake them.
00140 
00141     """
00142     for at in x.__dict__.values():
00143         if isinstance(at,dataplot.GenericPlot) and at.enable_caching and (at.autosave or force):
00144             at.makefiles()
00145 
00146 class Dataplot(dict):
00147     """Parsing logic for dataplot autoconfig tuples.
00148 
00149     This is just used for DRY convenience here and should not be used
00150     outside this module.
00151 
00152     """
00153 
00154     def __init__(self,plot,toset):
00155         """Initialize a dataplot using sensible defaults.
00156 
00157         This can be a
00158 
00159         dataplot (subclass of dataplot.GenericPlot, i.e. R.Scatter) in
00160         this case, we assume basename of scatter and a plot method
00161         called get_scatter_args.
00162 
00163         tuple (dataplot,dict) where dict is a dictionary of kwargs
00164         used to initialize the dataplot. So you can use this form if
00165         you want to override the default basename, get_plot_args
00166         method, or other plot parameters.
00167 
00168         """
00169         self.plot=plot
00170         if type(plot)==tuple:
00171             plot,kwargs=plot
00172             self.update(kwargs)
00173         self['plot']=plot
00174         self['toset']=toset
00175 
00176     def defaults(self):
00177         """Derive sensible defaults from provided info.
00178 
00179         """
00180         self.setdefault('plotname',self['plot'].__name__)
00181         # attribute name is by default the plot name
00182         self.setdefault('attribute',self['plotname'])
00183         # get_plot_args is by default the attribute name
00184         get_plot_args=self.get('get_plot_args',self['attribute'])
00185         #pdb.set_trace()
00186         if type(get_plot_args)==dict:
00187             self['plot_dict']=get_plot_args
00188             methodname=self['attribute']
00189         elif type(get_plot_args)==str:
00190             self['plot_dict']=None
00191             methodname=get_plot_args
00192         else:
00193             raise DataplotImproperlyConfigured(
00194                 "get_plot_args must be unassigned, dict, or str")
00195         self['methodname']='%s_args'%methodname
00196 
00197     def set_method(self):
00198         """Set data-gathering method if necessary.
00199         
00200         """
00201         no_method=not hasattr(
00202             self['toset'].__class__,self['methodname'])
00203         if isinstance(self['toset'],ModelBase):
00204             toset=self['toset']
00205         else:
00206             toset=self['toset'].__class__
00207         if self['plot_dict'] and no_method:
00208             setattr(
00209                 toset,
00210                 self['methodname'],
00211                 curry(get_plot_args,kwargs=self))
00212 
00213     def set_attribute(self):
00214         """Set dataplot instance.
00215 
00216         """
00217         if self['attribute']==self['plotname']:
00218             name=self['attribute']
00219         else:
00220             name='%s_%s'%(self['plotname'],self['attribute'])
00221         if isinstance(self['toset'],Model):
00222             name += '_id%s_%s'%(self['toset'].id,self['toset'])
00223         subdir=os.path.join(
00224             self['toset'].__module__.split('.')[-2],
00225             self['toset'].__class__.__name__)
00226         basename=subdir!=None and os.path.join(subdir,name) or name
00227         method=getattr(self['toset'],self['methodname'],None)
00228         if method:
00229             inst=self['plot'](
00230                 basename,method,**self.setdefault('init_args',{}))
00231         else:
00232             raise DataplotImproperlyConfigured(
00233                 "\nYou must define attribute "+
00234                 self['methodname']+
00235                 " for \n"+
00236                 str(self['toset'])+
00237                 "\nsince you gave\n"+
00238                 str(self.plot))
00239         setattr(self['toset'],self['attribute'],inst)
00240         

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