web/views/plots.py
changeset 1892 fb80d9c434e5
parent 1891 dd7c1d7715e7
child 1911 16af47588d41
--- a/web/views/plots.py	Thu May 21 16:36:47 2009 +0200
+++ b/web/views/plots.py	Thu May 21 17:31:05 2009 +0200
@@ -14,7 +14,7 @@
 from logilab.common import flatten
 from logilab.mtconverter import html_escape
 
-from cubicweb.utils import make_uid
+from cubicweb.utils import make_uid, UStringIO
 from cubicweb.vregistry import objectify_selector
 from cubicweb.web.views import baseviews
 
@@ -62,7 +62,23 @@
 def datetime2ticks(date):
     return time.mktime(date.timetuple()) * 1000
 
-class FlotPlotWidget(object):
+class PlotWidget(object):
+    # XXX refactor with cubicweb.web.views.htmlwidgets.HtmlWidget
+    def _initialize_stream(self, w=None):
+        if w:
+            self.w = w
+        else:
+            self._stream = UStringIO()
+            self.w = self._stream.write
+
+    def render(self, *args, **kwargs):
+        w = kwargs.pop('w', None)
+        self._initialize_stream(w)
+        self._render(*args, **kwargs)
+        if w is None:
+            return self._stream.getvalue()
+
+class FlotPlotWidget(PlotWidget):
     """PlotRenderer widget using Flot"""
     onload = u'''
 %(plotdefs)s
@@ -73,7 +89,7 @@
      xaxis: {mode: %(mode)s}});
 jQuery('#%(figid)s').bind('plothover', onPlotHover);
 '''
-    
+
     def __init__(self, labels, plots, timemode=False):
         self.labels = labels
         self.plots = plots # list of list of couples
@@ -86,15 +102,15 @@
         if self.timemode:
             plot = [(datetime2ticks(x), y, datetime2ticks(x)) for x,y in plot]
         return dumps(plot)
-    
-    def render(self, req, width=500, height=400, w=None):
+
+    def _render(self, req, width=500, height=400):
         # XXX IE requires excanvas.js
         req.add_js( ('jquery.flot.js', 'cubicweb.flot.js') )
         figid = u'figure%s' % make_uid('foo')
         plotdefs = []
         plotdata = []
-        w(u'<div id="%s" style="width: %spx; height: %spx;"></div>' %
-          (figid, width, height))
+        self.w(u'<div id="%s" style="width: %spx; height: %spx;"></div>' %
+               (figid, width, height))
         for idx, (label, plot) in enumerate(zip(self.labels, self.plots)):
             plotid = '%s_%s' % (figid, idx)
             plotdefs.append('var %s = %s;' % (plotid, self.dump_plot(plot)))
@@ -104,7 +120,7 @@
                                      'figid': figid,
                                      'plotdata': ','.join(plotdata),
                                      'mode': self.timemode and "'time'" or 'null'})
-    
+
 
 class PlotView(baseviews.AnyRsetView):
     id = 'plot'
@@ -131,27 +147,45 @@
     __select__ = at_least_two_columns() & columns_are_date_then_numbers()
     timemode = True
 
+
 try:
     from GChartWrapper import Pie, Pie3D
 except ImportError:
     pass
 else:
+
+    class PieChartWidget(PlotWidget):
+        def __init__(self, labels, values, pieclass=Pie, title=None):
+            self.labels = labels
+            self.values = values
+            self.pieclass = pieclass
+            self.title = title
+
+        def _render(self, width=None, height=None):
+            piechart = self.pieclass(self.values)
+            piechart.label(*self.labels)
+            if width is not None:
+                height = height or width
+                piechart.size(width, height)
+            if self.title:
+                piechart.title(self.title)
+            self.w(u'<img src="%s" />' % html_escape(piechart.url))
+
     class PieChartView(baseviews.AnyRsetView):
         id = 'piechart'
         pieclass = Pie
+
         __select__ = at_least_two_columns() & second_column_is_number()
 
         def call(self, title=None, width=None, height=None):
-            piechart = self.pieclass([(row[1] or 0) for row in self.rset])
             labels = ['%s: %s' % (row[0].encode(self.req.encoding), row[1])
                       for row in self.rset]
-            piechart.label(*labels)
+            values = [(row[1] or 0) for row in self.rset]
+            pie = PieChartWidget(labels, values, pieclass=self.pieclass,
+                                 title=title)
             if width is not None:
                 height = height or width
-                piechart.size(width, height)
-            if title:
-                piechart.title(title)
-            self.w(u'<img src="%s" />' % html_escape(piechart.url))
+            pie.render(width, height, w=self.w)
 
 
     class PieChart3DView(PieChartView):