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

Go to the documentation of this file.
00001 """Plots using R base graphics code and the rpy backend.
00002 
00003 """
00004 
00005 from rpy import r,RException
00006 import os,pdb,dataplot
00007 
00008 class RFunctionDoesNotExist(RException): pass
00009 
00010 def values_to_df(values):
00011     """Django values list of dicts -> R data.frame
00012 
00013     This makes writing Django and R code easy, since querysets and
00014     data.frames are the native ways of describing data tables in the
00015     respective programming paradigms.
00016 
00017     """
00018     dfkwargs={}
00019     for k in values[0].keys():
00020         dfkwargs[k]=[]
00021         for ride in values:
00022             val=ride[k]
00023             dfkwargs[k].append(val)
00024     df=r.data_frame(**dfkwargs)
00025     return df
00026 
00027 class Plot(dataplot.GenericPlot):
00028     """R plot for the web.
00029 
00030     Uses the rpy package and base R graphics. The idea is separation
00031     of R and python code, so each subclass needs to map to an R
00032     function (r_fun_name) in a .R code file (r_code_filename) that can
00033     be sourced and used for plotting by rpy.
00034 
00035     """
00036 
00037     convert_to={
00038         'png':{'suffix':'.png'},
00039         'thumb':{'suffix':'-thumb.png','convert_args':'-resize 65x90'},
00040         'pdf':{'suffix':'.pdf'},
00041         }
00042     convert_from='pdf'
00043     w=9
00044     h=6.5
00045     view_program='xpdf'
00046 
00047     def get_data_file(self):
00048         return self.get_full_base()+'.Rdata'
00049 
00050     def get_test_file(self):
00051         return self.get_full_base()+'.test.R'
00052 
00053     def get_r_fun(self,e=None):
00054         """Try to get the R function from the r environment.
00055 
00056         Returns true if it worked.
00057 
00058         """
00059         try:
00060             self.plot_fun=getattr(r,self.r_fun_name)
00061             return True
00062         except RException:
00063             if e:
00064                 raise e
00065 
00066     def __init__(self,*args,**kwargs):
00067         """Infer default values at init.
00068 
00069         """
00070         # infer default r_fun_name from class name
00071         if 'r_fun_name' not in dir(self):
00072             self.r_fun_name=self.__class__.__name__.lower().replace("_",".")
00073         #pdb.set_trace()
00074         super(Plot,self).__init__(*args,**kwargs)
00075 
00076     def check_files_for_function(self):
00077         """Go through files looking for the plot function.
00078 
00079         """
00080         # infer default r_code_filename from r_fun_name
00081         filename=getattr(self,'r_code_filename',self.r_fun_name+".R")
00082         # possible paths to the R source file, based on INSTALLED_APPS
00083         self.r_fullpaths=[
00084             os.path.join(d,"R",filename) for d in self.get_app_dirs()]
00085         actual_files=[f for f in self.r_fullpaths if os.path.exists(f)]
00086         # test each one by sourcing it and checking if fun exists after
00087         for r_code_fullpath in actual_files:
00088             try:
00089                 r.source(r_code_fullpath)
00090             except RException: # file does not exist or syntax error
00091                 pass
00092             # if it worked, return now
00093             if self.get_r_fun():
00094                 self.r_code_filename_fullpath=r_code_fullpath
00095                 return True
00096 
00097     def source_for_function(self):
00098         """Source R code files looking for fun_name.
00099 
00100         Raise error if fun_name is never found.
00101 
00102         """
00103         # if it already exists, return now
00104         if self.get_r_fun():
00105             return
00106         # if we can find it in a file, return now
00107         if self.check_files_for_function():
00108             return
00109         # if it didn't work by now, raise error
00110         e="Could not find R fun %s in %s"%(self.r_fun_name,self.r_fullpaths)
00111         self.get_r_fun(RFunctionDoesNotExist(e))
00112 
00113     def save_data(self):
00114         """Save result of call to get_plot_args in Rdata.
00115 
00116         """
00117         data_file=self.get_data_file()
00118         test_file=self.get_test_file()
00119         kwargs=self.set_r_args()
00120         if os.path.exists(test_file):
00121             print "Warning: %s already exists, not saving test file"%test_file
00122         else:
00123             self.check_files_for_function()
00124             Rcode='load("%s")\nsource("%s")\n%s(%s)\n'%(
00125                 data_file,
00126                 self.r_code_filename_fullpath,
00127                 self.r_fun_name,
00128                 ',\n'.join(['%s=%s'%(k,k) for k in kwargs]),
00129                 )
00130             f=open(test_file,'w')
00131             f.write(Rcode)
00132             f.close()
00133         if os.path.exists(data_file):
00134             print "Warning: %s already exists, not saving data file"%data_file
00135         else:
00136             for k in kwargs:
00137                 r.assign(k,kwargs[k])
00138             r.save(list=kwargs.keys(),file=data_file)
00139 
00140     def set_r_args(self):
00141         self.r_args=r_args=self.get_plot_args()
00142         return r_args
00143                 
00144     def makefile(self):
00145         """Start a PDF device and execute R plotting code.
00146 
00147         Also executes the conversion to other formats.
00148 
00149         """
00150         try:
00151             filename=self.get_filenames()['pdf']
00152             # Can't pass unicode strings here
00153             r.pdf(filename,h=self.h,w=self.w)
00154         except RException, e:
00155             raise dataplot.PlotError('\n'.join([
00156                 "Error in starting the R PDF graphics device.",
00157                 "Does the webserver have permission to write %s?"%filename]))
00158         # Get r_args from defaults and database
00159         r_args=self.set_r_args()
00160         # Look for function first -- get from r code if specified
00161         self.source_for_function()
00162         # Then actually draw the figure -- may fail if bad data
00163         try:
00164             # weird bug for french , decimal separator
00165             r.Sys_setlocale("LC_NUMERIC","C") 
00166             self.plot_fun_return_val=rval=self.plot_fun(**self.r_args)
00167             r.dev_off()
00168         except RException, e:
00169             try:
00170                 self.save_data()
00171             except:
00172                 pass
00173             raise dataplot.PlotError('\n'.join([
00174                 'Error in generating the plots.',
00175                 'Is all the required data present?\nR said: %s'%e]))
00176         r.warnings()
00177         # Also save the data if explicitly requested
00178         if getattr(self,'SAVE_DATA_ON_MAKEFILE',None):
00179             self.save_data()
00180         
00181 class Scatter(Plot):
00182     """Simple x-y scatterplot.
00183 
00184     Required:
00185     x: list of ints or floats: horizontal values.
00186     y: list of ints or floats: vertical values.
00187 
00188     Optional:
00189     ann: list of strings: labels for each data point.
00190     pch: plotting symbol to use; see R>example(points).
00191     fit.lty: lty of least squares fit line, default: 0 => no line.
00192     axis.round: decimal points for rounding axis labels.
00193     lty.x.y: lty of line at x=y, default: 0 => no line.
00194     one.to.one: Force axes to be same?
00195 
00196     """
00197     r_fun_name='generic.scatter.plot'
00198     default_args_map={
00199         'xlab':'x',
00200         'ylab':'y',
00201         }
00202 
00203 class SquareScatter(Scatter):
00204     w=h=6.5 # arbitrary but good for us paper
00205 
00206 class CorrScatter(SquareScatter):
00207     """Scatterplot used to judge correlation between 2 variables.
00208 
00209     Same as Scatter but with one.to.one=T and lty.x.y=2.
00210 
00211     """
00212     default_kwargs={
00213         'one.to.one':True,
00214         'lty.x.y':2,
00215         }
00216 
00217 class TimeSeries(Plot):
00218     """Simple cumulative time series.
00219 
00220     Required:
00221     d: list of time data producted with strftime('%s')
00222 
00223     Optional:
00224     y: values at time points. Will assume 1 for each as default.
00225     transform: how to transform the data before plotting, one of:
00226       'cumulative', 'monthly', 'daily'
00227 
00228     """
00229     r_fun_name='generic.time.series'
00230     default_args_map={'xlab':'d','ylab':'y'}
00231 
00232 class Histogram(Plot):
00233     """generic histogram for showing a univariate distribution.
00234 
00235     Arguments passed verbatim to R base function hist.
00236 
00237     """
00238     r_fun_name='hist'
00239 
00240 class NormalQQPlot(Plot):
00241     """Use to see if univariate data are approximately normal.
00242 
00243     All arguments are passed verbatim to R base function qqnorm.
00244 
00245     """
00246     r_fun_name='generic.qqnorm'
00247 
00248 class barplot(Plot):
00249     """Standard boring barplot.
00250 
00251     """
00252 
00253 class multi_time_series(Plot):
00254     """Multiple time series superimposed for comparison.
00255 
00256     """

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