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

Go to the documentation of this file.
00001 """Make data-driven plots on the web using your Django data.
00002 
00003 This module contains only the core file management backend. Plotting
00004 code is found in dataplot.*, where * is one of {R,matplotlib,etc.}
00005 
00006 """
00007 
00008 import os,sys,pdb
00009 from django.conf import settings
00010 from django.template.loader import render_to_string
00011 from django.utils.safestring import mark_safe
00012 
00013 class PlotError(Exception): pass
00014 
00015 class GenericPlot(object):
00016     """Singular representation of a plot for the web.
00017 
00018     Subclasses need to define:
00019 
00020     convert_to: dictionary that defines associated file suffixes, i.e.
00021     convert_to={
00022         'png':{'suffix':'.png'},
00023         'thumb':{'suffix':'-thumb.png','convert_args':'-resize 65x90'},
00024         'pdf':{'suffix':'.pdf'},
00025         }
00026         
00027     convert_from: one of the keys from convert_to, which specifies
00028     which of the files is created by the makefile method.
00029     
00030     makefile: a method that creates the image specified by
00031     convert_from on the filesystem.
00032 
00033     """
00034 
00035     # Default values can be overridden
00036     # by subclasses or after instantiation
00037     # If unspecified, try to get default image cache setting
00038     enable_caching = not settings.DEBUG
00039     chgrp=None
00040     autosave=False
00041     # Set defaults for convert location, can override later
00042     convert_binary='convert'
00043     view_program='display'
00044 
00045     def __init__(self,basename,tocall,**kwargs):
00046         """Make a new plot to display.
00047 
00048         Required args: (no sensible defaults)
00049 
00050         basename: basename of this plot (no .pdf)
00051         tocall: makes data dict to pass to the function for plotmaking.
00052 
00053         Other plot parameters may be specified after instantiation as
00054         attributes:
00055 
00056         enable_caching: should the image be remade every time?
00057         chgrp: group to set write permissions for
00058 
00059         """
00060         self.basename=basename.replace(" ","_")
00061         self.tocall=tocall
00062         for k in kwargs:
00063             setattr(self,k,kwargs[k])
00064 
00065     def get_plot_args(self):
00066         """Gather input data from defaults and return value of tocall.
00067         
00068         1. defaults for this plot type
00069         2. returned arguments from get_plot_args
00070         
00071         """
00072         dict_precedence=[
00073             getattr(self,'default_kwargs',None),
00074             self.tocall(),
00075             ]
00076         kwargs={}
00077         for D in dict_precedence:
00078             if D:
00079                 if type(D)!=dict:
00080                     raise ValueError, 'data must be specified as a dict!\n'\
00081                           'Got: %s'%plotargs
00082                 kwargs.update(D)
00083         return kwargs
00084 
00085     def __repr__(self):
00086         return '<%s: %s, %s>'%(
00087             self.__class__.__name__,
00088             self.tocall,
00089             self.basename,
00090             )
00091 
00092     def prefix(self,pre):
00093         """Generalized form of url/filename reporting.
00094 
00095         pre: prefix to attach to the basename and suffix.
00096 
00097         """
00098         di=dict(self.convert_to)
00099         return dict([(k,pre+self.basename+di[k]['suffix']) for k in di])
00100 
00101     def get_urls(self):
00102         """Return dictionary of image URLs.
00103 
00104         Make the plot if it doesn't exist or caching is off.
00105         
00106         """
00107         files_dont_exist=sum([
00108             not os.path.exists(fn) for fn in self.get_filenames().values()])
00109         if not self.enable_caching or files_dont_exist:
00110             try:
00111                 self.makefiles()
00112             # Need to raise unique exception here so django doesnt catch it
00113             # provide sys.exc_traceback so we can see full traceback
00114             except Exception, e:
00115                 raise PlotError,'%s: %s when trying to make %s'%(
00116                     e.__class__.__name__,e,self), sys.exc_traceback
00117         return self.prefix(settings.MEDIA_URL)
00118 
00119     def makefiles(self):
00120         """Make initial file and conversions.
00121 
00122         makefile() just makes the initial file.
00123 
00124         """
00125         self.makedirs()
00126         self.makefile()
00127         self.convert()
00128         self.enable_caching=True
00129 
00130     def makedirs(self):
00131         """Make subdirectories of media/ for this plot.
00132 
00133         """
00134         try:
00135             D,f=os.path.split(self.from_filename())
00136             os.makedirs(D)
00137         except OSError:
00138             pass
00139 
00140     def to_html(self):
00141         """Render the PNG image and link to the PDF.
00142 
00143         """
00144         return self.render_html('to_html.html')
00145         
00146     def to_html_thumb(self):
00147         """Render the PNG thumb.
00148 
00149         """
00150         return self.render_html('to_html_thumb.html')
00151 
00152     def to_html_nolink(self):
00153         """Render the PNG without link to PDF.
00154 
00155         """
00156         return self.render_html('to_html_nolink.html')
00157         
00158     def render_html(self,tfile):
00159         """Render a HTML template with self as context 'plot'.
00160         
00161         """
00162         try:
00163             # store enable_caching value
00164             # so we only have to make the plot once
00165             # even if the template calls get_urls more than once
00166             old=self.enable_caching
00167             html=render_to_string('dataplot/'+tfile,{'plot':self})
00168             # then recall the old value of enable_caching
00169             self.enable_caching=old
00170         except PlotError, e:
00171             if settings.DEBUG:
00172                 raise
00173             else: # for production version show error on page
00174                 html=render_to_string("dataplot/error.html",
00175                                       {'e':e,'etype':e.__class__.__name__})
00176         return mark_safe(html)
00177 
00178     def from_filename(self):
00179         return self.get_filenames()[self.convert_from]
00180 
00181     def from_url(self):
00182         return self.get_urls()[self.convert_from]
00183 
00184     def get_filenames(self):
00185         """Return dictionary of image filenames.
00186 
00187         """
00188         return self.prefix(os.path.join(settings.MEDIA_ROOT,''))
00189 
00190     def get_full_base(self):
00191         suffix=self.convert_to[self.convert_from]['suffix']
00192         return self.get_filenames()[self.convert_from][:-len(suffix)]
00193 
00194     def convert(self):
00195         """Convert from PDF to other formats using ImageMagick.
00196 
00197         """
00198         filenames=self.get_filenames()
00199         src=filenames.pop(self.convert_from)
00200         for k in filenames:
00201             cargs=self.convert_to[k].get('convert_args','')
00202             convert_cmd=' '.join([
00203                 self.convert_binary,
00204                 cargs,
00205                 src,
00206                 filenames[k],
00207                 ])
00208             os.system(convert_cmd)
00209         # Finally ensure permissions for group if requested
00210         self.do_chgrp()
00211 
00212     def do_chgrp(self):
00213         """Change group write perms if requested.
00214 
00215         This is useful if your testing and production webservers have
00216         different users but share the same media directory.
00217 
00218         """
00219         if self.chgrp:
00220             for fn in self.get_filenames().values():
00221                 self.do_chgrp_on(fn)
00222 
00223     def do_chgrp_on(self,fn):
00224         perm_cmd='chmod g+w %s ; chgrp %s %s'%(
00225             fn,self.chgrp,fn)
00226         os.system(perm_cmd)
00227 
00228     def get_app_dirs(self):
00229         """Dig through settings.INSTALLED_APPS for full paths.
00230 
00231         """
00232         return [os.path.dirname(
00233             __import__(mn,[],[],'.'.split(mn)[-1]).__file__)
00234             for mn in settings.INSTALLED_APPS]
00235     
00236     def view(self):
00237         """Use some other program to look at rendered source image.
00238 
00239         Will make the source image if it does not exist yet.
00240 
00241         """
00242         filename=self.from_filename()
00243         if not os.path.exists(filename):
00244             self.makefile()
00245         cmd='%s %s'%(self.view_program,filename)
00246         os.system(cmd)

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