pygdchart2alpha2004075500017500001750000000000000777443323200126355ustar00aldoaldopygdchart2alpha2/CVS004075500017500001750000000000000777443323100132675ustar00aldoaldopygdchart2alpha2/CVS/Root010064400017500001750000000000310777443323100142030ustar00aldoaldoaldo@ryoku:/home/cvs/cvs pygdchart2alpha2/CVS/Repository010064400017500001750000000000120777443323100154360ustar00aldoaldopygdchart pygdchart2alpha2/CVS/Entries010064400017500001750000000005560777443323100147050ustar00aldoaldo/CHANGELOG/1.1.1.1/Tue Oct 14 12:46:28 2003// /INSTALL/1.1.1.1/Tue Oct 14 12:46:28 2003// /README/1.1.1.1/Tue Oct 14 12:46:28 2003// /TODO/1.1.1.1/Tue Oct 14 12:46:28 2003// /_gdchartc.c/1.1.1.1/Tue Oct 14 12:46:28 2003// /gdchart.py/1.1.1.1/Tue Oct 14 12:46:29 2003// /lint/1.1.1.1/Tue Oct 14 12:46:29 2003// /setup.py/1.1.1.1/Tue Oct 14 12:46:29 2003// D/test//// pygdchart2alpha2/test004075500017500001750000000000000777443323200136145ustar00aldoaldopygdchart2alpha2/test/CVS004075500017500001750000000000000777443323100142465ustar00aldoaldopygdchart2alpha2/test/CVS/Root010064400017500001750000000000310777443323100151620ustar00aldoaldoaldo@ryoku:/home/cvs/cvs pygdchart2alpha2/test/CVS/Repository010064400017500001750000000000170777443323100164220ustar00aldoaldopygdchart/test pygdchart2alpha2/test/CVS/Entries010064400017500001750000000002450777443323100156570ustar00aldoaldo/README/1.1.1.1/Tue Oct 14 12:46:29 2003// /test_gdchart.py/1.1.1.1/Tue Oct 14 12:46:29 2003// /test_gdchartc.py/1.1.1.1/Tue Oct 14 12:46:29 2003// D/testgraphs//// pygdchart2alpha2/test/testgraphs004075500017500001750000000000000777443323200160005ustar00aldoaldopygdchart2alpha2/test/testgraphs/CVS004075500017500001750000000000000777443323100164325ustar00aldoaldopygdchart2alpha2/test/testgraphs/CVS/Root010064400017500001750000000000310777443323100173460ustar00aldoaldoaldo@ryoku:/home/cvs/cvs pygdchart2alpha2/test/testgraphs/CVS/Repository010064400017500001750000000000320777443323100206030ustar00aldoaldopygdchart/test/testgraphs pygdchart2alpha2/test/testgraphs/CVS/Entries010064400017500001750000000000540777443323100200410ustar00aldoaldo/error/1.1.1.1/Tue Oct 14 12:46:29 2003// D pygdchart2alpha2/test/testgraphs/colors004075500017500001750000000000000777443323100173005ustar00aldoaldopygdchart2alpha2/test/testgraphs/fonts004075500017500001750000000000000777443323200171315ustar00aldoaldopygdchart2alpha2/test/testgraphs/error010064400017500001750000000000000777443323200171160ustar00aldoaldopygdchart2alpha2/test/README010064400017500001750000000005130777443323200145470ustar00aldoaldoThe unit tests in this directory were written to be run by PyLid: http://www.nullcube.com/software/pylid That said, PyLid is built on the standard Python unit-testing framework, so it should not be hard to run the tests without it. After running the tests, check the testgraphs directory to make sure everything ran OK. pygdchart2alpha2/test/test_gdchart.py010064400017500001750000000626560777443323200167340ustar00aldoaldoimport unittest, os, shutil import gdchart class uUtilityFunctions(unittest.TestCase): def test_uniformLength(self): self.failUnlessEqual(gdchart._uniformLength(*([1, 2], [1, 2])), 2) self.failUnlessEqual(gdchart._uniformLength(*([1, 2],)), 2) self.failUnlessEqual(gdchart._uniformLength(*([1], [1, 2])), -1) def test_flattenList(self): expected = [1, 2, 3, 4] self.failUnless(gdchart._flattenList(*([1, 2], [3, 4])) == expected) self.failUnless(gdchart._flattenList(*([1, 2, 3], [4])) == expected) self.failUnless(gdchart._flattenList(*([1, 2, 3, 4],)) == expected) self.failUnless(gdchart._flattenList(*([],)) == []) class uRGB(unittest.TestCase): def test_int(self): rgb = gdchart.RGB(0,0,0) self.failUnlessEqual(repr(rgb), "0x0") rgb.r = 0xFF self.failUnlessEqual(repr(rgb), "0xff0000") rgb.g = 0xFF self.failUnlessEqual(repr(rgb), "0xffff00") rgb.b = 0xFF self.failUnlessEqual(repr(rgb), "0xffffff") def test_err(self): self.failUnlessRaises(ValueError, gdchart.RGB, 0, 0, 257) self.failUnlessRaises(ValueError, gdchart.RGB, 0, 257, 0) self.failUnlessRaises(ValueError, gdchart.RGB, 257, 0, 0) def test_rgbFactory(self): gdchart.rgbFactory("black") class uChartBase(unittest.TestCase): def setUp(self): # We use the graph class to test the ChartBase functionality. self.g = gdchart.GraphBase() def test_setOption_err(self): self.failUnlessRaises(ValueError, self.g.setOption, "foo", 2) def test_setOption(self): self.g.setOption("hard_graphwidth", 12) def test_getOption(self): self.failUnless(self.g.getOption("hard_graphwidth") == 0) self.g.setOption("hard_graphwidth", 10) self.failUnless(self.g.getOption("hard_graphwidth") == 10) self.failUnlessRaises(ValueError, self.g.getOption, "foo") def test_getAllOptions(self): x = self.g.getAllOptions()["hard_graphwidth"] self.g.setOption("hard_graphwidth", 99) self.failUnlessEqual(self.g.getAllOptions()["hard_graphwidth"], 99) def test_noattr(self): try: self.g.asfdasdf except AttributeError: pass else: fail() def test_noattrSet(self): try: self.g.asfdasdf = "foo" except AttributeError: pass else: fail() class uOptions(unittest.TestCase): # FIXME: Generalise this to test ALL options for both types def setUp(self): self.graph = gdchart.GraphBase() self.pie = gdchart.Pie() def _testOption(self, opType, testValue, chartType): """ First we zero out all options. Then we retrieve the options, and check that they are zero. Then we restore the defaults, retrieve the options again, and check that the value agrees with the cached default dictionary. """ # Set all options to testValue for i in chartType._defaultOptions: # Ignore constrained values if not chartType._lookupOptions.has_key(i) and not chartType._maskOptions.has_key(i): o = chartType._defaultOptions[i] if o[1] == opType: chartType.setOption(i, testValue) chartType._actualiseOptions() # Retrieve the options, and check that they are all testValue zeros = gdchart._gdchartc.getOptions(chartType._myType) for i in zeros: o = zeros[i] if o[1] == opType: # Ignore constrained values if not chartType._lookupOptions.has_key(i) and not chartType._maskOptions.has_key(i): self.failUnlessEqual(o[2], testValue) # Now restore the defaults chartType.restoreDefaultOptions() chartType._actualiseOptions() # Retrieve the options, and check that they are all set to the defaults defaults = gdchart._gdchartc.getOptions(chartType._myType) for i in defaults: # Ignore constrained values if not chartType._lookupOptions.has_key(i) and not chartType._maskOptions.has_key(i): self.failUnlessEqual(defaults[i], chartType._defaultOptions[i]) def test_options(self): self._testOption(gdchart._gdchartc.OPT_INT, 0, self.graph) self._testOption(gdchart._gdchartc.OPT_COLOR, 0, self.graph) self._testOption(gdchart._gdchartc.OPT_SHORT, 0, self.graph) self._testOption(gdchart._gdchartc.OPT_USHORT, 0, self.pie) self._testOption(gdchart._gdchartc.OPT_UCHAR, 0, self.graph) self._testOption(gdchart._gdchartc.OPT_BOOL, 0, self.graph) self._testOption(gdchart._gdchartc.OPT_FONTSIZE, 0, self.graph) self._testOption(gdchart._gdchartc.OPT_LONG, 0, self.graph) self._testOption(gdchart._gdchartc.OPT_FLOAT, 0.0, self.graph) self._testOption(gdchart._gdchartc.OPT_STRING, "foo", self.graph) self._testOption(gdchart._gdchartc.OPT_INT_A, range(500), self.pie) self._testOption(gdchart._gdchartc.OPT_COLOR_A, range(500), self.pie) self._testOption(gdchart._gdchartc.OPT_BOOL_A, [1, 0, 1]*100, self.pie) def test_optionsColor(self): self.graph.bg_color = "black" self.failUnlessEqual(self.graph.bg_color, 0) def test_optionsColorA(self): self.graph.ext_color = ["black", "black", "black"] self.failUnlessEqual(self.graph.ext_color, [0, 0, 0]) def test_maskOptions(self): self.graph.setOption("border", ("TOP", "X")) self.failUnlessRaises(gdchart.GDChartError, self.graph.setOption, "border", ("TOP", "foo")) def test_lookupOptions(self): self.graph.setOption("image_type", "GIF") self.failUnlessRaises(gdchart.GDChartError, self.graph.setOption, "image_type", "foo") def test_getOptions(self): self.graph.setOption("border", ("TOP", "X")) ret = self.graph.getOption("border") ret.sort() self.failUnlessEqual(ret, ["TOP", "X"]) ret = self.graph.border ret.sort() self.failUnlessEqual(ret, ["TOP", "X"]) self.graph.setOption("image_type", "GIF") self.failUnlessEqual(self.graph.getOption("image_type"), "GIF") def test_getOptions_dimensions(self): self.graph.width self.graph.height def test_getAllOptions(self): self.graph.setOption("border", ("TOP", "X")) self.graph.setOption("image_type", "GIF") all = self.graph.getAllOptions() border = all["border"] border.sort() self.failUnlessEqual(border, ["TOP", "X"]) self.failUnlessEqual(all["image_type"], "GIF") def test_typeErr(self): self.failUnlessRaises(gdchart.GDChartError, self.graph.setOption, "threeD_depth", "foo") self.failUnlessRaises(gdchart.GDChartError, self.graph.setOption, "annotation_font_size", "foo") self.failUnlessRaises(gdchart.GDChartError, self.graph.setOption, "border", "foo") self.failUnlessRaises(gdchart.GDChartError, self.graph.setOption, "bg_color", "foo") self.failUnlessRaises(gdchart.GDChartError, self.graph.setOption, "xlabel_spacing", "foo") self.failUnlessRaises(gdchart.GDChartError, self.pie.setOption, "perspective", "foo") self.failUnlessRaises(gdchart.GDChartError, self.graph.setOption, "bar_width", "foo") self.failUnlessRaises(gdchart.GDChartError, self.graph.setOption, "bar_width", 101) self.graph.setOption("bar_width", 100) self.failUnlessRaises(gdchart.GDChartError, self.graph.setOption, "threeD_angle", "foo") self.failUnlessRaises(gdchart.GDChartError, self.pie.setOption, "other_threshold", "foo") self.failUnlessRaises(gdchart.GDChartError, self.pie.setOption, "explode", [1, 2, "a"]) class uSimpleBase(unittest.TestCase): def setUp(self): self.sb = gdchart.SimpleBase() def test_getSimpleData(self): data = [(1, 2), (3, 4), (5, 6)] len, lst = self.sb._getSimpleData(*data) self.failUnlessEqual(len, 2) self.failUnlessEqual(lst, [1, 2, 3, 4, 5, 6]) def test_getSimpleDataErr(self): data = [(1,), (3, 4), (5, 6)] self.failUnlessRaises(gdchart.GDChartError, self.sb._getSimpleData, *data) class uMultisetBase(unittest.TestCase): def setUp(self): self.fb = gdchart.FloatingBarBase() def test_getMultisetData(self): data = [ [ (1, 2, 3), (4, 5, 6)], [ (7, 8, 9), (10, 11, 12)] ] len, lst = self.fb._getMultisetData(2, *data) self.failUnlessEqual(len, 3) self.failUnlessEqual(lst, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) data = [ [ (1, 2, 3), (4, 5, 6), (7, 8, 9)], [ (10, 11, 12), (13, 14, 15), (16, 17, 18)] ] len, lst = self.fb._getMultisetData(3, *data) self.failUnlessEqual(len, 3) self.failUnlessEqual(lst, range(1, 19)) def test_getMultisetDataErr(self): data = [ [ (1, 2, 3), (4, 5, 6)], [ (7, 8, 9), (11, 12)] ] self.failUnlessRaises(gdchart.GDChartError, self.fb._getMultisetData, 2, *data) data = [ [ (1, 2, 3), (4, 5, 6)], [ (7, 8, 9)] ] self.failUnlessRaises(gdchart.GDChartError, self.fb._getMultisetData, 2, *data) data = [ [ (1, 2, 3), (4, 5, 6)], [ (1, 2, 3), (4, 5, 6)], [ (7, 8), (11, 12)] ] self.failUnlessRaises(gdchart.GDChartError, self.fb._getMultisetData, 2, *data) class uConformanceErrors(unittest.TestCase): def test_conformance(self): gd = gdchart.Line() gd.setData(range(100)) self.failUnlessRaises(gdchart.GDChartError, gd.setLabels, range(10)) gd = gdchart.Line() gd.setLabels(range(100)) self.failUnlessRaises(gdchart.GDChartError, gd.setData, range(10)) gd = gdchart.LineLineCombo() gd.setLabels(range(100)) gd.setComboData(range(100)) self.failUnlessRaises(gdchart.GDChartError, gd.setData, range(10)) gd = gdchart.LineLineCombo() gd.setComboData(range(100)) self.failUnlessRaises(gdchart.GDChartError, gd.setData, range(10)) gd = gdchart.LineLineCombo() gd.setLabels(range(100)) gd.setData(range(100)) self.failUnlessRaises(gdchart.GDChartError, gd.setComboData, range(10)) gd = gdchart.LineLineCombo() gd.setLabels(range(100)) self.failUnlessRaises(gdchart.GDChartError, gd.setData, range(10)) gd = gdchart.LineLineCombo() gd.setLabels(range(100)) gd.setData(range(100)) self.failUnlessRaises(gdchart.GDChartError, gd.setComboData, range(10)) def test_conformance(self): gd = gdchart.Pie() gd.setLabels(range(100)) self.failUnlessRaises(gdchart.GDChartError, gd.setData, range(10)) class uComboErrors(unittest.TestCase): def test_comboerr(self): gd = gdchart.HLCAreaCombo() gd.setData(((5, 7, 10), (0, 2, 4), (3, 4, 6))) gd.setLabels([1, 2, 3]) self.failUnlessRaises(gdchart.GDChartError, gd.draw, os.path.join("error")) gd = gdchart.LineBarCombo() gd.setData((5, 7, 10)) gd.setLabels([1, 2, 3]) self.failUnlessRaises(gdchart.GDChartError, gd.draw, os.path.join("error")) class uPie(unittest.TestCase): def setUp(self): self.gp = gdchart.Pie() def test_empty(self): self.failUnlessRaises(gdchart.GDChartError, self.gp.draw, "err") class uPieSuite(unittest.TestCase): OUTPUT = "testgraphs" def setUp(self): try: os.mkdir(self.OUTPUT) except OSError: pass def test_simple(self): p = gdchart.Pie() p.setData(*range(5)) p.setLabels(range(5)) colors = ["red", "green", "blue", "yellow", "orange"] p.color = colors p.draw(os.path.join(self.OUTPUT, "pie.png")) def test_simple3d(self): p = gdchart.Pie3D() p.setData(*range(5)) p.setLabels(range(5)) colors = [ gdchart.rgbFactory("red"), gdchart.rgbFactory("green"), gdchart.rgbFactory("blue"), gdchart.rgbFactory("yellow"), gdchart.rgbFactory("orange"), ] p.color = colors p.draw(os.path.join(self.OUTPUT, "pie3d.png")) def test_explode(self): p = gdchart.Pie3D() p.setData(*range(5)) p.setLabels(range(5)) colors = [ gdchart.rgbFactory("red"), gdchart.rgbFactory("green"), gdchart.rgbFactory("blue"), gdchart.rgbFactory("yellow"), gdchart.rgbFactory("orange"), ] p.color = colors p.explode = [0, 0, 0, 20, 80] p.draw(os.path.join(self.OUTPUT, "explode.png")) def test_drawtofp(self): p = gdchart.Pie() p.setData(*range(5)) p.setLabels(range(5)) colors = ["red", "green", "blue", "yellow", "orange"] p.color = colors f = file(os.path.join(self.OUTPUT, "tofile-pie.png"), "w") p.draw(f) class uScatter(unittest.TestCase): def setUp(self): self.s = gdchart.Scatter(0, 0) def test_type(self): try: self.s.type = "foo" except ValueError: pass else: self.fail() self.s.type = "TRIANGLE_DOWN" self.failUnlessEqual(self.s.type, "TRIANGLE_DOWN") def test_width(self): try: self.s.width = "foo" except ValueError: pass else: self.fail() try: self.s.width = 101 except (ValueError): pass else: self.fail() self.s.width = 99 self.failUnlessEqual(self.s.width, 99) def test_setScatter(self): gd = gdchart.GraphBase() gd.setLabels(["one", "two", "three"]) scats = [] for i in range(10): s = gdchart.Scatter(0, 0) s.point = i scats.append(s) self.failUnlessRaises(ValueError, gd.setScatter, scats) class uAnnotate(unittest.TestCase): def setUp(self): self.s = gdchart.GraphBase() def test_datalen(self): self.s._datalen = 5 self.failUnlessRaises(ValueError, self.s.annotate, 10) self.s._datalen = None self.s._labels = [1, 2, 3] self.failUnlessRaises(ValueError, self.s.annotate, 10) def test_label(self): self.s._labels = ["one", "two", "three"] self.failUnlessRaises(ValueError, self.s.annotate, 10) def test_label(self): self.failUnlessRaises(ValueError, self.s.annotate, 10, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") def test_color(self): self.failUnlessRaises(gdchart.GDChartError, self.s.annotate, 10, color="foo") def test_clear(self): self.s.annotate(10, "aaaaaaaaa", 1) self.s.clearAnnotation() self.failIf(self.s._annotation) class uGraphSuite(unittest.TestCase): OUTPUT = "testgraphs" def setUp(self): try: os.mkdir(self.OUTPUT) except OSError: pass def test_size(self): gd = gdchart.Line() gd.setData(range(100)) gd.setLabels(range(100)) gd.draw(os.path.join(self.OUTPUT, "sizetest-default.png")) gd = gdchart.Line() gd.setData(range(100)) gd.setLabels(range(100)) gd.setOption("width", 0) self.failUnlessRaises(gdchart.GDChartError, gd.draw, os.path.join(self.OUTPUT, "error")) gd = gdchart.Line() gd.setData(range(100)) gd.setLabels(range(100)) gd.setOption("width", 500) gd.setOption("height", 0) self.failUnlessRaises(gdchart.GDChartError, gd.draw, os.path.join(self.OUTPUT, "error")) gd = gdchart.Line() gd.setOption("width", 60) gd.setOption("height", 60) gd.setData(range(2)) gd.setLabels(range(2)) gd.draw(os.path.join(self.OUTPUT, "sizetest-tiny.png")) gd = gdchart.Line() gd.setOption("width", 1000) gd.setOption("height", 1000) gd.setData(range(100)) gd.setLabels(range(100)) gd.draw(os.path.join(self.OUTPUT, "sizetest-big.png")) def test_mydata(self): gd = gdchart.Line() gd.setData(range(100000)) gd.setLabels(range(100000)) gd.draw(os.path.join(self.OUTPUT, "data-big.png")) gd = gdchart.Line() gd.setData(range(1)) gd.setLabels(range(1)) gd.draw(os.path.join(self.OUTPUT, "data-small.png")) gd = gdchart.Line() gd.setData([]) gd.setLabels([]) self.failUnlessRaises(gdchart.GDChartError, gd.draw, os.path.join(self.OUTPUT, "error")) def test_simpleTypes(self): gd = gdchart.Line() gd.setData(range(100), range(100, 0, -1)) gd.setLabels(range(100)) gd.draw(os.path.join(self.OUTPUT, "types-Line.png")) gd = gdchart.Line3D() gd.setData(range(100), range(100, 0, -1)) gd.setLabels(range(100)) gd.draw(os.path.join(self.OUTPUT, "types-Line3D.png")) gd = gdchart.Area() gd.setData(range(100), range(100, 0, -1)) gd.setLabels(range(100)) gd.draw(os.path.join(self.OUTPUT, "types-Area.png")) gd = gdchart.Area3D() gd.setData(range(100), range(100, 0, -1)) gd.setLabels(range(100)) gd.draw(os.path.join(self.OUTPUT, "types-Area3D.png")) gd = gdchart.Bar() gd.setData((50, 100, 300)) gd.setLabels([50, 100, 300]) gd.draw(os.path.join(self.OUTPUT, "types-Bar.png")) gd = gdchart.Bar3D() gd.setData((50, 100, 300)) gd.setLabels([50, 100, 300]) gd.draw(os.path.join(self.OUTPUT, "types-Bar.png")) def test_floatingBarTypes(self): gd = gdchart.FloatingBar() gd.setData(((1, 2, 3), (5, 6, 7))) gd.setLabels([1, 2, 3]) gd.draw(os.path.join(self.OUTPUT, "types-floatingBar.png")) gd = gdchart.FloatingBar3D() gd.setData(((1, 2, 3), (5, 6, 7))) gd.setLabels([1, 2, 3]) gd.draw(os.path.join(self.OUTPUT, "types-floatingBar3D.png")) def test_HLCTypes(self): gd = gdchart.HLC() gd.setData(((5, 7, 10), (0, 2, 4), (3, 4, 6))) gd.setLabels([1, 2, 3]) gd.draw(os.path.join(self.OUTPUT, "types-HLC.png")) gd = gdchart.HLC3D() gd.setData(((5, 7, 10), (0, 2, 4), (3, 4, 6))) gd.setLabels([1, 2, 3]) gd.draw(os.path.join(self.OUTPUT, "types-HLC3D.png")) def test_HLCComboTypes(self): gd = gdchart.HLCAreaCombo() gd.setData(((5, 7, 10), (0, 2, 4), (3, 4, 6))) gd.setLabels([1, 2, 3]) gd.setComboData((5, 7, 10)) gd.draw(os.path.join(self.OUTPUT, "types-HLCAreaCombo.png")) gd = gdchart.HLCAreaCombo3D() gd.setData(((5, 7, 10), (0, 2, 4), (3, 4, 6))) gd.setLabels([1, 2, 3]) gd.setComboData((5, 7, 10)) gd.draw(os.path.join(self.OUTPUT, "types-HLCAreaCombo3D.png")) gd = gdchart.HLCBarCombo() gd.setData(((5, 7, 10), (0, 2, 4), (3, 4, 6))) gd.setLabels([1, 2, 3]) gd.setComboData((5, 7, 10)) gd.draw(os.path.join(self.OUTPUT, "types-HLCBarCombo.png")) gd = gdchart.HLCBarCombo3D() gd.setData(((5, 7, 10), (0, 2, 4), (3, 4, 6))) gd.setLabels([1, 2, 3]) gd.setComboData((5, 7, 10)) gd.draw(os.path.join(self.OUTPUT, "types-HLCBarCombo3D.png")) def test_SimpleComboTypes(self): gd = gdchart.LineBarCombo() gd.setData(range(5)) gd.setComboData(range(5, 0, -1)) gd.setLabels(range(5)) gd.draw(os.path.join(self.OUTPUT, "types-LineBarCombo.png")) gd = gdchart.LineAreaCombo() gd.setData(range(5)) gd.setComboData(range(5, 0, -1)) gd.setLabels(range(5)) gd.draw(os.path.join(self.OUTPUT, "types-LineAreaCombo.png")) gd = gdchart.LineLineCombo() gd.setData(range(5)) gd.setComboData(range(5, 0, -1)) gd.setLabels(range(5)) gd.draw(os.path.join(self.OUTPUT, "types-LineLineCombo.png")) gd = gdchart.LineBarCombo3D() gd.setData(range(5)) gd.setComboData(range(5, 0, -1)) gd.setLabels(range(5)) gd.draw(os.path.join(self.OUTPUT, "types-LineBarCombo3D.png")) gd = gdchart.LineAreaCombo3D() gd.setData(range(5)) gd.setComboData(range(5, 0, -1)) gd.setLabels(range(5)) gd.draw(os.path.join(self.OUTPUT, "types-LineAreaCombo3D.png")) gd = gdchart.LineLineCombo3D() gd.setData(range(5)) gd.setComboData(range(5, 0, -1)) gd.setLabels(range(5)) gd.draw(os.path.join(self.OUTPUT, "types-LineLineCombo3D.png")) def test_colors(self): gd = gdchart.Line() colorPath = os.path.join(self.OUTPUT, "colors") try: os.mkdir(colorPath) except OSError: pass gd.setOption("width", 100) gd.setOption("height", 100) gd.setData(range(10)) gd.setLabels(range(10)) x = gdchart.RGB() for r in range(0, 256, 64): x.r = r for g in range(0, 256, 64): x.g = g for b in range(0, 256, 64): x.b = b gd.setOption("bg_color", x) gd.draw(os.path.join(colorPath, "color-%s.png"%int(x))) def test_scolors(self): gd = gdchart.Bar() gd.setData(range(5), range(2, 7), range(4, 9)) colors = [ gdchart.rgbFactory("red"), gdchart.rgbFactory("blue"), gdchart.rgbFactory("green"), ] gd.set_color = colors gd.draw(os.path.join(self.OUTPUT, "set_color.png")) def test_xlabel_ctl(self): gd = gdchart.Bar() gd.setData(range(5)) gd.setLabels(range(5)) gd.xlabel_ctl = [1, 0, 1, 0, 1] gd.draw(os.path.join(self.OUTPUT, "xlabel_ctl.png")) def test_options(self): gd = gdchart.Line() gd.setData(range(100)) gd.setLabels(range(100)) gd.setOption("xtitle", "xtitle") gd.setOption("ytitle", "ytitle") gd.setOption("title", "Main Title") gd.draw(os.path.join(self.OUTPUT, "titles.png")) def test_maskoptions(self): gd = gdchart.Line() gd.setData(range(100)) gd.setLabels(range(100)) gd.setOption("border", ("TOP", "X")) gd.draw(os.path.join(self.OUTPUT, "borders.png")) def test_fonts(self): fontPath = os.path.join(self.OUTPUT, "fonts") try: os.mkdir(fontPath) except OSError: pass gd = gdchart.Line() gd.setData(range(100)) gd.setLabels(range(100)) gd.setOption("xtitle", "xtitle") gd.setOption("ytitle", "ytitle") gd.setOption("ytitle_font_size", "TINY") gd.setOption("xtitle_font_size", "TINY") gd.draw(os.path.join(fontPath, "TINY.png")) gd = gdchart.Line() gd.setData(range(100)) gd.setLabels(range(100)) gd.setOption("xtitle", "xtitle") gd.setOption("ytitle", "ytitle") gd.setOption("ytitle_font_size", "SMALL") gd.setOption("xtitle_font_size", "SMALL") gd.draw(os.path.join(fontPath, "SMALL.png")) gd = gdchart.Line() gd.setData(range(100)) gd.setLabels(range(100)) gd.setOption("xtitle", "xtitle") gd.setOption("ytitle", "ytitle") gd.setOption("ytitle_font_size", "MEDBOLD") gd.setOption("xtitle_font_size", "MEDBOLD") gd.draw(os.path.join(fontPath, "MEDBOLD.png")) gd = gdchart.Line() gd.setData(range(100)) gd.setLabels(range(100)) gd.setOption("xtitle", "xtitle") gd.setOption("ytitle", "ytitle") gd.setOption("ytitle_font_size", "LARGE") gd.setOption("xtitle_font_size", "LARGE") gd.draw(os.path.join(fontPath, "LARGE.png")) gd = gdchart.Line() gd.setData(range(100)) gd.setLabels(range(100)) gd.setOption("xtitle", "xtitle") gd.setOption("ytitle", "ytitle") gd.setOption("ytitle_font_size", "GIANT") gd.setOption("xtitle_font_size", "GIANT") gd.draw(os.path.join(fontPath, "GIANT.png")) def test_scatter(self): gd = gdchart.Line() gd.setData(range(100)) gd.setLabels(range(100)) gd.grid = "NONE" scats = [ gdchart.Scatter(10, 30, type="CIRCLE", width=100, color=gdchart.rgbFactory("red")), gdchart.Scatter(30, 50, width=100, color=gdchart.rgbFactory("blue")), ] gd.setScatter(scats) gd.draw(os.path.join(self.OUTPUT, "scatter.png")) def test_annotate(self): gd = gdchart.Line() gd.setData(range(100)) gd.setLabels(range(100)) gd.annotate(5, "foo") gd.draw(os.path.join(self.OUTPUT, "annotate.png")) def test_missingvalues(self): gd = gdchart.Bar() gd.setData([1, 2, None, 3, None, 5]) gd.draw(os.path.join(self.OUTPUT, "missingvalues.png")) def test_tofile(self): gd = gdchart.Line() gd.setData(range(100), range(100, 0, -1)) gd.setLabels(range(100)) f = file(os.path.join(self.OUTPUT, "tofile-graph.png"), "w") gd.draw(f) pygdchart2alpha2/test/test_gdchartc.py010064400017500001750000000114600777443323200170620ustar00aldoaldoimport unittest, os, os.path, shutil import _gdchartc class uPyGDChart(unittest.TestCase): SCRATCH = "scratch" def setUp(self): try: os.mkdir(self.SCRATCH) except OSError: pass def tearDown(self): shutil.rmtree(self.SCRATCH) def test_constants(self): # Check a random constant... self.failUnless(hasattr(_gdchartc, "GDC_LINE")) # Check the single float constant self.failUnless(hasattr(_gdchartc, "GDC_INTERP_VALUE")) def test_options(self): self.failUnless(_gdchartc.getOptions(_gdchartc.GRAPH)) self.failUnless(_gdchartc.getOptions(_gdchartc.PIE)) def test_out_graph_nonfile(self): try: _gdchartc.out_graph(1, 2, 1, 1, 1, ["one", "two"], 1, [1, 2], [1, 2]) except TypeError: pass else: self.fail() def test_out_graph_nonlist(self): f = file(os.path.join(self.SCRATCH, "outgraph"), "w") self.failUnlessRaises(TypeError, _gdchartc.out_graph, 1, 2, f, 1, 1, 2, 1, [1, 2], [1, 2]) self.failUnlessRaises(TypeError, _gdchartc.out_graph, 1, 2, f, 1, 1, [1, 2], 1, 2, [1, 2]) self.failUnlessRaises(TypeError, _gdchartc.out_graph, 1, 2, f, 1, 1, [1, 2], 1, [1, 2], 2) _gdchartc.out_graph(100, 100, f, 1, 1, [1, 2], 1, [1, 2], [1, 2]) def test_out_graph_notfloats(self): f = file(os.path.join(self.SCRATCH, "outgraph"), "w") self.failUnlessRaises(TypeError, _gdchartc.out_graph, 1, 2, f, 1, 1, [1, 2], 1, ["one", "two"], [1, 2]) def test_out_graph_nulls(self): f = file(os.path.join(self.SCRATCH, "outgraph"), "w") _gdchartc.out_graph(100, 100, f, 1, 1, None, 1, [1, 2], [1, 2]) _gdchartc.out_graph(100, 100, f, 1, 1, None, 1, [1, 2], None) _gdchartc.out_graph(100, 100, f, 1, 1, None, 1, [1, 2], [1, 2, None, 3, None]) self.failUnlessRaises(TypeError, _gdchartc.out_graph, 1, 2, f, 1, 1, None, 1, None, None) def test_out_graph_succeed(self): f = file(os.path.join(self.SCRATCH, "outgraph"), "w") _gdchartc.out_graph(100, 100, f, 1, 1, ["one", "two"], 1, [1, 2], [1, 2]) class uPyGDChartOptions(unittest.TestCase): def _testOption(self, setFunction, option, testvalue, chartType=_gdchartc.GRAPH): opts = _gdchartc.getOptions(chartType) val = opts[option][2] setFunction(chartType, opts[option][0], testvalue) opts = _gdchartc.getOptions(chartType) self.failUnlessEqual(opts[option][2], testvalue) # Now we restore the value... setFunction(chartType, opts[option][0], val) def test_setoptions(self): self._testOption(_gdchartc.setOption, "grid", 99) # INT self._testOption(_gdchartc.setOption, "xlabel_spacing", 99) # SHORT self._testOption(_gdchartc.setOption, "perspective", 99, _gdchartc.PIE) # USHORT self._testOption(_gdchartc.setOption, "threeD_angle", 20) # UCHAR self._testOption(_gdchartc.setOption, "bg_transparent", 20) # BOOL self._testOption(_gdchartc.setOption, "annotation_font_size", 20) # FONT self._testOption(_gdchartc.setOption, "bar_width", 20) # PERCENT self._testOption(_gdchartc.setOption, "other_threshold", 20, _gdchartc.PIE) # CHAR self._testOption(_gdchartc.setOption, "bg_color", 20) # LONG self._testOption(_gdchartc.setOption, "threeD_depth", 20) # FLOAT self._testOption(_gdchartc.setOption, "bg_image", "foinklebar") # STRING self._testOption(_gdchartc.setOption, "explode", range(500), _gdchartc.PIE) # INT_A bools = [1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0] self._testOption(_gdchartc.setOption, "xlabel_ctl", bools) # BOOL_A self._testOption(_gdchartc.setOption, "ext_color", range(500)) # COLORL_A class Scat: point = 0 val = 0 width = 0 color = 0 _type = 0 class uScatter(unittest.TestCase): def test_scatter(self): self.failUnlessRaises(TypeError, _gdchartc.setScatter, 1) s = Scat() s.point = "foo" self.failUnlessRaises(TypeError, _gdchartc.setScatter, [s, Scat(), Scat(), Scat()]) _gdchartc.setScatter([Scat(), Scat(), Scat(), Scat()]) _gdchartc.setScatter(None) class Anno: point = 0 color = 0 note = "foo" class uAnnotate(unittest.TestCase): def test_anno(self): _gdchartc.annotate(None) a = Anno() _gdchartc.annotate(a) _gdchartc.annotate(None) _gdchartc.annotate(None) try: _gdchartc.annotate(1) except TypeError: pass _gdchartc.annotate(None) pygdchart2alpha2/lint010075500017500001750000000004250777443323200136060ustar00aldoaldo#!/bin/sh # This is only of use to developers of PyGDChart. We used the version of lint # distributed with OpenBSD - you may have to modify it to work with your local # version. lint -vubh -I../gdchart0.11.4dev -I/usr/local/include/python2.2 -DHAVE_LIBFREETYPE _gdchartc.c pygdchart2alpha2/gdchart.py010064400017500001750000000675460777443323200147210ustar00aldoaldo# PyGDChart # # Copyright (c) 2003, Nullcube Pty Ltd # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # * Neither the name of Nullcube nor the names of its contributors may be used to # endorse or promote products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ PyGDChart is an interface to the gdchart graphing library. """ import types import _gdchartc class GDChartError(Exception): pass class _Bucket: """ An internal PyGDChart general dataholder class. """ def __init__(self, **kwargs): self.__dict__ = kwargs def _uniformLength(*lst): """ Takes a list of lists, and tests wether all lists have the same length. Returns a 0 if lengths differ, 1 if not. This is an internal PyGDChart utility function. """ baselen = len(lst[0]) for l in lst: if len(l) != baselen: return -1 return baselen def _flattenList(*lst): """ Takes a set of lists, and flattens them by appending them all together. This is an internal PyGDChart utility function. """ flat = [] for i in lst: flat.extend(i) return flat class RGB: """ A simple class for representing RGB colors. """ def __init__(self, r=0, g=0, b=0): self.r, self.g, self.b = r, g, b self._sanity() def _sanity(self): checks = [0 <= i <= 256 for i in (self.r, self.g, self.b)] if 0 in checks: raise ValueError("All RGB values should be 0 <= val <= 100") def __int__(self): self._sanity() intval = self.r*(256**2) intval += self.g*(256) intval += self.b return intval def __hex__(self): return hex(int(self)) def __repr__(self): return hex(self) def rgbFactory(color): """ Manufacture an RGB object by colour name. Included colours are: black, white, blue, green, yellow, red, orange """ # This should be re-written using a dictionary. if color == "black": return RGB(0,0,0) elif color == "white": return RGB(255,255,255) elif color == "blue": return RGB(50,50,204) elif color == "green": return RGB(37,180,21) elif color == "yellow": return RGB(255,255,21) elif color == "red": return RGB(255,0,0) elif color == "orange": return RGB(255,127,0) raise GDChartError, "No such colour: %s."%color class ChartBase(object): """ Base class of both Pie and Graph chart classes. """ _ImageTypes = { "GIF": _gdchartc.GDC_GIF, "JPEG": _gdchartc.GDC_JPEG, "PNG": _gdchartc.GDC_PNG, "WBMP": _gdchartc.GDC_WBMP } _FontSizes = { "TINY": _gdchartc.GDC_TINY, "SMALL": _gdchartc.GDC_SMALL, "MEDBOLD": _gdchartc.GDC_MEDBOLD, "LARGE": _gdchartc.GDC_LARGE, "GIANT": _gdchartc.GDC_GIANT } _lookupOptions = {} _maskOptions = {} def __init__(self): self.__dict__["_options"] = {} self.__dict__["_width"] = 500 self.__dict__["_height"] = 500 self.__dict__["_data"] = None self.__dict__["_labels"] = None self.__dict__["_datalen"] = None self.__dict__["_scatterPoints"] = None def __getattr__(self, attr): try: return self.getOption(attr) except ValueError: raise AttributeError def __setattr__(self, attr, val): try: return self.setOption(attr, val) except ValueError: if self.__dict__.has_key(attr): self.__dict__[attr] = val else: raise AttributeError def _actualiseOptions(self): for i in self._defaultOptions.values(): _gdchartc.setOption(self._myType, i[0], i[2]) for k, v in self._options.iteritems(): index = self._defaultOptions[k][0] _gdchartc.setOption(self._myType, index, v) _gdchartc.setScatter(self._scatterPoints) def setOption(self, option, myval): """ Set an option. Using this function explicitly is discouraged - it is equivalent to using explicit attribute assignment, like so: myclass.foo = val """ if self._defaultOptions.has_key(option): if self._lookupOptions.has_key(option): # We have to look the value up in our dictionary if self._lookupOptions[option].has_key(myval): val = self._lookupOptions[option][myval] else: values = ", ".join([k for k in self._lookupOptions[option].keys()]) raise GDChartError("%s must be one of the following: %s"%(option, values)) elif self._maskOptions.has_key(option): val = 0 for i in myval: bits = self._maskOptions[option].get(i, None) if bits is not None: val |= bits else: values = ", ".join([k for k in self._maskOptions[option].keys()]) raise GDChartError("%s must be a list chosen from the following strings: %s"% (option, values)) else: # Now we do some standard format checks type = self._defaultOptions[option][1] if type == _gdchartc.OPT_FLOAT: try: val = float(myval) except ValueError: raise GDChartError("%s must be representable as a float."%(option)) elif type in ( _gdchartc.OPT_FONTSIZE, _gdchartc.OPT_INT, _gdchartc.OPT_LONG, _gdchartc.OPT_SHORT, _gdchartc.OPT_USHORT, _gdchartc.OPT_UCHAR, _gdchartc.OPT_CHAR): try: val = int(myval) except ValueError: raise GDChartError("%s must be representable as an int."%(option)) elif type == _gdchartc.OPT_COLOR: try: rgb = rgbFactory(myval) except GDChartError: try: val = int(myval) except ValueError: raise GDChartError("%s must be representable as an int."%(option)) else: val = int(rgb) elif type == _gdchartc.OPT_PERCENT: try: val = int(myval) except ValueError: raise GDChartError("%s must be representable as an int."%(option)) if not (0 <= val <= 100): raise GDChartError, "Percentage must be > 0, and < 100" elif type == _gdchartc.OPT_COLOR_A: try: colours = [rgbFactory(i) for i in myval] except GDChartError: colours = myval try: val = [int(i) for i in colours] except ValueError: raise GDChartError("%s must be representable as a list of ints."%(option)) elif type in [_gdchartc.OPT_COLOR_A, _gdchartc.OPT_INT_A, _gdchartc.OPT_BOOL_A]: try: val = [int(i) for i in myval] except ValueError: raise GDChartError("%s must be representable as a list of ints."%(option)) else: val = myval self.__dict__["_options"][option] = val elif option == "width": self.__dict__["_width"] = int(myval) elif option == "height": self.__dict__["_height"] = int(myval) else: raise ValueError, "No such option: %s"%option def getOption(self, option): """ Retrieve an option. Using this function is equivalent to just referring to an option as a chart-object attribute. """ if self._options.has_key(option): # Now convert it to a value the user will recognise... val = self._options[option] if self._lookupOptions.has_key(option): for k, v in self._lookupOptions[option].items(): if v == val: return k else: raise GDChartError, "Lookup value not known - this should never happen. Please contact software authors." elif self._maskOptions.has_key(option): lst = [] for k, v in self._maskOptions[option].items(): if (val&v): lst.append(k) return lst else: return self._options[option] elif self._defaultOptions.has_key(option): return self._defaultOptions[option][2] elif option == "width": return self._width elif option == "height": return self._height else: raise ValueError, "No such option: %s"%option def getAllOptions(self): """ Retrieve a dictionary of all options. """ x = {} for i in self._defaultOptions: x[i] = self.getOption(i) x["width"] = self._width x["height"] = self._height return x def restoreDefaultOptions(self): """ Restore options to their default values. """ self._options = {} self._scatterPoints = None def setLabels(self, labels): """ Set chart labels. The argument is a single list of strings. """ if self._datalen: if len(labels) != self._datalen: raise GDChartError, "List of labels must have same length as data." self._labels = labels class PieBase(ChartBase): """ Base class of all Pie chart classes. """ _myType = _gdchartc.PIE _defaultOptions = _gdchartc.getOptions(_gdchartc.PIE) _ChartTypes = { "3D": _gdchartc.GDC_3DPIE, "2D": _gdchartc.GDC_2DPIE, } _PercentPlacement = { "NONE": _gdchartc.GDCPIE_PCT_NONE, "ABOVE": _gdchartc.GDCPIE_PCT_ABOVE, "BELOW": _gdchartc.GDCPIE_PCT_BELOW, "RIGHT": _gdchartc.GDCPIE_PCT_RIGHT, "LEFT": _gdchartc.GDCPIE_PCT_LEFT, } _lookupOptions = { "title_size": ChartBase._FontSizes, "label_size": ChartBase._FontSizes, "image_type": ChartBase._ImageTypes, "percent_labels": _PercentPlacement, } def __init__(self, *args, **kwargs): ChartBase.__init__(self, *args, **kwargs) def _conformanceCheck(self): if self._labels: if self._datalen: if self._datalen != len(self._labels): raise GDChartError, "Datasets must be of same length as list of labels." def draw(self, filedef): """ Draw a graph to filename. """ if not self._datalen: raise GDChartError, "No data to graph" if type(filedef) in types.StringTypes: filedef = open(filedef, "w") self._actualiseOptions() try: _gdchartc.out_pie( self._width, self._height, filedef, self._type, self._datalen, self._labels, self._data, ) except _gdchartc.PGError, val: raise GDChartError, val def setData(self, *data): """ Set pie data to be graphed. mypie.setData(1, 2, 3, 4) """ self._datalen = len(data) self._data = data self._conformanceCheck() class Pie(PieBase): """ A 2D pie chart. """ _type = _gdchartc.GDC_2DPIE class Pie3D(PieBase): """ A 3D pie chart. """ _type = _gdchartc.GDC_3DPIE class Scatter(object): """ This class represents a scatter point. You would normally construct an array of these to pass to the setScatter method of graph classes. The constructor takes the following arguments: type - Scatter graph types are: TRIANGLE_DOWN TRIANGLE_UP CIRCLE point - X-axis co-ordinate val - Y-axis co-ordinate width - 0-100% color - An RGB object, or an integer representing the point colour. """ _ScatterTypes = { "TRIANGLE_DOWN": _gdchartc.GDC_SCATTER_TRIANGLE_DOWN, "TRIANGLE_UP": _gdchartc.GDC_SCATTER_TRIANGLE_UP, "CIRCLE": _gdchartc.GDC_SCATTER_CIRCLE, } def __init__(self, point, val, type="TRIANGLE_DOWN", width=100, color="white"): self.type = type self.point = point self.val = val self.width = width try: color = rgbFactory(color) except GDChartError: pass try: self.color = int(color) except ValueError: raise GDChartError, "Colour must be representable as an int." def _setType(self, val): if not self._ScatterTypes.has_key(val): values = ", ".join([k for k in self._ScatterTypes.keys()]) raise ValueError("Scatter type must be one of %s"%values) else: self._type = self._ScatterTypes[val] def _getType(self): for k, v in self._ScatterTypes.items(): if (v == self._type): return k else: raise GDChartError("Unknown type set. This should never happen.") def _setWidth(self, val): i = int(val) if (i < 0) or (i > 100): raise ValueError("Width must be 0 > width > 100.") self._width = val def _getWidth(self): return self._width type = property(_getType, _setType) width = property(_getWidth, _setWidth) class GraphBase(ChartBase): """ Base class for all Graph charts. """ _myType = _gdchartc.GRAPH _defaultOptions = _gdchartc.getOptions(_gdchartc.GRAPH) _StackTypes = { "DEPTH": _gdchartc.GDC_STACK_DEPTH, "SUM": _gdchartc.GDC_STACK_SUM, "BESIDE": _gdchartc.GDC_STACK_BESIDE, "LAYER": _gdchartc.GDC_STACK_LAYER, } _TickTypes = { "LABELS": _gdchartc.GDC_TICK_LABELS, "POINTS": _gdchartc.GDC_TICK_POINTS, "NONE": _gdchartc.GDC_TICK_NONE, } _BorderTypes = { "NONE": _gdchartc.GDC_BORDER_NONE, "ALL": _gdchartc.GDC_BORDER_ALL, "X": _gdchartc.GDC_BORDER_X, "Y": _gdchartc.GDC_BORDER_Y, "Y2": _gdchartc.GDC_BORDER_Y2, "TOP": _gdchartc.GDC_BORDER_TOP, } _HilocloseTypes = { "DIAMOND": _gdchartc.GDC_HLC_DIAMOND, "CLOSE_CONNECTED": _gdchartc.GDC_HLC_CLOSE_CONNECTED, "CONNECTING": _gdchartc.GDC_HLC_CONNECTING, "I_CAP": _gdchartc.GDC_HLC_I_CAP, } _lookupOptions = { "image_type": ChartBase._ImageTypes, "stack_type": _StackTypes, "grid": _TickTypes, "ticks": _TickTypes, "title_font_size": ChartBase._FontSizes, "xtitle_font_size": ChartBase._FontSizes, "ytitle_font_size": ChartBase._FontSizes, "xaxisfont_size": ChartBase._FontSizes, "yaxisfont_size": ChartBase._FontSizes, "annotation_font_size": ChartBase._FontSizes, } _maskOptions = { "hlc_style": _HilocloseTypes, "border": _BorderTypes, } def __init__(self, *args, **kwargs): ChartBase.__init__(self, *args, **kwargs) self.__dict__["_numsets"] = None self.__dict__["_combodata"] = None self.__dict__["_combodatalen"] = None self.__dict__["_combonumsets"] = None self.__dict__["_annotation"] = None def _conformanceCheck(self): if self._labels: if self._datalen: if self._datalen != len(self._labels): raise GDChartError, "Datasets must be of same length as list of labels." if self._combodatalen: if self._combodatalen != len(self._labels): raise GDChartError, "Combo datasets must be of same length as list of labels." if self._datalen: if self._combodatalen: if self._datalen != self._combodatalen: raise GDChartError, "Main and combo datasets must be of same length." def setScatter(self, scatterpoints): """ Set scatter points. This should be a list of Scatter objects. """ slen = None if self._datalen: slen = self._datalen elif self._labels: slen = len(self._labels) if slen: for i in scatterpoints: if i.point > slen or i.point < 0: raise ValueError("Scatter point value must be > 0 and < numpoints.") self._scatterPoints = scatterpoints def clearAnnotation(self): self._annotation = None def annotate(self, point=0, note = "", color="white"): """ Set an annotation. At the moment the gdchart library is limited to one annotation per graph. """ slen = None if self._datalen: slen = self._datalen elif self._labels: slen = len(self._labels) if slen: if (point>slen) or (point<0): raise ValueError("Annotation point value must be > 0 and < numpoints.") if len(note) > _gdchartc.MAX_NOTE_LEN: raise ValueError("Annotation note length must be < %i."%(_gdchartc.MAX_NOTE_LEN)) try: intcolor = rgbFactory(color) except GDChartError: try: intcolor = int(color) except ValueError: raise GDChartError("color must be representable as an int.") intcolor = int(intcolor) b = _Bucket(point=point, note=note, color=intcolor) self._annotation = b def draw(self, filedef): """ Draw a graph to file. """ if not self._datalen: raise GDChartError, "No data to graph" if type(filedef) in types.StringTypes: filedef = open(filedef, "w") self._actualiseOptions() _gdchartc.annotate(self._annotation) try: _gdchartc.out_graph( self._width, self._height, filedef, self._type, self._datalen, self._labels, self._numsets, self._data, self._combodata ) except _gdchartc.PGError, val: raise GDChartError, val # # Simple data graphs # class SimpleBase(GraphBase): """ Base class for "Simple" graph types. """ def _getSimpleData(self, *data): """ Returns the data length, the number of sets and the flattened data """ length = _uniformLength(*data) if length < 0: raise GDChartError, "All data sets have to be of the same length." return length, _flattenList(*data) def setData(self, *data): """ Set the data to graph. This method takes a set of lists of data, that should all be of the same length. I.e. x.setData([1, 2, 3], [4, 5, 6]) """ self._numsets = len(data) self._datalen, self._data = self._getSimpleData(*data) self._conformanceCheck() class Line(SimpleBase): """ A simple line graph. """ _type = _gdchartc.GDC_LINE class Area(SimpleBase): """ A graph with the area under the data filled. """ _type = _gdchartc.GDC_AREA class Bar(SimpleBase): """ A classical bar graph. """ _type = _gdchartc.GDC_BAR class Area3D(SimpleBase): """ A 3D graph with the area under the line filled. """ _type = _gdchartc.GDC_3DAREA class Line3D(SimpleBase): """ A 3D line graph. """ _type = _gdchartc.GDC_3DLINE class Bar3D(SimpleBase): """ A 3D bar graph. """ _type = _gdchartc.GDC_3DBAR class MultisetGraphBase(GraphBase): """ The base class of all multiset graphs. """ def _getMultisetData(self, setlen, *data): """ Returns the data length, the number of sets and the flattened data """ baseLength = None allData = [] for i in data: if len(i) != setlen: raise GDChartError("Sets of %s data lists required."%setlen) length = _uniformLength(*i) if length < 0: raise GDChartError, "All data sets must be of the same length." if baseLength: if length != baseLength: raise GDChartError, "All data sets must be of the same length." else: baseLength = length allData += _flattenList(*i) return baseLength, allData # # Floating Bars # class FloatingBarBase(MultisetGraphBase): """ Base class of all floating bar graphs. """ def setData(self, *data): """ This function takes a set of data tuples, where the first element of the tuple are all of the lower values, and the second element the upper values. Eg. x.setData(((1, 2, 3), (4, 5, 6)), ((3, 6, 9), (6, 9, 12))) """ self._numsets = len(data) self._datalen, self._data = self._getMultisetData(2, *data) self._conformanceCheck() class FloatingBar(FloatingBarBase): """ A floating bar graph. """ _type = _gdchartc.GDC_FLOATINGBAR class FloatingBar3D(FloatingBarBase): """ A 3D floating bar graph. """ _type = _gdchartc.GDC_3DFLOATINGBAR # # HLC # class HLCBase(MultisetGraphBase): """ Base class for High-Low-Close graphs. """ def setData(self, *data): """ Takes a list of data triplets, where the first element is high, the second, low, and the third close. Eg. x.setData(((6, 9, 12), (1, 2, 3), (5, 6, 7))) """ self._numsets = len(data) self._datalen, self._data = self._getMultisetData(3, *data) self._conformanceCheck() class HLC(HLCBase): _type = _gdchartc.GDC_HILOCLOSE class HLC3D(HLCBase): _type = _gdchartc.GDC_3DHILOCLOSE # # HLC Combo Graphs # class HLCComboBase(HLCBase, SimpleBase): """ Base class for HLC combo data. """ def setComboData(self, *data): """ Set the combo data for this graph. This function takes a simple list of data sets. """ self._combonumsets = len(data) self._combodatalen, self._combodata = self._getSimpleData(*data) self._conformanceCheck() def draw(self, filename): """ Write the graph to file. """ if not self._combodata: raise GDChartError, "Combo data must be specified for a combo graph." # We should be using super for this... SimpleBase.draw(self, filename) class HLCAreaCombo(HLCComboBase): """ A High-Low-Close/Area combo graph. """ _type = _gdchartc.GDC_COMBO_HLC_AREA class HLCAreaCombo3D(HLCComboBase): """ A 3D High-Low-Close/Area combo graph. """ _type = _gdchartc.GDC_3DCOMBO_HLC_AREA class HLCBarCombo(HLCComboBase): """ A High-Low-Close/Bar combo graph. """ _type = _gdchartc.GDC_COMBO_HLC_BAR class HLCBarCombo3D(HLCComboBase): """ A 3D High-Low-Close/Bar combo graph. """ _type = _gdchartc.GDC_3DCOMBO_HLC_BAR # # Simple Combo Graphs # class SimpleComboBase(SimpleBase): """ Base class for "simple" combo graph types. """ def setData(self, *data): """ Set the data to graph. This method takes a set of lists of data, that should all be of the same length. I.e. x.setData([1, 2, 3], [4, 5, 6]) """ self._numsets = len(data) self._datalen, self._data = self._getSimpleData(*data) self._conformanceCheck() def setComboData(self, *data): """ Set the combo data to graph. This method takes a set of lists of data, that should all be of the same length. I.e. x.setComboData([1, 2, 3], [4, 5, 6]) """ self._combonumsets = len(data) self._combodatalen, self._combodata = self._getSimpleData(*data) self._conformanceCheck() def draw(self, filename): if not self._combodata: raise GDChartError, "Combo data must be specified for a combo graph." # We should be using super for this... SimpleBase.draw(self, filename) class LineBarCombo(SimpleComboBase): """ A Line/Bar combo graph. """ _type = _gdchartc.GDC_COMBO_LINE_BAR class LineAreaCombo(SimpleComboBase): """ A Line/Area combo graph. """ _type = _gdchartc.GDC_COMBO_LINE_AREA class LineLineCombo(SimpleComboBase): """ A Line/Line combo graph. """ _type = _gdchartc.GDC_COMBO_LINE_LINE class LineBarCombo3D(SimpleComboBase): """ A 3D Line/Bar combo graph. """ _type = _gdchartc.GDC_3DCOMBO_LINE_BAR class LineAreaCombo3D(SimpleComboBase): """ A 3D Line/Area combo graph. """ _type = _gdchartc.GDC_3DCOMBO_LINE_AREA class LineLineCombo3D(SimpleComboBase): """ A 3D Line/Line combo graph. """ _type = _gdchartc.GDC_3DCOMBO_LINE_LINE pygdchart2alpha2/_gdchartc.c010064400017500001750000001303440777443323200150000ustar00aldoaldo/* PyGDChart Copyright (c) 2003, Nullcube Pty Ltd All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Nullcube Pty Ltd nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "Python.h" #include "gdchart.h" #include "gdcpie.h" #include "gdc.h" #ifndef HAVE_JPEG #define GDC_JPEG 1 #endif static PyObject *PGError; typedef enum { GRAPH, PIE } charttype; typedef enum { OPT_BOOL, /* CHAR */ OPT_BOOL_A, /* CHAR */ OPT_COLOR, OPT_COLOR_A, OPT_CHAR, OPT_FLOAT, OPT_DOUBLE, OPT_FONTSIZE, /* INT */ OPT_INT, OPT_INT_A, OPT_LONG, OPT_PERCENT, /* Unsigned char */ OPT_SHORT, OPT_STRING, OPT_USHORT, OPT_UCHAR } options; typedef struct Option Option; struct Option { char *keyword; int type; void *var; int size; }; Option GraphOptions[] = { { "annotation_font_size", OPT_FONTSIZE, &GDC_annotation_font_size, 0}, { "bar_width", OPT_PERCENT, &GDC_bar_width, 0}, { "bg_color", OPT_COLOR, &GDC_BGColor, 0}, { "bg_image", OPT_STRING, &GDC_BGImage, 0}, { "bg_transparent", OPT_BOOL, &GDC_transparent_bg, 0}, { "border", OPT_INT, &GDC_border, 0}, { "ext_color", OPT_COLOR_A, &GDC_ExtColor, 0}, /* numsets * numpoints */ { "ext_vol_color", OPT_COLOR_A, &GDC_ExtVolColor, 0}, /* numpoints */ { "generate_img", OPT_BOOL, &GDC_generate_img, 0}, { "grid", OPT_INT, &GDC_grid, 0}, { "grid_color", OPT_COLOR, &GDC_GridColor, 0}, { "hard_graphheight", OPT_INT, &GDC_hard_grapheight, 0}, { "hard_graphwidth", OPT_INT, &GDC_hard_graphwidth, 0}, { "hard_size", OPT_BOOL, &GDC_hard_size, 0}, { "hard_xorig", OPT_INT, &GDC_hard_xorig, 0}, { "hard_yorig", OPT_INT, &GDC_hard_yorig, 0}, { "hlc_cap_width", OPT_PERCENT, &GDC_HLC_cap_width, 0}, { "hlc_style", OPT_INT, &GDC_HLC_style, 0}, { "hold_img", OPT_INT, &GDC_hold_img, 0}, { "interpolations", OPT_BOOL, &GDC_interpolations, 0}, { "image_type", OPT_INT, &GDC_image_type, 0}, { "jpeg_quality", OPT_INT, &GDC_jpeg_quality, 0}, { "line_color", OPT_COLOR, &GDC_LineColor, 0}, { "plot_color", OPT_COLOR, &GDC_PlotColor, 0}, { "requested_yinterval", OPT_FLOAT, &GDC_requested_yinterval, 0}, { "requested_ymax", OPT_FLOAT, &GDC_requested_ymax, 0}, { "requested_ymin", OPT_FLOAT, &GDC_requested_ymin, 0}, { "set_color", OPT_COLOR_A, &GDC_SetColor, 0}, /* numsets */ { "stack_type", OPT_INT, &GDC_stack_type, 0}, /* Python names cannot start with digits - so we rename these options slightly:*/ { "threeD_angle", OPT_UCHAR, &GDC_3d_angle, 0}, { "threeD_depth", OPT_FLOAT, &GDC_3d_depth, 0}, { "thumblabel", OPT_STRING, &GDC_thumblabel, 0}, { "thumbnail", OPT_BOOL, &GDC_thumbnail, 0}, { "thumbval", OPT_FLOAT, &GDC_thumbval, 0}, { "ticks", OPT_INT, &GDC_ticks, 0}, { "title", OPT_STRING, &GDC_title, 0}, { "title_color", OPT_COLOR, &GDC_TitleColor, 0}, { "title_font_size", OPT_FONTSIZE, &GDC_title_size, 0}, { "vol_color", OPT_COLOR, &GDC_VolColor, 0}, { "xaxis", OPT_BOOL, &GDC_xaxis, 0}, { "xaxis_angle", OPT_DOUBLE, &GDC_xaxis_angle, 0}, { "xaxis_font_size", OPT_FONTSIZE, &GDC_xaxisfont_size, 0}, { "xlabel_color", OPT_COLOR, &GDC_XLabelColor, 0}, { "xlabel_spacing", OPT_SHORT, &GDC_xlabel_spacing, 0}, { "xlabel_ctl", OPT_BOOL_A, &GDC_xlabel_ctl, 0}, /* numpoints */ { "xtitle", OPT_STRING, &GDC_xtitle, 0}, { "xtitle_color", OPT_COLOR, &GDC_XTitleColor, 0}, { "xtitle_font_size", OPT_FONTSIZE, &GDC_xtitle_size, 0}, { "yaxis", OPT_BOOL, &GDC_yaxis, 0}, { "yaxis2", OPT_BOOL, &GDC_yaxis2, 0}, { "yaxis_font_size", OPT_FONTSIZE, &GDC_yaxisfont_size, 0}, { "ylabel_color", OPT_COLOR, &GDC_YLabelColor, 0}, { "ylabel_density", OPT_PERCENT, &GDC_ylabel_density, 0}, { "ylabel_fmt", OPT_STRING, &GDC_ylabel_fmt, 0}, { "ylabel2_color", OPT_COLOR, &GDC_YLabel2Color, 0}, { "ylabel2_fmt", OPT_STRING, &GDC_ylabel2_fmt, 0}, { "ytitle", OPT_STRING, &GDC_ytitle, 0}, { "ytitle_color", OPT_COLOR, &GDC_YTitleColor, 0}, { "ytitle_font_size", OPT_FONTSIZE, &GDC_ytitle_size, 0}, { "ytitle2", OPT_STRING, &GDC_ytitle2, 0}, { "ytitle2_color", OPT_COLOR, &GDC_YTitle2Color, 0}, { "yval_style", OPT_BOOL, &GDC_yval_style, 0}, { "zeroshelf", OPT_BOOL, &GDC_0Shelf, 0}, #ifdef HAVE_LIBFREETYPE { "annotation_font", OPT_STRING, &GDC_annotation_font, 0}, { "annotation_ptsize", OPT_DOUBLE, &GDC_annotation_ptsize, 0}, { "title_font", OPT_STRING, &GDC_title_font, 0}, { "title_ptsize", OPT_DOUBLE, &GDC_title_ptsize, 0}, { "xaxis_font", OPT_STRING, &GDC_xaxis_font, 0}, { "xaxis_ptsize", OPT_DOUBLE, &GDC_xaxis_ptsize, 0}, { "xtitle_font", OPT_STRING, &GDC_xtitle_font, 0}, { "xtitle_ptsize", OPT_DOUBLE, &GDC_xtitle_ptsize, 0}, { "yaxis_font", OPT_STRING, &GDC_yaxis_font, 0}, { "yaxis_ptsize", OPT_DOUBLE, &GDC_yaxis_ptsize, 0}, { "ytitle_font", OPT_STRING, &GDC_ytitle_font, 0}, { "ytitle_ptsize", OPT_DOUBLE, &GDC_ytitle_ptsize, 0}, #endif { NULL } }; Option PieOptions[] = { { "bg_color", OPT_COLOR, &GDCPIE_BGColor, 0}, { "bg_image", OPT_STRING, &GDC_BGImage, 0}, { "edge_color", OPT_COLOR, &GDCPIE_EdgeColor, 0}, { "explode", OPT_INT_A, &GDCPIE_explode, 0}, /* numpoints */ { "generate_img", OPT_BOOL, &GDC_generate_img, 0}, { "image_type", OPT_INT, &GDC_image_type, 0}, { "jpeg_quality", OPT_INT, &GDC_jpeg_quality, 0}, { "label_dist", OPT_INT, &GDCPIE_label_dist, 0}, { "label_font_size", OPT_FONTSIZE, &GDCPIE_label_size, 0}, { "label_line", OPT_BOOL, &GDCPIE_label_line, 0}, { "line_color", OPT_COLOR, &GDCPIE_LineColor, 0}, { "missing", OPT_BOOL_A, &GDCPIE_missing, 0}, /* numpoints */ { "other_threshold", OPT_CHAR, &GDCPIE_other_threshold, 0}, { "percent_format", OPT_STRING, &GDCPIE_percent_fmt, 0}, { "percent_labels", OPT_INT, &GDCPIE_percent_labels, 0}, { "perspective", OPT_USHORT, &GDCPIE_perspective, 0}, { "color", OPT_COLOR_A, &GDCPIE_Color, 0}, /* numpoints */ { "plot_color", OPT_COLOR, &GDCPIE_PlotColor, 0}, { "threeD_angle", OPT_USHORT, &GDCPIE_3d_angle, 0}, { "threeD_depth", OPT_USHORT, &GDCPIE_3d_depth, 0}, { "title", OPT_STRING, &GDCPIE_title, 0}, { "title_font_size", OPT_FONTSIZE, &GDCPIE_title_size, 0}, #ifdef HAVE_LIBFREETYPE { "label_font", OPT_STRING, &GDCPIE_label_font, 0}, { "label_ptsize", OPT_FLOAT, &GDCPIE_label_ptsize, 0}, { "title_font", OPT_STRING, &GDCPIE_title_font, 0}, { "title_ptsize", OPT_FLOAT, &GDCPIE_title_ptsize, 0}, #endif { NULL } }; #define MEMPOOLSIZE 256 void *mempool[MEMPOOLSIZE]; /* The global memory pool array. */ int mempool_final = -1; /* The greatest filled array index. */ /* Add a float constant to a module. Same as PyModule_AddIntConstant. */ int AddFloatConstant(PyObject *m, char *name, double value){ return PyModule_AddObject(m, name, PyFloat_FromDouble(value)); } /* Frees all memory in mempool. */ void clearMempool(void){ int i; for (i = 0; i < mempool_final; i++){ if (mempool[i]){ free(mempool[i]); mempool[i] = NULL; } } } /* * Add a piece of allocated memory to the mempool. As arguments, it takes the * new pointer, and the old pointer. If the old pointer is found in the * mempool, it is free()d, and replaced with the new pointer. Otherwise, the * new pointer is placed in an empty slot. * The new pointer can be NULL. * The function returns the new pointer. */ void addMempool(void *new, void *old){ int i; for (i = 0; i < MEMPOOLSIZE; i++) { if (mempool[i] == NULL){ if (new == NULL){ return; } mempool[i] = new; mempool_final = i; return; } else if (mempool[i] == old){ free(old); if (new == NULL){ mempool[i] = mempool[mempool_final]; mempool[mempool_final] = NULL; --mempool_final; } else mempool[i] = new; return; } } /* FIXME: Error here... */ fprintf(stderr, "Mempool is full. This should never happen - please contact software authors.\n"); } PyObject *getInt(Option opt){ return PyInt_FromLong((long)*(int*)opt.var); } PyObject *getShort(Option opt){ return PyInt_FromLong((long)*(short*)opt.var); } PyObject *getUshort(Option opt){ return PyInt_FromLong((long)(*(unsigned short*)opt.var)); } PyObject *getUchar(Option opt){ return PyInt_FromLong((long)(*((unsigned char*)opt.var))); } PyObject *getChar(Option opt){ return PyInt_FromLong((long)(*(char *)opt.var)); } PyObject *getDouble(Option opt){ return PyFloat_FromDouble(*(double *)opt.var); } PyObject *getFloat(Option opt){ return PyFloat_FromDouble((double)(*(float *)opt.var)); } PyObject *getString(Option opt){ if (!(*(char**)opt.var)){ Py_INCREF(Py_None); return Py_None; } return PyString_FromString(*(char**)opt.var); } PyObject *getIntA(Option opt){ int i; PyObject *pint; PyObject *list = PyList_New(0); if (!list) return NULL; if (!(*(int**)opt.var)){ Py_INCREF(Py_None); return Py_None; } for (i = 0; i < opt.size; i++){ pint = PyInt_FromLong((long)(*(int **)opt.var)[i]); if (!pint || PyList_Append(list, pint) < 0) goto cleanup; Py_DECREF(pint); } return list; cleanup: Py_DECREF(list); return NULL; } PyObject *getBoolA(Option opt){ int i; PyObject *pint; PyObject *list = PyList_New(0); if (!list) return NULL; if (!(*(char**)opt.var)){ Py_INCREF(Py_None); return Py_None; } for (i = 0; i < opt.size; i++){ pint = PyInt_FromLong((long)(*(char**)opt.var)[i]); if (!pint || PyList_Append(list, pint) < 0) goto cleanup; Py_DECREF(pint); } return list; cleanup: Py_DECREF(list); return NULL; } PyObject *getColorA(Option opt){ int i; PyObject *pint; PyObject *list = PyList_New(0); if (!list) return NULL; if (!(*(char**)opt.var)){ Py_INCREF(Py_None); return Py_None; } for (i = 0; i < opt.size; i++){ pint = PyInt_FromLong((*(long**)opt.var)[i]); if (!pint || PyList_Append(list, pint) < 0) goto cleanup; Py_DECREF(pint); } return list; cleanup: Py_DECREF(list); return NULL; } /* Construct a dictionary of the following format: * option: (index, type, value) */ PyObject *makeOptionDict(Option *opts){ PyObject *(*funcptr)(Option); PyObject *ret; int optIndex = 0; PyObject *tup; PyObject *dict = PyDict_New(); while (opts[optIndex].keyword != NULL) { tup = PyTuple_New(3); PyTuple_SET_ITEM(tup, 0, PyInt_FromLong((long)optIndex)); PyTuple_SET_ITEM(tup, 1, PyInt_FromLong((long)opts[optIndex].type)); switch (opts[optIndex].type){ case OPT_INT: case OPT_LONG: case OPT_COLOR: funcptr = getInt; break; case OPT_SHORT: funcptr = getShort; break; case OPT_USHORT: funcptr = getUshort; break; case OPT_PERCENT: case OPT_BOOL: case OPT_FONTSIZE: case OPT_UCHAR: funcptr = getUchar; break; case OPT_CHAR: funcptr = getChar; break; case OPT_STRING: funcptr = getString; break; case OPT_FLOAT: funcptr = getFloat; break; case OPT_DOUBLE: funcptr = getDouble; break; case OPT_INT_A: funcptr = getIntA; break; case OPT_BOOL_A: funcptr = getBoolA; break; case OPT_COLOR_A: funcptr = getColorA; break; default: PyErr_SetString(PyExc_ValueError, "Argument is not a valid option type."); goto clean; } if (funcptr && opts[optIndex].var){ ret = funcptr(opts[optIndex]); if (!ret) goto clean; PyTuple_SET_ITEM(tup, 2, ret); } else { PyTuple_SET_ITEM(tup, 2, Py_None); } if (PyDict_SetItemString(dict, opts[optIndex].keyword, tup) < 0) goto clean; optIndex ++; } return dict; clean: Py_DECREF(dict); return NULL; } /* * Retrieve current values of the specified chart options. Returns a * dictionary. */ PyObject *getOptions(PyObject *self, PyObject *args){ int type; if (!PyArg_ParseTuple(args, "i", &type)) return NULL; if (type == GRAPH) return makeOptionDict(GraphOptions); else if (type == PIE) return makeOptionDict(PieOptions); else{ PyErr_SetString(PyExc_ValueError, "Argument is neither PIE nor GRAPH."); return NULL; } } /* * Set an option. */ PyObject *setOption(PyObject *self, PyObject *args){ int type, optIndex; PyObject *val, *tmp; long ival; double dval; char *sval, *mstr; Option *table; if (!PyArg_ParseTuple(args, "iiO", &type, &optIndex, &val)){ return NULL; } if (type == GRAPH) table = GraphOptions; else if (type == PIE) table = PieOptions; else{ PyErr_SetString(PyExc_ValueError, "Argument is neither PIE nor GRAPH."); return NULL; } switch (table[optIndex].type){ case OPT_INT: case OPT_COLOR: case OPT_SHORT: case OPT_USHORT: case OPT_UCHAR: case OPT_BOOL: case OPT_FONTSIZE: case OPT_PERCENT: case OPT_CHAR: case OPT_LONG: /* FIXME: Check return value... */ tmp = PyNumber_Int(val); if (PyErr_Occurred()) return NULL; ival = PyInt_AsLong(tmp); Py_DECREF(tmp); if (PyErr_Occurred()) return NULL; switch (table[optIndex].type){ case OPT_INT: *(int*)table[optIndex].var = ival; break; case OPT_SHORT: *(short*)table[optIndex].var = ival; break; case OPT_USHORT: *(unsigned short*)table[optIndex].var = ival; break; case OPT_UCHAR: case OPT_PERCENT: *(unsigned char*)table[optIndex].var = ival; break; case OPT_BOOL: *(char*)table[optIndex].var = ival; break; case OPT_FONTSIZE: *(int*)table[optIndex].var = ival; break; case OPT_CHAR: *(char*)table[optIndex].var = ival; break; case OPT_LONG: case OPT_COLOR: *(long*)table[optIndex].var = ival; break; } break; case OPT_FLOAT: case OPT_DOUBLE: tmp = PyNumber_Float(val); if (PyErr_Occurred()) return NULL; dval = PyFloat_AsDouble(tmp); Py_DECREF(tmp); if (PyErr_Occurred()) return NULL; if (table[optIndex].type == OPT_FLOAT) *(float*)table[optIndex].var = dval; else *(double*)table[optIndex].var = dval; break; case OPT_STRING: if (val == Py_None){ addMempool(NULL, *(char**)table[optIndex].var); *(char**)table[optIndex].var = NULL; } else { tmp = PyObject_Str(val); if (!tmp) return NULL; sval = PyString_AsString(tmp); Py_DECREF(tmp); if (!sval) return NULL; mstr = malloc(strlen(sval) + 1); if (!mstr){ PyErr_NoMemory(); return NULL; } addMempool(mstr, *(char**)table[optIndex].var); strcpy(mstr, sval); *(char**)table[optIndex].var = mstr; } break; case OPT_INT_A: if (val == Py_None){ addMempool(NULL, *(int**)table[optIndex].var); *(int**)table[optIndex].var = NULL; } else { int i, len; int *arr; PyObject *aval; len = PyObject_Length(val); if (len < 0){ PyErr_SetString(PyExc_ValueError, "Cannot retrieve length of item."); return NULL; } arr = calloc((size_t)len, sizeof(int)); if (!arr){ PyErr_NoMemory(); return NULL; } for (i = 0; i < len; i++){ aval = PySequence_GetItem(val, i); if (aval == NULL){ free(arr); PyErr_SetString(PyExc_ValueError, "Cannot access list item."); return NULL; }; arr[i] = (int)PyInt_AsLong(aval); Py_DECREF(aval); if (PyErr_Occurred()){ free(arr); return NULL; } } addMempool(arr, *(int**)table[optIndex].var); *(int**)table[optIndex].var = arr; table[optIndex].size = len; } break; case OPT_BOOL_A: if (val == Py_None){ addMempool(NULL, *(char**)table[optIndex].var); *(char**)table[optIndex].var = NULL; } else { int i, len; char *arr; PyObject *aval; len = PyObject_Length(val); if (len < 0){ PyErr_SetString(PyExc_ValueError, "Cannot retrieve length of item."); return NULL; } arr = calloc((size_t)len, sizeof(char)); if (!arr){ PyErr_NoMemory(); return NULL; } for (i = 0; i < len; i++){ aval = PySequence_GetItem(val, i); if (aval == NULL){ free(arr); PyErr_SetString(PyExc_ValueError, "Cannot access list item."); return NULL; }; arr[i] = (char)PyInt_AsLong(aval); Py_DECREF(aval); if (PyErr_Occurred()){ free(arr); return NULL; } } addMempool(arr, *(char**)table[optIndex].var); *(char**)table[optIndex].var = arr; table[optIndex].size = len; } break; case OPT_COLOR_A: if (val == Py_None){ addMempool(NULL, *(long**)table[optIndex].var); *(long**)table[optIndex].var = NULL; } else { int i, len; long *arr; PyObject *aval; len = PyObject_Length(val); if (len < 0){ PyErr_SetString(PyExc_ValueError, "Cannot retrieve length of item."); return NULL; } arr = calloc((size_t)len, sizeof(long)); if (!arr){ PyErr_NoMemory(); return NULL; } for (i = 0; i < len; i++){ aval = PySequence_GetItem(val, i); if (aval == NULL){ free(arr); PyErr_SetString(PyExc_ValueError, "Cannot access list item."); return NULL; }; arr[i] = PyInt_AsLong(aval); Py_DECREF(aval); if (PyErr_Occurred()){ free(arr); return NULL; } } addMempool(arr, *(long**)table[optIndex].var); *(long**)table[optIndex].var = arr; table[optIndex].size = len; } break; default: PyErr_SetString(PyExc_ValueError, "Option type unknown."); return NULL; } Py_INCREF(Py_None); return Py_None; } /* * The argument should be a list containing only strings. * The function returns an array of C strings. Both the * array and the strings should be freed after use. * Returns NULL on error. */ char **getStringsFromSequence(PyObject *lst){ int i, j, slen; size_t len; char **strings; char *mem; PyObject *pobj, *pstr; len = PyObject_Length(lst); if (len < 0) return NULL; strings = calloc((size_t)len, sizeof(char*)); if (!strings){ PyErr_NoMemory(); return NULL; } for (i = 0; i < len; i++){ pobj = PySequence_GetItem(lst, i); pstr = PyObject_Str(pobj); Py_DECREF(pobj); if (pstr == NULL) goto cleanup; slen = PyString_Size(pstr); if (slen == NULL) goto cleanup; mem = malloc((size_t)slen+1); if (mem == NULL){ PyErr_NoMemory(); goto cleanup; } strcpy(mem, PyString_AsString(pstr)); Py_DECREF(pstr); strings[i] = mem; } return strings; cleanup: for (j = 0; j < len; j++){ if (strings[j]) free(strings[j]); else break; } free(strings); PyErr_SetString(PyExc_ValueError, "Label cannot be converted to string."); return NULL; } /* * The argument should be a list containing only floats, ints and None objects. * The function returns a list of C floats. Note that the caller should free * this list after use. * * Returns NULL on error. */ float *getFloatsFromSequence(PyObject *lst){ int i, len; float *floats; PyObject *pnum; len = PyObject_Length(lst); floats = malloc(len * sizeof(float)); if (floats == NULL){ PyErr_NoMemory(); return NULL; } for (i = 0; i < len; i++){ pnum = PySequence_GetItem(lst, i); if (pnum == Py_None){ floats[i] = GDC_NOVALUE; } else { if ((!pnum) || (!PyNumber_Check(pnum))){ PyMem_Free(floats); return NULL; } floats[i] = (float)PyFloat_AsDouble(pnum); } Py_DECREF(pnum); } return floats; } PyObject *pygd_out_pie(PyObject *self, PyObject *args){ int width, height, graphtype, numpoints; int i; PyObject *pfile; PyObject *labels = NULL; PyObject *data = NULL; PyObject *ret = NULL; char **labels_strings = NULL; float *data_floats = NULL; FILE *fp; if (!PyArg_ParseTuple(args, "iiO!iiOO", &width, &height, &PyFile_Type, &pfile, &graphtype, &numpoints, &labels, &data)){ return NULL; } if (!PySequence_Check(data)){ PyErr_SetString(PyExc_TypeError, "Argument data should be a list."); goto cleanup; } if (PyObject_IsTrue(labels)){ if (!PySequence_Check(labels)){ PyErr_SetString(PyExc_TypeError, "Argument labels should be a list."); goto cleanup; } if (!PyObject_Length(labels) == numpoints){ PyErr_SetString(PyExc_TypeError, "Number of labels should equal numpoints."); goto cleanup; } labels_strings = getStringsFromSequence(labels); if (labels_strings == NULL){ PyErr_SetString(PyExc_TypeError, "Could not convert labels arguments to strings."); goto cleanup; } } if (!PyObject_Length(data) == numpoints){ PyErr_SetString(PyExc_TypeError, "Number of data points should equal numpoints."); goto cleanup; } data_floats = getFloatsFromSequence(data); if (data_floats == NULL){ PyErr_SetString(PyExc_TypeError, "Could not convert data arguments to floats."); goto cleanup; } fp = PyFile_AsFile(pfile); /* Why doesn't this function have a return value? */ GDC_out_pie( width, height, fp, graphtype, numpoints, labels_strings, data_floats); Py_INCREF(Py_None); ret = Py_None; cleanup: if (labels_strings){ for (i = 0; i < numpoints; i++) free(labels_strings[i]); free(labels_strings); } if (data_floats) free(data_floats); return ret; } PyObject *pygd_out_graph(PyObject *self, PyObject *args){ int width, height, graphtype, numpoints, numsets, retval; int i; PyObject *pfile, *labels, *data, *combodata; PyObject *ret = NULL; char **labels_strings = NULL; float *data_floats = NULL; float *combodata_floats = NULL; FILE *fp; if (!PyArg_ParseTuple(args, "iiO!iiOiOO", &width, &height, &PyFile_Type, &pfile, &graphtype, &numpoints, &labels, &numsets, &data, &combodata)){ return NULL; } if (!PySequence_Check(data)){ PyErr_SetString(PyExc_TypeError, "Argument data should be a list."); goto cleanup; } if (PyObject_IsTrue(labels)){ if (!PySequence_Check(labels)){ PyErr_SetString(PyExc_TypeError, "Argument labels should be a list."); goto cleanup; } if (!PyObject_Length(labels) == numpoints){ PyErr_SetString(PyExc_TypeError, "Number of labels should equal numpoints."); goto cleanup; } labels_strings = getStringsFromSequence(labels); if (labels_strings == NULL){ PyErr_SetString(PyExc_TypeError, "Could not convert labels arguments to strings."); goto cleanup; } } if (PyObject_IsTrue(combodata)){ if (!PySequence_Check(combodata)){ PyErr_SetString(PyExc_TypeError, "Argument combodata should be a list."); goto cleanup; } if (!PyObject_Length(combodata) == numpoints){ PyErr_SetString(PyExc_TypeError, "Number of combo data points should equal numpoints."); goto cleanup; } combodata_floats = getFloatsFromSequence(combodata); if (combodata_floats == NULL){ PyErr_SetString(PyExc_TypeError, "Could not convert combodata arguments to floats."); goto cleanup; } } if (!PyObject_Length(data) == numpoints){ PyErr_SetString(PyExc_TypeError, "Number of data points should equal numpoints."); goto cleanup; } data_floats = getFloatsFromSequence(data); if (data_floats == NULL){ PyErr_SetString(PyExc_TypeError, "Could not convert data arguments to floats."); goto cleanup; } fp = PyFile_AsFile(pfile); retval = GDC_out_graph( width, height, fp, graphtype, numpoints, labels_strings, numsets, data_floats, combodata_floats); if (retval){ PyErr_SetString(PGError, "Generic error: could not draw graph."); ret = NULL; } else { Py_INCREF(Py_None); ret = Py_None; } cleanup: if (labels_strings){ for (i = 0; i < numpoints; i++) free(labels_strings[i]); free(labels_strings); } if (combodata_floats) free(combodata_floats); if (data_floats) free(data_floats); return ret; } PyObject *pygd_set_scatter(PyObject *self, PyObject *args){ int i, len; GDC_SCATTER_T *scatters; PyObject *scatList, *s, *attr, *aval; if (!PyArg_ParseTuple(args, "O", &scatList)){ return NULL; } if (scatList == Py_None){ addMempool(NULL, GDC_scatter); GDC_scatter = NULL; GDC_num_scatter_pts = 0; Py_INCREF(Py_None); return Py_None; } /* TODO: If scatlist is None, we clear the scatter points. */ if (!PySequence_Check(scatList)){ PyErr_SetString(PyExc_TypeError, "Argument data should be a list."); return NULL; } len = PyObject_Length(scatList); scatters = malloc(len * sizeof(GDC_SCATTER_T)); for (i = 0; i < len; i++){ s = PySequence_GetItem(scatList, i); attr = PyObject_GetAttrString(s, "point"); if (attr == NULL) goto cleanup; aval = PyNumber_Float(attr); Py_DECREF(attr); if (aval == NULL){ PyErr_SetString(PyExc_TypeError, "Point value must be representable as a float."); goto free; } scatters[i].point = (float)PyFloat_AsDouble(aval); Py_DECREF(aval); attr = PyObject_GetAttrString(s, "val"); if (attr == NULL) goto cleanup; aval = PyNumber_Float(attr); Py_DECREF(attr); if (aval == NULL){ PyErr_SetString(PyExc_TypeError, "Value must be representable as a float."); goto free; } scatters[i].val = (float)PyFloat_AsDouble(aval); Py_DECREF(aval); attr = PyObject_GetAttrString(s, "width"); if (attr == NULL) goto cleanup; aval = PyNumber_Int(attr); Py_DECREF(attr); if (aval == NULL){ PyErr_SetString(PyExc_TypeError, "Width must be representable as an int."); goto free; } scatters[i].width = (int)PyInt_AsLong(aval); Py_DECREF(aval); attr = PyObject_GetAttrString(s, "color"); if (attr == NULL) goto cleanup; aval = PyNumber_Int(attr); Py_DECREF(attr); if (aval == NULL){ PyErr_SetString(PyExc_TypeError, "Color must be representable as an int."); goto free; } scatters[i].color = (unsigned long)PyInt_AsLong(aval); Py_DECREF(aval); attr = PyObject_GetAttrString(s, "_type"); if (attr == NULL) goto cleanup; aval = PyNumber_Int(attr); Py_DECREF(aval); if (aval == NULL){ PyErr_SetString(PyExc_TypeError, "Type must be representable as an int."); goto free; } scatters[i].ind = (int)PyInt_AsLong(aval); Py_DECREF(aval); Py_DECREF(s); } addMempool(scatters, GDC_scatter); GDC_scatter = scatters; GDC_num_scatter_pts = len; Py_INCREF(Py_None); return Py_None; cleanup: PyErr_SetString(PyExc_TypeError, "Object does not seem to be a scatter point object."); free: free(scatters); return NULL; } PyObject *pygd_annotate(PyObject *self, PyObject *args){ PyObject *anno, *attr, *aval; GDC_ANNOTATION_T *canno; if (!PyArg_ParseTuple(args, "O", &anno)){ return NULL; } if (anno == Py_None){ if (GDC_annotation) free(GDC_annotation); GDC_annotation = NULL; } else { canno = malloc(sizeof(GDC_ANNOTATION_T)); if (canno == NULL){ PyErr_NoMemory(); return NULL; } attr = PyObject_GetAttrString(anno, "point"); if (attr == NULL) goto cleanup; aval = PyNumber_Float(attr); Py_DECREF(attr); if (aval == NULL){ PyErr_SetString(PyExc_TypeError, "Point value must be representable as a float."); goto free; } canno->point = (float)PyFloat_AsDouble(aval); Py_DECREF(aval); attr = PyObject_GetAttrString(anno, "color"); if (attr == NULL) goto cleanup; aval = PyNumber_Int(attr); Py_DECREF(attr); if (aval == NULL){ PyErr_SetString(PyExc_TypeError, "Color value must be representable as a long."); goto free; } canno->color = PyInt_AsLong(aval); Py_DECREF(aval); attr = PyObject_GetAttrString(anno, "note"); if (attr == NULL) goto cleanup; aval = PyObject_Str(attr); Py_DECREF(attr); if (aval == NULL){ PyErr_SetString(PyExc_TypeError, "Note must be representable as a str."); goto free; } strncpy(canno->note, PyString_AsString(aval), MAX_NOTE_LEN+1); Py_DECREF(aval); if (GDC_annotation) free(GDC_annotation); GDC_annotation = canno; } Py_INCREF(Py_None); return Py_None; cleanup: PyErr_SetString(PyExc_TypeError, "Object does not seem to be an annotation object."); free: free(canno); return NULL; } static PyMethodDef methods[] = { {"out_graph", pygd_out_graph, METH_VARARGS, "Output a graph." }, {"out_pie", pygd_out_pie, METH_VARARGS, "Output a pie." }, {"getOptions", getOptions, METH_VARARGS, "Retrieve all chart options." }, {"setOption", setOption, METH_VARARGS, "Set an option." }, {"setScatter", pygd_set_scatter, METH_VARARGS, "Set scatter points." }, {"annotate", pygd_annotate, METH_VARARGS, "Set an annotation point." }, { NULL, NULL } }; void init_gdchartc(void){ PyObject *module; Py_AtExit(clearMempool); module = Py_InitModule4("_gdchartc", methods, NULL, NULL, PYTHON_API_VERSION); PGError = PyErr_NewException("_gdchartc.PGError", NULL, NULL); PyModule_AddObject(module, "PGError", PGError); /* Expose our option type identifiers. */ PyModule_AddIntConstant(module, "OPT_BOOL", (long) OPT_BOOL); PyModule_AddIntConstant(module, "OPT_BOOL_A", (long) OPT_BOOL_A); PyModule_AddIntConstant(module, "OPT_COLOR", (long) OPT_COLOR); PyModule_AddIntConstant(module, "OPT_COLOR_A", (long) OPT_COLOR_A); PyModule_AddIntConstant(module, "OPT_FLOAT", (long) OPT_FLOAT); PyModule_AddIntConstant(module, "OPT_FONTSIZE", (long) OPT_FONTSIZE); PyModule_AddIntConstant(module, "OPT_INT", (long) OPT_INT); PyModule_AddIntConstant(module, "OPT_INT_A", (long) OPT_INT_A); PyModule_AddIntConstant(module, "OPT_LONG", (long) OPT_LONG); PyModule_AddIntConstant(module, "OPT_SHORT", (long) OPT_SHORT); PyModule_AddIntConstant(module, "OPT_USHORT", (long) OPT_USHORT); PyModule_AddIntConstant(module, "OPT_PERCENT", (long) OPT_PERCENT); PyModule_AddIntConstant(module, "OPT_STRING", (long) OPT_STRING); PyModule_AddIntConstant(module, "OPT_UCHAR", (long) OPT_UCHAR); PyModule_AddIntConstant(module, "OPT_CHAR", (long) OPT_CHAR); /* Expose the chart type identifiers */ PyModule_AddIntConstant(module, "GRAPH", (long) GRAPH); PyModule_AddIntConstant(module, "PIE", (long) PIE); /* ************************ gdc.h ************************ */ /* Max annotation length: */ PyModule_AddIntConstant(module, "MAX_NOTE_LEN", (long) MAX_NOTE_LEN); /* Image formats: */ PyModule_AddIntConstant(module, "GDC_GIF", (long) GDC_GIF); PyModule_AddIntConstant(module, "GDC_JPEG", (long) GDC_JPEG); PyModule_AddIntConstant(module, "GDC_PNG", (long) GDC_PNG); PyModule_AddIntConstant(module, "GDC_WBMP", (long) GDC_WBMP); /* Font sizes: */ PyModule_AddIntConstant(module, "GDC_TINY", (long) GDC_TINY); PyModule_AddIntConstant(module, "GDC_SMALL", (long) GDC_SMALL); PyModule_AddIntConstant(module, "GDC_MEDBOLD", (long) GDC_MEDBOLD); PyModule_AddIntConstant(module, "GDC_LARGE", (long) GDC_LARGE); PyModule_AddIntConstant(module, "GDC_GIANT", (long) GDC_GIANT); /* Chart styles */ PyModule_AddIntConstant(module, "GDC_LINE", (long) GDC_LINE); PyModule_AddIntConstant(module, "GDC_AREA", (long) GDC_AREA); PyModule_AddIntConstant(module, "GDC_BAR", (long) GDC_BAR); PyModule_AddIntConstant(module, "GDC_FLOATINGBAR", (long) GDC_FLOATINGBAR); PyModule_AddIntConstant(module, "GDC_HILOCLOSE", (long) GDC_HILOCLOSE); PyModule_AddIntConstant(module, "GDC_COMBO_LINE_BAR", (long) GDC_COMBO_LINE_BAR); PyModule_AddIntConstant(module, "GDC_COMBO_HLC_BAR", (long) GDC_COMBO_HLC_BAR); PyModule_AddIntConstant(module, "GDC_COMBO_LINE_AREA", (long) GDC_COMBO_LINE_AREA); PyModule_AddIntConstant(module, "GDC_COMBO_LINE_LINE", (long) GDC_COMBO_LINE_LINE); PyModule_AddIntConstant(module, "GDC_COMBO_HLC_AREA", (long) GDC_COMBO_HLC_AREA); PyModule_AddIntConstant(module, "GDC_3DHILOCLOSE", (long) GDC_3DHILOCLOSE); PyModule_AddIntConstant(module, "GDC_3DCOMBO_LINE_BAR", (long) GDC_3DCOMBO_LINE_BAR); PyModule_AddIntConstant(module, "GDC_3DCOMBO_LINE_AREA",(long) GDC_3DCOMBO_LINE_AREA); PyModule_AddIntConstant(module, "GDC_3DCOMBO_LINE_LINE",(long) GDC_3DCOMBO_LINE_LINE); PyModule_AddIntConstant(module, "GDC_3DCOMBO_HLC_BAR", (long) GDC_3DCOMBO_HLC_BAR); PyModule_AddIntConstant(module, "GDC_3DCOMBO_HLC_AREA", (long) GDC_3DCOMBO_HLC_AREA); PyModule_AddIntConstant(module, "GDC_3DBAR", (long) GDC_3DBAR); PyModule_AddIntConstant(module, "GDC_3DFLOATINGBAR", (long) GDC_3DFLOATINGBAR); PyModule_AddIntConstant(module, "GDC_3DAREA", (long) GDC_3DAREA); PyModule_AddIntConstant(module, "GDC_3DLINE", (long) GDC_3DLINE); /* Pie styles */ PyModule_AddIntConstant(module, "GDC_3DPIE", (long) GDC_3DPIE); PyModule_AddIntConstant(module, "GDC_2DPIE", (long) GDC_2DPIE); /* TODO: Justification, font type, font size */ /* ************************ gdchart.h ************************ */ /* Stack options: */ PyModule_AddIntConstant(module, "GDC_STACK_DEPTH", (long) GDC_STACK_DEPTH); PyModule_AddIntConstant(module, "GDC_STACK_SUM", (long) GDC_STACK_SUM); PyModule_AddIntConstant(module, "GDC_STACK_BESIDE", (long) GDC_STACK_BESIDE); PyModule_AddIntConstant(module, "GDC_STACK_LAYER", (long) GDC_STACK_LAYER); /* Hi-lo-close styles: */ PyModule_AddIntConstant(module, "GDC_HLC_DIAMOND", (long) GDC_HLC_DIAMOND); PyModule_AddIntConstant(module, "GDC_HLC_CLOSE_CONNECTED", (long) GDC_HLC_CLOSE_CONNECTED); PyModule_AddIntConstant(module, "GDC_HLC_CONNECTING", (long) GDC_HLC_CONNECTING); PyModule_AddIntConstant(module, "GDC_HLC_I_CAP", (long) GDC_HLC_I_CAP); /* Scatter point styles: */ PyModule_AddIntConstant(module, "GDC_SCATTER_TRIANGLE_DOWN", (long) GDC_SCATTER_TRIANGLE_DOWN); PyModule_AddIntConstant(module, "GDC_SCATTER_TRIANGLE_UP", (long) GDC_SCATTER_TRIANGLE_UP); PyModule_AddIntConstant(module, "GDC_SCATTER_CIRCLE", (long) GDC_SCATTER_CIRCLE); /* Tick styles: */ PyModule_AddIntConstant(module, "GDC_TICK_LABELS", (long) GDC_TICK_LABELS); PyModule_AddIntConstant(module, "GDC_TICK_POINTS", (long) GDC_TICK_POINTS); PyModule_AddIntConstant(module, "GDC_TICK_NONE", (long) GDC_TICK_NONE); /* Border styles: */ PyModule_AddIntConstant(module, "GDC_BORDER_NONE", (long) GDC_BORDER_NONE); PyModule_AddIntConstant(module, "GDC_BORDER_ALL", (long) GDC_BORDER_ALL); PyModule_AddIntConstant(module, "GDC_BORDER_X", (long) GDC_BORDER_X); PyModule_AddIntConstant(module, "GDC_BORDER_Y", (long) GDC_BORDER_Y); PyModule_AddIntConstant(module, "GDC_BORDER_Y2", (long) GDC_BORDER_Y2); PyModule_AddIntConstant(module, "GDC_BORDER_TOP", (long) GDC_BORDER_TOP); /* Other magic: */ AddFloatConstant(module, "GDC_INTERP_VALUE", (double) GDC_INTERP_VALUE); /* ************************ gdcpie.h ************************ */ /* Percent placement (pie charts): */ PyModule_AddIntConstant(module, "GDCPIE_PCT_NONE", (long) GDCPIE_PCT_NONE); PyModule_AddIntConstant(module, "GDCPIE_PCT_ABOVE", (long) GDCPIE_PCT_ABOVE); PyModule_AddIntConstant(module, "GDCPIE_PCT_BELOW", (long) GDCPIE_PCT_BELOW); PyModule_AddIntConstant(module, "GDCPIE_PCT_RIGHT", (long) GDCPIE_PCT_RIGHT); PyModule_AddIntConstant(module, "GDCPIE_PCT_LEFT", (long) GDCPIE_PCT_LEFT); } pygdchart2alpha2/TODO010064400017500001750000000003770777443323200134100ustar00aldoaldoTODO ==== - We may want to support drawing to StringIO and cStringIO objects. - The project needs to be fully distutils-ified. Ideally, gdchart itself should be built using autoconf. We may do this ourselves when we have time. - Expand the manual. pygdchart2alpha2/README010064400017500001750000000003210777443323200135650ustar00aldoaldo PyGDChart 2.0 Beta ================== This is the Beta release of the new version of PyGDChart2. It is essentially a bugfix release, fixing problems affecting setting some options, and using TrueType fonts. pygdchart2alpha2/INSTALL010064400017500001750000000012650777443323200137460ustar00aldoaldo PyGDChart 2.0 Beta 31/12/03 ================== Since this is a Beta release, we'll assume our users know what they're doing: 1. Install the latest version of Bruce Verderaime's GDChart library (0.11.4dev, at the time of writing). 2. Edit the setup.py file to point to the appropriate libraries on your system. 3. Now do python setup.py build_ext -i This will build the C extension in-place, allowing you to test it before installation. Preferably, you should do the testing with PyLid (also available at www.nullcube.com): cd test /path/to/pylid.py 5. Once the unit-tests have run successfully (please report any errors): cd .. python setup.py install pygdchart2alpha2/test.py010064400017500001750000000007640777443323200142510ustar00aldoaldo#!/usr/bin/env python2.2 import sys import gdchart g = gdchart.Line() g.bg_color = "white" g.width = 600 g.height = 600 g.title = "Risk Event Trend Graph" g.set_color = ["red", "blue"] g.ytitle = "Risk" g.xtitle = "Assessments" g.setData((10, 20, 30), (30, 20, 10)) g.setLabels(("one", "two", "three")) g.ticks = "NONE" g.ylabel_density = 40 #g.title_font_size = "GIANT" g.title_font = "/home/aldo/.fonts/Elephnt.ttf" g.title_ptsize = 12 print "Content-Type: image/png" print g.draw(sys.stdout) pygdchart2alpha2/CHANGELOG010064400017500001750000000017440777443323200141310ustar00aldoaldoAlpha 1 - Initial release Alpha 2 - Many code cleanups - Attempting to assign to a non-option attribute on Chart classes now raises AttributeError. This prevents errors like accidental mistyping of option attributes from going unnoticed. - setData now accepts None values to indicate missing data. - .draw methods now accept either a string filename, or a file pointer. - .setLabels now takes a single list as argument. The previous calling convention was found to be too confusing by some people. - .getAllOptions now inlcudes the "with" and "height" options. - Rename 3d* options to threeD*. Python properties can't start with a digit. Beta - Fix a type bug that stopped TrueType fonts from working (thanks to Amit J. Patel) - Fix a bug that manifested itself when setting some options to "None" (thanks to Perry Tew) pygdchart2alpha2/setup.py010064400017500001750000000030370777443323200144260ustar00aldoaldofrom distutils.core import setup, Extension GDCHART_PATH = "../gdchart0.11.4dev" GD_PATH = "../gd-1.8.4" setup( name="pygdchart", version="2.0 Beta", description="Python bindings to the GDChart library", author="Nullcube Pty Ltd", author_email="aldo@nullcube.com", url="http://www.nullcube.com", py_modules = ["gdchart"], ext_modules=[ Extension( "_gdchartc", ["_gdchartc.c"], include_dirs=[GDCHART_PATH], library_dirs=[ GD_PATH, GDCHART_PATH, "/usr/local/lib", "/usr/X11R6/lib", "/usr/lib" ], define_macros=[ ("HAVE_LIBFREETYPE", 1), ("HAVE_JPEG", 1), ], libraries=["gdc", "gd", "png", "z", "jpeg", "freetype"] ) ] ) pygdchart2alpha2/doc004075500017500001750000000000000777443323200134025ustar00aldoaldopygdchart2alpha2/doc/graphs004075500017500001750000000000000777443323200146665ustar00aldoaldopygdchart2alpha2/doc/graphs/combined004075500017500001750000000000000777443323200164465ustar00aldoaldopygdchart2alpha2/doc/graphs/combined/hlcarea.html010064400017500001750000000027160777443323200210150ustar00aldoaldo <--previous | contents | next-->

HLCAreaCombo

HLCAreaCombo
HLCAreaCombo3D

Data Format

The .setData() method accepts the same data format as the HLC .setData() method.

The .setComboData() method accepts the same data format as the Area .setData() method.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/graphs/combined/hlcbar.html010064400017500001750000000027000777443323200206420ustar00aldoaldo <--previous | contents | next-->

HLCBarCombo

HLCBarCombo
HLCBarCombo3D

Data Format

The .setData() method accepts the same data format as the HLC .setData() method.

The .setComboData() method accepts the same data format as the Bar .setData() method.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/graphs/combined/linebar.html010064400017500001750000000027100777443323200210240ustar00aldoaldo <--previous | contents | next-->

LineBarCombo

LineBarCombo
LineBarCombo3D

Data Format

The .setData() method accepts the same data format as the Line .setData() method.

The .setComboData() method accepts the same data format as the Bar .setData() method.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/graphs/combined/linearea.html010064400017500001750000000027200777443323200211710ustar00aldoaldo <--previous | contents | next-->

LineAreaCombo

LineAreaCombo
LineAreaCombo3D

Data Format

The .setData() method accepts the same data format as the Line .setData() method.

The .setComboData() method accepts the same data format as the Area .setData() method.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/graphs/combined/lineline.html010064400017500001750000000027300777443323200212110ustar00aldoaldo <--previous | contents | next-->

LineLineCombo

LineLineCombo
LineLineCombo3D

The 2D form of the LineLineCombo graph is functionally the same as using a Line graph, and plotting multiple

Data Format

The .setData() and setComboData() methods accept the same data format as the Line .setData() method.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/graphs/line.html010064400017500001750000000023160777443323200165610ustar00aldoaldo <--previous | contents | next-->

Line Graphs

Line
Line3D

Data Format

As for Bar Graphs.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/graphs/area.html010064400017500001750000000023300777443323200165360ustar00aldoaldo <--previous | contents | next-->

Area Graphs

Area
Area3D

Data Format

As for Bar Graphs.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/graphs/floating.html010064400017500001750000000117520777443323200174410ustar00aldoaldo <--previous | contents | next-->

Floating Bar Graphs

FloatingBar
FloatingBar3D

Data Format

The FloatingBar .setData() method accepts an arbitrary number of tuples. The first element of the tuple is a list of the lower values of the floating bar, and the second element is a list of the upper values. Here is an example that plots a single set of data (spaced for clarity):

x.setData(
                (
                    [10, 20, 40, 20, 0],
                    [60, 90, 80, 50, 80]
                )
            )

... and for multiple sets we might do the following:

x.setData(
                (
                    [10, 20, 40, 20, 0],
                    [60, 90, 80, 50, 80]
                ),
                (
                    [0, 80, 40, 10, 0],
                    [30, 100, 90, 20, 40]
                )
            )

<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/graphs/hlc.html010064400017500001750000000152310777443323200164000ustar00aldoaldo <--previous | contents | next-->

High-Low-Close Graphs

HLC
HLC3D

High-Low-Close graphs are commonly used do depict stock-market price movements - "high" indicates the highest value reached during a period of trading, "low" the lowest, and "close" the value at close of markets.

Data Format

The HLC .setData() method accepts an arbitrary number of lists of the form [high, low, close], where each element is a list of values. To draw a single HLC graph, we might invoke .setData() as follows:

x.setData(
            (
                [40, 100, 80, 30, 50],
                [0, 60, 70, 0, 10],
                [10, 95, 75, 25, 20]
            )
        )

... and for multiple sets we might do the following (spaced to make things clearer):

x.setData(
            (
                [40, 100, 80, 30, 50],
                [0, 60, 70, 0, 10],
                [10, 95, 75, 25, 20]
            ),
            (
                [20, 30, 40, 50, 60],
                [0, 10, 20, 30, 40],
                [10, 20, 30, 40, 50]
            )
        )

Options

There are a number of special options associated with HLC graphs.

hlc_style

This option affects the drawing style of HLC graphs. It should be a list, containing one or more of the following strings "DIAMOND", "CLOSE_CONNECTED", "CONNECTING", "I_CAP".

hlc_cap_width

The width of the HLC cap. This is a percentage, i.e. it should be an integer between 0 and 100.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/graphs/combined.html010064400017500001750000000024140777443323200174110ustar00aldoaldo <--previous | contents | next-->

Combination Graphs

Combination graphs allow you to place two different plot types at on the same graph. The primary data (i.e. data for the graph type that occurs first in the combo graph name) is set using the usual .setData() method. Secondary data is set using the .setComboData() method. Note that the .setData() and .setComboData() methods enforce data conformance - that is, you cannot plot data of different lengths in your primary and secondary graphs.

Each combination graph type also as a corresponding 3D graph type. The 3D types plot the primary graph type in 3D, with the secondary data type as a 2D backdrop.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/graphs/scatter.html010064400017500001750000000162050777443323200173010ustar00aldoaldo <--previous | contents | next-->

Scatter

Scatter Graph

GDChart provides the ability to add scatter points to any of the standard graph types. In PyGDChart, this is done by instantiating a number of Scatter objects, and adding them to a graph using the .setScatter() method.

The Scatter Class

Scatter objects are instantiated as follows:

x = Scatter(x, y, type, width, color)

  • The x value should not exceed the number of points in the associated graph.
  • type is one of "TRIANGLE_DOWN", "TRIANGLE_UP" and "CIRCLE", defaulting to "TRIANGLE_DOWN".
  • width is a precentage defaulting to 100.
  • color defaults to "white".

Example

The graph at the head of this chapter was drawn using the following program:

import random
import gdchart

sgraph = gdchart.Line()
sgraph.width = 250
sgraph.height = 250
sgraph.sgraphtitle = "Weekday"
sgraph.ytitle = "Percentage"
sgraph.title = "Scatter"
sgraph.plot_color = "red"
sgraph.sgraphtitle_color = "white"
sgraph.ytitle_color = "white"
sgraph.setData(range(100))
sgraph.setLabels(range(100))

scats = []
for i in range(150):
    x = random.randrange(30, 80)
    y = random.randrange(30, 80)
    s = gdchart.Scatter(x, y, "CIRCLE", 100, "blue")
    scats.append(s)
sgraph.setScatter(scats)
sgraph.draw("scatter.png")

<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/graphs/bar.html010064400017500001750000000072410777443323200164000ustar00aldoaldo <--previous | contents | next-->

Bar Graphs

Bar
Bar3D

Data Format

The .setData() method accepts simple lists of integers or floats. The following would plot a single set of data:

x.setData([20, 100, 80, 30, 50])

... and this would plot multiple sets of data:

x.setData([20, 100, 80, 30, 50], [30, 60, 70, 20, 10], [80, 100, 10, 30, 40])

<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/graphs/options.html010064400017500001750000000242060777443323200173270ustar00aldoaldo <--previous | contents | next-->

Graph Options

Below is a complete list of all options that can be set on Graph objects. Not all options are explained, but the names are fairly self-explanatory. In time, the descriptions in this table will become more complete.

See the Type Legend table at the bottom of this page for an explanation of the various data types.

Option Type Description
annotation_font STRING
annotation_font_size FONTSIZE
annotation_ptsize FLOAT
bar_width PERCENT
bg_color COLOR Background colour.
bg_image STRING Set a background image.
bg_transparent BOOL
border CUSTOM A list of one or more of the following: "NONE", "ALL", "X", "Y", "Y2", "TOP".
ext_color COLOR_A The colour of the primary graph.
ext_vol_color COLOR_A The colour of the secondary graph.
generate_img BOOL
grid CUSTOM One of "LABELS", "POINTS", "NONE".
grid_color COLOR
hard_graphheight INT
hard_graphwidth INT
hard_size BOOL
hard_xorig INT
hard_yorig INT
hlc_cap_width PERCENT The width of the HLC cap. See HLC Graph for more detail.
hlc_style INT The HLC style. This is option is a list, consisting of one or more of the following: "DIAMOND", "CLOSE_CONNECTED", "CONNECTING" and "I_CAP". See HLC Graph for more detail.
hold_img INT
interpolations BOOL
image_type INT One of the following: "GIF", "JPEG", "PNG", "WBMP".
jpeg_quality INT
line_color COLOR
plot_color COLOR The colour of the primary plot.
requested_yinterval FLOAT
requested_ymax FLOAT
requested_ymin FLOAT
set_color COLOR_A
stack_type CUSTOM One of "DEPTH", "SUM", "BESIDE", "LAYER".
thumblabel STRING
threeD_angle UCHAR
threeD_depth FLOAT
thumbnail BOOL
thumbval FLOAT
ticks CUSTOM One of "LABELS", "POINTS", "NONE"
title STRING Title at the top of the graph.
title_color COLOR
title_font STRING
title_font_size FONTSIZE
title_ptsize FLOAT
vol_color COLOR
xaxis BOOL
xaxis_angle FLOAT
xaxis_font STRING
xaxis_font_size FONTSIZE
xaxis_ptsize FLOAT
xlabel_color COLOR
xlabel_spacing SHORT
xlabel_ctl BOOL_A
xtitle STRING Label on the X axis.
xtitle_color COLOR Colour of the label on the X axis.
xtitle_font STRING
xtitle_font_size FONTSIZE
xtitle_ptsize FLOAT
yaxis BOOL
yaxis2 BOOL
yaxis_font STRING
yaxis_font_size FONTSIZE
yaxis_ptsize FLOAT
ylabel_color COLOR
ylabel_density PERCENT
ylabel_fmt STRING
ylabel2_color COLOR
ylabel2_fmt STRING
ytitle STRING Title on the Y axis.
ytitle_color COLOR Colour of the title on the Y axis.
ytitle_font STRING
ytitle_font_size FONTSIZE
ytitle_ptsize FLOAT
ytitle2 STRING
ytitle2_color COLOR
yval_style BOOL
zeroshelf BOOL

Type Legend

Type* Description
BOOL True if the value passed evaluates to true (ie. "if a: print 1" prints 1).
BOOL_A An array of BOOL values.
COLOR Values can be specified as a descriptive name (i.e. "blue"), as an integer (i.e. 0xFF0000), or as an RGB object (i.e. RGB(0xFF, 0x00, 0x00)).
COLOR_A An array of COLOR values.
FLOAT A floating point value.
FONTSIZE One of "TINY", "SMALL", "MEDBOLD", "LARGE", "GIANT".
INT An integer.
PERCENT An integer x, such that 0 <= x <= 100.
STRING A string.
UCHAR An unsigned char. That is, a small positive integer.

* Note that types are NOT enforced by type check - that means that you don't have to pass a Python integer to an integer option: an object with an __int__ method will do. Same goes for string options and objects with a __str__ or __repr__ method, etc.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/pies004075500017500001750000000000000777443323200143425ustar00aldoaldopygdchart2alpha2/doc/pies/options.html010064400017500001750000000151050777443323200170010ustar00aldoaldo <--previous | contents | next-->

Pie Options

Below is a complete list of all options that can be set on Pie objects. Not all options are explained, but the names are fairly self-explanatory. In time, the descriptions in this table will become more complete.

See the Type Legend table at the bottom of this page for an explanation of the various data types.

Option Type Description
bg_color COLOR
bg_image STRING
edge_color COLOR
explode INT_A An array that specifies which slices of the pie to "explode", and by how much. See the Pie Chart chapter for an example of use.
generate_img BOOL
image_type INT
jpeg_quality INT
label_dist INT
label_font STRING
label_font_size FONTSIZE
label_line BOOL
label_ptsize FLOAT
line_color COLOR
missing BOOL_A If an element is true, the corresponding "slice" of the pie will be missing.
other_threshold CHAR
percent_format STRING
percent_labels INT
perspective USHORT
color COLOR_A A list of color entries. Each entry specifies the color for the corresponding slice of the pie.
plot_color COLOR
threeD_angle USHORT
threeD_depth USHORT
title STRING The title at the top of the chart.
title_font STRING
title_font_size FONTSIZE
title_ptsize FLOAT

Type Legend

Type* Description
BOOL True if the value passed evaluates to true (ie. "if a: print 1" prints 1).
BOOL_A An array of BOOL values.
COLOR Values can be specified as a descriptive name (i.e. "blue"), as an integer (i.e. 0xFF0000), or as an RGB object (i.e. RGB(0xFF, 0x00, 0x00)).
COLOR_A An array of COLOR values.
FLOAT A floating point value.
FONTSIZE One of "TINY", "SMALL", "MEDBOLD", "LARGE", "GIANT".
INT An integer.
INT_A An array of integers.
PERCENT An integer x, such that 0 <= x <= 100.
STRING A string.
UCHAR An unsigned char. That is, a small positive integer.

* Note that types are NOT enforced by type check - that means that you don't have to pass a Python integer to an integer option: an object with an __int__ method will do. Same goes for string options and objects with a __str__ or __repr__ method, etc.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/style004075500017500001750000000000000777443323200145425ustar00aldoaldopygdchart2alpha2/doc/style/style.css010064400017500001750000000006620777443323200164740ustar00aldoaldo BODY { font-family: verdana,arial,helvetica,sans-serif; font-size:medium; color: #333333; } CODE { font-size: medium; color: blue;} code.TEMPLATE { color: blue; } code.OUTPUT { color: green; } A:link { text-decoration:none; color: #6666aa; } A:visited { text-decoration:none; color: #6666aa; } A:active { text-decoration:none; color: #6666aa; } A:hover { text-decoration; color:#FF0000 } pygdchart2alpha2/doc/images004075500017500001750000000000000777443323200146475ustar00aldoaldopygdchart2alpha2/doc/images/simple.png010064400017500001750000000031500777443323200167210ustar00aldoaldoPNG  IHDRzG$PLTE 22f%Z n4IDATxKr0Ql$EQT#>66zG5n$c4?=n\(9^\B U֑Pj%?iڞ>i}455VU=A5}=Le%!} !iuj7h}z5R }, =}֥vu=˩ _5FY<}w?95M^H^XeeK eKeeK o3^}B(Dӟ57ܹ^o+ҏ\;(.;s҉z>@s傤ӥu?ѝ N_#ĝ˝(*}:\}u z>d~5Ў3 >.wGw 6]Ԧ r6.wCn|є]t.vz;zxab$.O(wңKr]LsPz.]/ϑ.\$wSv?Ȥʔكw{آO1:>8c1%xwAUCG<cOgKinTr]Pyk3F kwK`OSQj>]2pg7]?w 75 . #:fw[YkފF.<.m ']p 4s҅]Ty4s.vy>I͜0]]ZvUt|sq .x|莠߁yx|CtJJ%f|Gcۉc)Iּ5ƕ=qǿURt*xsr#t'h{k[%%݅"Zk"nxwQH/t 5^|@W4"'&hmZvuV&쫬Bgv2ŋs|܅.3Ž.VBzү)*M:IOWiСLzҠC쵉/0ʴ?Ê zM/gKq.]rz]jb/b?b/H?M^n (:rPz}1wqFuU|^׵qmZd:8koE=]~hZǖC^gϊyxeyxe摻hAovkMN,](/Dӏtݢ]8?žF~#zZ¦!_"'JkܸW&u=vL¢!_"'I݅E7o h9`+.L_ %_!zZU#bv-Ӥ[!{b>GwO^_11vFP]u3@yD04ˆ2A9vN#f^hytt;!k9"au4Ï%#z\4"zSn~c#̸ۥ xᅠHgeNTx#}l8[5?5?]t4zVZOp/TI͞IENDB`pygdchart2alpha2/doc/images/area.png010064400017500001750000000024450777443323200163460ustar00aldoaldoPNG  IHDR PLTEIDATx;6PQ)@jhhYJ)#e&,ay?ymIt1y,;хm$Uɞ^M|%#bO}wxEF oEA2>}Bbr1SEz^%H=?=`^˥?! [dyLdSwDG|]1 ?b~j]=>ೊ"篌s$PMG~?<@= yf!/{Gc|W?ټl~ gT/3"__o_x8XT8\~q~I2ܞ7m<0oO+~y>Esq~&ؿM'?d{~xguzS]_7^L/ݾYz^?gX TK/x?{7_{ }Ugk/?;}b۳ߏ7V\{??n/+ȇgs_ &omN_ |)`x4~S/~G9C/0U sIK^?qޘ_Z5?VoE.,T o?Du~:iCۏȟ>{+!% .վ&c՗߱VU~VS7ޓ|wzmn܊nxջ("NV׆z ysOIENDB`pygdchart2alpha2/doc/images/area3D.png010064400017500001750000000035150777443323200165340ustar00aldoaldoPNG  IHDRzGPLTE%Z $-IDATx (\dgZ_ P?Z2= _1ݍTSGoKժd7`e|VzL.b{Z^Pd]{nW1S6h ".IWuI‡DKU7)A 韴ѾklC ]xv5buZ1!&ө3YԑC 3^}oEN)=?!>=u}CvtudŖq<5nJyd|DF/#E]Zbgˢ.,OF]udeQ&~⥤&. u)TFOL„NՅMwG]ڸnQ6tg%KIo¥ۉyt t7%ۨ+A|A] n|_.]?\b.}5)sh/;&62[iM>H]`hsV6  m2y.B%ћ.vuQtx<hI_kO7;N3׿N9=ftPPGM#fyM'+WI]OL8O M~͹h:3cݬ]WDҰ/COt7]@!]uez/C5.)\vV2tUqe\dM7_LsVŪL .ouqoקӖKLOO~\7y^bzy&K~mA.t7CO:yMkLIş@= ɤ+%Fw8h<]PS) 0Zp@QWX>0Nx`99?x/ِȡ~_`~7KG 1 2IEmOw䶻k93~hL3oI_?&sdJSoy?1rܹX={J5ySɝI%\rgIENDB`pygdchart2alpha2/doc/images/bar.png010064400017500001750000000020130777443323200161710ustar00aldoaldoPNG  IHDRzGPLTE22%']IDATxKr0 Lz;z3]GdZ YX>~[GO&)9!$tcd?ŝ>;&&epf$kPVF7э~:O/}<}}]X+M{+Q-kHᭈkZF? =tX령XH "F?ݲ s_T.2u+莡DJta?Oq̔(rlu‰""C(: z>ODEMW쯂-,^D;2LZ~^ksȈW=ٿC6ʳtl;߼]|.2r2mFNBY7##' my\s;˟[EGJw,=*z].nn3}*1)uAo&YSD/}uuK"NUev[~Tv計=oEk} FK~| hVYrFN9Pzו"F7:l;aI/ 4ssIJ_v/fBEnttv? Aw]3-1эnӡ--qOoߏ` ƇN;"vu2MUDYK̘Ű.E%xݏ~|U>ZoVLSjEVA+Zq۵tq>"7M_y#$|mljO:8dӧ꽜ս޵LL].w`SǎUre^V޶je2 MI}KOVx_:Bҡ>` |VnIENDB`pygdchart2alpha2/doc/images/bar3D.png010064400017500001750000000030160777443323200163640ustar00aldoaldoPNG  IHDRzG$PLTE 22f%Z n4IDATxKr0Ql$EQT#>66[ V'.[E0F//3J/K|I}hGHԺC8ZThC#YRpEˤkI"ѵ$]QZx~#O B$ԯa}"} ^JWu{^tbҝRӵ>>Q{^t^EQvÉS}'mEOgv|}sltMW&.jڀ`}]/wQ8iE19H=]]HQH'G (=2.\8$wҵ^LrH:hwL:L=x]~:чqwTW4#k=s8]k{N;1Y{vDu^;oF zU.(Qvm@sTt _2N+]FFuxf !WOqKq+.m /]Cv ͻys.v~>I0]#ap~FU}s@.+]y=mq~ =AѾ!Ja@!Ưiw$=>ڗґ`6}E$=eAqӡjURto_Fky6N[%% U Zk"xwQH/t W3* ;D]MХu&aVg+m¼*tfw?F*=]:wL]35z wqo(g.[~Ps”ӓU}v }v@ym.t]@鎻ӭ[0ӭ(k]'IdXlcgQDtRwKw"κs+s+{摻]]4fG }I4}O߸+Gۈ~!}DOK]3D@KDBD\[Dt4.r=Ӎ]83D@KDB$铻p-R! ]L܅M?C DD+DO+ԈQx4mxہ4 kO_=5Z$?t\ Ěf&e# KlN+l}kg}v`-tjvtt;!vh>j+s`EY׭V##:^kڳ:ߢs9LWǧN<,COبFj4f7f>H7ڝ̏C?:ZpW}$') IENDB`pygdchart2alpha2/doc/images/float.png010064400017500001750000000021740777443323200165420ustar00aldoaldoPNG  IHDRzG!PLTE22%` l`n[IDATxQ Cվ7حB e[+͒1m,w !3%Xuv2toJ=HKٍntF8%&rIɏMTz/пu}*Y~,M^77F7чыPz1M"/?79w?ȪV ({B]NחF7э> *hc=s1;[* ;/;6Pe{0@Uh[!t鎷[ z5:3-?@JNO7šzZ=2C-PKMy\ywsVn`Lf̴ӏ8-Zc-hq[@]:aZ\q8L?JnNE<ɵHj=r=>,+cOWz}ׯ"=~KKL\p\ CXöitF#Α?/u_߶Qur*J+CitFFBd594IdU) P] WG/><F7эQ8Nr@ӷ{ 5Vf+@[i5"vm5˯J}&NE|y'YBF]Kr"Q:4ZbWyH2w {*izmweaeйO>hwY,+:-MFX8 tKNe$md^OlT)É4LA1ԤO:cMXwBr1ڦIENDB`pygdchart2alpha2/doc/images/float3D.png010064400017500001750000000036400777443323200167300ustar00aldoaldoPNG  IHDR2?K ޾-ut82?}n t ?zgjW;V6Y}GJdqWװ5/겱j)-k E[I; ƠKiXF0/a=^M,zd::G9:,G&Ga95}+IUYdd`GWe0EWeAWe蛋^" |vɆ@i|zAAn }9g\ϫ^UqWa}_BOnUiXFG&qt6 GwtG7.vI4&qi$UnY_SK#@%0*zKã#t\ƥa1r#~ͥQr%~ѥaqr'9Nw^. 9JC=v(^AHSEѩ;^E+ s^> s4O}NT$z1 x8Ǡ1DzǮA^\'@TS"OBà A5r j* зO۞<ޖ7"XfEtN KNi9A]Ȟ s4.{蘬 <`@jG҄|ҀT. BnZȍOy%7. Nn $'\ :XP.7JvQ{i[B/Vc˓}&\UE zˣZ]У %+9ƘDo|5 :k؂5ٿJT :{hBaP)c:U?ܠCGu-AF *5t\]tʠB'̪ *%ߔTA`Rhކ.58]RhB?Gѻz0z`msi=\"P%uW"ӣSO q%A.9DtpsabkS9{szʱҬj>[Ydy5Kjo.-mz\fؖ?규Gr)( 7G/~\M }yy2ڀlemםM8]ƀu$X3%ksUD=}L1_M1IENDB`pygdchart2alpha2/doc/images/hlc.png010064400017500001750000000024440777443323200162030ustar00aldoaldoPNG  IHDR PLTE IDATx=6`RbF@JbV9ĞB*Hj] {ԩg;eO6]?c_| gLycϘ~3"Z'WfN'giFz =X{tb {+ď|?g{ک z|}Y||Əv16ѥ?"K@KiaOq~4!3_Eop}^'y_"[? `<Ꙏ?"wc~_}/[g~ܑG܏gCğBoۋh8~ƚkyՍŵ=v{|l%>."c%p!=T"=!aϓ<*ɋ))b?W WO{OQi3ɱ͟}IEȏW z?{o7^? ^{%ͶwpTg'gv_~m=gO8EWϯ?$7/o{K/SFy&㟿  >~1e7yBw?? w?׎s9!!b}Tsu0YUX¼6[WlNoqo*M{ҙɶ/ם}MAJ?CeσuUPWw/5AIk;(́'2uSg^@;[?[i[QSaI:դ ꋏ76,X"l=ԷT֭*F7o[;2Ҋkml(KX2ʬwIENDB`pygdchart2alpha2/doc/images/hlc3D.png010064400017500001750000000040360777443323200163710ustar00aldoaldoPNG  IHDRzGPLTE%Z $-IDATx v:ѱmrY@z*_/, !iy-Fq]cwnNoΡq}xҕ翖~Z+8fȤ92/=tC ?)Z3 ?"xL9x7r >Si?~ FNL?޻/&;<4]Io S_ZPG^>F);G"Z?8)8>C.0]~GWo020]EߊLVtaS8" .o.x? .&o.mkS̴t9FŬ 52=.f]a@]Luus>Bcщ5CL]8:1I=4-=6[׾o. /-lO_Qأ.Vt/D{=bM&M.5/1uЭEHtQxezոK#uAJ晃J׾Jۖn2{U:REE{M7r}\'kAr*Uu.8Χ^suՅ%帙V*v;Uo)tWY]IgORZ]蔇>>0=(}5 Qu)c6JCz.bY-I:;'/t?ׯ]l9r}} 먺0a?ӆtu: etwOVttw 'c.򄢣DQ.-|l~GoXo Y3-?ՅM:;XbB>5T]ӗia%r^":@W\1}?|:IW"]"ݹ=g2PyE{V6arCӋ4Z&Wa v..t/5aekN.>&İ'<6daO2JRKf"7\ҧ:H:Z5=i}mrzt/痹=+O| zތ)ȭq?^q̩jt3n;q+lw&ݏ;EC᤻ӑnK/vb )z"Jm=h]9]D. ]jLoo-̤*c+I-ݬ]Ԣ,uQv{O@?9qѿ0}C~/[yj&N5BwpT=뾋bJ)}j=Yn/b/s"f'|XS?&e]Gδt@Ol ߯vKc聩юڠ9Ih@j:`d0ۛ1p@Y8Ny b:ͺGOz㞒p˽P`S'%!=C!FAN{Smwk\s-2}\a?P{IG52ѥr4߬'M-}hi; A S3W c 7(UIENDB`pygdchart2alpha2/doc/images/gdmodule-0.42.tar.gz010064400017500001750000001333340777443323200202420ustar00aldoaldoi>gdmodule-0.42.taroovgk;8OFȉ'(~7)b[n)yWɿ~@V7mllr܉'2Iu|9I"}>4D;Ip`yF|S>snGbOLd Е3'l_ .Q`IKā& "x9JoPmHCl˱ DF$cg n~q[o.0PD3J] qo rm!a:#8h'"wAm/saD Wٍx&<8 g5s|䏦)P0 `mhXŁX13q|f>،Ϟ2[j0~a 1OTL"ad>A@k|q1`ϖc>8 X*I\AOvFƀo|T"ȉLDDT_x4I\1nZWjk e M2i0PQ P7hj )u@S*}XwE׉T$ɒƨ@t#FG-jևztOk#Dҋb\á8CWB#2 y?qE]x8^ʀ-.eRHKA BobIݯ@F`Nӏm:zPQO] M0!x|47gvR pmm0uw|A{(&BDb$ V'7!jO4>gG\l? K=FdRz,pdq (AD1A3IA۰91kL@e ꊢ@_:F)VtYÁ"q'fޠ leh1 Rb+Y{d2RIjn ¿֒ҽsҽۊvjۤڮzߠ3i.gh> K3T-TTQ$a֡Մ Mf7uu8V-' w> 7WoTw5AFC#7QT.` g8ȯLy68y!e6r[*ṮSL5|b?* JYYLMj #WtOJ6V/_9^ysSxf@:X*ЮNE-`;rO}R}'ʙ} ĕg/`+WS*\'b £ iB G68,H`]Wcf)"^E|o!vQ##4?WUU% dy% _.rF"t,=ءr|+!Xu \kzr'*YqAG199pRl 0<,+Dk"22׭ȶ4 Z]H5=Шap-uoIAsÉ̑Q\!YʱN E_Qvrn@P'D&A`, ~M'ȏ *C$/2<@n7~q2%2*pnk4T&-)gH )DbK=͡, ˨ `t :E<,֡Ɏ/9tT532FeY -5uR"_Urg~a'XNTo~]r<ǧĩee=0,b dWjf apH)X 7n,hsJ5T4k+]sG׃jE4˻,huXN ][)I\ 5Br'sb&G5L&$2Xf/8eU*h瑇mƎjn&M{.U]SB+Q\@$.Tְ2a 3 @Y䪮TE=ho .8 BL?7PUW'<ލ00X3ޢy\E#C'٤ ]j WKz!mZU\g3*:_n(oWb,1 A+TbTߕ>;(HjͰM(5.ܥ1KM7; c5{2>"LLM@lnVxi,^Bɛr-q{Ŋd{= UU*0!Yia)@ #>huwUpcBقs-/rT-v& )A0  .jk/c\9N&w ."GުHɼe쭆[{g- IK-&+ q%ehaHyU[8ILʨ8dεp!E&.Ѭr e!k>X]7%O7,8Ppwa56R_ )(/AB|'ô ̬ܳ/G7buRhCGYZ `B ̣4•VF%j o˧UipuעƤ1-åe`犑W:8 ]WCΚ j>Jqkf0YۅlPja,D]U]{웆=U|ӈլ1B6.X83rlDzB4%&Er]^6.[_}c95YBqĞWxMW^*ggSjahf;Rts; U*>erˢ+ޙF&401~9/DxZ2uV״Tf%V,.“ZHk7yA4hm24ڎkeljt'pUZ&1UzT8K]A_&iPRJ WnC"L)]ku_B&"fă4"aπAq2)*\GXR>%bbXO10o>נcTGTIZ)\z{q5*0 n2Y?yq&}9i㦨/ Y% U~Vg\_:Uӛxۂ K۠ȍŻ˓W}?x?]yu!xI~*^ҩd:իt ^¶F)a;8M)vvW--cڀp?p>RAn5;V[Ո5R?ri6HN`Q7߬zNA㡕 3At6G0cc~$ OmZ0%!>GYM^ 9JA Z\ǜw&a.R4^mrٴo.O>Q* @M{0]A;xw~xt~Q?xd^o=|"ͿXޫv۶>ߢ͉V`QM/ȀvYe$9!VQUfoC']E!L{]g{Y=im|p~QtAe5ybz]2,8Xf͎0:i0Vu$i1IFnșx`x /%l,64/V7k;r54$4t-SɈQB^DNYoˣóN}8R6w+Q'`p1weԨ2. _3{L>R>_{SDyh+BxȐ?!Z~А}Ps}S|C~td" Z|)cقWW|L}?Osko?k?zn:|/=~ͧ_c|e꒮.g@ZP! ݂v7"x+cR?aJ{䎢6z,uƮ 5zH&ΗVӝXӽ\V3~EI,UH5>sv$!jUX][dkW̰ VafaʀC BA#5K{ cu[k +*<[ħxH8%UX"wZ٪R:"[kݵukuwy_+rf-ujogҊқif}} *t W_Эz &U'䖟(|9W</zg//Q'1cͧ}{(' &6iEq}٣kW@?5LJ;F`.EQlDuN ,~(GzU0PJ;p',Q*xK[Ku?I=̘WG$OA t ডMy=W C?),RvؗTYEѡ TsCTw.eSҳmUM+@KQ]u9Ki0 rV% M !ЀpJ7 ˗0s$4 ̼sAA15 ~?fy״w wk [ϚOS^QV漢ӼiwzbիbSL-}1WI1CeX}[0M fK8Y)Y/ON~T#7V@w'<mx2C[H[>ׁ} tdqscpX|  0Kk w%4 Yb́\uPN$KTȲbGbKlGNKKQ%V8y)KvH\\$0wuUuuuUuwA(M;/lDJj`攺׎/AMZO3p0mDr"ylY%E9)жAo4HĨjWPX*pT D n-Ԏb h0mwdLLh!GkF`tf*P=i{* RL% ;ӰHe7e& iŔaGU0i0v|e0 yv  +IJNujS`24+j|iLR؛OOpX2sNlLDMs0e2EAK%>yJ͒B͠;qvSg"16/]\)uwKW/޸^lLU:`'`V0 c!cV(ߩ|J؂n@#,,/{VZB%u~۬@ӌM0is3|wڜJN)  p9jn:rϻI,2AIv1o.̯/^e.,ƠKۨ]h,>)0@ z65p@ܒ]UhDp] +bmDQʷ ?=F'`4H]5MGrNÑB@|j oDΨRAv4U~{IՂeF"sV\-ݫ _7IA%&׋4I( A9gp6-+][X{gR! tf--aZ`)q x Af NJ;`A#؉ǵ*\ZV ,p8M&' 7Lq$.̬3p 3qdMyO\t 8PYtoXy>%9o\k р?XJhrm UyOoOfEV4x ^ bgܝK-1Ģ4'|*Yb)ɮvcsȎV<RpK߾>{4u3Q.toa2ymueNb q89`(0;ڮ^ !ql S%'/CȜȩC&n;,mқKoy,!nf>7@e:~|O<wO@GvzND3t+⾝ۙ9SP0, R-vf V,9H:U,)$9x-)RZD)ҦénM}O9q\trP<"6IT}וa_ٯl#\{,6]_.apr,)O Cw3H}5,?d)*iuɒ&y kN<hcHf,` ]G7F0:204!۾}̵I!\GlQ5hͮc2 ;MRuBXZt(I>RQI;R)X$;bgsF$8`N/1a}ScB,铺&,@z'oOG ǚHh^kGPd.'K)2lX&[S/GXBb$qM"$3CTJ@a)@V C`(X0;Q/R(~r? Xu*!`?`o@; 0 hSuGwGbfq(͇AmeuόzZҥ\ҫ-D8%qM{8Qtwat9g %d@)+ RDAx G;9&Iq'N!bܴ[$&'b3+ a`$T$?pshPv #^(W(v^z.SvT.B"ήCΪל*AryɧY%- ?dMW(NCi CZRBfsj v:?9G*ւpe|2Pfs bH4،{`I鈧^As榄OM'͆?Yr"BÇEG£h$1p(B6&W%e W& g;i.sઊ-=ng 3{xdh R#rA#5I9ig4)2&b' Kς0,*\iΖWC(w/G- C;ɕ Y*"YL(o5>hK=KŝK7r*NB F&d^:N<3)u nDr`R4y3Od,w1[,?$ Ӹ,M eoD4;xwG_[-d0}gJ3')Hm/r0M>>+q3=D-P@N4Oxް9c |h&Ϝ Tǃ9L6&R ::\J TQàH@"LlR* 33Ab$]7E+*{ `p2< l AjFN㶬;5n*痡(+LSv#_dp6 Kmn*yg@Z"r[?[D\S${Xwؐ mM`__\>$W9zmuN>ӏ7Xܼumʓʍŕ `nvc+ Ec#:Nĕw!Y6k+ gDD8p/MoNE"h4!ۉK,drSxf0HiY', PN&Uَj?zY~F!H/%1FF&e?9W _܄juZ{{ ~?QE m@w.lVqQY.[e(w_Z؋ܟ+-,F''l^[YKmQ`^-UC^)q.~nJNs*2-aBR&_Kf(29 e,sk+U&˴K1La ~~G5zyۉt =mRQS.GOjPי<Ie61$t ٽx.|d n^Dm+ۡ1$ P8 րP.I]UM6K0EmdenyZgd(CD`8>*B] D3UؼjAS.e@VV7ab)ȧIƈwp$ݷ+^G#1u8|옸 ;M@+>4 z-̅P*Ae n @MLrd<!LJ+vgNn1ski/8TDe1& 0qoo*K=FA43e9ňܔG=6 o҆A_b {:-%Yb~~.*VY%dl;WNYԲ˶jw{)xlAB o?ΤB "d/ \T\XTF!KNh I<JU~iZp#8fa%R/hfwYKdԬޏd G`G|(e2x6B"ދ(=ldf\2x: *t,9c/oHvW4{߅1e v}Q4B[֞ 9JqcEBv( :6[#a+-o]/`~%}e3m4 I Ӂ8K;A 4Yg#>fE+Ō-ւ"u'8\ŒQr>> F L :9G*DQ-a߉ =Qfm҉VFpDKs}J h Qܺ_ s&'`_Fd,`Yf xmXd") 4I$C U?B*HrZqGFM| fC S$t!.DN0엏3̏"kxūz\rQocɌυ:2CO>C.OefMDu4bO)!˾l"c UڤK|$a* F‘p?ѳl!2.񄴇S kvJGk%M'ʙI]\'Zi4 ZPB4!S]7f@*u$D IӦ$ պ z*١ňVjԂxTo1B,EJLuTD@PӾ&)N.#}`lU){RJ^ jJB`rAq$fi/@GE3fQoP5v`B42OCĀOKy $-tki҄N.wQDZrnk&`HecԮX eip,,m%2Vϗhzm2hT֤*'T=+dgVtDߧYԮKK r 7t~)&)DsCi=䬕^&~wK`"CW?Î&l^t{,G-I0;[@-RĎ_d=j^Uq[<Ϋ{2X$y! /e uRn$;UwgL< ~>rٶa(')dܶ+.r ~">],eSn@`6ZFpOFJT1ga=M&)"(RFj\1}}S:!s%/E1̂}06Bn}GV`o-`^0?TZWS&[.YX2?LR0ijΨf6 MuP6?8R k +$͓")VMd>J. .R8fpyBӒEB]0ۅCN+^xBPK!QڂQ.\ x$_"=$F2+R$sn'ݶ`rP623k`!9١Q\#kWW. gxF3062=;gccCc#~`hdxDK{Dt1'z2v$v w4!nk/ڷ&n"p @H'v,XqylB  Wھ/1~~"Qx= G㧳Ý[;>`G`l3HR3finy)%cA5wA`,c[Z6qن11f!g=.nvǸ&= AOv R^@I͖$`c0wV\9<;80#ÕK_9:]8<w8 )Jer "'OJ8a$9Шljh*E JY 5GVBDze*40BwJdAsiAONE٦F8ё 2{hY^HC,2Pd%gmζD4,mA^8l7$ xIеN"]n nNax0PvbUctPP^#yӭVyZwr$g=GݔKiÚ NVxZ,]%8 x_3.b@ܹke$i } @1' 0KՓ%$߁848*]snԗأ[`ƂE) # #r uu/ LM]qWMh M9DaP +e(dZLW03v"-tdyZNLJeꝠWt}8ێEȞXO}/w2vH+jEn%ij*(ȡzlqn:WO7KWnS65Fn]GS& N nMNdG71W+P1Mw/ ux5;ŴS3LBSO\j N J_$p`"M5 4Ûwq&(@CG< Bw3ٱ:q{mQޖ} dG Au'$FVJKHǑdAѤƪ"/{ X$>҄ Ӂ#Ь{H,»?TpncǭLd07:`z Sj]N`xhh0|{(?"_%xAOWmT V>Efa/onnΐ DwCU |xW{w~^ i_q߃%1||JM\P_ӁXۓcB])TPQ?E7DO>`o|ޕ n>' £НѯVA-~~o8zG5UY' ^~}6ll ofF8?DcuP.ZOL ~ O?Sg?L)3O?Sg߾q+|0,1G‚:$'oIXOBP q!<+ka@BL*G[(%.iL)gӮ|UC.T *PZ5vg_0/ ¯/|U /?[ouiZRb:})~o|`qo!j4\~lߟ7M& nE 2 {%b(h0 fYԉzKFaf=Y:''_Es[Ǿ(XC]uEO>zP5܀ ^XW筷Th,E}EyEj-MhbẌ/,UV}k/*^|5cr1tLBN3#*EyTx`_#N}R v޶dYe ͖s&]J1$Wԍg?VɃ13M?̴镦馏-4}d?Q|zbNޓ'O>U]SFOE`ES8j zHG^808_b8Z[i5;/X/t67#+BɅ.I8^tz~ʍ 4CA"\<H}c&sa0FG9x3_?XusڽGhIźWZee̽릆}z~Yv[yVJz- Uou7~V(13 W¤,DnՒ)Kj,]0z1]2 56sۂyl-Q'I%pHhf $lt Ǻͦs C=,x 9 txb[Ww^ȃ/5_?{V5ԴuTF*\7ܓ+bCyV_KLl}jZc-oy'+DݭjLOs郉iGӿ_vUukVoCuxũ)#GʅGFzZ%#8ba~)eq  @l׷ b*U‡Ϣf42w SQf?6-pro.鳏/kU]s3kOt賿v˯".BBUo3TQW3T['b:'a`=.#XH֌DQsL4Z?o{ԭṶ? _duxׂϴO }ʞپBTw1ښ2j1shuz.+e_^QZ RZjLUl1jyF$!c^-]TLgalS`.xOJw=csk<`˿>7ɽӦ]X9)Q)ݿ}O(eerUo-Tf1f`4,8Yޝ xB! t897/i>/"/9^qlzH5Qqyې>.uV‡fX.Xrve[fc/W'ςV ֬V =Q]fu cgu!\/]h,rƱ[A1ӭsb3hv=qRVϣ< h0^>= %^Whj;Pb2rUVQ傃A$4<\p1بJmɛjEϋZ~?&/~RMB &kkKB@wO-u-:Q#EEDB?ׇuDӛ:ʓg 7ntLwmZU ;~]m%FV\oh׉eQ ~|2.8V`)~qi`J\x?{Z}޹xB齅 3W~cfU\ZC/xwcO5W.EKmvFGsuTKVAo`LV تPr"Hi<)vP U dId!׿k&O-On #]sb\N`CIO7;`hyAP?{XUScSU(UaށQgЉU tI366J_zF kMnoJO" ֏p7Rf/~Y~o5FUszlh}L@s83>NiFf5`6MzYVPozy{)d6tGc.ОsC*o>^pVtK\Ͽ=Ti6޹?ܳҦ;em#tQzØ`=׿@?=5:XL${'{mUn2xLіaqTVLڴ0S5Z[~cY$vLCp"*Ll{w]-j~oC ePzj`Koۇ_ҭjGvWC|K9Aٙ2Z*t4}jS|U{[k A37`jl6UW[D N5:Y3D'̪ffMڰƺL#M_ZOlLk/bmֆ?T4~z卉nll}ҟ>( 胯uA&.,xmuEW :,3w iX 9G㺐Ed.uryT.j@g}abV[y:sҜ&9-^ܹzP#z淟j_mseљ8g\:Qc0~/]'[7EqQ[DŽ; Ell74Ԛ C{Y\b2 n)nNZ 'QfG zY|uzCpwPW[WmGcJ>f}߫ϫŗ[#X/z7mˬ4`ݠvݫIAm@o4g::;hn,r<6#xj11Ӻ Nڜ(Haܤo<\zawYve/5JʪJSKhԋ.΅&/Ue\CebDU I:mQ^gݙiwOy'COl}}&}MrBM[U_WV-nA&A;m6ogQ/H%z`.z}L(MR\&E6{ZŠ7bߘ}'gRpwdj)(/V/7{?;ut;p7vWn {)t}S\Z^8*5=2钪,f8o0̘ ur45l\ĄK W`?^VY!4MզQ%GՁp 5˹8MȆ*AEpZx% +t4Me0K[l;Z #AkFHm&Avޜ7uo}|04+^W_quلC>lg:PeS [?V$QwX%  BYiYY,5kLjADrgܓINPxy>tXA, ^lqJsI=ߙq9^}l,v^N#O &[[7_6~UY|3Ss˿,-3 “NjZK[[kK*sm\Fg̴ˠH!KKI4_/i鬲θʚRH4i@ 0Nfp^dԚ*L =%mi;Ȓ)Xũ2v?,/zѵhpOܸa(+3\&>IU.xmmMUf|{YYyiiYX`M r b[E:OB3$:csww.~w'{euwY4=JaƟy>q_~W^?}4]Ѥ/A _/aBN(h,1K-5%F S+MͦS$TEW:ڠqDJ(yi33a4B{8I*UU]Ut9N9ILXP*9+ \#kfݕ~z~鞙wEC[s9{n ]QҰ6s3nKS/;\7^T{I 釆˿;_/vnVvk#u lVu_!Ft'K|Y Oee*C'+QTPPJ:ZOUrʃ媴r&;{zOU8`hX8E*)j>k3/jXm{3/}5'՗4p˶n?`'f*&_P:zݛS&OQɪ{'X߱ S^YGjǟh5V:WnMjn];}?)^7hSe9 g@F<ᬌ<7kk阞Ʌ{bOF<{a u DoҁGO?bO>&r|'xi60/).*d5M  2p c)WdSCe '':kV|g׭ 5Iy|xWwځszsá0jB~FUS!̵c''ݰE1.>qG L=ͦAViy~͜RpA^n41z֠B"' lJmMbRߚVOu]qAu_kzpu-q+%g<%yubj,O5Q2? 9+}5?P{+GBu"_81Ux8qʡkBz?a;/yT% lś;?~el.Z# <|<9'(;uM><=OŜ/?l5l`W?1Zםu3GOj Cy5groypǗ׾Е?wL70v2-d<0`RG#'4` |'GZ'rO}gu;m׾7s#ߑt7vbcl_l,U}42pa0rJb0|p#ްwč7=8b$k+{_[:>4z$__5y2M[}߿i|iPT/U).N$"'+W$%0)ω݆{^ɋ9s[K%V1kܓϬ oYUsMg5R9Om&rߞy{?ks.VKK96TNN ( bu@m  euhV;,@q+~\!zOUuX84z>ћ3xsuKoh"h(yg?e;.m~C^H%~DzݒTi &r@V4| v,g6x"B8qz[n8!?{0ܬs|罇\v-KTt?rI_|pyF^#ĬX)DzXCgdT>\% ,_Nr@lބIN޶/ywb;׆FE˞{/;7ޛsw!}ഋFV?r9yع"9r$UQ--)g7#=dFB0#(* [mnF3Q'ڌ,ٯrD㧜_V5 ?{wE[o&Sh{R9T<'OU:ǥ{0ʤW:l[ x-?iJkjKӏ{nkߒ7=ԧZ!$ܦ]"PqQ);y Ⲍp(. %bCA;0'w8XN ￉z `osO**%Ⱦk=K+g[-H?ν *}?PJh?éH <6*JgX#<M2s#++}+宜 uwK]gޕf  df3ORYM zs<3= }i{)Lz}D* $=6t!'q] 6_K HpIa~";Wsq煩nIY9ќ oܜhv$ɰFBYP4eym+ȁ5$/v0Sk:[V*'V{/;^,y{;VY.DcNch?4䏇K(q S#tioP(y]7v*[*ǞpPAsr!۳}xL[~ܓJ< +8oRBT $.?`ֆyp$#m]=anCC'oT:i=O5=SMz3g{@}<3[&O퟾_Y~ws'}[HՇTB!ӓBhf='r7)Ht< h랅ѾC߶vy[=s|Kv=?FϏ7vPӇsۋg9ʼnhV&Cc4Pt@;_:Hm8Rl8_m6Uu5o ߗWA>qϽnaEC]ue5g{.8TN{|  +##+ 5͓]e8iv'<۽;{ҟZ+>ˍ}S真 PYuea,{32pve"\MxO,% C}1ju(oSMx/#'5Gj?}PA/˩#]77͜k_\vC[OyU<K KSlk&fepܽ"wYP)txǶ[?tmmÞXo4z;FU|PVjlXrX3&:b\vn{蘏qƳ<=}y]N0& ͫ< 7m'9}?L%= yħ:>J>y]G;#مWzj=oͽuu+C2T;/NujO\I^SY3KJKJJV+ʼnxH,rP:~);HAMbِtwrȑ#?{(Co)z/L?*Si+ӷ|چ"~v^5{K:g&U5@~"7'uCvKe?)Mہ/h{{<I~PUs5?}Wi3=ggPS6Oqg\ ֞t#UxK_ߝ F`_8zbzFrrh2bPf;amq+ _;i_/'XIVf\zC]qSE7Gk<%g֓_[~_gǖi$-Se猒ɌdF< s9MS$ڛT<8qMӖfn~ʕ+6y9~?rB +m:(q8!С:N_#Iɪ )gqr>8Q}n8N+w.)Sw+~RU)J9$8G~8sg՜T]?;N' 9N7qoqJcn=8:NtR[B~Tͳz)KߵTr ry͎sY38)?i9ϝqI"gYq&Oޯ_hK{u|yQ"߷[}tn0my_ὗwFqݛl{stg‡!߫uys.%-9y~ pIqݴ?;:|r',#?_,g{gK7>T|"p }"pnϣd,Z~_ܨo<[l)u#{~ws9eOIgisY\r_&k;Io徕٩;vm_бg8al'4Fgܝ Ǜ(,/uʜr=#NSI Wاy4:MNbrsgrӜ'NOu39(&Δ38Μ3,8Β8Κl`i[ζ:g9g;OqΑy>풫ua ..Mv |G'ns/'zɯ_;8Fգp̵o:[؉^KQ&*Y0FKak׽6$7{;L(M}s滗 XeX_eM}p? +*A>QLu^lP|ߌNءNR[!~oq6r ar/{F8N(<?~H8S̼!ݏ%_sV7UqMo_7MVnp4u= 85: Fc7\ MyK}<XnB2XG5ic\@raRLuaؠFIlvU1zo: 8bw9] w+>{o>a 8 ]CrG5qI`BI=8i9pF}A8y$.%_v7« \Öhp;&d ii(Q06DwiM Ʊ M”4B]}#,Wa%Cv(\d 7-Msa3: XL.v(e~ю78!u J.<*(ۺ1|S[A^.% #ؾb҆`e0ioa,lpWasmwPqXva{M=;aX{꛰zFV!%[LSؠp#-o=abZjvC;.7Kad8 kXo #û(zM*$3J=ؤ,+;WrMe\w702 r r= a._X]nt6Br,D>GX<"|6?;`57 kS=GL 7E`­`bRv ] w+CJSd DpTyCj9`q}9PUD%M/Az?a69 F->c_q(z-pި폅鿂EXB%Ql XTGXpH- - w(M.؃o ݫ8CH#ꌤ GqsyFqJ1 (h-a1₸(.)ky^WN6~}))kow){ ۻ;_aĸ m?$y<b4bK ;|*kbŰ9 آ6]P./-T-}48 aמ0BsRcz?N)<̦/KYVWrrĐ vͯۡfh9oҗ[)t&ܗ$֕*bMvTC-w)-I.XZAlԶ3E6]P.[EVW>z\0 *WC{r5N*|TR̴3,,;yqA\~Žb~M"=6֒=NK4HSac`.;Ga2u~nJ? "XSҸSo$IXis +*<8?O7&j\ݮVoJߩgv)ܭp|N\\r8B-̓W1% 8^QqJn9fxY3$EˮWѦdG-l5N].\AK%aH([NU@H~Xx+A`$h,܈}%g`3.YLJ%ni4Z@_# dx5u q!g spY]7m&p (;SIzߗ $e߁QddLw5UL݅e`9Bi|ڸ,I$5.K" Q$vhlP|k6a?IlQL+֕sV}%'_~f[YaŌS'p N(yS`}\:WLMGX}*G_YL-Z;-|6Z+o19pءzN <+ ^z<Cg<$!8%!;ᤵذqJӒƌb8ˈ5[̼8(~Y\QxV(OmxҾn!&|a]#s` ?$ ͛Gr=*W|$l1mv^lP|#G_3abZZfu6v(}٥p=|"_k> ![pV:_H}Cb8Ӵ HF8 3/. |$l\gWݯ5,5Z7i#l{pd#Kzd{ S0FNHٮ2zdZX[ hO~L ab- p#r.@`bZW톥gVi _qV@s#Qzdx!K-@D)O>κ9 ᢸzΊ«p [-0nІ - _wT]"€s 2vN cnum1WXrw Z]g;C!Ҿ(z ֋ oZ 5 Ŵu.T],}٥p=BtaG^B!4UF*D#5pvqzB4bIZB4bR4U!Ʌn S̼@[TF~=( p\ 7W!yB4bivISF~ u0H},҈\Ehk0:G[]V"ږCF#Eh~[ZaؠyEhN [&J٩'t)ܭpه]"͏!Za$[-?# EH?F(B?6*)BQfrI1JRi"wFE"GF~zbj+ƞdljb1 cȼQ*yba%V]=ȹ{Z$_Ybc ={1ƞ-{l;SR[ǰ{#U Wfo5XTS)vipZYl/ Oc)OSCv1MW̼ g1l\Ref)V^|==pnn1O,A#aF:%jӿ,oqW?`ÃړµԈz| oNKa;V|SD3V.J3`?W䍃ʉID=c 2Scτ8IѬq߲9"l1>@ r6.ɫzšJM|j%ڦ,A]8WT?H`O1٦ &VHR$`ԦR=XZJW^lP|VRqآJsl;SR[a".O[T;4J%pO9 Ǒ^)ҶRORKqJ /EkpN1H%_3W^6 JR$oRʐa 2d~2m'WAB)ieN"+mfSDy̎`RehVsIsFنMzBslQL.v(e؃hOͻ.SX !F[eH)ÆSjZPAߗa5& ++KJHn*ZA&ܤ@m d%lȬ֑ ;[0BTIKy͏ 4ƵXf%p^<V++LkIۛFD%uK%ڪD% WV)~yV"AGSl)|JdG8i0اqFyE敚ɪV؎MJmwjU!àkcǬ <`'~`6CDUHg^^]8RlXtyr(vfe"#Ue|UQ{uUؒmWQvbl 9Xg*ATQ7z*$c{,~nZ#BJokFUCm-nF7¨om+ &}XO`>~i5r,ҪBXJAU#{K5uApbZ5=AȲ{6kE1zKVVͿJߩgv)ܭp9CpP9B2T[(vXM-3*A߮,Xn]7F–m|j$lhkz${̤K$|͛2ޒNO[O)t_8XB m=ֵqM ҶJZr,kSK{hk5DWIe딊gVa\!†km~;zh+5H68F;Y[I'0.0N)~^]%53XC~nPe=gEXk % jA5p:Xø~<k*|m#<}5\\?U]EGw|ZXuբ~_]Phfjȯ`5-afjȃe߈֢ofZZh1]i]PN=KnmQK-Mikp]G3jΏ[b\=K)yː #ۀd ]: gf=E16ؠ9ڴ$ i+otc+ ߞ<.Bj6Y~q=B)gYʸeZeXxz$wp]7 ]Jڨ=C2t/ax#<Fi0QI#<&Ӽ<,Ј<a!y.bO#5¤E5jsVh?ѝהf]۠UlD6o=| FiB0G4ie =oc&xL&|Մ `rXDՄ? KG`XN砭e4O ф-\G?ۄ o+kB/jh1Ioф9c =ZhB}Mp@Mr8BhBQ<&y&5M 5MҬK6-f 6M" mZe=g޿ m^hiЦpCۤ>6͗Aۥ$ m~Ysa͆foX_`n0L[hCfE،6`1kFT2lmznFkjmڽ«04m6klf;mHzmڟG/fͷÈk{l?kqvK%ntm`{?mbjD ڜ-hFJ_/[gl:c ڴzf ´;ahA_hDZ؂6knZЦaBIziR4ZkA&Gb}-hpՂ6-k+i\M|<y-h$~[V'HkE߆WaSZڗa>mE_BݭvVKa ˱VtsXIkj3.F=f5E1U[тm>?ZO V'sሻSr>G)Lۺ>}:s*7[s"ɯo?df;awnF&s6? 6Z6)tEzrfkJǵQ iڐðf9N(ƪmZ!)ثOiewPaPmH4ܘ38M(g{iW塵Ck.]Zك~AQΛOBkE{h*>FZJ=𒸬+UܐL6/zmpA;H9м^|ԏ0ދ`4zK oסZ"Lڬu/2E.#mZbsм^,}',O+\ W2R襍 jZ^$o1V׮ o?E fw(o]PN=Kn{^ϰWk=ZE !,Vr8 8~1:լu/6kݫY^Zbg$pN1\p mֺWֽpqM/V|nO6XWwf{5k݇6o%0LC;ݧ>L>8GKY^ k̗C߶uz.,%+aNzQL-5=>7*ܤ'4ӖGiU>;SR[a;MRݯL=Og1pXI1~>Wp\Px}?h}4fm8yqF<\Re=gE_eާ}˸Ї>rzo;oga_6;H:s`n=0~LgdO0ύۮt ~Z!,JyX5,c$ۏjGkcZQLuњA񍔺] mI?Z[eJߩt)ܭpke饽G~j\?4ښQ?>8 G)q)p m&#pm?-yHJ6G3/,0G%_3W[[eGupC2ԧmvkmŏ86AFUh0By;QW`P05:-hsSŴThRX QX`PAۍ<6-N tڴFFhs([WN=Knm5 Gf@{`ԋ ;O PcfКw] oKPM9K x;@k~f-UtF7Lզ>e>ƀg'.Dk =0- Z[66HA;蚟dmhNz'wcA>XΎ?bFڅ̭vn Dk*Ƞmњغ ZH1h+F1n:l;SR[K<olhh=GˡAͶ 8?=.9L(ܖwOu0i ?D Q? _>t7D=~ͯBZ!XL;?6K`{,K;,Һ\n;u!i1n;6bdn;6wabZ];wFo;6Jߩgv)ܭp*Qi!i=C:/?u!i%Mv2r4p MÄxCh8iPHJbMKr}mk*ݺdMr6|!%Ͱ5mm.@[ֺ0us醵by9L$upy!wƝ2E=\0|+ua,wi16VѦ*lTZFߨgں0zpT؆2ah);.{;k3aO kEcX+Z԰V41ZahPf55-~ S+M>e=ZĈ>[J!gmХp=b/ZNI)y)y)pXIᡥ1F)N!$Sf̒B&Ha3OM‹)N#{$g-+)td٠oM,pJgSXI+RXQ4v3#QtQ4KE?veT6suF{zA*Ƒ0_e9 8rSqj#8rV(r ,'t*d{8K|EO {;L ;aJe0 ''8~ gY$<,fbB&tk V 7U- { D:pAw ڬFٓbsm>8lR@[}0rRs#q&),^P5)/V|9m$rVR&÷aʵQEv'5\XG>rkQqOQF{,}Y*(n^]hǠݮ0unֹi0unFoIa] [SD8nzNi0u{n)i)i)i)i)i)i)i)i)i)i)i)iشNON++3}eFc3}eFAV0KAVg\Xg `1ڙAV_tF7!-3eF+3eF#(3eF#(3eFvݎ2Qfz8#hFvݎ2Qft;ʌnGG4#hFvݎ2 ,;EV0fufvYhv5΁Ydu1,t EV?%>X[άv ",TGigq\PxdY?geWsYY̼@]EV%_sV^UxMZW>7h7f2I>YdS9!AF9$?K2,&^X =sHv۸Ű{n+shϩCbޑX;fB:Nz틘CbPجkNE ipF9MS<̜kN5,kp]ܠ!-nB9Y<9 >8wo3ѻ#|zy CXHyA{4t^Y.Lw1h^><3z,W6=浧z}nVy;ç[`z`(FÂX./8yveRbAw .9-t0ώ O^blָ(G; W[ү}Տ,YT?~dQȢE#GՏ,/YT?~dQȢE#GՏ,YT?~dQȢE#GՏ,YT?~dQȢE#GՏ,YT?~dQȢE#GՏ,YT?~dQȢE#Gt&k Y- ߦsK50],!IFCK^Hu%\.|N.!(%:[~%hO0]]Dnm̸Dn mux|~aKlV{Wu*)VW˗พ37gYtj vZүko:#U4mJ__Ӹ{iH1{{֨A72Y95vP$^63}R ҆6iamRЪ,n[ [fU(,+ha {3}X;yҽڌ:kaGQMoc[a.cujk!k:󊶓B|u_NuS`)v*ם'GN[huӺ3._-u^ujUpN1xZ[֑0\Qxx߮+[^nu_voܐ!?sC~ 37gnP!?sC~ 37gnܐ!?sC~ 37gnܐ!?sC~ 37gnِ!?sC~ 37gnܐ!?sC~ Ն 37gnqzY)m֦M$fY ބ6u=ӗC Db0OGHmϦf7ؕM$81BbwJtQ&n6OL&Ӽu75Ğgb江M$9(.)KߦM$fyXc$yM$bI[;6u75BVWh0 կa<po6`>BVrX>ӆl!f][Xϳ-d}hCij )[&[H;N9̻/ h ~YYQxUYsו -$c1[qKi[HJKm_à[lSFa,o,>I`'ȧژe[X"#(^Kwٽ;H`t m&hg01˶,H5o{$˽> %_sV^Ux )ml#Alk̲6/uгl#o8;ČvJkF;Hhmu=L$v/0XH}qҏb$f7҂ж ,OV $hwX-M qfvgQqJ6,'mGj;H/KJoggvW5>|n9mѺvG?ƏDz[vua Fݥ}B6sԣ]]$B]bcVvw1vm}bc؍DJo.s]l:87] [{jY4c]]3OEbEqIW5p]qf]v5B=](/{0ffA/`P E0h_!_$2i<`!Rey/+sWOB ' ?@f~  XGD>@ooyOO1A hF(ʴPF[T>x4B<= ++} edfd a~"m (gHI8c!>+?Tn-$!{2Idf l$a/ޑEr{BcҰ=ʲV&C=L>쬬̬`ffVEZ|$6V#bEO4۰ a Z$I KrUQ{}!,+/o Eʛm$`{,aʭ20=d3yvVV̈#Y/,f{N7KEYLF&, prd#p8;d"Bp8˿V:?Mab34y'tH2ɶd2[{d|:cɌEXO8I{T޽XyAde$YzRD쳁QHN$f#ٙ9Hvv"HJAVH$|D#G. eE=ɤCfrr=8Y%'Yhv4'#;;'ːaټ=38ޓ>񞼼哛he{N0HTv4=VE3sr{vvfʋC8g[E{(t4f hFc{9HN,'''7 'X,3'94'\H%rN D"M!r24 eGshp^,7Dc1^ sRgGf5'Da^h),8T ˵PP,eB(H4w= +H$sXa D$h4+ 'V,'{2#QFefϳ30LO7sUxNA{58y~.xs{.\:/?8JNп; 7{n<ŏVw/xB. o y2hr,.~`]rɁ2Gn;)EoE.EwqK4OׇUYX=+=zKo~h=w%tєt|Id{\[:ewӽH~8]\38.;v î$ѣmN~e#obemMgV>6R~{g}nJ=w~oݸOwϤ)t>;jaWr~v=L|:v|5uYvoc%]-fYzl)&}i渖tA_gb!̉o?2X_Ie-uw~WZw֑fاAmYF{mܑjzqvѐ^&:CǟF#tDkB4:PE̷1t2u.9:,{WH eLnD3l+86r^ɇrL^kdrP胯D۠gҫ}{zW* }۪^ԩ=.oH_z= ]%6rtvuޘKj.htLv?7M >t) DBOt0CӕטCE M\9a"4.6wuBNu'[8B)Atꆃ]zjk~/sE$qbz.tr2˃BwMenHutnҝ+GT^7ע]'g*+.5ÞBGCt[WdVH]*  G_Y`O3M߼m&.ml~vˬAL&9-s8=}dۖ2l.St}6՗Wdj\sF]~W(3`-t~.mvҥ63G/K֖ߜ2r>]>Kz@![5݂t -nFg@_n c.RE0A_~}.t+(xwC݉A3 %!kάHt FsZID9SXT]xۢ{s&Lq8O#'GBGG< ʮMvA;2dvO)%m+.hkV!t2n`SS mKW|9?NJ.43224K,3gFq~_ 6-ePyBٗQV[ AuAEa=.zҁDGs0t 5|,>S֎V}NtevΏE]}ߦ.6OE9FaEjgQI]s.hwO~]l'nCBX]lMKօCbO4!(vDg5Ůyvj]ȺY[ ߐ{包4ь鬮Vn]rE>j+BZD V4sp\ܰqoG]0mA_ KW$u}u BS Ia=Qv1tK]0&objvjuaC=mS@]{E|u79.8]ΐfoJ_n蓽0wAotѝ$.x) GhJ$E,զ.WD(=lc =9Φ;#Nz5N;u/t.cB]CzZ]_CO ݨ ~JzZ] M'ZušO3s2x.dwwF^twSjSÉS؟f$Zؖ59.}hNfN\u;=O]ȐZvtU$;<8}R33Ֆ~I Sr}]E}u,xtױ=;Y>rzwԴ< UYyonTZVЩC˰[Eg=|9d-tRD+ stL~a_ g[{`wRh<ݵt[Uz&*àDU _\^啸aen'& ߁nʇT͇M#q.|v t-6N#^o:-t.\};=uA:ߤ!oގCr4btz\,>MӅw?& t]铠|]1{]3VuC*@W=.Asl;:M LKv"E~ҽ.O"zt9wybY./te[]L `~i~f/EÚet\zzKNtuukN-N箻tH \纾CJE"3tm 5O"BWYަytuoB/1:6]no#ctvo~ݝ~t ¾ҭ%t9EJM{qj^CD]'cx溬WC74,SHǫ Tz?GDs3+RL:8QF|.6þ :2˸|+:HC'^.2tLr6S<ѱbub~%ԹCDר,(6>?q>GIm2..װR]CqjecTqw{&ҕNs0? ܐũloI/W6̫ nyFOkqN <Ut|kuQu|q/A'XOriq=NgEʲ$ydLh)2*Òm"]]f2NEEw" {_۝t.]D?I/[Kq<,\ݿQEԮb:'ny _YPC4,x:co^SuŮ;! {];Ir&].6vxoU tbE븅ra|ϓ|ů)jj bUpP<ѣG5阳A=.t1Լj>t<{>8#\^ht ڍeIENDB`pygdchart2alpha2/doc/images/hlcbar.png010064400017500001750000000034060777443323200166670ustar00aldoaldoPNG  IHDRzGPLTEIDATx v*vsݹdP-0NYEE56=;&00l_`*tmP h!`[xd(v x;NgDy-w p黲UڪB?@VqGԥy§xj2scu/tco<WA>_]!nQfM_P=ަs6|S9Wpa .~=,mBt52,̬U#"ElqLQ-h:A~mSuB4Vx1 zOG ttQmhuo!uA]~ξr~78zd|#?X3'RUkN>/ xݞ}>YL=CϜX..3'#=.s =K67srt2%uا*t4׻OUV{U]rqŹ4}oq =81ylk]͹%Lk\s+#j>DkHȚR}o:SiYw}~i =#1NYfwG}M:{=ݼt}!gcfΌTuE-+$gN@ uǝPXV$*aѩuF '_](mx'bi P:^m& [s.}O Gyn↡iPzm`}ϳFoFo t6-1ʤMGě2>}@{Pw ]@u3!lB#,惤;bq JcyUa+du3.onWfl,ٍYWV*S!z5j▖VQ9\pUjOIxQpZuFul-Zfx{WS4:/(o-Fш% :{U ގ9HT#PT5݊:tȺv[$ >յ9|IENDB`pygdchart2alpha2/doc/images/linearea.png010064400017500001750000000045250777443323200172170ustar00aldoaldoPNG  IHDRzGPLTE IDATx z8`u%>izkFnv,gƀaxoƩ}6{gg3L}q>޸?pǏaHvyF_T4Am#GD̋7=N葖mX HM ~FP稾] 1 Pi}ke>H=:T/շ@_3'ݮYGmպ7nH>N=v:}\wꂢvCKu}u4E\|/bU%p[-8MZ.uoi|?{E[GOV3VW}?%K z^5d]t:=\Bh`mhUeN_Bgf7HUIANMGn.W^{e١ӮO^mmq}lBg;ueuAԝ͎߂Eu{N2}7˗mҙ$~up4={_ոdUxT_dE̼^Icݘsjݯm 9a%CnBƸ{u!>ڗ|gcG$)AL*{G+ÅDVK;Au KWCB%GڸK}e^{#oreޤzЀ WO/{(`cM#}YV:3#e#*/<|֍Eb\Fn/Y O";+/k!y=N7zE)j%"]Q^~zM鏋t-*BW5:ėX,2}ރ8,2tv㐥x /'];h>Q.++(3~2]VpyUD~xImcuP۴ꬥi [o_?feh'mdGXEw=/ ?ċO6':5z ?#٣6,I1 ־HdCWB4}DޥX8+հE3N+YokhTYwt[wtHm:eF`iAt/ֱb(aҊu#I{wg}G$wu=[ U:__8*vNWߕys/rG89k_UM_Ox<*?#/V?F߷{)6oL%o4 DLt@3L!lQ^_\yqW{P>oN^l8'oFp/pFDz9zux=>wh@F071^8/b||&<{_ F>{ֻ=i_qz..^pao?_M\u>Wt= zw/f˩w[8&}Ȼ 0g3/|Ѷ=|~^yX?K78=0|߶Cm=L 7ovRzP>;+&bgĹ v~^-xV} 9 y6y=^ͼ@>O_nGxPv 3«g{l|9Cٸv_b6`3(? o`}Cyz,oWA?^v?ٿH7A?ٿ z~/> 'g^<Οg _I:xS1y|,sZ ː7kڋ7o~M_r忘ֿw^ўM73o\`a+]e>_c37?xחgr >!_+{ ~8jg΋8_{} ^Ez`ĻU^_ZH3G.{5&7+tlf's: 8nF?owWy*_%?%󃐯?-PWJoy} R|T-ڏy{Iy}ugګ/p% yuyNJo/~oNů>=fo7UJ{>?E]{pC˔wߏȥ/c;۽:xv|^E*Ozxl)&mx%,{MqieM[ybS?0OmRol; 4(W2;8)C5*K{4+|*JZb(ܟ ' ׿}q>9uk-"x٧h|鹊OOմp<7߇ O|}ѮO-C{)\FS/ⰿi|wsW ոCuC5b}ۢ3ՈPshCr q3}AZmGUIENDB`pygdchart2alpha2/doc/images/line3D.png010064400017500001750000000037160777443323200165560ustar00aldoaldoPNG  IHDRzGPLTEf zIDATx r, x 0imdֿ%5liʓdPb!5k[.[-۶,T Vv78͢DW>\qG];Ny;GևR<(C< %6D1I&]Ct_~U76& }h!^Ct; CzC`)NCLҁltnj1IsDBsݢ=_I_tleratT|k\OGŗ+D|z D|A_x?z!Wy羈Y*"fEM3@6mIOYt۬@|~:6SMt_|u݅K_"mAt>}M}^gՠQ;'wV^fgQzFz?Z.ay m7~sCJo8tKGU.\cn8wt[X)ģѨ T8NǞP9#ܠ۠led:vR]頳 o.;.ݤ<u]ކ@'c~9EyƆt١hإ^ezPt,Xtw݅tq>U4B`6v>F4Ix=:u sE&C#9蛾H7itߡAsT(m¨1M$w|5_a_YuTI ΊLٗ&сrC>VwgUC$9 .|j F ҃̉m0Rcd8tBw3' kDt:!ۡobDp"nJ$з\%NAw=iwF^}1sOv?wݖw&FWG5zLWtq!p EuAֈNtCk4~Хҕqަ J7DzPkĠ8] }cאDWбk (to}}È_!a5设bo&վ.zr08=)uB2Y,U}tҩ5E@$z8+t4Y^.]:q0ʣ;EvRsGOg>]tçN 9 :=Ny묒f3itC{2}5H}Pz4PzA:VˤSF~rhco_aq??!Ytx,;U?LǮ1D;9CQ':>;QC;M7a!O+LyTzm B_ďAwuzL7&7_N;6D!gHO5y CБ*tXG].EMUvȐ_JzFu"m-zFQO.j};bQJQF-]1ʨW]Oަ'O3O<6Eߒޚ[[<Ê}wаGВ 'Z]⧑O# 4.R魆-R 7{A`ɌӐFu)tuߎNÝ;%x0؄FA=S~({aK-2ǥW՞yݱiծoいUלHn9ݷ*4N%9ެqgc;Da3*_>\kK>xR5闁`?%hOIENDB`pygdchart2alpha2/doc/images/linearea3D.png010064400017500001750000000050350777443323200174030ustar00aldoaldoPNG  IHDRzGPLTE q IDATxv(` h{oӽI}7zWY ~ffN['3`18麯 QF2{w#=u|׭l0WC)cq1+溜WH?T?R< L=Vs7çK>sDY5hR~kJ\s|y}Oa7T:~yz`zQuZwttii}]>aza/֢.;a}_8x]2=zg]B{ zud`ؑt3˴O3.]W ]aC~- KToQ]p$xL`L׽*G .DV=Gwb?/{*vJ˲t kF=vuzX]@}w1ϠB.TE ~NMjg_~٥sGaîBG L[lw8dswOe(lHTy]^ "/mt݀vvlWR"G=zwV:޼%4]cnW_|_[MA/cɯ"z}s"a )!R]%v0Z]DuwOw;>suHgGÎ#Et50b}vn8^wu:w YW+m8OO,%BԷO`ˏyXpAO S9N_K>O9ΝnK8^܈|;~u-kYuˉ`CTyA*v'P 靁ER_0v|VTDYf"x;m..tTW;t#EFwn|]~qwVn=#E?%SHSnuoOTݩ:v.ݛdXt/YC_ uR}v'mB' 5W8sܦnGuk"U[h[P.zMu]&vS{; 2ݦ/zHK%> TE tu?P]sJO7o.GT u$.dkݤ^扢u]X]uT }I2=rRϮQ`$.;tE7C}*RޫJ)"}vu"uwj}F^}r]L^Swәǫ 5eݮSozЋ{Bؑ6=b:_u^ӗ>JOQOvFWÎoz|Q='Q=va=W@Ds]= kW~+ԗ0>nUq= }M?nU副ѵʌa7ӻb:xW﹣wszO=!2yV DOkuѥ2}^TY6]|\muċ5AG.HtQ몺 %^9?Z=ߎcR=|}'^뽣O9MF4|vnS{=zR7y͹ѳn'}vuF(.&)G}Wȩ.P=xۯtC'to=Ok5{{ȳz2^{;.x\.ڢ8t}tVzuwNOYiy6?p}3}t5::P=.u?#uINSd^ 8WC ,x).zkF]Љ8vAiͬ]Xf.Vץ&?'$ji#&V Al2 EZWR`Ÿ|s;Q!8Cz>l=:R^/lHw23j s"m@N~X{~G~\Wjc^#owɺ=:Lq]nG2]NA=Rˉ?BfdIENDB`pygdchart2alpha2/doc/images/linebar.png010064400017500001750000000040730777443323200170510ustar00aldoaldoPNG  IHDRzGPLTE22%;IDATxMr(`{<9]^qMf*Wzc =PJc" ^맛|¢KqՓN\dCiM۴N衵B/LⅶI{ɟd%S?c.!*^X Tә :csc21d0luG9ʆer/r<:C?o*~迒?t&!?T)锰FCǿ6Я$痹m/uYel{xNNΫ ~I>iUt G׵aWO~_n?}OP8jaWM'+uVR<0̞R gYU]L14n"z:—͘UOY~Y冝n;:_m:mw ]q6ty*'M5*R6 *:t'ϢR,(荡a7.|:hvѹw _dl]T= .,mnm? 5:m[gE[X%V^6='u+.ze>cJ %Z I; `)twc)(fht>[y0ηr+ZHks@?]Wƒ11uS|tO ~FU%3KG6ꐸ*$&>2mF;O:NmG7X8_"|ncN)>W3'Q~sЃf}ޒܦJ7>]ZwoD輄ϫu܂>rf_w^@]Cz7Cj.yQ8ҧ{diW׃{aϜ ALsy HG.vvZ?sϜTv{D]䞻ꉒ"z {g9czݍoEtUAuUc:Yz7QKyG ;s: xm IPm/q]u='߬m^Um=?5BtO{JsJZ2hy8>  E(C!kytȯ ,U  ʖm,/kۘq-~ÿG=xih}׶N;Q>t~o*C}BOάgetՍ 4.w7y-uv/6jOxWC @ IENDB`pygdchart2alpha2/doc/images/linebar3D.png010064400017500001750000000045130777443323200172370ustar00aldoaldoPNG  IHDRzGPLTE22%?WIDATx;6I8Dv{Y H: +^)_u.oz1"g(yp]xyEQ6c7* +W]tƫu3NKo]h:֢K*|ӽ66pmdw ~Z(Kgc :+Fo,zS4SkRuuŰRfLVpK=޻ސD:T^_=פs`O5G~oO;E?ÎNW38Eq.ޖ~CStÑEi}g6ayp=F?&wS͇|6E1}ЃG;ߏGAߑ반~?Kkι!S[T3T%C nJl?gsyZW<=k :@btf+[S u_] (Z.X(uQYEzT]|t|~:Rxދ*3#J~{x.ŎBrz ag=~סW=<Zu1#]tmbWöL3mt:(U}D?\N;MWfjEKnaTIwanн]#XA\P\O|~΂]0wAf͹NaẞiX9^'ސ7O>+y㮂SEeo߯{dAؖLta gHk_)tpk:-^JTH"w^{˟eۢcywwd5xy~1<͗hwo FO>XI_|=#M9zՍ4$Kwc}{e>ey:Uה.}M]~DK i=#IENDB`pygdchart2alpha2/doc/images/lineline.png010064400017500001750000000050330777443323200172310ustar00aldoaldoPNG  IHDRzGPLTE IDATx ( @zƞ|Nϴ*hUTvg @T- s~+_v,Iְ?IoG7nk5+ĵM3˘kq[K3Mcӧ?Sy>~t\C .o~`~;-㟝~+_)(:}&FzZC_5K[^@Z?2tSgiSVwxOO`UPW7=Q5+PyJ׏Oe^J[c }}DTTVDܵ<;_+m-?,ݽHak]IZoGק 2>z&ti#"&UD_=3A1Eӑ=Nc|*B˼)b )-\|BOw!wӧ #rbDtf{ ) EԻ@GnzDVzuәD/>h\ KOvXqN=F<'Czv53+R3Hn %O*@EW#% tpEƢ:>B__9u,JFFqB}5+"N[92O/,uW9 )t*$JWǤ }Ñ]!Fߗj>s<\e€c10~dEqֻH\V ]]:9a%|xߦO8DW>^Y:OE*Z:^'ȷE[I;Μhk%mfv;IWB* =XC3~]4>R(g81='gJ^%0>t]&lok?.u]L:飚M1"ЇLO!R:'e>md?>u_ +xY|Oۑ }Iۺd#h9M۽ h}}iz\ctingQbꦛtsoT4u9/QMD?Tn/=1vҀqYk>픹Ǚ+B'#ʧ{2zu}(ЧرܛDmI@CQd56 VIBZݯ"L(]HfT>FA&9躟}}8KnU#=NzHyzj-ԼɷtNwz7 7? L^F E!|u W:λ(܏):$gnU)&#'htA!dN:e4X]nÈ Gxg!ULQs_^Zy_C__CwߺW®]eɟKd}~-ֻ}[X:Vе{]Ċ:s)ЅVI6 v|ĵFy1oE翟'ʧU*M'=+4KUF3K~6JޯhhRR_KhUtp,=! ~Ԗ?w퇁TxB2֋;KU|wfТZՇ;XWySGߍ.9.2k&E' \\sqG>L;hoy-?=?mSz<ݿqpyUk'mw;LI˻}DVj;qgQ^eR#f{T}pVXnPJ2')sәJ:9Hﯤs"=S{S9R:2LkL\JƟKƧc>ɧ Ys魌qz KÛ5Q̗WI˔Jt_&ỡEꢨ䁺pm7;wh;P_yfSٕѡا??CuʖEajiu-3Miu!.QͮN Do?·ߥ? ݯL/J1U>]>>ENGu:$}<΄jEEul{_E]H9 I #2jWot.鞺_&KSD./7xfMt}DVw|1]ltqmHv5?L8=Tjzn]zsNV^;]})yJ]thWo{Ut,Ӷ7k`Z4`dՌ A_1:8ܤAЩ7tqC^nsAɢ04{toIM{Jl?kЩLYjw_A07.=u<{,<_Z % ЛCoAB.}Lc=ctVFG{eMK7_@*/7tWU".Dm19uVƺgdb> ]Z]`!NKVu+yi.T[DUX=lvi.lѴa:nG&KW"/qo7 \L>xb>Hg^k&ЛbboWgA_+eP]i㇙Pd_eWn6_B_;j6c]T]苺Bӭ/WYLWF+̤/ycU].I|.t6fӝlO8qų%ӽ]L 题]d ~ӴE!]Ihy*6Auы.Z"OZIz'*Wsm'mtг42FBǏ1.|L%Q=.ZuQDI Bl.+v53vgt8ޛ}ty ]Nt33vy}]zLmS \hdIPwmX4_bװDEVsjtOoFdhxjiЉ:h:wqxA>m}ʿp7T}=qF/DF]'UuޏVCG%t g7}tRW?}yfp;IENDB`pygdchart2alpha2/doc/images/pie.png010064400017500001750000000023550777443323200162130ustar00aldoaldoPNG  IHDRzGPLTE%22_IDATxMn0` |+] yJ̐C2AgEVGZNTUJWε\5jًW/QSoZi::U.֮L_Uj50]SY~Ubl*v-͋^ni3_-eڹh;vjz9_k^h^گ)[a(>IL9Kϔޅaǻpg,ݸ[ݸGqO> {pޛ⋮ſgƽ`I6ۋkwkF+Gջdݏk_Kx==?@Iu\{yNx!\ 9q(%|Q}~]>?Ňuz3Cסeߙw _N?_vڼ4au7N;e>JNf@uxrzc:Nw5IՃ8'~'nz# Yttp:S͞<׸׃8oC :8>t N9zD_>Vп5|A}Sѷ8e~g,=x#A?}:z.]}ıՓ.qlT݃#N|84݋#'}+<{'aU}}Gӷ1Wr!}w'OEիM*-wT5 wE7B귺lVұ8~v\=pֳN#t TOIVO{q_#&::Kx)WP-[taa?#q|-W~s_t9勮Pwoc:TWm,?? f t|aZVejjB3t?+zj);2JIENDB`pygdchart2alpha2/doc/images/pie3D.png010064400017500001750000000030160777443323200163750ustar00aldoaldoPNG  IHDRzG'PLTE%Z  ?22f9ZeIDATx=oHeq @ħ>E*aN*XU*Q{GwMrvv0`rH 07Q$q'̫^'̟+u0%FFglU=Yg몍Kbu+\qa„ &L0a„ &L0a„yXjM9gw=i_]Gi`utW/UwvsF4=5zc)w7p)jLsWs3-)wFv~.ƕw>՟ҏuC~7>՟?gD?8 ?}gY9~VT?Tz&n\gneCDz>8/55z/_­w7E>NHw:T߆_kkz-^j' UߗקxAކO|k2D7V/; >P]YOL IV_QT/)z/] #qAucX|i8+ݬ/՛7uv) V8ഗ©tT`pKiϲG, zp?(mF?VQELm3!Ki_lۊى.;|thF|ςw `~ŭ \w˂O̓wTς7K@W_n(~ou5>Ձ7zm|3]cgǵMtmpjq^;}k NsUo N_4fT7z"7^?Z U6G}cчx0n#Q=~ x()@[?:ů]pv.š#nR]CntS,Ct%(~V꤃ǜa] 8,x 8K-IyBV>¼/Q$QeOػZTpWKWd|S7mdM{w)XWM<^SBQ7zP ::cloK[oW쒷)MtK*j,Uđw[ꭣۅu%jT?޻T$QE 6TёUtW_҅XG 868,:.8dCl!oYz#6:A>8`Cҏ~C+· MqfpqUΛd~aթ]I_\vjZXߊk%Z]N0a„ &L0a„ &LP&%IENDB`pygdchart2alpha2/doc/images/scatter.png010064400017500001750000000045710777443323200171050ustar00aldoaldoPNG  IHDRzGPLTE22̷9t %IDATx r&Atfgط*Tʔc3/bwKץsL7HmhfbfFZYTzʙ kW.z$33e'J_*F@qc^i`N;?P¦7xU)1 fY澬Do?aO cڥC8:qV5ԝ|I:!r5\Iq=,j >zitKoOٸYRL +FXnRVeeWNQAd)00@[hhHH hG5QgA1/gڙSAS_"-nuQֳx޷~/2dOeT{vtUJDeWTb|a |È0wl0=DFxv'j:OWN$DMk/sR oҞV- :Cq<ut 7ajfyKwD+[[DgrP30Sv[.,^lio(Bzƹ',=ohX}+e'\w<]--/7u(jDWzpntVA8QUhPw:+\:S!onYr礏n+W`g"w&k CoګuYb̓6Wf+iG08O륋^7퉗9W:̺͔2־8{p0#e3-s@~ivuigjrFɿ>!]{*Ⱥ5bUګDV^hwSǘ?;~PTҙPJ2;sߑ2^ +ik@]ho+],>`jWZZ^8s`w3)L+iGѮ$x º^^V^{*sk\*s.Wx;'q|bD3W-1mT`dvC)\֝Ğ8He;s6X7~ݿ mi42ґf9Q/*5]&G{iOJi+ wsFګkƙ=QxH;wv8&=QPZe[y^*ҿԩ *b+Hj6(G}OYcdveDso/f} OO=R@ΉA%zAhgS龑ʸqtfȚ`C\j'< &'kW7NeW̶wg.e^ zJoG*1_oUZIX;潛$yzIM7>rʲ|o2F{z݌;^#D9љOSk#|h= zG_퉾}K_IJϯ>'g=;?)m0 glߨ˜idS.S:yV5ڌV^D`+Fh#Dn%蟝F>6'#[OadtFcS,L'kM|*Sdd%sڝIV2IF,+ CW9JVEiV> YEfdkl }O4eL#[4ET+YO%\+Yϵd+YOi:yJf[$]V2I곑:]!]1%?q<W&܇A1+&{1mSʆ #;bljd:=Gl?(yY5CY'Pֵd9"cG;L}zEH$|!oYn~&6y;;-K:UJRIENDB`pygdchart2alpha2/doc/images/hlcarea3D.png010064400017500001750000000051350777443323200172230ustar00aldoaldoPNG  IHDRzGPLTE q IDATxMs8aCRݻvTb_Y}j$LXxZ^d=T]x f}w<]ttūMt-_D^w*X+zُl RS:^i:v3$kk9_w׽tBCFG|dyga려3#uX҉(}o} Pu10ŅT9uB1$I44=hO}9~QhMBNTu}{]. ]yv@]8LUN~Q>Mԅ/;O]8;nA'.C~Bl?0 vHӧ5,Ui An7TӜtNI/hw.L'L~+Xs: st؃=au'7ڏ E*:v=uq.E* s 51tO](B׏{ݞ(~9M,}ñx3jmgҕ'>>r K^LbF_8zV],@|]e,TӴPt~7ӞRM{ ɛ⽪]Pk`jGOKⰺnϦBꂦ8lxt.]ϐWkO]-\sНÊUϠC;IŲ]J_U.s;u"S5>>6wWr`~tretNЃAүzz|'ѿ>+u.BG}?utW :uOsiuAS:q?聺yE cNm?MBBӯhV3xBMo{ n,쁦?nw O9ȦC]]ht=PN葐i 荞O̔[\vOj|Zo>#Io$IՍE܎o˧E1*ZU@=e{3Izv~iRt=pWӅ齽'Ӛ֌r;.ųХs,?;hnbK֍﷐%L/}J{؀[S>F܇>' 1v cz9=+}IWW%#r#O}z,t:UɘޤJ w@A{/I/+]|(yy>ytg{".;l| ꏨӏKWp/l4<e (}O/8pkI#FO8m:.i&ݙ݁_r"]/vHLzwIwy@xs -8voޙUl:0uf]/>:|ǡ# n_a^4{+/XBoQz4Hzy?ݎqNt(ޙ$:/VIy؎程,}؀|ln.,`BVL 5㻧mnY٘NeUWqp?nE\Io>uU PMY?'\]dn|iaM_ȅ7]A/YIb,}ȷU^'(MiLYFVK0!6(1Š,ea}Fڂ,]]$M#uN_9cl-G:,qZܐ;fF1=?O8J}G.^&8+<+eKMw;r/6vPFMW;С`l>u妫S.{]]ohw\4j:Qa`~͞ux}9:;~,YھOS{{œI$ߙ><tx`]_LML#;aMCj49t9x"vI EEIENDB`pygdchart2alpha2/doc/graphs.html010064400017500001750000000032770777443323200156410ustar00aldoaldo <--previous | contents | next-->

Graphs

PyGDChart exposes a set of classes that allow the programmer to draw various graphs on classical Cartesian axes. All of these Graph types share an underlying set of options, and obey the same basic interface. Please see sections discussing particular graph types for more information.

Interface

In addition to the common interface Graph types expose the following methods:

setScatter(scatterpoints)

Here, scatterpoints is a list of Scatter objects. See the section on Scatter Graphs for an in-depth discussion of the use of this method.

annotate(point=0, note="", colour="white")

The GDChart library allows the user to add a single annotation to a given graph. The point argument indicates the X-axis offset of the annotation, note is the annotation text itself, and colour is the annotation colour.

clearAnnotation()

Clear the annotation, if any.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/index.html010064400017500001750000000062660777443323200154650ustar00aldoaldo previous | contents | next-->

PyGDChart User's Manual

v2.0 Beta
www.nullcube.com

Contents


Written and maintained by Aldo Cortesi (aldo@nullcube.com).
previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/colours.html010064400017500001750000000125540777443323200160410ustar00aldoaldo <--previous | contents | next-->

Colours

Both PyGDChart and GDChart itself store and manipulate colours as RGB integers. Users will be familiar with RGB colour definitions from other contexts - for instance, colours in HTML are often specified in the form "#RRGGBB", where each component is a hex number between 0 and 256. Since the naked RGB integer is cumbersome to work with, the PyGDChart library provides a number of simple facilities to make the programmer's life easier.

The RGB Class

The first of the colour manipulation facilities provided by PyGDChart is the RGB class. This class is simply a way to collect and manipulate the components of a normal RGB colour definition. It is instantiated as follows:

x = gdchart.RGB(r, g, b)

After instantiation, an RGB object exposes the attributes r, g, and b, which can be inspected and set independently. RGB objects have an __int__ method that converts the RGB colour definition to the correct numerical value. As such, an RGB object can be used wherever a colour definition is required.

The rgbFactory() function

The rgbFactory() function is an easy way to manufacture RGB objects corresponding to common colours:

x = gdchart.rgbFactory("blue")

At the moment only entries for "blue", "red", "green", "orange", "white", "black" and "yellow" are provided, but this list will grow in future.

Colours and PyGDChart

From the preceding sections, we already know of two major ways to specify a colour to PyGDChart. Firstly, as a plain integer:

x.bg_color = 0x3232CC

And secondly, as an RGB object:

x.bg_color = gdchart.rgbFactory("blue")

From the latter example, however, an even more convenient way of specifying a colour leaps to mind. Since options in PyGDChart are "smart", we can check wether an option has been passed a string, and call rgbFactory automatically to generate an RGB object. This leads us to the third way of specifying colours in PyGDChart - simply by using a descriptive string:

x.bg_color = "blue"

<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/admin.html010064400017500001750000000047260777443323200154450ustar00aldoaldo <--previous | contents | next

Administrivia

Contact

Please send any comments, suggestions and bug reports to aldo@nullcube.com.

License

PyGDChart is licensed under the BSD license. The full text is included below, but the essential gist of it is that you can do whatever you like with PyGDChart, as long as the copyright stays intact.


Copyright (c) 2002, Nullcube Pty Ltd
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Nullcube nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


<--previous | contents | next (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/pies.html010064400017500001750000000111130777443323200153010ustar00aldoaldo <--previous | contents | next-->

Pie Charts

Pie
Pie3D

Data Format

The argument to .setData() is simply an arbitrary number of floats or integers. Values passed will be scaled proportionally to fit on the Pie chart.

Example

The 3D graph above was generated with the following program:

import gdchart

myPie = gdchart.Pie3D()
myPie.width = 250
myPie.height = 250
myPie.title = "Pie3D"
myPie.setData(1, 2, 3, 4, 5)
myPie.setLabels(["One", "Two", "Three", "Four", "Five"])
myPie.color = ["red", "green", "yellow", "orange", "blue"]
myPie.explode = [0, 0, 20, 0, 0]
myPie.draw("pie3D.png")

<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/intro.html010064400017500001750000000021510777443323200154760ustar00aldoaldo previous | contents | next-->

Introduction

PyGDChart is a set of Python bindings for the GDChart library by Bruce Verderaime. GDChart itself can be obtained on here.

At the moment both this manual and PyGDChart2 itself are in the Beta development stage. Any bug reports, whether of the documentation or the software itself, would be greatly appreciated.

Requirements

This version of PyGDChart requires the following:

  • Python 2.2.
  • GDChart 0.11.4dev.


previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/start.html010064400017500001750000000235120777443323200155040ustar00aldoaldo <--previous | contents | next-->

Getting Started

This section gives a quick overview of the features of the PyGDChart library by working through a simple example. We first show the example program, and the graph it produces, in full. Then we proceed with a line-by-line analysis, introducing the basic workings of PyGDChart as we go along.

The Code

import gdchart

x = gdchart.Bar3D()
x.width = 250
x.height = 250
x.xtitle = "Weekday"
x.ytitle = "Percentage"
x.title = "Example Graph"
x.ext_color = [ "white", "yellow", "red", "blue", "green"]
x.setData([20, 100, 80, 30, 50])
x.setLabels(["Mon", "Tue", "Wed", "Thu", "Fri"])
x.draw("simple.png")

Explanation

Choosing a Chart Class

x = gdchart.Bar3D()

The PyGDChart library is based around a number of chart classes, each of which represents a different chart style. The first step in using PyGDChart is usually to instantiate one of these classes. In this case, we will be drawing a 3D bar graph.

Setting Options

x.width = 250
x.height = 250
x.xtitle = "Weekday"
x.ytitle = "Percentage"
x.title = "Example Graph"
x.ext_color = [ "white", "yellow", "red", "blue", "green"]

Although they look like simple object attributes, PyGDChart options are actually "smart" properties. Whenever you assign to, or retreive the value of, an option, a certain amount of checking and conversion code is run. This allows us to ensure that values assigned to options are appropriate - for instance, we can prevent a user from assigning a string to an option when the underlying C library expects an integer.

"Smart" options can also make things more convenient by performing some types of automatic data conversion. Note that the code snippet above uses descriptive names to specify colours. In the underlying library, however, colours are stored as integers - colour names are converted to the appropriate integer values on assignment. PyGDChart's colour handling capabilities are discussed in greater depth later in this manual.

Data and Labels

x.setData([20, 100, 80, 30, 50])

Each chart type has a .setData() method, but different chart types may require different data formats. Bar graphs, like the one in the example, can be specified using one or more lists of values. If were drawing a floating bar graph, however, the data format would be more complex, since we would have to specify both the upper and lower bounds for every bar. The data requirements for the various chart types are discussed in the appropriate sections elsewhere in this manual.

x.setLabels(["Mon", "Tue", "Wed", "Thu", "Fri"])

The .setLabels method is used to specify the labels that appear on the X axis of a graph. In order to avoid ambiguity, PyGDChart ensures that the number of labels conforms with the number of data points along the X axis.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual
pygdchart2alpha2/doc/interface.html010064400017500001750000000041150777443323200163050ustar00aldoaldo <--previous | contents | next-->

Common Interface

All graph and pie classes share a common basic interface:

setOption(option, value)

Set an option by option name and value. This method also does data type conversion (see the discussion of colour handling), and type conformance checks.

getOption(option)

Retrieve the value of an option by name.

getAllOptions()

Retrieve a dictionary of all option-value pairs.

restoreDefaultOptions()

Restore the values of all options to the defaults for this graph type.

setLabels([label1, label2, ...])

Set the X-axis labels for Graph types, and per-slice labels for Pie charts. The number of arguments passed to this function should correspond with the number of discrete data points to be plotted.

setData(data1, [data2, ...])

Set the data to be charted. The data format expected differs from chart type to chart type - please see the corresponding chart section for more information.

draw(filespec)

Draw the graph to the specified file. If the filespec argument is a string, it will be treated as the path to a file. Otherwise, filespec is assumed to be a Python file object.

Options as properties

All options are also exposed as properties. Getting and setting an option as a property, is functionally identical to making the corresponding getOption and setOption calls.


<--previous | contents | next--> (12/31/03)
PyGDChart User's Manual