root/trunk/pycha/stackedbar.py

Revision 176, 4.4 kB (checked in by lgs, 3 years ago)

Fix in the computation of the bar width when there is just one data point and a custom range. Fixes #20

Line 
1# Copyright(c) 2009 by Yaco S.L. <lgs@yaco.es>
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.bar import BarChart, VerticalBarChart, HorizontalBarChart, Rect
19from pycha.chart import uniqueIndices
20
21
22class StackedBarChart(BarChart):
23
24    def __init__(self, surface=None, options={}):
25        super(StackedBarChart, self).__init__(surface, options)
26        self.barWidth = 0.0
27
28    def _updateXY(self):
29        super(StackedBarChart, self)._updateXY()
30        # each dataset is centered around a line segment. that's why we
31        # need n + 1 divisions on the x axis
32        self.xscale = 1 / (self.xrange + 1.0)
33
34        if self.options.axis.y.range is None:
35            # Fix the yscale as we accumulate the y values
36            stores = self._getDatasetsValues()
37            n_stores = len(stores)
38            flat_y = [pair[1] for pair in reduce(lambda a, b: a+b, stores)]
39            store_size = len(flat_y) / n_stores
40            accum = [sum(flat_y[j]for j in xrange(i,
41                                                  i + store_size * n_stores,
42                                                  store_size))
43                     for i in range(len(flat_y) / n_stores)]
44            self.yrange = float(max(accum))
45            if self.yrange == 0:
46                self.yscale = 1.0
47            else:
48                self.yscale = 1.0 / self.yrange
49
50    def _updateChart(self):
51        """Evaluates measures for vertical bars"""
52        stores = self._getDatasetsValues()
53        uniqx = uniqueIndices(stores)
54
55        if len(uniqx) == 1:
56            self.minxdelta = 1.0
57        else:
58            self.minxdelta = min([abs(uniqx[j] - uniqx[j-1])
59                                  for j in range(1, len(uniqx))])
60
61        k = self.minxdelta * self.xscale
62        self.barWidth = k * self.options.barWidthFillFraction
63        self.barMargin = k * (1.0 - self.options.barWidthFillFraction) / 2
64
65        self.bars = []
66
67
68class StackedVerticalBarChart(StackedBarChart, VerticalBarChart):
69
70    def _updateChart(self):
71        """Evaluates measures for vertical bars"""
72        super(StackedVerticalBarChart, self)._updateChart()
73
74        accumulated_heights = {}
75        for i, (name, store) in enumerate(self.datasets):
76            for item in store:
77                xval, yval = item
78                x = ((xval - self.minxval) * self.xscale) + self.barMargin
79                w = self.barWidth
80                h = abs(yval) * self.yscale
81                if yval > 0:
82                    y = (1.0 - h) - self.area.origin
83                else:
84                    y = 1 - self.area.origin
85
86                accumulated_height = accumulated_heights.setdefault(xval, 0)
87                y -= accumulated_height
88                accumulated_heights[xval] += h
89
90                rect = Rect(x, y, w, h, xval, yval, name)
91
92                if (0.0 <= rect.x <= 1.0) and (0.0 <= rect.y <= 1.0):
93                    self.bars.append(rect)
94
95
96class StackedHorizontalBarChart(StackedBarChart, HorizontalBarChart):
97
98    def _updateChart(self):
99        """Evaluates measures for horizontal bars"""
100        super(StackedHorizontalBarChart, self)._updateChart()
101
102        accumulated_widths = {}
103        for i, (name, store) in enumerate(self.datasets):
104            for item in store:
105                xval, yval = item
106                y = ((xval - self.minxval) * self.xscale) + self.barMargin
107                h = self.barWidth
108                w = abs(yval) * self.yscale
109                if yval > 0:
110                    x = self.area.origin
111                else:
112                    x = self.area.origin - w
113
114                accumulated_width = accumulated_widths.setdefault(xval, 0)
115                x += accumulated_width
116                accumulated_widths[xval] += w
117
118                rect = Rect(x, y, w, h, xval, yval, name)
119
120                if (0.0 <= rect.x <= 1.0) and (0.0 <= rect.y <= 1.0):
121                    self.bars.append(rect)
Note: See TracBrowser for help on using the browser.