"""Making data-driven plots on the web using your Django data.
This module contains only the core file management backend. Plotting
code is found in django.contrib.dataplot.*, where * is one of
{R,pil,etc.}
"""
import os,pdb
from django.conf import settings
from django.template import loader,Context
class GenericPlot(object):
"""Singular representation of a plot for the web.
Subclasses need to define:
convert_to: dictionary that defines associated file suffixes, i.e.
convert_to={
'png':{'suffix':'.png'},
'thumb':{'suffix':'-thumb.png','convert_args':'-resize 65x90'},
'pdf':{'suffix':'.pdf'},
}
convert_from: one of the keys from convert_to, which specifies
which of the files is created by the makefile method.
makefile: a method that creates the image specified by
convert_from on the filesystem.
"""
# Default values can be overridden
# by subclasses or after instantiation
# If unspecified, try to get default image cache setting
enable_caching = not settings.DEBUG
chgrp=None
# Set defaults for convert location, can override later
convert_binary='convert'
view_program='display'
def __init__(self,basename,get_plot_args,**kwargs):
"""Make a new plot to display.
Required args: (no sensible defaults)
basename: basename of this plot (no .pdf)
get_plot_args: makes data to pass to the function for plotmaking.
Other plot parameters may be specified after instantiation as
attributes:
enable_caching: should the image be remade every time?
chgrp: group to set write permissions for
"""
self.basename=basename
self.get_plot_args=get_plot_args
for k in kwargs:
setattr(self,k,kwargs[k])
def __repr__(self):
return '<%s: %s, %s>'%(
self.__class__.__name__,
self.get_plot_args,
self.basename,
)
def prefix(self,pre):
"""Generalized form of url/filename reporting.
pre: prefix to attach to the basename and suffix.
"""
di=dict(self.convert_to)
return dict([(k,pre+self.basename+di[k]['suffix']) for k in di])
def get_urls(self):
"""Return dictionary of image URLs.
Make the plot if it doesn't exist or caching is off.
"""
files_dont_exist=sum([
not os.path.exists(fn) for fn in self.get_filenames().values()])
if not self.enable_caching or files_dont_exist:
self.makefiles()
return self.prefix(settings.MEDIA_URL)
def makefiles(self):
"""Make initial file and conversions.
makefile() just makes the initial file.
"""
self.makefile()
self.convert()
self.enable_caching=True
def to_html(self):
"""Render the PNG image and link to the PDF.
"""
return self.render_html('to_html.html')
def to_html_thumb(self):
"""Render the PNG thumb.
"""
return self.render_html('to_html_thumb.html')
def to_html_nolink(self):
"""Render the PNG without link to PDF.
"""
return self.render_html('to_html_nolink.html')
def render_html(self,template_filename):
"""Render a HTML template with self as context 'plot'.
"""
co=Context({'plot':self})
tmp=loader.get_template('dataplot/'+template_filename)
html=tmp.render(co)
return html
def get_filenames(self):
"""Return dictionary of image filenames.
"""
return self.prefix(settings.MEDIA_ROOT+'/')
def get_full_base(self):
suffix=self.convert_to[self.convert_from]['suffix']
return self.get_filenames()[self.convert_from][:-len(suffix)]
def convert(self):
"""Convert from PDF to other formats using ImageMagick.
"""
filenames=self.get_filenames()
src=filenames.pop(self.convert_from)
for k in filenames:
try:
cargs=self.convert_to[k]['convert_args']
except KeyError:
cargs=''
convert_cmd=' '.join([
self.convert_binary,
cargs,
src,
filenames[k],
])
os.system(convert_cmd)
# Finally ensure permissions for group if requested
self.do_chgrp()
def do_chgrp(self):
"""Change group write perms if requested.
This is useful if your testing and production webservers have
different users but share the same media directory.
"""
if self.chgrp:
for fn in self.get_filenames():
perm_cmd='chmod g+w %s ; chgrp %s %s'%(
fn,self.chgrp,fn)
os.system(perm_cmd)
def get_app_dirs(self):
"""Dig through settings.INSTALLED_APPS for full paths.
"""
return [os.path.dirname(
__import__(mn,[],[],'.'.split(mn)[-1]).__file__)
for mn in settings.INSTALLED_APPS]
def view(self):
"""Use some other program to look at rendered source image.
"""
cmd='%s %s'%(
self.view_program,self.get_filenames()[self.convert_from])
os.system(cmd)