2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002-2004 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2003-2004 Michael Schindler <m-schindler@users.sourceforge.net>
7 # Copyright (C) 2002-2004 André Wobst <wobsta@users.sourceforge.net>
9 # This file is part of PyX (http://pyx.sourceforge.net/).
11 # PyX is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # PyX is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with PyX; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 import math
, re
, string
27 from pyx
import canvas
, path
, trafo
, unit
28 from pyx
.graph
.axis
import painter
, axis
31 goldenmean
= 0.5 * (math
.sqrt(5) + 1)
35 """an axispos linear along a line with a fix direction for the ticks"""
37 def __init__(self
, convert
, x1
, y1
, x2
, y2
, fixtickdirection
):
38 """initializes the instance
39 - only the convert method is needed from the axis
40 - x1, y1, x2, y2 are PyX lengths (start and end position of the line)
41 - fixtickdirection is a tuple tick direction (fixed along the line)"""
42 self
.convert
= convert
47 self
.x1_pt
= unit
.topt(x1
)
48 self
.y1_pt
= unit
.topt(y1
)
49 self
.x2_pt
= unit
.topt(x2
)
50 self
.y2_pt
= unit
.topt(y2
)
51 self
.fixtickdirection
= fixtickdirection
53 def vbasepath(self
, v1
=None, v2
=None):
58 return path
.line_pt((1-v1
)*self
.x1_pt
+v1
*self
.x2_pt
,
59 (1-v1
)*self
.y1_pt
+v1
*self
.y2_pt
,
60 (1-v2
)*self
.x1_pt
+v2
*self
.x2_pt
,
61 (1-v2
)*self
.y1_pt
+v2
*self
.y2_pt
)
63 def basepath(self
, x1
=None, x2
=None):
72 return path
.line_pt((1-v1
)*self
.x1_pt
+v1
*self
.x2_pt
,
73 (1-v1
)*self
.y1_pt
+v1
*self
.y2_pt
,
74 (1-v2
)*self
.x1_pt
+v2
*self
.x2_pt
,
75 (1-v2
)*self
.y1_pt
+v2
*self
.y2_pt
)
77 def gridpath(self
, x
):
78 raise RuntimeError("gridpath not available")
80 def vgridpath(self
, v
):
81 raise RuntimeError("gridpath not available")
83 def vtickpoint_pt(self
, v
):
84 return (1-v
)*self
.x1_pt
+v
*self
.x2_pt
, (1-v
)*self
.y1_pt
+v
*self
.y2_pt
86 def vtickpoint(self
, v
):
87 return (1-v
)*self
.x1
+v
*self
.x2
, (1-v
)*self
.y1
+v
*self
.y2
89 def tickpoint_pt(self
, x
):
91 return (1-v
)*self
.x1_pt
+v
*self
.x2_pt
, (1-v
)*self
.y1_pt
+v
*self
.y2_pt
93 def tickpoint(self
, x
):
95 return (1-v
)*self
.x1
+v
*self
.x2
, (1-v
)*self
.y1
+v
*self
.y2
97 def tickdirection(self
, x
):
98 return self
.fixtickdirection
100 def vtickdirection(self
, v
):
101 return self
.fixtickdirection
104 class lineaxisposlinegrid(lineaxispos
):
105 """an axispos linear along a line with a fix direction for the ticks
106 with support for grid lines for a rectangular graphs"""
108 __implements__
= painter
._Iaxispos
110 def __init__(self
, convert
, x1
, y1
, x2
, y2
, fixtickdirection
, startgridlength
, endgridlength
):
111 """initializes the instance
112 - only the convert method is needed from the axis
113 - x1, y1, x2, y2 are PyX lengths (start and end position of the line)
114 - fixtickdirection is a tuple tick direction (fixed along the line)
115 - startgridlength and endgridlength are PyX lengths for the starting
116 and end point of the grid, respectively; the gridpath is a line along
117 the fixtickdirection"""
118 lineaxispos
.__init
__(self
, convert
, x1
, y1
, x2
, y2
, fixtickdirection
)
119 self
.startgridlength
= startgridlength
120 self
.endgridlength
= endgridlength
121 self
.startgridlength_pt
= unit
.topt(self
.startgridlength
)
122 self
.endgridlength_pt
= unit
.topt(self
.endgridlength
)
124 def gridpath(self
, x
):
126 return path
.line_pt((1-v
)*self
.x1_pt
+v
*self
.x2_pt
+self
.fixtickdirection
[0]*self
.startgridlength_pt
,
127 (1-v
)*self
.y1_pt
+v
*self
.y2_pt
+self
.fixtickdirection
[1]*self
.startgridlength_pt
,
128 (1-v
)*self
.x1_pt
+v
*self
.x2_pt
+self
.fixtickdirection
[0]*self
.endgridlength_pt
,
129 (1-v
)*self
.y1_pt
+v
*self
.y2_pt
+self
.fixtickdirection
[1]*self
.endgridlength_pt
)
131 def vgridpath(self
, v
):
132 return path
.line_pt((1-v
)*self
.x1_pt
+v
*self
.x2_pt
+self
.fixtickdirection
[0]*self
.startgridlength_pt
,
133 (1-v
)*self
.y1_pt
+v
*self
.y2_pt
+self
.fixtickdirection
[1]*self
.startgridlength_pt
,
134 (1-v
)*self
.x1_pt
+v
*self
.x2_pt
+self
.fixtickdirection
[0]*self
.endgridlength_pt
,
135 (1-v
)*self
.y1_pt
+v
*self
.y2_pt
+self
.fixtickdirection
[1]*self
.endgridlength_pt
)
138 class graphxy(canvas
.canvas
):
142 def plot(self
, data
, styles
=None):
144 raise RuntimeError("layout setup was already performed")
153 raise RuntimeError() # TODO: default styles handling ...
156 style
= d
.defaultstyle
157 elif style
!= d
.defaultstyle
:
158 raise RuntimeError("defaultstyles differ")
160 d
.setstyles(self
, styles
)
161 self
.plotdata
.append(d
)
164 def pos_pt(self
, x
, y
, xaxis
=None, yaxis
=None):
166 xaxis
= self
.axes
["x"]
168 yaxis
= self
.axes
["y"]
169 return self
.xpos_pt
+ xaxis
.convert(x
)*self
.width_pt
, self
.ypos_pt
+ yaxis
.convert(y
)*self
.height_pt
171 def pos(self
, x
, y
, xaxis
=None, yaxis
=None):
173 xaxis
= self
.axes
["x"]
175 yaxis
= self
.axes
["y"]
176 return self
.xpos
+ xaxis
.convert(x
)*self
.width
, self
.ypos
+ yaxis
.convert(y
)*self
.height
178 def vpos_pt(self
, vx
, vy
):
179 return self
.xpos_pt
+ vx
*self
.width_pt
, self
.ypos_pt
+ vy
*self
.height_pt
181 def vpos(self
, vx
, vy
):
182 return self
.xpos
+ vx
*self
.width
, self
.ypos
+ vy
*self
.height
184 def vgeodesic(self
, vx1
, vy1
, vx2
, vy2
):
185 """returns a geodesic path between two points in graph coordinates"""
186 return path
.line_pt(self
.xpos_pt
+ vx1
*self
.width_pt
,
187 self
.ypos_pt
+ vy1
*self
.height_pt
,
188 self
.xpos_pt
+ vx2
*self
.width_pt
,
189 self
.ypos_pt
+ vy2
*self
.height_pt
)
191 def vgeodesic_el(self
, vx1
, vy1
, vx2
, vy2
):
192 """returns a geodesic path element between two points in graph coordinates"""
193 return path
.lineto_pt(self
.xpos_pt
+ vx2
*self
.width_pt
,
194 self
.ypos_pt
+ vy2
*self
.height_pt
)
196 def vcap_pt(self
, direction
, length_pt
, vx
, vy
):
197 """returns an error cap path for a given direction, lengths and
198 point in graph coordinates"""
200 return path
.line_pt(self
.xpos_pt
+ vx
*self
.width_pt
- 0.5*length_pt
,
201 self
.ypos_pt
+ vy
*self
.height_pt
,
202 self
.xpos_pt
+ vx
*self
.width_pt
+ 0.5*length_pt
,
203 self
.ypos_pt
+ vy
*self
.height_pt
)
204 elif direction
== "y":
205 return path
.line_pt(self
.xpos_pt
+ vx
*self
.width_pt
,
206 self
.ypos_pt
+ vy
*self
.height_pt
- 0.5*length_pt
,
207 self
.xpos_pt
+ vx
*self
.width_pt
,
208 self
.ypos_pt
+ vy
*self
.height_pt
+ 0.5*length_pt
)
210 raise ValueError("direction invalid")
212 def keynum(self
, key
):
214 while key
[0] in string
.letters
:
220 def removedomethod(self
, method
):
224 self
.domethods
.remove(method
)
230 if not self
.removedomethod(self
.dolayout
): return
232 # count the usage of styles and perform selects
233 # TODO: move it into the styles
235 for data
in self
.plotdata
:
236 for style
in data
.styles
:
238 styletotal
[id(style
)] += 1
240 styletotal
[id(style
)] = 1
242 for data
in self
.plotdata
:
243 for style
in data
.styles
:
245 styleindex
[id(style
)] += 1
247 styleindex
[id(style
)] = 0
248 index
= styleindex
[id(data
.styles
[0])]
249 total
= styletotal
[id(data
.styles
[0])]
250 for style
in data
.styles
[1:]:
251 if index
!= styleindex
[id(style
)] or total
!= styletotal
[id(style
)]:
252 raise RuntimeError("inconsistent style modification not yet supported")
253 data
.selectstyle(self
, index
, total
)
255 # adjust the axes ranges
256 for step
in range(3):
257 for data
in self
.plotdata
:
258 data
.adjustaxes(self
, step
)
261 XPattern
= re
.compile(r
"%s([2-9]|[1-9][0-9]+)?$" % self
.axisnames
[0])
262 YPattern
= re
.compile(r
"%s([2-9]|[1-9][0-9]+)?$" % self
.axisnames
[1])
263 xaxisextents
= [0, 0]
264 yaxisextents
= [0, 0]
265 needxaxisdist
= [0, 0]
266 needyaxisdist
= [0, 0]
267 items
= list(self
.axes
.items())
268 items
.sort() #TODO: alphabetical sorting breaks for axis numbers bigger than 9
269 # TODO: linked axes are not taken into account (consider x being a link to x2)
270 for key
, axis
in items
:
271 num
= self
.keynum(key
)
272 num2
= 1 - num
% 2 # x1 -> 0, x2 -> 1, x3 -> 0, x4 -> 1, ...
273 num3
= 2 * (num
% 2) - 1 # x1 -> 1, x2 -> -1, x3 -> 1, x4 -> -1, ...
274 if XPattern
.match(key
):
275 if needxaxisdist
[num2
]:
276 xaxisextents
[num2
] += self
.axesdist
277 self
.axespos
[key
] = lineaxisposlinegrid(self
.axes
[key
].convert
,
279 self
.ypos
+ num2
*self
.height
- num3
*xaxisextents
[num2
],
280 self
.xpos
+ self
.width
,
281 self
.ypos
+ num2
*self
.height
- num3
*xaxisextents
[num2
],
283 xaxisextents
[num2
], xaxisextents
[num2
] + self
.height
)
285 self
.xbasepath
= self
.axespos
[key
].basepath
286 self
.xvbasepath
= self
.axespos
[key
].vbasepath
287 self
.xgridpath
= self
.axespos
[key
].gridpath
288 self
.xvgridpath
= self
.axespos
[key
].vgridpath
289 self
.xtickpoint_pt
= self
.axespos
[key
].tickpoint_pt
290 self
.xtickpoint
= self
.axespos
[key
].tickpoint
291 self
.xvtickpoint_pt
= self
.axespos
[key
].vtickpoint_pt
292 self
.xvtickpoint
= self
.axespos
[key
].tickpoint
293 self
.xtickdirection
= self
.axespos
[key
].tickdirection
294 self
.xvtickdirection
= self
.axespos
[key
].vtickdirection
295 elif YPattern
.match(key
):
296 if needyaxisdist
[num2
]:
297 yaxisextents
[num2
] += self
.axesdist
298 self
.axespos
[key
] = lineaxisposlinegrid(self
.axes
[key
].convert
,
299 self
.xpos
+ num2
*self
.width
- num3
*yaxisextents
[num2
],
301 self
.xpos
+ num2
*self
.width
- num3
*yaxisextents
[num2
],
302 self
.ypos
+ self
.height
,
304 yaxisextents
[num2
], yaxisextents
[num2
] + self
.width
)
306 self
.ybasepath
= self
.axespos
[key
].basepath
307 self
.yvbasepath
= self
.axespos
[key
].vbasepath
308 self
.ygridpath
= self
.axespos
[key
].gridpath
309 self
.yvgridpath
= self
.axespos
[key
].vgridpath
310 self
.ytickpoint_pt
= self
.axespos
[key
].tickpoint_pt
311 self
.ytickpoint
= self
.axespos
[key
].tickpoint
312 self
.yvtickpoint_pt
= self
.axespos
[key
].vtickpoint_pt
313 self
.yvtickpoint
= self
.axespos
[key
].tickpoint
314 self
.ytickdirection
= self
.axespos
[key
].tickdirection
315 self
.yvtickdirection
= self
.axespos
[key
].vtickdirection
317 raise ValueError("Axis key '%s' not allowed" % key
)
318 axis
.finish(self
.axespos
[key
])
319 if XPattern
.match(key
):
320 xaxisextents
[num2
] += axis
.axiscanvas
.extent
321 needxaxisdist
[num2
] = 1
322 if YPattern
.match(key
):
323 yaxisextents
[num2
] += axis
.axiscanvas
.extent
324 needyaxisdist
[num2
] = 1
327 def dobackground(self
):
329 if not self
.removedomethod(self
.dobackground
): return
330 if self
.backgroundattrs
is not None:
331 self
.draw(path
.rect_pt(self
.xpos_pt
, self
.ypos_pt
, self
.width_pt
, self
.height_pt
),
332 self
.backgroundattrs
)
336 if not self
.removedomethod(self
.doaxes
): return
337 for axis
in self
.axes
.values():
338 self
.insert(axis
.axiscanvas
)
342 if not self
.removedomethod(self
.dodata
): return
343 for data
in self
.plotdata
:
348 if not self
.removedomethod(self
.dokey
): return
349 if self
.key
is not None:
350 c
= self
.key
.paint(self
.plotdata
)
354 x
= self
.xpos_pt
+ self
.width_pt
- bbox
.urx_pt
- self
.key
.hdist_pt
356 x
= self
.xpos_pt
+ self
.width_pt
- bbox
.llx_pt
+ self
.key
.hdist_pt
359 x
= self
.xpos_pt
- bbox
.llx_pt
+ self
.key
.hdist_pt
361 x
= self
.xpos_pt
- bbox
.urx_pt
- self
.key
.hdist_pt
364 y
= self
.ypos_pt
+ self
.height_pt
- bbox
.ury_pt
- self
.key
.vdist_pt
366 y
= self
.ypos_pt
+ self
.height_pt
- bbox
.lly_pt
+ self
.key
.vdist_pt
369 y
= self
.ypos_pt
- bbox
.lly_pt
+ self
.key
.vdist_pt
371 y
= self
.ypos_pt
- bbox
.ury_pt
- self
.key
.vdist_pt
372 self
.insert(c
, [trafo
.translate_pt(x
, y
)])
375 while len(self
.domethods
):
378 def initwidthheight(self
, width
, height
, ratio
):
379 if (width
is not None) and (height
is None):
380 self
.width
= unit
.length(width
)
381 self
.height
= (1.0/ratio
) * self
.width
382 elif (height
is not None) and (width
is None):
383 self
.height
= unit
.length(height
)
384 self
.width
= ratio
* self
.height
386 self
.width
= unit
.length(width
)
387 self
.height
= unit
.length(height
)
388 self
.width_pt
= unit
.topt(self
.width
)
389 self
.height_pt
= unit
.topt(self
.height
)
390 if self
.width_pt
<= 0: raise ValueError("width <= 0")
391 if self
.height_pt
<= 0: raise ValueError("height <= 0")
393 def initaxes(self
, axes
, addlinkaxes
=0):
394 for key
in self
.axisnames
:
395 if not axes
.has_key(key
):
396 axes
[key
] = axis
.linear()
397 elif axes
[key
] is None:
400 if not axes
.has_key(key
+ "2") and axes
.has_key(key
):
401 axes
[key
+ "2"] = axes
[key
].createlinkaxis()
402 elif axes
[key
+ "2"] is None:
406 def __init__(self
, xpos
=0, ypos
=0, width
=None, height
=None, ratio
=goldenmean
,
407 key
=None, backgroundattrs
=None, axesdist
=0.8*unit
.v_cm
, **axes
):
408 canvas
.canvas
.__init
__(self
)
409 self
.xpos
= unit
.length(xpos
)
410 self
.ypos
= unit
.length(ypos
)
411 self
.xpos_pt
= unit
.topt(self
.xpos
)
412 self
.ypos_pt
= unit
.topt(self
.ypos
)
413 self
.initwidthheight(width
, height
, ratio
)
414 self
.initaxes(axes
, 1)
418 self
.backgroundattrs
= backgroundattrs
419 self
.axesdist
= axesdist
421 self
.domethods
= [self
.dolayout
, self
.dobackground
, self
.doaxes
, self
.dodata
, self
.dokey
]
427 return canvas
.canvas
.bbox(self
)
429 def outputPS(self
, file):
431 canvas
.canvas
.outputPS(self
, file)
435 # some thoughts, but deferred right now
437 # class graphxyz(graphxy):
439 # axisnames = "x", "y", "z"
441 # def _vxtickpoint(self, axis, v):
442 # return self._vpos(v, axis.vypos, axis.vzpos)
444 # def _vytickpoint(self, axis, v):
445 # return self._vpos(axis.vxpos, v, axis.vzpos)
447 # def _vztickpoint(self, axis, v):
448 # return self._vpos(axis.vxpos, axis.vypos, v)
450 # def vxtickdirection(self, axis, v):
451 # x1, y1 = self._vpos(v, axis.vypos, axis.vzpos)
452 # x2, y2 = self._vpos(v, 0.5, 0)
453 # dx, dy = x1 - x2, y1 - y2
454 # norm = math.hypot(dx, dy)
455 # return dx/norm, dy/norm
457 # def vytickdirection(self, axis, v):
458 # x1, y1 = self._vpos(axis.vxpos, v, axis.vzpos)
459 # x2, y2 = self._vpos(0.5, v, 0)
460 # dx, dy = x1 - x2, y1 - y2
461 # norm = math.hypot(dx, dy)
462 # return dx/norm, dy/norm
464 # def vztickdirection(self, axis, v):
466 # x1, y1 = self._vpos(axis.vxpos, axis.vypos, v)
467 # x2, y2 = self._vpos(0.5, 0.5, v)
468 # dx, dy = x1 - x2, y1 - y2
469 # norm = math.hypot(dx, dy)
470 # return dx/norm, dy/norm
472 # def _pos(self, x, y, z, xaxis=None, yaxis=None, zaxis=None):
473 # if xaxis is None: xaxis = self.axes["x"]
474 # if yaxis is None: yaxis = self.axes["y"]
475 # if zaxis is None: zaxis = self.axes["z"]
476 # return self._vpos(xaxis.convert(x), yaxis.convert(y), zaxis.convert(z))
478 # def pos(self, x, y, z, xaxis=None, yaxis=None, zaxis=None):
479 # if xaxis is None: xaxis = self.axes["x"]
480 # if yaxis is None: yaxis = self.axes["y"]
481 # if zaxis is None: zaxis = self.axes["z"]
482 # return self.vpos(xaxis.convert(x), yaxis.convert(y), zaxis.convert(z))
484 # def _vpos(self, vx, vy, vz):
485 # x, y, z = (vx - 0.5)*self._depth, (vy - 0.5)*self._width, (vz - 0.5)*self._height
486 # d0 = float(self.a[0]*self.b[1]*(z-self.eye[2])
487 # + self.a[2]*self.b[0]*(y-self.eye[1])
488 # + self.a[1]*self.b[2]*(x-self.eye[0])
489 # - self.a[2]*self.b[1]*(x-self.eye[0])
490 # - self.a[0]*self.b[2]*(y-self.eye[1])
491 # - self.a[1]*self.b[0]*(z-self.eye[2]))
492 # da = (self.eye[0]*self.b[1]*(z-self.eye[2])
493 # + self.eye[2]*self.b[0]*(y-self.eye[1])
494 # + self.eye[1]*self.b[2]*(x-self.eye[0])
495 # - self.eye[2]*self.b[1]*(x-self.eye[0])
496 # - self.eye[0]*self.b[2]*(y-self.eye[1])
497 # - self.eye[1]*self.b[0]*(z-self.eye[2]))
498 # db = (self.a[0]*self.eye[1]*(z-self.eye[2])
499 # + self.a[2]*self.eye[0]*(y-self.eye[1])
500 # + self.a[1]*self.eye[2]*(x-self.eye[0])
501 # - self.a[2]*self.eye[1]*(x-self.eye[0])
502 # - self.a[0]*self.eye[2]*(y-self.eye[1])
503 # - self.a[1]*self.eye[0]*(z-self.eye[2]))
504 # return da/d0 + self._xpos, db/d0 + self._ypos
506 # def vpos(self, vx, vy, vz):
507 # tx, ty = self._vpos(vx, vy, vz)
508 # return unit.t_pt(tx), unit.t_pt(ty)
510 # def xbaseline(self, axis, x1, x2, xaxis=None):
511 # if xaxis is None: xaxis = self.axes["x"]
512 # return self.vxbaseline(axis, xaxis.convert(x1), xaxis.convert(x2))
514 # def ybaseline(self, axis, y1, y2, yaxis=None):
515 # if yaxis is None: yaxis = self.axes["y"]
516 # return self.vybaseline(axis, yaxis.convert(y1), yaxis.convert(y2))
518 # def zbaseline(self, axis, z1, z2, zaxis=None):
519 # if zaxis is None: zaxis = self.axes["z"]
520 # return self.vzbaseline(axis, zaxis.convert(z1), zaxis.convert(z2))
522 # def vxbaseline(self, axis, v1, v2):
523 # return (path._line(*(self._vpos(v1, 0, 0) + self._vpos(v2, 0, 0))) +
524 # path._line(*(self._vpos(v1, 0, 1) + self._vpos(v2, 0, 1))) +
525 # path._line(*(self._vpos(v1, 1, 1) + self._vpos(v2, 1, 1))) +
526 # path._line(*(self._vpos(v1, 1, 0) + self._vpos(v2, 1, 0))))
528 # def vybaseline(self, axis, v1, v2):
529 # return (path._line(*(self._vpos(0, v1, 0) + self._vpos(0, v2, 0))) +
530 # path._line(*(self._vpos(0, v1, 1) + self._vpos(0, v2, 1))) +
531 # path._line(*(self._vpos(1, v1, 1) + self._vpos(1, v2, 1))) +
532 # path._line(*(self._vpos(1, v1, 0) + self._vpos(1, v2, 0))))
534 # def vzbaseline(self, axis, v1, v2):
535 # return (path._line(*(self._vpos(0, 0, v1) + self._vpos(0, 0, v2))) +
536 # path._line(*(self._vpos(0, 1, v1) + self._vpos(0, 1, v2))) +
537 # path._line(*(self._vpos(1, 1, v1) + self._vpos(1, 1, v2))) +
538 # path._line(*(self._vpos(1, 0, v1) + self._vpos(1, 0, v2))))
540 # def xgridpath(self, x, xaxis=None):
542 # if xaxis is None: xaxis = self.axes["x"]
543 # v = xaxis.convert(x)
544 # return path._line(self._xpos+v*self._width, self._ypos,
545 # self._xpos+v*self._width, self._ypos+self._height)
547 # def ygridpath(self, y, yaxis=None):
549 # if yaxis is None: yaxis = self.axes["y"]
550 # v = yaxis.convert(y)
551 # return path._line(self._xpos, self._ypos+v*self._height,
552 # self._xpos+self._width, self._ypos+v*self._height)
554 # def zgridpath(self, z, zaxis=None):
556 # if zaxis is None: zaxis = self.axes["z"]
557 # v = zaxis.convert(z)
558 # return path._line(self._xpos, self._zpos+v*self._height,
559 # self._xpos+self._width, self._zpos+v*self._height)
561 # def vxgridpath(self, v):
562 # return path.path(path._moveto(*self._vpos(v, 0, 0)),
563 # path._lineto(*self._vpos(v, 0, 1)),
564 # path._lineto(*self._vpos(v, 1, 1)),
565 # path._lineto(*self._vpos(v, 1, 0)),
568 # def vygridpath(self, v):
569 # return path.path(path._moveto(*self._vpos(0, v, 0)),
570 # path._lineto(*self._vpos(0, v, 1)),
571 # path._lineto(*self._vpos(1, v, 1)),
572 # path._lineto(*self._vpos(1, v, 0)),
575 # def vzgridpath(self, v):
576 # return path.path(path._moveto(*self._vpos(0, 0, v)),
577 # path._lineto(*self._vpos(0, 1, v)),
578 # path._lineto(*self._vpos(1, 1, v)),
579 # path._lineto(*self._vpos(1, 0, v)),
582 # def _addpos(self, x, y, dx, dy):
586 # def _connect(self, x1, y1, x2, y2):
588 # return path._lineto(x2, y2)
592 # if not self.removedomethod(self.doaxes): return
593 # axesdist_pt = unit.topt(self.axesdist)
594 # XPattern = re.compile(r"%s([2-9]|[1-9][0-9]+)?$" % self.axisnames[0])
595 # YPattern = re.compile(r"%s([2-9]|[1-9][0-9]+)?$" % self.axisnames[1])
596 # ZPattern = re.compile(r"%s([2-9]|[1-9][0-9]+)?$" % self.axisnames[2])
597 # items = list(self.axes.items())
598 # items.sort() #TODO: alphabetical sorting breaks for axis numbers bigger than 9
599 # for key, axis in items:
600 # num = self.keynum(key)
601 # num2 = 1 - num % 2 # x1 -> 0, x2 -> 1, x3 -> 0, x4 -> 1, ...
602 # num3 = 1 - 2 * (num % 2) # x1 -> -1, x2 -> 1, x3 -> -1, x4 -> 1, ...
603 # if XPattern.match(key):
606 # axis._vtickpoint = self._vxtickpoint
607 # axis.vgridpath = self.vxgridpath
608 # axis.vbaseline = self.vxbaseline
609 # axis.vtickdirection = self.vxtickdirection
610 # elif YPattern.match(key):
613 # axis._vtickpoint = self._vytickpoint
614 # axis.vgridpath = self.vygridpath
615 # axis.vbaseline = self.vybaseline
616 # axis.vtickdirection = self.vytickdirection
617 # elif ZPattern.match(key):
620 # axis._vtickpoint = self._vztickpoint
621 # axis.vgridpath = self.vzgridpath
622 # axis.vbaseline = self.vzbaseline
623 # axis.vtickdirection = self.vztickdirection
625 # raise ValueError("Axis key '%s' not allowed" % key)
626 # if axis.painter is not None:
628 # # if XPattern.match(key):
629 # # self._xaxisextents[num2] += axis._extent
630 # # needxaxisdist[num2] = 1
631 # # if YPattern.match(key):
632 # # self._yaxisextents[num2] += axis._extent
633 # # needyaxisdist[num2] = 1
635 # def __init__(self, tex, xpos=0, ypos=0, width=None, height=None, depth=None,
636 # phi=30, theta=30, distance=1,
637 # backgroundattrs=None, axesdist=0.8*unit.v_cm, **axes):
638 # canvas.canvas.__init__(self)
642 # self._xpos = unit.topt(xpos)
643 # self._ypos = unit.topt(ypos)
644 # self._width = unit.topt(width)
645 # self._height = unit.topt(height)
646 # self._depth = unit.topt(depth)
648 # self.height = height
650 # if self._width <= 0: raise ValueError("width < 0")
651 # if self._height <= 0: raise ValueError("height < 0")
652 # if self._depth <= 0: raise ValueError("height < 0")
653 # self._distance = distance*math.sqrt(self._width*self._width+
654 # self._height*self._height+
655 # self._depth*self._depth)
656 # phi *= -math.pi/180
657 # theta *= math.pi/180
658 # self.a = (-math.sin(phi), math.cos(phi), 0)
659 # self.b = (-math.cos(phi)*math.sin(theta),
660 # -math.sin(phi)*math.sin(theta),
662 # self.eye = (self._distance*math.cos(phi)*math.cos(theta),
663 # self._distance*math.sin(phi)*math.cos(theta),
664 # self._distance*math.sin(theta))
665 # self.initaxes(axes)
666 # self.axesdist = axesdist
667 # self.backgroundattrs = backgroundattrs
670 # self.domethods = [self.dolayout, self.dobackground, self.doaxes, self.dodata]
672 # self.defaultstyle = {}
676 # return bbox._bbox(self._xpos - 200, self._ypos - 200, self._xpos + 200, self._ypos + 200)