root/tags/0.4.1/src/line.py

Revision 109, 4.4 kB (checked in by lgs, 4 years ago)

Some refactoring and support for negative values in line and bar charts. Inspired by Nicolas patch

Line 
1# Copyright (c) 2007-2008 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
21class LineChart(Chart):
22
23    def __init__(self, surface=None, options={}):
24        super(LineChart, self).__init__(surface, options)
25        self.points = []
26
27    def _updateChart(self):
28        """Evaluates measures for line charts"""
29        self.points = []
30
31        for i, (name, store) in enumerate(self.datasets):
32            for item in store:
33                xval, yval = item
34                x = (xval - self.minxval) * self.xscale
35                y = 1.0 - (yval - self.minyval) * self.yscale
36                point = Point(x, y, xval, yval, name)
37
38                if 0.0 <= point.x <= 1.0 and 0.0 <= point.y <= 1.0:
39                    self.points.append(point)
40
41    def _renderChart(self, cx):
42        """Renders a line chart"""
43        def preparePath(storeName):
44            cx.new_path()
45            firstPoint = True
46            lastX = None
47            if self.options.shouldFill:
48                # Go to the (0,0) coordinate to start drawing the area
49                #cx.move_to(self.area.x, self.area.y + self.area.h)
50                cx.move_to(self.area.x,
51                           self.area.y + (1.0 - self.area.origin) * self.area.h)
52
53            for point in self.points:
54                if point.name == storeName:
55                    if not self.options.shouldFill and firstPoint:
56                        # starts the first point of the line
57                        cx.move_to(point.x * self.area.w + self.area.x,
58                                   point.y * self.area.h + self.area.y)
59                        firstPoint = False
60                        continue
61                    cx.line_to(point.x * self.area.w + self.area.x,
62                               point.y * self.area.h + self.area.y)
63                    # we remember the last X coordinate to close the area
64                    # properly. See bug #4
65                    lastX = point.x
66
67            if self.options.shouldFill:
68                # Close the path to the start point
69                y = (1.0 - self.area.origin) * self.area.h + self.area.y
70                cx.line_to(lastX * self.area.w + self.area.x, y)
71                cx.line_to(self.area.x, y)
72                cx.close_path()
73            else:
74                cx.set_source_rgb(*self.options.colorScheme[storeName])
75                cx.stroke()
76
77
78        cx.save()
79        cx.set_line_width(self.options.stroke.width)
80        if self.options.shouldFill:
81            def drawLine(storeName):
82                if self.options.stroke.shadow:
83                    # draw shadow
84                    cx.save()
85                    cx.set_source_rgba(0, 0, 0, 0.15)
86                    cx.translate(2, -2)
87                    preparePath(storeName)
88                    cx.fill()
89                    cx.restore()
90
91                # fill the line
92                cx.set_source_rgb(*self.options.colorScheme[storeName])
93                preparePath(storeName)
94                cx.fill()
95
96                if not self.options.stroke.hide:
97                    # draw stroke
98                    cx.set_source_rgb(*hex2rgb(self.options.stroke.color))
99                    preparePath(storeName)
100                    cx.stroke()
101
102            # draw the lines
103            for key in self._getDatasetsKeys():
104                drawLine(key)
105        else:
106            for key in self._getDatasetsKeys():
107                preparePath(key)
108
109        cx.restore()
110
111class Point(object):
112    def __init__(self, x, y, xval, yval, name):
113        self.x, self.y = x, y
114        self.xval, self.yval = xval, yval
115        self.name = name
116
117    def __str__(self):
118        return "<pycha.line.Point@(%.2f, %.2f)>" % (self.x, self.y)
Note: See TracBrowser for help on using the browser.