web/views/plots.py
author Sylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 01 Jun 2010 12:21:03 +0200
branchstable
changeset 5617 f0bc8f5ddee2
parent 5424 8ecbcbff9777
child 5940 0e3ae19b181a
permissions -rw-r--r--
[tableview] support for json-paginated table if paginable
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
     1
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
     2
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
     3
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
     4
# This file is part of CubicWeb.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
     5
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
     6
# CubicWeb is free software: you can redistribute it and/or modify it under the
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
     7
# terms of the GNU Lesser General Public License as published by the Free
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
     8
# Software Foundation, either version 2.1 of the License, or (at your option)
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
     9
# any later version.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
    10
#
5424
8ecbcbff9777 replace logilab-common by CubicWeb in disclaimer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5421
diff changeset
    11
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
    12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
    13
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
    14
# details.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
    15
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
    16
# You should have received a copy of the GNU Lesser General Public License along
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5389
diff changeset
    17
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
1886
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
    18
"""basic plot views
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
    19
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
    20
"""
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
    21
__docformat__ = "restructuredtext en"
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
    22
4466
8b0ca7904820 moved generic datetime manipulation function to lgc
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4459
diff changeset
    23
from logilab.common.date import datetime2ticks
2312
af4d8f75c5db use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2161
diff changeset
    24
from logilab.mtconverter import xml_escape
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    25
4719
aaed3f813ef8 kill dead/useless code as suggested by pylint
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
    26
from cubicweb.utils import UStringIO
2657
de974465d381 [appobject] kill VObject class, move base selector classes to appobject
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2312
diff changeset
    27
from cubicweb.appobject import objectify_selector
4320
4efd4c306746 closes #345410: two_lines_rset, two_cols_rset, two_etypes_rset are badly named
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    28
from cubicweb.selectors import multi_columns_rset
5389
809d3b5b3d31 [python2.6] careful: json-py provides a json package. We don't want that.
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 5377
diff changeset
    29
from cubicweb.web import dumps
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    30
from cubicweb.web.views import baseviews
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    31
742
99115e029dca replaced most of __selectors__ assignments with __select__
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 0
diff changeset
    32
@objectify_selector
2161
200481e7b156 prepare time where it won't be mandatory to give rset to select()
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2009
diff changeset
    33
def all_columns_are_numbers(cls, req, rset=None, *args, **kwargs):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    34
    """accept result set with at least one line and two columns of result
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    35
    all columns after second must be of numerical types"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    36
    for etype in rset.description[0]:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    37
        if etype not in ('Int', 'Float'):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    38
            return 0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    39
    return 1
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    40
1886
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
    41
@objectify_selector
2161
200481e7b156 prepare time where it won't be mandatory to give rset to select()
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2009
diff changeset
    42
def second_column_is_number(cls, req, rset=None, *args, **kwargs):
1886
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
    43
    etype = rset.description[0][1]
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
    44
    if etype not  in ('Int', 'Float'):
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
    45
        return 0
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
    46
    return 1
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
    47
1888
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    48
@objectify_selector
2161
200481e7b156 prepare time where it won't be mandatory to give rset to select()
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2009
diff changeset
    49
def columns_are_date_then_numbers(cls, req, rset=None, *args, **kwargs):
1888
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    50
    etypes = rset.description[0]
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    51
    if etypes[0] not in ('Date', 'Datetime'):
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    52
        return 0
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    53
    for etype in etypes[1:]:
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    54
        if etype not in ('Int', 'Float'):
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    55
            return 0
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    56
    return 1
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    57
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    58
1888
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    59
def filterout_nulls(abscissa, plot):
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    60
    filtered = []
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    61
    for x, y in zip(abscissa, plot):
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    62
        if x is None or y is None:
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    63
            continue
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    64
        filtered.append( (x, y) )
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
    65
    return sorted(filtered)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    66
1892
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    67
class PlotWidget(object):
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    68
    # XXX refactor with cubicweb.web.views.htmlwidgets.HtmlWidget
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    69
    def _initialize_stream(self, w=None):
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    70
        if w:
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    71
            self.w = w
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    72
        else:
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    73
            self._stream = UStringIO()
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    74
            self.w = self._stream.write
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    75
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    76
    def render(self, *args, **kwargs):
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    77
        w = kwargs.pop('w', None)
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    78
        self._initialize_stream(w)
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    79
        self._render(*args, **kwargs)
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    80
        if w is None:
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    81
            return self._stream.getvalue()
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    82
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    83
class FlotPlotWidget(PlotWidget):
1891
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
    84
    """PlotRenderer widget using Flot"""
4209
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    85
    onload = u"""
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    86
var fig = jQuery("#%(figid)s");
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    87
if (fig.attr('cubicweb:type') != 'prepared-plot') {
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    88
    %(plotdefs)s
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    89
    jQuery.plot(jQuery("#%(figid)s"), [%(plotdata)s],
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    90
        {points: {show: true},
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    91
         lines: {show: true},
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    92
         grid: {hoverable: true},
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    93
         xaxis: {mode: %(mode)s}});
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    94
    jQuery("#%(figid)s").bind("plothover", onPlotHover);
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    95
    fig.attr('cubicweb:type','prepared-plot');
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    96
}
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
    97
"""
1892
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
    98
1891
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
    99
    def __init__(self, labels, plots, timemode=False):
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   100
        self.labels = labels
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   101
        self.plots = plots # list of list of couples
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   102
        self.timemode = timemode
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   103
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   104
    def dump_plot(self, plot):
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   105
        # XXX for now, the only way that we have to customize properly
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   106
        #     datetime labels on tooltips is to insert an additional column
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   107
        #     cf. function onPlotHover in cubicweb.flot.js
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   108
        if self.timemode:
4721
8f63691ccb7f pylint style fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4719
diff changeset
   109
            plot = [(datetime2ticks(x), y, datetime2ticks(x)) for x, y in plot]
1891
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   110
        return dumps(plot)
1892
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   111
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   112
    def _render(self, req, width=500, height=400):
4209
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
   113
        if req.ie_browser():
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
   114
            req.add_js('excanvas.js')
8712d699beb2 do not recompute the plot on subsequent onload events #615338
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3785
diff changeset
   115
        req.add_js(('jquery.flot.js', 'cubicweb.flot.js'))
3338
cd137d90f896 can't use anymore make_uid to generate a valid js var name
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3097
diff changeset
   116
        figid = u'figure%s' % req.varmaker.next()
1891
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   117
        plotdefs = []
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   118
        plotdata = []
1892
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   119
        self.w(u'<div id="%s" style="width: %spx; height: %spx;"></div>' %
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   120
               (figid, width, height))
1891
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   121
        for idx, (label, plot) in enumerate(zip(self.labels, self.plots)):
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   122
            plotid = '%s_%s' % (figid, idx)
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   123
            plotdefs.append('var %s = %s;' % (plotid, self.dump_plot(plot)))
3714
3cb7dcd9ae77 ugly workaround to javascript serialisation problem #481437 (not considered fixed by this changeset)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 3689
diff changeset
   124
            # XXX ugly but required in order to not crash my demo
3cb7dcd9ae77 ugly workaround to javascript serialisation problem #481437 (not considered fixed by this changeset)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 3689
diff changeset
   125
            plotdata.append("{label: '%s', data: %s}" % (label.replace(u'&', u''), plotid))
1891
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   126
        req.html_headers.add_onload(self.onload %
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   127
                                    {'plotdefs': '\n'.join(plotdefs),
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   128
                                     'figid': figid,
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   129
                                     'plotdata': ','.join(plotdata),
5041
ebdab53b0c45 [cleanup] remove 3.7 deprecation warning
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4721
diff changeset
   130
                                     'mode': self.timemode and "'time'" or 'null'})
1892
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   131
1891
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   132
1888
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
   133
class PlotView(baseviews.AnyRsetView):
3408
c92170fca813 [api] use __regid__ instead of deprecated id
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3338
diff changeset
   134
    __regid__ = 'plot'
1888
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
   135
    title = _('generic plot')
4320
4efd4c306746 closes #345410: two_lines_rset, two_cols_rset, two_etypes_rset are badly named
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
   136
    __select__ = multi_columns_rset() & all_columns_are_numbers()
1891
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   137
    timemode = False
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   138
1888
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
   139
    def call(self, width=500, height=400):
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
   140
        # prepare data
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3408
diff changeset
   141
        rqlst = self.cw_rset.syntax_tree()
1888
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
   142
        # XXX try to make it work with unions
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
   143
        varnames = [var.name for var in rqlst.children[0].get_selected_variables()][1:]
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3408
diff changeset
   144
        abscissa = [row[0] for row in self.cw_rset]
1891
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   145
        plots = []
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3408
diff changeset
   146
        nbcols = len(self.cw_rset.rows[0])
1891
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   147
        for col in xrange(1, nbcols):
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3408
diff changeset
   148
            data = [row[col] for row in self.cw_rset]
1991
8a9d8f1ee100 bugfix for plots
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1977
diff changeset
   149
            plots.append(filterout_nulls(abscissa, data))
1891
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   150
        plotwidget = FlotPlotWidget(varnames, plots, timemode=self.timemode)
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3408
diff changeset
   151
        plotwidget.render(self._cw, width, height, w=self.w)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   152
1888
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
   153
f36d43f00f32 [views] plot with flot and get rid of matplotlib
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1886
diff changeset
   154
class TimeSeriePlotView(PlotView):
4320
4efd4c306746 closes #345410: two_lines_rset, two_cols_rset, two_etypes_rset are badly named
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
   155
    __select__ = multi_columns_rset() & columns_are_date_then_numbers()
1891
dd7c1d7715e7 [views][plots] extract the plotting mechanism in an HTMLWidget to make mit more re-usable
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1888
diff changeset
   156
    timemode = True
1886
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   157
1892
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   158
1886
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   159
try:
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   160
    from GChartWrapper import Pie, Pie3D
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   161
except ImportError:
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   162
    pass
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   163
else:
1892
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   164
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   165
    class PieChartWidget(PlotWidget):
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   166
        def __init__(self, labels, values, pieclass=Pie, title=None):
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   167
            self.labels = labels
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   168
            self.values = values
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   169
            self.pieclass = pieclass
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   170
            self.title = title
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   171
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   172
        def _render(self, width=None, height=None):
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   173
            piechart = self.pieclass(self.values)
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   174
            piechart.label(*self.labels)
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   175
            if width is not None:
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   176
                height = height or width
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   177
                piechart.size(width, height)
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   178
            if self.title:
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   179
                piechart.title(self.title)
2312
af4d8f75c5db use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2161
diff changeset
   180
            self.w(u'<img src="%s" />' % xml_escape(piechart.url))
1892
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   181
1886
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   182
    class PieChartView(baseviews.AnyRsetView):
3408
c92170fca813 [api] use __regid__ instead of deprecated id
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3338
diff changeset
   183
        __regid__ = 'piechart'
1886
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   184
        pieclass = Pie
1892
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   185
4320
4efd4c306746 closes #345410: two_lines_rset, two_cols_rset, two_etypes_rset are badly named
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
   186
        __select__ = multi_columns_rset() & second_column_is_number()
1886
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   187
1956
9865daa96cd7 [views][plot] piechart view now accepts either final or non final entities in the first column
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1911
diff changeset
   188
        def _guess_vid(self, row):
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3408
diff changeset
   189
            etype = self.cw_rset.description[row][0]
4045
f4a52abb6f4f cw 3.6 api update
Sandrine Ribeau <sandrine.ribeau@logilab.fr>
parents: 3890
diff changeset
   190
            if self._cw.vreg.schema.eschema(etype).final:
1956
9865daa96cd7 [views][plot] piechart view now accepts either final or non final entities in the first column
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1911
diff changeset
   191
                return 'final'
9865daa96cd7 [views][plot] piechart view now accepts either final or non final entities in the first column
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1911
diff changeset
   192
            return 'textincontext'
9865daa96cd7 [views][plot] piechart view now accepts either final or non final entities in the first column
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1911
diff changeset
   193
1886
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   194
        def call(self, title=None, width=None, height=None):
1956
9865daa96cd7 [views][plot] piechart view now accepts either final or non final entities in the first column
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1911
diff changeset
   195
            labels = []
9865daa96cd7 [views][plot] piechart view now accepts either final or non final entities in the first column
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1911
diff changeset
   196
            values = []
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3408
diff changeset
   197
            for rowidx, (_, value) in enumerate(self.cw_rset):
1956
9865daa96cd7 [views][plot] piechart view now accepts either final or non final entities in the first column
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1911
diff changeset
   198
                if value is not None:
9865daa96cd7 [views][plot] piechart view now accepts either final or non final entities in the first column
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1911
diff changeset
   199
                    vid = self._guess_vid(rowidx)
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3408
diff changeset
   200
                    label = '%s: %s' % (self.view(vid, self.cw_rset, row=rowidx, col=0),
1956
9865daa96cd7 [views][plot] piechart view now accepts either final or non final entities in the first column
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1911
diff changeset
   201
                                        value)
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3408
diff changeset
   202
                    labels.append(label.encode(self._cw.encoding))
1956
9865daa96cd7 [views][plot] piechart view now accepts either final or non final entities in the first column
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1911
diff changeset
   203
                    values.append(value)
1892
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   204
            pie = PieChartWidget(labels, values, pieclass=self.pieclass,
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   205
                                 title=title)
1886
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   206
            if width is not None:
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   207
                height = height or width
1892
fb80d9c434e5 [views] extract a PieWidget from pie views
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1891
diff changeset
   208
            pie.render(width, height, w=self.w)
1886
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   209
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   210
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   211
    class PieChart3DView(PieChartView):
3408
c92170fca813 [api] use __regid__ instead of deprecated id
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3338
diff changeset
   212
        __regid__ = 'piechart3D'
1886
f0e28ddba7c5 [views] add pie chart views with google chart / GChartWrapper
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   213
        pieclass = Pie3D