From 36ff0b51719975fbd9d64ff96c4ca3d3e402efbd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A9=20Wobst?= Date: Tue, 6 Jul 2010 16:31:34 +0000 Subject: [PATCH] 3d bars completed (as long as they are not stacked and only a single dataset is drawn) git-svn-id: https://pyx.svn.sourceforge.net/svnroot/pyx/trunk/pyx@3030 069f4177-920e-0410-937b-c2a4a81bcd90 --- manual/graph.tex | 11 ++++- pyx/graph/style.py | 94 ++++++++++++++++++++++++---------------- test/functional/test_bargraph.py | 6 +++ 3 files changed, 72 insertions(+), 39 deletions(-) diff --git a/manual/graph.tex b/manual/graph.tex index 897e4bfc..a0076d53 100644 --- a/manual/graph.tex +++ b/manual/graph.tex @@ -1002,11 +1002,18 @@ definition is: top of the bar. \end{classdesc} % }}} -\begin{classdesc}{bar}{barattrs=[]} % {{{ +\begin{classdesc}{bar}{barattrs=[], epsilon=1e-10, gradient=color.gradient.RedBlack} % {{{ This class draws bars in a bar graph. The bars are filled using \var{barattrs}. \var{barattrs} is merged with \code{defaultbarattrs} which is a list containing \code{[color.gradient.Rainbow, deco.stroked([color.grey.black])]}. + + On 3d graphs \var{epsilon} is used to prevent numerical + instabilities on bars without hight. When \var{gradient} is not + \code{None} it is used to calculate a lighting coloring taking into + account the angle between the view ray and the bar and the distance + between viewer and bar. The precise conversion is defined in the + \method{lighting} method. \end{classdesc} % }}} \begin{classdesc}{changebar}{barattrs=[]} % {{{ @@ -1014,7 +1021,7 @@ definition is: \var{barattrs} to be changed on subsequent data instances the \var{barattrs} are changed for each value within a single data instance. In the result the style can't be applied to several data - instances. The style raises an error instead. + instances and does not support 3d. The style raises an error instead. \end{classdesc} % }}} \begin{classdesc}{gridpos}{index1=0, index2=1, % {{{ diff --git a/pyx/graph/style.py b/pyx/graph/style.py index 5bd8ebf5..25d75d98 100644 --- a/pyx/graph/style.py +++ b/pyx/graph/style.py @@ -1479,8 +1479,13 @@ class bar(_style): defaultbarattrs = [color.gradient.Rainbow, deco.stroked([color.grey.black])] - def __init__(self, barattrs=[]): + def __init__(self, barattrs=[], epsilon=1e-10, gradient=color.gradient.RedBlack): self.barattrs = barattrs + self.epsilon = epsilon + self.gradient = gradient + + def lighting(self, angle, zindex): + return self.gradient.getcolor(0.7-0.4*abs(angle)+0.1*zindex) def columnnames(self, privatedata, sharedata, graph, columnnames): return [] @@ -1492,6 +1497,7 @@ class bar(_style): privatedata.barcanvas = graph.insert(canvas.canvas()) sharedata.stackedbardraw = 1 privatedata.stackedbar = sharedata.stackedbar + privatedata.todraw = [] def drawpointfill(self, privatedata, p): if p: @@ -1521,45 +1527,59 @@ class bar(_style): p.append(path.closepath()) self.drawpointfill(privatedata, p) elif len(vbarrange) == 3: - p = graph.vgeodesic(vbarrange[0][0], vbarrange[1][0], vbarrange[2][0], vbarrange[0][1], vbarrange[1][0], vbarrange[2][0]) - p.append(graph.vgeodesic_el(vbarrange[0][1], vbarrange[1][0], vbarrange[2][0], vbarrange[0][1], vbarrange[1][1], vbarrange[2][0])) - p.append(graph.vgeodesic_el(vbarrange[0][1], vbarrange[1][1], vbarrange[2][0], vbarrange[0][0], vbarrange[1][1], vbarrange[2][0])) - p.append(graph.vgeodesic_el(vbarrange[0][0], vbarrange[1][1], vbarrange[2][0], vbarrange[0][0], vbarrange[1][0], vbarrange[2][0])) - p.append(path.closepath()) - self.drawpointfill(privatedata, p) - p = graph.vgeodesic(vbarrange[0][0], vbarrange[1][0], vbarrange[2][1], vbarrange[0][1], vbarrange[1][0], vbarrange[2][1]) - p.append(graph.vgeodesic_el(vbarrange[0][1], vbarrange[1][0], vbarrange[2][1], vbarrange[0][1], vbarrange[1][1], vbarrange[2][1])) - p.append(graph.vgeodesic_el(vbarrange[0][1], vbarrange[1][1], vbarrange[2][1], vbarrange[0][0], vbarrange[1][1], vbarrange[2][1])) - p.append(graph.vgeodesic_el(vbarrange[0][0], vbarrange[1][1], vbarrange[2][1], vbarrange[0][0], vbarrange[1][0], vbarrange[2][1])) - p.append(path.closepath()) - self.drawpointfill(privatedata, p) - p = graph.vgeodesic(vbarrange[0][0], vbarrange[1][0], vbarrange[2][0], vbarrange[0][1], vbarrange[1][0], vbarrange[2][0]) - p.append(graph.vgeodesic_el(vbarrange[0][1], vbarrange[1][0], vbarrange[2][0], vbarrange[0][1], vbarrange[1][0], vbarrange[2][1])) - p.append(graph.vgeodesic_el(vbarrange[0][1], vbarrange[1][0], vbarrange[2][1], vbarrange[0][0], vbarrange[1][0], vbarrange[2][1])) - p.append(graph.vgeodesic_el(vbarrange[0][0], vbarrange[1][0], vbarrange[2][1], vbarrange[0][0], vbarrange[1][0], vbarrange[2][0])) - p.append(path.closepath()) - self.drawpointfill(privatedata, p) - p = graph.vgeodesic(vbarrange[0][0], vbarrange[1][1], vbarrange[2][0], vbarrange[0][1], vbarrange[1][1], vbarrange[2][0]) - p.append(graph.vgeodesic_el(vbarrange[0][1], vbarrange[1][1], vbarrange[2][0], vbarrange[0][1], vbarrange[1][1], vbarrange[2][1])) - p.append(graph.vgeodesic_el(vbarrange[0][1], vbarrange[1][1], vbarrange[2][1], vbarrange[0][0], vbarrange[1][1], vbarrange[2][1])) - p.append(graph.vgeodesic_el(vbarrange[0][0], vbarrange[1][1], vbarrange[2][1], vbarrange[0][0], vbarrange[1][1], vbarrange[2][0])) - p.append(path.closepath()) - self.drawpointfill(privatedata, p) - p = graph.vgeodesic(vbarrange[0][0], vbarrange[1][0], vbarrange[2][0], vbarrange[0][0], vbarrange[1][1], vbarrange[2][0]) - p.append(graph.vgeodesic_el(vbarrange[0][0], vbarrange[1][1], vbarrange[2][0], vbarrange[0][0], vbarrange[1][1], vbarrange[2][1])) - p.append(graph.vgeodesic_el(vbarrange[0][0], vbarrange[1][1], vbarrange[2][1], vbarrange[0][0], vbarrange[1][0], vbarrange[2][1])) - p.append(graph.vgeodesic_el(vbarrange[0][0], vbarrange[1][0], vbarrange[2][1], vbarrange[0][0], vbarrange[1][0], vbarrange[2][0])) - p.append(path.closepath()) - self.drawpointfill(privatedata, p) - p = graph.vgeodesic(vbarrange[0][1], vbarrange[1][0], vbarrange[2][0], vbarrange[0][1], vbarrange[1][1], vbarrange[2][0]) - p.append(graph.vgeodesic_el(vbarrange[0][1], vbarrange[1][1], vbarrange[2][0], vbarrange[0][1], vbarrange[1][1], vbarrange[2][1])) - p.append(graph.vgeodesic_el(vbarrange[0][1], vbarrange[1][1], vbarrange[2][1], vbarrange[0][1], vbarrange[1][0], vbarrange[2][1])) - p.append(graph.vgeodesic_el(vbarrange[0][1], vbarrange[1][0], vbarrange[2][1], vbarrange[0][1], vbarrange[1][0], vbarrange[2][0])) - p.append(path.closepath()) - self.drawpointfill(privatedata, p) + planes = [] + if abs(vbarrange[0][0] - vbarrange[0][1]) > self.epsilon and abs(vbarrange[1][0] - vbarrange[1][1]): + planes.append((vbarrange[0][0], vbarrange[1][0], vbarrange[2][0], + vbarrange[0][1], vbarrange[1][0], vbarrange[2][0], + vbarrange[0][1], vbarrange[1][1], vbarrange[2][0], + vbarrange[0][0], vbarrange[1][1], vbarrange[2][0])) + planes.append((vbarrange[0][0], vbarrange[1][0], vbarrange[2][1], + vbarrange[0][0], vbarrange[1][1], vbarrange[2][1], + vbarrange[0][1], vbarrange[1][1], vbarrange[2][1], + vbarrange[0][1], vbarrange[1][0], vbarrange[2][1])) + if abs(vbarrange[0][0] - vbarrange[0][1]) > self.epsilon and abs(vbarrange[2][0] - vbarrange[2][1]): + planes.append((vbarrange[0][0], vbarrange[1][0], vbarrange[2][0], + vbarrange[0][0], vbarrange[1][0], vbarrange[2][1], + vbarrange[0][1], vbarrange[1][0], vbarrange[2][1], + vbarrange[0][1], vbarrange[1][0], vbarrange[2][0])) + planes.append((vbarrange[0][0], vbarrange[1][1], vbarrange[2][0], + vbarrange[0][1], vbarrange[1][1], vbarrange[2][0], + vbarrange[0][1], vbarrange[1][1], vbarrange[2][1], + vbarrange[0][0], vbarrange[1][1], vbarrange[2][1])) + if abs(vbarrange[1][0] - vbarrange[1][1]) > self.epsilon and abs(vbarrange[2][0] - vbarrange[2][1]): + planes.append((vbarrange[0][0], vbarrange[1][0], vbarrange[2][0], + vbarrange[0][0], vbarrange[1][1], vbarrange[2][0], + vbarrange[0][0], vbarrange[1][1], vbarrange[2][1], + vbarrange[0][0], vbarrange[1][0], vbarrange[2][1])) + planes.append((vbarrange[0][1], vbarrange[1][0], vbarrange[2][0], + vbarrange[0][1], vbarrange[1][0], vbarrange[2][1], + vbarrange[0][1], vbarrange[1][1], vbarrange[2][1], + vbarrange[0][1], vbarrange[1][1], vbarrange[2][0])) + v = [0.5 * (vbarrange[0][0] + vbarrange[0][1]), + 0.5 * (vbarrange[1][0] + vbarrange[1][1]), + 0.5 * (vbarrange[2][0] + vbarrange[2][1])] + v[sharedata.barvalueindex] = 0.5 + zindex = graph.vzindex(*v) + for v11, v12, v13, v21, v22, v23, v31, v32, v33, v41, v42, v43 in planes: + angle = graph.vangle(v11, v12, v13, v21, v22, v23, v41, v42, v43) + if angle > 0: + p = graph.vgeodesic(v11, v12, v13, v21, v22, v23) + p.append(graph.vgeodesic_el(v21, v22, v23, v31, v32, v33)) + p.append(graph.vgeodesic_el(v31, v32, v33, v41, v42, v43)) + p.append(graph.vgeodesic_el(v41, v42, v43, v11, v12, v13)) + p.append(path.closepath()) + if self.gradient: + privatedata.todraw.append((-zindex, p, privatedata.barattrs + [self.lighting(angle, zindex)])) + else: + privatedata.todraw.append((-zindex, p, privatedata.barattrs)) else: raise TypeError("bar style restricted to two- and three dimensional graphs") + def donedrawpoints(self, privatedata, sharedata, graph): + privatedata.todraw.sort() + for vzindex, p, a in privatedata.todraw: + privatedata.barcanvas.fill(p, a) + def key_pt(self, privatedata, sharedata, graph, x_pt, y_pt, width_pt, height_pt): selectindex = privatedata.stackedbar selecttotal = sharedata.stackedbar + 1 diff --git a/test/functional/test_bargraph.py b/test/functional/test_bargraph.py index 31c0cd64..d0236310 100755 --- a/test/functional/test_bargraph.py +++ b/test/functional/test_bargraph.py @@ -35,11 +35,17 @@ def test_bar4(c, x, y): graph.data.data(graph.data.points([['x', 10, 3], ['y', 11, 2], ['z', 12, 1]], id=1, y=2, ystack1=3, title="test"), xname="id, ('B', 'Z')")], [graph.style.barpos(fromvalue=0), graph.style.bar(), graph.style.stackedbarpos("ystack1", addontop=1), graph.style.bar([color.gradient.ReverseRainbow])]) +def test_bar5(c, x, y): + g = c.insert(graph.graphxyz(x, y, size=3, x=graph.axis.bar(), y=graph.axis.bar(), z=graph.axis.lin())) + g.plot(graph.data.data(graph.data.points([[1, 1, 1.4], [1, 2, 1.8], [2, 1, -0.5], [2, 2, 0.9]]), xname=1, yname=2, z=3), + [graph.style.barpos(fromvalue=0, frompathattrs=None), graph.style.bar(barattrs=[style.linejoin.bevel])]) + c = canvas.canvas() test_bar(c, 0, 0) test_bar2(c, 7, 0) test_bar3(c, 0, -7) test_bar4(c, 0, -14) +test_bar5(c, 7, -19) c.writeEPSfile("test_bargraph", paperformat=document.paperformat.A4) c.writePDFfile("test_bargraph", paperformat=document.paperformat.A4) -- 2.11.4.GIT