root/trunk/pycha/line.py

Revision 169, 4.3 kB (checked in by lgs, 3 years ago)

Big refactor about how the colors scheme are created and used. See #29

Line 
1# Copyright(c) 2007-2009 by Lorenzo Gil Sanchez <lorenzo.gil.sanchez@gmail.com>
2#
3# This file is part of PyCha.
4#
5# PyCha is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# PyCha is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU Lesser General Public License for more details.
14#
15# You should have received a copy of the GNU Lesser General Public License
16# along with PyCha.  If not, see <http://www.gnu.org/licenses/>.
17
18from pycha.chart import Chart
19from pycha.color import hex2rgb
20
21
22class LineChart(Chart):
23
24    def __init__(self, surface=None, options={}):
25        super(LineChart, self).__init__(surface, options)
26        self.points = []
27
28    def _updateChart(self):
29        """Evaluates measures for line charts"""
30        self.points = []
31
32        for i, (name, store) in enumerate(self.datasets):
33            for item in store:
34                xval, yval = item
35                x = (xval - self.minxval) * self.xscale
36                y = 1.0 - (yval - self.minyval) * self.yscale
37                point = Point(x, y, xval, yval, name)
38
39                if 0.0 <= point.x <= 1.0 and 0.0 <= point.y <= 1.0:
40                    self.points.append(point)
41
42    def _renderChart(self, cx):
43        """Renders a line chart"""
44
45        def preparePath(storeName):
46            cx.new_path()
47            firstPoint = True
48            lastX = None
49            if self.options.shouldFill:
50                # Go to the (0,0) coordinate to start drawing the area
51                #cx.move_to(self.area.x, self.area.y + self.area.h)
52                offset = (1.0 - self.area.origin) * self.area.h
53                cx.move_to(self.area.x, self.area.y + offset)
54
55            for point in self.points:
56                if point.name == storeName:
57                    if not self.options.shouldFill and firstPoint:
58                        # starts the first point of the line
59                        cx.move_to(point.x * self.area.w + self.area.x,
60                                   point.y * self.area.h + self.area.y)
61                        firstPoint = False
62                        continue
63                    cx.line_to(point.x * self.area.w + self.area.x,
64                               point.y * self.area.h + self.area.y)
65                    # we remember the last X coordinate to close the area
66                    # properly. See bug #4
67                    lastX = point.x
68
69            if self.options.shouldFill:
70                # Close the path to the start point
71                y = (1.0 - self.area.origin) * self.area.h + self.area.y
72                cx.line_to(lastX * self.area.w + self.area.x, y)
73                cx.line_to(self.area.x, y)
74                cx.close_path()
75            else:
76                cx.set_source_rgb(*self.colorScheme[storeName])
77                cx.stroke()
78
79
80        cx.save()
81        cx.set_line_width(self.options.stroke.width)
82        if self.options.shouldFill:
83
84            def drawLine(storeName):
85                if self.options.stroke.shadow:
86                    # draw shadow
87                    cx.save()
88                    cx.set_source_rgba(0, 0, 0, 0.15)
89                    cx.translate(2, -2)
90                    preparePath(storeName)
91                    cx.fill()
92                    cx.restore()
93
94                # fill the line
95                cx.set_source_rgb(*self.colorScheme[storeName])
96                preparePath(storeName)
97                cx.fill()
98
99                if not self.options.stroke.hide:
100                    # draw stroke
101                    cx.set_source_rgb(*hex2rgb(self.options.stroke.color))
102                    preparePath(storeName)
103                    cx.stroke()
104
105            # draw the lines
106            for key in self._getDatasetsKeys():
107                drawLine(key)
108        else:
109            for key in self._getDatasetsKeys():
110                preparePath(key)
111
112        cx.restore()
113
114
115class Point(object):
116
117    def __init__(self, x, y, xval, yval, name):
118        self.x, self.y = x, y
119        self.xval, self.yval = xval, yval
120        self.name = name
121
122    def __str__(self):
123        return "<pycha.line.Point@(%.2f, %.2f)>" % (self.x, self.y)
Note: See TracBrowser for help on using the browser.