diff options
| author | Fabien Pinckaers <fp@tinyerp.com> | 2009-03-15 20:07:01 +0100 |
|---|---|---|
| committer | Fabien Pinckaers <fp@tinyerp.com> | 2009-03-15 20:07:01 +0100 |
| commit | 81ed36a9f2e28ae426b07f4dbf4bf444728b2166 (patch) | |
| tree | f68937f7873228898c56d2808de59594b8e057e1 /bin/pychart/area.py | |
| parent | 4ab081becaa3822c8965933603924504694f5c11 (diff) | |
Adding Pychart due to bug in recent pychart versions
bzr revid: fp@tinyerp.com-20090315190701-996gxy21rdr47a8c
Diffstat (limited to 'bin/pychart/area.py')
| -rw-r--r-- | bin/pychart/area.py | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/bin/pychart/area.py b/bin/pychart/area.py new file mode 100644 index 00000000000..a0e76876ec0 --- /dev/null +++ b/bin/pychart/area.py @@ -0,0 +1,249 @@ +# +# Copyright (C) 2000-2005 by Yasushi Saito (yasushi.saito@gmail.com) +# +# Jockey is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any +# later version. +# +# Jockey is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +import coord +import line_style +import legend +import axis +import pychart_util +import chart_object +import fill_style +import canvas +import area_doc +import linear_coord +import category_coord +import theme +from pychart_types import * +from types import * + +_dummy_legend = legend.T() + +def range_doc(t): + u = t.upper() + + return """Specifies the range of %s values that are displayed in the + chart. IF the value is None, both the values are computed + automatically from the samples. Otherwise, the value must be a + tuple of format (MIN, MAX). MIN and MAX must be either None or a + number. If None, the value is computed automatically from the + samples. For example, if %s_range = (None,5), then the minimum %s + value is computed automatically, but the maximum %s value is fixed + at 5.""" % (u, t, u, u) + +_keys = { + "loc" : (CoordType, (0,0), + """The location of the bottom-left corner of the chart. +@cindex chart location +@cindex location, chart +"""), + "size" : (CoordType, (120,110), + """The size of the chart-drawing area, excluding axis labels, + legends, tick marks, etc. +@cindex chart size +@cindex size, chart + """), + "bg_style": (fill_style.T, None, "Background fill-pattern."), + "border_line_style": (line_style.T, None, "Line style of the outer frame of the chart."), + "x_coord": + (coord.T, linear_coord.T(), + """Set the X coordinate system.""", + """A linear coordinate system."""), + "y_coord": (coord.T, linear_coord.T(), + "Set the Y coordinate system.", + """A linear coordinate system."""), + "x_range": (CoordType, None, range_doc("x")), + "y_range": (CoordType, None, range_doc("y")), + "x_axis": (axis.X, None, "The X axis. <<axis>>."), + "x_axis2": (axis.X, None, """The second X axis. This axis should be non-None either when you want to display plots with two distinct domains or when + you just want to display two axes at the top and bottom of the chart. + <<axis>>"""), + "y_axis": (axis.Y, None, "The Y axis. <<axis>>."), + "y_axis2": (axis.Y, None, + """The second Y axis. This axis should be non-None either when you want to display plots with two distinct ranges or when + you just want to display two axes at the left and right of the chart. <<axis>>"""), + "x_grid_style" : (line_style.T, None, + """The style of horizontal grid lines. +@cindex grid lines"""), + "y_grid_style" : (line_style.T, line_style.gray70_dash3, + "The style of vertical grid lines."), + "x_grid_interval": (IntervalType, None, + """The horizontal grid-line interval. + A numeric value + specifies the interval at which + lines are drawn. If value is a function, it + takes two arguments, (MIN, MAX), that tells + the minimum and maximum values found in the + sample data. The function should return a list + of values at which lines are drawn."""), + "y_grid_interval": (IntervalType, None, + "The vertical grid-line interval. See also x_grid_interval"), + "x_grid_over_plot": (IntType, False, + "If True, grid lines are drawn over plots. Otherwise, plots are drawn over grid lines."), + "y_grid_over_plot": (IntType, False, "See x_grid_over_plot."), + "plots": (ListType, pychart_util.new_list, + """Used only internally by pychart."""), + "legend": (legend.T, _dummy_legend, "The legend of the chart.", + """a legend is by default displayed + in the right-center of the chart."""), + } + + +class T(chart_object.T): + keys = _keys + __doc__ = area_doc.doc +##AUTOMATICALLY GENERATED + +##END AUTOMATICALLY GENERATED + def x_pos(self, xval): + "Return the x position (on the canvas) corresponding to XVAL." + off = self.x_coord.get_canvas_pos(self.size[0], xval, + self.x_range[0], self.x_range[1]) + return self.loc[0] + off + + def y_pos(self, yval): + "Return the y position (on the canvas) corresponding to YVAL." + off = self.y_coord.get_canvas_pos(self.size[1], yval, + self.y_range[0], self.y_range[1]) + return self.loc[1] + off + + def x_tic_points(self, interval): + "Return the list of X values for which tick marks and grid lines are drawn." + if type(interval) == FunctionType: + return apply(interval, self.x_range) + + return self.x_coord.get_tics(self.x_range[0], self.x_range[1], interval) + def y_tic_points(self, interval): + "Return the list of Y values for which tick marks and grid lines are drawn." + if type(interval) == FunctionType: + return apply(interval, self.y_range) + + return self.y_coord.get_tics(self.y_range[0], self.y_range[1], interval) + def __draw_x_grid_and_axis(self, can): + if self.x_grid_style: + for i in self.x_tic_points(self.x_grid_interval): + x = self.x_pos(i) + if x > self.loc[0]: + can.line(self.x_grid_style, + x, self.loc[1], x, self.loc[1]+self.size[1]) + if self.x_axis: + self.x_axis.draw(self, can) + if self.x_axis2: + self.x_axis2.draw(self, can) + def __draw_y_grid_and_axis(self, can): + if self.y_grid_style: + for i in self.y_tic_points(self.y_grid_interval): + y = self.y_pos(i) + if y > self.loc[1]: + can.line(self.y_grid_style, + self.loc[0], y, + self.loc[0]+self.size[0], y) + if self.y_axis: + self.y_axis.draw(self, can) + if self.y_axis2: + self.y_axis2.draw(self, can) + + def __get_data_range(self, r, which, coord, interval): + if isinstance(coord, category_coord.T): + # This info is unused for the category coord type. + # So I just return a random value. + return ((0,0), 1) + + r = r or (None, None) + + if len(self.plots) == 0: + raise ValueError, "No chart to draw, and no data range specified.\n"; + dmin, dmax = 999999, -999999 + + for plot in self.plots: + this_min, this_max = plot.get_data_range(which) + dmin = min(this_min, dmin) + dmax = max(this_max, dmax) + + if interval and type(interval) == FunctionType: + tics = apply(interval, (dmin, dmax)) + dmin = tics[0] + dmax = tics[len(tics)-1] + else: + dmin, dmax, interval = coord.get_min_max(dmin, dmax, interval) + + if r[0] != None: + dmin = r[0] + if r[1] != None: + dmax = r[1] + return ((dmin, dmax), interval) + def draw(self, can = None): + "Draw the charts." + + if can == None: + can = canvas.default_canvas() + + self.type_check() + for plot in self.plots: + plot.check_integrity() + + self.x_range, self.x_grid_interval = \ + self.__get_data_range(self.x_range, 'X', + self.x_coord, + self.x_grid_interval) + + self.y_range, self.y_grid_interval = \ + self.__get_data_range(self.y_range, 'Y', + self.y_coord, + self.y_grid_interval) + + can.rectangle(self.border_line_style, self.bg_style, + self.loc[0], self.loc[1], + self.loc[0] + self.size[0], self.loc[1] + self.size[1]) + + if not self.x_grid_over_plot: + self.__draw_x_grid_and_axis(can) + + if not self.y_grid_over_plot: + self.__draw_y_grid_and_axis(can) + + clipbox = theme.adjust_bounding_box([self.loc[0], self.loc[1], + self.loc[0] + self.size[0], + self.loc[1] + self.size[1]]) + + can.clip(clipbox[0], clipbox[1], + clipbox[2], clipbox[3]) + + for plot in self.plots: + plot.draw(self, can) + + can.endclip() + + if self.x_grid_over_plot: + self.__draw_x_grid_and_axis(can) + if self.y_grid_over_plot: + self.__draw_y_grid_and_axis(can) + + if self.legend == _dummy_legend: + self.legend = legend.T() + + if self.legend: + legends = [] + for plot in self.plots: + entry = plot.get_legend_entry() + if entry == None: + pass + elif type(entry) != ListType: + legends.append(entry) + else: + for e in entry: + legends.append(e) + self.legend.draw(self, legends, can) + + def add_plot(self, *plots): + "Add PLOTS... to the area." + self.plots.extend(plots) |
