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-2005 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 import math
, re
, string
, warnings
27 from pyx
import canvas
, path
, trafo
, unit
28 from pyx
.graph
import style
29 from pyx
.graph
.axis
import axis
, positioner
32 goldenmean
= 0.5 * (math
.sqrt(5) + 1)
36 """style data storage class
38 Instances of this class are used to store data from the styles
39 and to pass point data to the styles by instances named privatedata
40 and sharedata. sharedata is shared between all the style(s) in use
41 by a data instance, while privatedata is private to each style and
42 used as a storage place instead of self to prevent side effects when
43 using a style several times."""
49 def __init__(self
, graph
, data
, styles
):
51 self
.title
= data
.title
53 # add styles to ensure all needs of the given styles
54 provided
= [] # already provided sharedata variables
55 addstyles
= [] # a list of style instances to be added in front
59 defaultprovider
= style
.getdefaultprovider(n
)
60 addstyles
.append(defaultprovider
)
61 provided
.extend(defaultprovider
.providesdata
)
62 provided
.extend(s
.providesdata
)
64 self
.styles
= addstyles
+ styles
65 self
.sharedata
= styledata()
66 self
.privatedatalist
= [styledata() for s
in self
.styles
]
68 # perform setcolumns to all styles
69 self
.usedcolumnnames
= []
70 for privatedata
, s
in zip(self
.privatedatalist
, self
.styles
):
71 self
.usedcolumnnames
.extend(s
.columnnames(privatedata
, self
.sharedata
, graph
, self
.data
.columnnames
))
73 def selectstyles(self
, graph
, selectindex
, selecttotal
):
74 for privatedata
, style
in zip(self
.privatedatalist
, self
.styles
):
75 style
.selectstyle(privatedata
, self
.sharedata
, graph
, selectindex
, selecttotal
)
77 def adjustaxesstatic(self
, graph
):
78 for columnname
, data
in self
.data
.columns
.items():
79 for privatedata
, style
in zip(self
.privatedatalist
, self
.styles
):
80 style
.adjustaxis(privatedata
, self
.sharedata
, graph
, columnname
, data
)
82 def makedynamicdata(self
, graph
):
83 self
.dynamiccolumns
= self
.data
.dynamiccolumns(graph
)
85 def adjustaxesdynamic(self
, graph
):
86 for columnname
, data
in self
.dynamiccolumns
.items():
87 for privatedata
, style
in zip(self
.privatedatalist
, self
.styles
):
88 style
.adjustaxis(privatedata
, self
.sharedata
, graph
, columnname
, data
)
90 def draw(self
, graph
):
91 for privatedata
, style
in zip(self
.privatedatalist
, self
.styles
):
92 style
.initdrawpoints(privatedata
, self
.sharedata
, graph
)
95 for columnname
in self
.usedcolumnnames
:
97 useitems
.append((columnname
, self
.dynamiccolumns
[columnname
]))
99 useitems
.append((columnname
, self
.data
.columns
[columnname
]))
101 raise ValueError("cannot draw empty data")
102 for i
in xrange(len(useitems
[0][1])):
103 for columnname
, data
in useitems
:
104 point
[columnname
] = data
[i
]
105 for privatedata
, style
in zip(self
.privatedatalist
, self
.styles
):
106 style
.drawpoint(privatedata
, self
.sharedata
, graph
, point
)
107 for privatedata
, style
in zip(self
.privatedatalist
, self
.styles
):
108 style
.donedrawpoints(privatedata
, self
.sharedata
, graph
)
110 def key_pt(self
, graph
, x_pt
, y_pt
, width_pt
, height_pt
):
111 for privatedata
, style
in zip(self
.privatedatalist
, self
.styles
):
112 style
.key_pt(privatedata
, self
.sharedata
, graph
, x_pt
, y_pt
, width_pt
, height_pt
)
114 def __getattr__(self
, attr
):
115 # read only access to the styles privatedata
116 stylesdata
= [getattr(styledata
, attr
)
117 for styledata
in self
.privatedatalist
118 if hasattr(styledata
, attr
)]
119 if len(stylesdata
) > 1:
121 elif len(stylesdata
) == 1:
123 raise AttributeError("access to styledata attribute '%s' failed" % attr
)
126 class graph(canvas
.canvas
):
129 canvas
.canvas
.__init
__(self
)
136 def did(self
, method
, *args
, **kwargs
):
137 if not self
._calls
.has_key(method
):
138 self
._calls
[method
] = []
139 for callargs
in self
._calls
[method
]:
140 if callargs
== (args
, kwargs
):
142 self
._calls
[method
].append((args
, kwargs
))
147 return canvas
.canvas
.bbox(self
)
149 def registerPS(self
, registry
):
151 canvas
.canvas
.registerPS(self
, registry
)
153 def registerPDF(self
, registry
):
155 canvas
.canvas
.registerPDF(self
, registry
)
157 def processPS(self
, file, writer
, context
, registry
, bbox
):
159 canvas
.canvas
.processPS(self
, file, writer
, context
, registry
, bbox
)
161 def processPDF(self
, file, writer
, context
, registry
, bbox
):
163 canvas
.canvas
.processPDF(self
, file, writer
, context
, registry
, bbox
)
165 def plot(self
, data
, styles
=None, rangewarning
=1):
166 if self
.didranges
and rangewarning
:
167 warnings
.warn("axes ranges have already been analysed; no further adjustments will be performed")
169 raise RuntimeError("can't add further data while data has already been processed")
182 styles
= d
.defaultstyles
183 elif styles
!= d
.defaultstyles
:
184 raise RuntimeError("defaultstyles differ")
187 plotitems
.append(plotitem(self
, d
, styles
))
188 self
.plotitems
.extend(plotitems
)
190 for aplotitem
in plotitems
:
191 aplotitem
.makedynamicdata(self
)
198 if self
.did(self
.doranges
):
200 for plotitem
in self
.plotitems
:
201 plotitem
.adjustaxesstatic(self
)
202 for plotitem
in self
.plotitems
:
203 plotitem
.makedynamicdata(self
)
204 for plotitem
in self
.plotitems
:
205 plotitem
.adjustaxesdynamic(self
)
209 raise NotImplementedError
211 def dobackground(self
):
212 raise NotImplementedError
215 raise NotImplementedError
218 if self
.did(self
.dodata
):
223 # count the usage of styles and perform selects
225 def stylesid(styles
):
226 return ":".join([str(id(style
)) for style
in styles
])
227 for plotitem
in self
.plotitems
:
229 styletotal
[stylesid(plotitem
.styles
)] += 1
231 styletotal
[stylesid(plotitem
.styles
)] = 1
233 for plotitem
in self
.plotitems
:
235 styleindex
[stylesid(plotitem
.styles
)] += 1
237 styleindex
[stylesid(plotitem
.styles
)] = 0
238 plotitem
.selectstyles(self
, styleindex
[stylesid(plotitem
.styles
)],
239 styletotal
[stylesid(plotitem
.styles
)])
241 for plotitem
in self
.plotitems
:
247 raise NotImplementedError
256 class graphxy(graph
):
258 def __init__(self
, xpos
=0, ypos
=0, width
=None, height
=None, ratio
=goldenmean
,
259 key
=None, backgroundattrs
=None, axesdist
=0.8*unit
.v_cm
,
260 xaxisat
=None, yaxisat
=None, **axes
):
265 self
.xpos_pt
= unit
.topt(self
.xpos
)
266 self
.ypos_pt
= unit
.topt(self
.ypos
)
267 self
.xaxisat
= xaxisat
268 self
.yaxisat
= yaxisat
270 self
.backgroundattrs
= backgroundattrs
271 self
.axesdist_pt
= unit
.topt(axesdist
)
277 raise ValueError("specify width and/or height")
279 self
.width
= ratio
* self
.height
281 self
.height
= (1.0/ratio
) * self
.width
282 self
.width_pt
= unit
.topt(self
.width
)
283 self
.height_pt
= unit
.topt(self
.height
)
285 for axisname
, aaxis
in axes
.items():
286 if aaxis
is not None:
287 if not isinstance(aaxis
, axis
.linkedaxis
):
288 self
.axes
[axisname
] = axis
.anchoredaxis(aaxis
, self
.texrunner
, axisname
)
290 self
.axes
[axisname
] = aaxis
291 for axisname
, axisat
in [("x", xaxisat
), ("y", yaxisat
)]:
292 okey
= axisname
+ "2"
293 if not axes
.has_key(axisname
):
294 if not axes
.has_key(okey
):
295 self
.axes
[axisname
] = axis
.anchoredaxis(axis
.linear(), self
.texrunner
, axisname
)
296 self
.axes
[okey
] = axis
.linkedaxis(self
.axes
[axisname
], okey
)
298 self
.axes
[axisname
] = axis
.linkedaxis(self
.axes
[okey
], axisname
)
299 elif not axes
.has_key(okey
) and axisat
is None:
300 self
.axes
[okey
] = axis
.linkedaxis(self
.axes
[axisname
], okey
)
302 if self
.axes
.has_key("x"):
303 self
.xbasepath
= self
.axes
["x"].basepath
304 self
.xvbasepath
= self
.axes
["x"].vbasepath
305 self
.xgridpath
= self
.axes
["x"].gridpath
306 self
.xtickpoint_pt
= self
.axes
["x"].tickpoint_pt
307 self
.xtickpoint
= self
.axes
["x"].tickpoint
308 self
.xvtickpoint_pt
= self
.axes
["x"].vtickpoint_pt
309 self
.xvtickpoint
= self
.axes
["x"].tickpoint
310 self
.xtickdirection
= self
.axes
["x"].tickdirection
311 self
.xvtickdirection
= self
.axes
["x"].vtickdirection
313 if self
.axes
.has_key("y"):
314 self
.ybasepath
= self
.axes
["y"].basepath
315 self
.yvbasepath
= self
.axes
["y"].vbasepath
316 self
.ygridpath
= self
.axes
["y"].gridpath
317 self
.ytickpoint_pt
= self
.axes
["y"].tickpoint_pt
318 self
.ytickpoint
= self
.axes
["y"].tickpoint
319 self
.yvtickpoint_pt
= self
.axes
["y"].vtickpoint_pt
320 self
.yvtickpoint
= self
.axes
["y"].tickpoint
321 self
.ytickdirection
= self
.axes
["y"].tickdirection
322 self
.yvtickdirection
= self
.axes
["y"].vtickdirection
324 self
.axesnames
= ([], [])
325 for axisname
, aaxis
in self
.axes
.items():
326 if axisname
[0] not in "xy" or (len(axisname
) != 1 and (not axisname
[1:].isdigit() or
327 axisname
[1:] == "1")):
328 raise ValueError("invalid axis name")
329 if axisname
[0] == "x":
330 self
.axesnames
[0].append(axisname
)
332 self
.axesnames
[1].append(axisname
)
333 aaxis
.setcreatecall(self
.doaxiscreate
, axisname
)
336 def pos_pt(self
, x
, y
, xaxis
=None, yaxis
=None):
338 xaxis
= self
.axes
["x"]
340 yaxis
= self
.axes
["y"]
341 return (self
.xpos_pt
+ xaxis
.convert(x
)*self
.width_pt
,
342 self
.ypos_pt
+ yaxis
.convert(y
)*self
.height_pt
)
344 def pos(self
, x
, y
, xaxis
=None, yaxis
=None):
346 xaxis
= self
.axes
["x"]
348 yaxis
= self
.axes
["y"]
349 return (self
.xpos
+ xaxis
.convert(x
)*self
.width
,
350 self
.ypos
+ yaxis
.convert(y
)*self
.height
)
352 def vpos_pt(self
, vx
, vy
):
353 return (self
.xpos_pt
+ vx
*self
.width_pt
,
354 self
.ypos_pt
+ vy
*self
.height_pt
)
356 def vpos(self
, vx
, vy
):
357 return (self
.xpos
+ vx
*self
.width
,
358 self
.ypos
+ vy
*self
.height
)
360 def vgeodesic(self
, vx1
, vy1
, vx2
, vy2
):
361 """returns a geodesic path between two points in graph coordinates"""
362 return path
.line_pt(self
.xpos_pt
+ vx1
*self
.width_pt
,
363 self
.ypos_pt
+ vy1
*self
.height_pt
,
364 self
.xpos_pt
+ vx2
*self
.width_pt
,
365 self
.ypos_pt
+ vy2
*self
.height_pt
)
367 def vgeodesic_el(self
, vx1
, vy1
, vx2
, vy2
):
368 """returns a geodesic path element between two points in graph coordinates"""
369 return path
.lineto_pt(self
.xpos_pt
+ vx2
*self
.width_pt
,
370 self
.ypos_pt
+ vy2
*self
.height_pt
)
372 def vcap_pt(self
, coordinate
, length_pt
, vx
, vy
):
373 """returns an error cap path for a given coordinate, lengths and
374 point in graph coordinates"""
376 return path
.line_pt(self
.xpos_pt
+ vx
*self
.width_pt
- 0.5*length_pt
,
377 self
.ypos_pt
+ vy
*self
.height_pt
,
378 self
.xpos_pt
+ vx
*self
.width_pt
+ 0.5*length_pt
,
379 self
.ypos_pt
+ vy
*self
.height_pt
)
380 elif coordinate
== 1:
381 return path
.line_pt(self
.xpos_pt
+ vx
*self
.width_pt
,
382 self
.ypos_pt
+ vy
*self
.height_pt
- 0.5*length_pt
,
383 self
.xpos_pt
+ vx
*self
.width_pt
,
384 self
.ypos_pt
+ vy
*self
.height_pt
+ 0.5*length_pt
)
386 raise ValueError("direction invalid")
388 def xvgridpath(self
, vx
):
389 return path
.line_pt(self
.xpos_pt
+ vx
*self
.width_pt
, self
.ypos_pt
,
390 self
.xpos_pt
+ vx
*self
.width_pt
, self
.ypos_pt
+ self
.height_pt
)
392 def yvgridpath(self
, vy
):
393 return path
.line_pt(self
.xpos_pt
, self
.ypos_pt
+ vy
*self
.height_pt
,
394 self
.xpos_pt
+ self
.width_pt
, self
.ypos_pt
+ vy
*self
.height_pt
)
396 def axistrafo(self
, axis
, t
):
397 c
= canvas
.canvas([t
])
398 c
.insert(axis
.canvas
)
401 def axisatv(self
, axis
, v
):
402 if axis
.positioner
.fixtickdirection
[0]:
404 self
.axistrafo(axis
, trafo
.translate_pt(self
.xpos_pt
+ v
*self
.width_pt
- axis
.positioner
.x1_pt
, 0))
407 self
.axistrafo(axis
, trafo
.translate_pt(0, self
.ypos_pt
+ v
*self
.height_pt
- axis
.positioner
.y1_pt
))
409 def doaxispositioner(self
, axisname
):
410 if self
.did(self
.doaxispositioner
, axisname
):
414 self
.axes
["x"].setpositioner(positioner
.lineaxispos_pt(self
.xpos_pt
, self
.ypos_pt
,
415 self
.xpos_pt
+ self
.width_pt
, self
.ypos_pt
,
416 (0, 1), self
.xvgridpath
))
417 elif axisname
== "x2":
418 self
.axes
["x2"].setpositioner(positioner
.lineaxispos_pt(self
.xpos_pt
, self
.ypos_pt
+ self
.height_pt
,
419 self
.xpos_pt
+ self
.width_pt
, self
.ypos_pt
+ self
.height_pt
,
420 (0, -1), self
.xvgridpath
))
421 elif axisname
== "y":
422 self
.axes
["y"].setpositioner(positioner
.lineaxispos_pt(self
.xpos_pt
, self
.ypos_pt
,
423 self
.xpos_pt
, self
.ypos_pt
+ self
.height_pt
,
424 (1, 0), self
.yvgridpath
))
425 elif axisname
== "y2":
426 self
.axes
["y2"].setpositioner(positioner
.lineaxispos_pt(self
.xpos_pt
+ self
.width_pt
, self
.ypos_pt
,
427 self
.xpos_pt
+ self
.width_pt
, self
.ypos_pt
+ self
.height_pt
,
428 (-1, 0), self
.yvgridpath
))
430 if axisname
[1:] == "3":
431 dependsonaxisname
= axisname
[0]
433 dependsonaxisname
= "%s%d" % (axisname
[0], int(axisname
[1:]) - 2)
434 self
.doaxiscreate(dependsonaxisname
)
435 sign
= 2*(int(axisname
[1:]) % 2) - 1
436 if axisname
[0] == "x":
437 y_pt
= self
.axes
[dependsonaxisname
].positioner
.y1_pt
- sign
* (self
.axes
[dependsonaxisname
].canvas
.extent_pt
+ self
.axesdist_pt
)
438 self
.axes
[axisname
].setpositioner(positioner
.lineaxispos_pt(self
.xpos_pt
, y_pt
,
439 self
.xpos_pt
+ self
.width_pt
, y_pt
,
440 (0, sign
), self
.xvgridpath
))
442 x_pt
= self
.axes
[dependsonaxisname
].positioner
.x1_pt
- sign
* (self
.axes
[dependsonaxisname
].canvas
.extent_pt
+ self
.axesdist_pt
)
443 self
.axes
[axisname
].setpositioner(positioner
.lineaxispos_pt(x_pt
, self
.ypos_pt
,
444 x_pt
, self
.ypos_pt
+ self
.height_pt
,
445 (sign
, 0), self
.yvgridpath
))
447 def doaxiscreate(self
, axisname
):
448 if self
.did(self
.doaxiscreate
, axisname
):
450 self
.doaxispositioner(axisname
)
451 self
.axes
[axisname
].create()
454 if self
.did(self
.dolayout
):
456 for axisname
in self
.axes
.keys():
457 self
.doaxiscreate(axisname
)
458 if self
.xaxisat
is not None:
459 self
.axisatv(self
.axes
["x"], self
.axes
["y"].convert(self
.xaxisat
))
460 if self
.yaxisat
is not None:
461 self
.axisatv(self
.axes
["y"], self
.axes
["x"].convert(self
.yaxisat
))
463 def dobackground(self
):
464 if self
.did(self
.dobackground
):
466 if self
.backgroundattrs
is not None:
467 self
.draw(path
.rect_pt(self
.xpos_pt
, self
.ypos_pt
, self
.width_pt
, self
.height_pt
),
468 self
.backgroundattrs
)
471 if self
.did(self
.doaxes
):
475 for axis
in self
.axes
.values():
476 self
.insert(axis
.canvas
)
479 if self
.did(self
.dokey
):
483 if self
.key
is not None:
484 c
= self
.key
.paint(self
.plotitems
)
486 def parentchildalign(pmin
, pmax
, cmin
, cmax
, pos
, dist
, inside
):
487 ppos
= pmin
+0.5*(cmax
-cmin
)+dist
+pos
*(pmax
-pmin
-cmax
+cmin
-2*dist
)
488 cpos
= 0.5*(cmin
+cmax
)+(1-inside
)*(1-2*pos
)*(cmax
-cmin
+2*dist
)
490 x
= parentchildalign(self
.xpos_pt
, self
.xpos_pt
+self
.width_pt
,
491 bbox
.llx_pt
, bbox
.urx_pt
,
492 self
.key
.hpos
, unit
.topt(self
.key
.hdist
), self
.key
.hinside
)
493 y
= parentchildalign(self
.ypos_pt
, self
.ypos_pt
+self
.height_pt
,
494 bbox
.lly_pt
, bbox
.ury_pt
,
495 self
.key
.vpos
, unit
.topt(self
.key
.vdist
), self
.key
.vinside
)
496 self
.insert(c
, [trafo
.translate_pt(x
, y
)])
499 # some thoughts, but deferred right now
501 # class graphxyz(graphxy):
503 # axisnames = "x", "y", "z"
505 # def _vxtickpoint(self, axis, v):
506 # return self._vpos(v, axis.vypos, axis.vzpos)
508 # def _vytickpoint(self, axis, v):
509 # return self._vpos(axis.vxpos, v, axis.vzpos)
511 # def _vztickpoint(self, axis, v):
512 # return self._vpos(axis.vxpos, axis.vypos, v)
514 # def vxtickdirection(self, axis, v):
515 # x1, y1 = self._vpos(v, axis.vypos, axis.vzpos)
516 # x2, y2 = self._vpos(v, 0.5, 0)
517 # dx, dy = x1 - x2, y1 - y2
518 # norm = math.hypot(dx, dy)
519 # return dx/norm, dy/norm
521 # def vytickdirection(self, axis, v):
522 # x1, y1 = self._vpos(axis.vxpos, v, axis.vzpos)
523 # x2, y2 = self._vpos(0.5, v, 0)
524 # dx, dy = x1 - x2, y1 - y2
525 # norm = math.hypot(dx, dy)
526 # return dx/norm, dy/norm
528 # def vztickdirection(self, axis, v):
530 # x1, y1 = self._vpos(axis.vxpos, axis.vypos, v)
531 # x2, y2 = self._vpos(0.5, 0.5, v)
532 # dx, dy = x1 - x2, y1 - y2
533 # norm = math.hypot(dx, dy)
534 # return dx/norm, dy/norm
536 # def _pos(self, x, y, z, xaxis=None, yaxis=None, zaxis=None):
537 # if xaxis is None: xaxis = self.axes["x"]
538 # if yaxis is None: yaxis = self.axes["y"]
539 # if zaxis is None: zaxis = self.axes["z"]
540 # return self._vpos(xaxis.convert(x), yaxis.convert(y), zaxis.convert(z))
542 # def pos(self, x, y, z, xaxis=None, yaxis=None, zaxis=None):
543 # if xaxis is None: xaxis = self.axes["x"]
544 # if yaxis is None: yaxis = self.axes["y"]
545 # if zaxis is None: zaxis = self.axes["z"]
546 # return self.vpos(xaxis.convert(x), yaxis.convert(y), zaxis.convert(z))
548 # def _vpos(self, vx, vy, vz):
549 # x, y, z = (vx - 0.5)*self._depth, (vy - 0.5)*self._width, (vz - 0.5)*self._height
550 # d0 = float(self.a[0]*self.b[1]*(z-self.eye[2])
551 # + self.a[2]*self.b[0]*(y-self.eye[1])
552 # + self.a[1]*self.b[2]*(x-self.eye[0])
553 # - self.a[2]*self.b[1]*(x-self.eye[0])
554 # - self.a[0]*self.b[2]*(y-self.eye[1])
555 # - self.a[1]*self.b[0]*(z-self.eye[2]))
556 # da = (self.eye[0]*self.b[1]*(z-self.eye[2])
557 # + self.eye[2]*self.b[0]*(y-self.eye[1])
558 # + self.eye[1]*self.b[2]*(x-self.eye[0])
559 # - self.eye[2]*self.b[1]*(x-self.eye[0])
560 # - self.eye[0]*self.b[2]*(y-self.eye[1])
561 # - self.eye[1]*self.b[0]*(z-self.eye[2]))
562 # db = (self.a[0]*self.eye[1]*(z-self.eye[2])
563 # + self.a[2]*self.eye[0]*(y-self.eye[1])
564 # + self.a[1]*self.eye[2]*(x-self.eye[0])
565 # - self.a[2]*self.eye[1]*(x-self.eye[0])
566 # - self.a[0]*self.eye[2]*(y-self.eye[1])
567 # - self.a[1]*self.eye[0]*(z-self.eye[2]))
568 # return da/d0 + self._xpos, db/d0 + self._ypos
570 # def vpos(self, vx, vy, vz):
571 # tx, ty = self._vpos(vx, vy, vz)
572 # return unit.t_pt(tx), unit.t_pt(ty)
574 # def xbaseline(self, axis, x1, x2, xaxis=None):
575 # if xaxis is None: xaxis = self.axes["x"]
576 # return self.vxbaseline(axis, xaxis.convert(x1), xaxis.convert(x2))
578 # def ybaseline(self, axis, y1, y2, yaxis=None):
579 # if yaxis is None: yaxis = self.axes["y"]
580 # return self.vybaseline(axis, yaxis.convert(y1), yaxis.convert(y2))
582 # def zbaseline(self, axis, z1, z2, zaxis=None):
583 # if zaxis is None: zaxis = self.axes["z"]
584 # return self.vzbaseline(axis, zaxis.convert(z1), zaxis.convert(z2))
586 # def vxbaseline(self, axis, v1, v2):
587 # return (path._line(*(self._vpos(v1, 0, 0) + self._vpos(v2, 0, 0))) +
588 # path._line(*(self._vpos(v1, 0, 1) + self._vpos(v2, 0, 1))) +
589 # path._line(*(self._vpos(v1, 1, 1) + self._vpos(v2, 1, 1))) +
590 # path._line(*(self._vpos(v1, 1, 0) + self._vpos(v2, 1, 0))))
592 # def vybaseline(self, axis, v1, v2):
593 # return (path._line(*(self._vpos(0, v1, 0) + self._vpos(0, v2, 0))) +
594 # path._line(*(self._vpos(0, v1, 1) + self._vpos(0, v2, 1))) +
595 # path._line(*(self._vpos(1, v1, 1) + self._vpos(1, v2, 1))) +
596 # path._line(*(self._vpos(1, v1, 0) + self._vpos(1, v2, 0))))
598 # def vzbaseline(self, axis, v1, v2):
599 # return (path._line(*(self._vpos(0, 0, v1) + self._vpos(0, 0, v2))) +
600 # path._line(*(self._vpos(0, 1, v1) + self._vpos(0, 1, v2))) +
601 # path._line(*(self._vpos(1, 1, v1) + self._vpos(1, 1, v2))) +
602 # path._line(*(self._vpos(1, 0, v1) + self._vpos(1, 0, v2))))
604 # def xgridpath(self, x, xaxis=None):
606 # if xaxis is None: xaxis = self.axes["x"]
607 # v = xaxis.convert(x)
608 # return path._line(self._xpos+v*self._width, self._ypos,
609 # self._xpos+v*self._width, self._ypos+self._height)
611 # def ygridpath(self, y, yaxis=None):
613 # if yaxis is None: yaxis = self.axes["y"]
614 # v = yaxis.convert(y)
615 # return path._line(self._xpos, self._ypos+v*self._height,
616 # self._xpos+self._width, self._ypos+v*self._height)
618 # def zgridpath(self, z, zaxis=None):
620 # if zaxis is None: zaxis = self.axes["z"]
621 # v = zaxis.convert(z)
622 # return path._line(self._xpos, self._zpos+v*self._height,
623 # self._xpos+self._width, self._zpos+v*self._height)
625 # def vxgridpath(self, v):
626 # return path.path(path._moveto(*self._vpos(v, 0, 0)),
627 # path._lineto(*self._vpos(v, 0, 1)),
628 # path._lineto(*self._vpos(v, 1, 1)),
629 # path._lineto(*self._vpos(v, 1, 0)),
632 # def vygridpath(self, v):
633 # return path.path(path._moveto(*self._vpos(0, v, 0)),
634 # path._lineto(*self._vpos(0, v, 1)),
635 # path._lineto(*self._vpos(1, v, 1)),
636 # path._lineto(*self._vpos(1, v, 0)),
639 # def vzgridpath(self, v):
640 # return path.path(path._moveto(*self._vpos(0, 0, v)),
641 # path._lineto(*self._vpos(0, 1, v)),
642 # path._lineto(*self._vpos(1, 1, v)),
643 # path._lineto(*self._vpos(1, 0, v)),
646 # def _addpos(self, x, y, dx, dy):
650 # def _connect(self, x1, y1, x2, y2):
652 # return path._lineto(x2, y2)
656 # if not self.removedomethod(self.doaxes): return
657 # axesdist_pt = unit.topt(self.axesdist)
658 # XPattern = re.compile(r"%s([2-9]|[1-9][0-9]+)?$" % self.axisnames[0])
659 # YPattern = re.compile(r"%s([2-9]|[1-9][0-9]+)?$" % self.axisnames[1])
660 # ZPattern = re.compile(r"%s([2-9]|[1-9][0-9]+)?$" % self.axisnames[2])
661 # items = list(self.axes.items())
662 # items.sort() #TODO: alphabetical sorting breaks for axis numbers bigger than 9
663 # for key, axis in items:
664 # num = self.keynum(key)
665 # num2 = 1 - num % 2 # x1 -> 0, x2 -> 1, x3 -> 0, x4 -> 1, ...
666 # num3 = 1 - 2 * (num % 2) # x1 -> -1, x2 -> 1, x3 -> -1, x4 -> 1, ...
667 # if XPattern.match(key):
670 # axis._vtickpoint = self._vxtickpoint
671 # axis.vgridpath = self.vxgridpath
672 # axis.vbaseline = self.vxbaseline
673 # axis.vtickdirection = self.vxtickdirection
674 # elif YPattern.match(key):
677 # axis._vtickpoint = self._vytickpoint
678 # axis.vgridpath = self.vygridpath
679 # axis.vbaseline = self.vybaseline
680 # axis.vtickdirection = self.vytickdirection
681 # elif ZPattern.match(key):
684 # axis._vtickpoint = self._vztickpoint
685 # axis.vgridpath = self.vzgridpath
686 # axis.vbaseline = self.vzbaseline
687 # axis.vtickdirection = self.vztickdirection
689 # raise ValueError("Axis key '%s' not allowed" % key)
690 # if axis.painter is not None:
692 # # if XPattern.match(key):
693 # # self._xaxisextents[num2] += axis._extent
694 # # needxaxisdist[num2] = 1
695 # # if YPattern.match(key):
696 # # self._yaxisextents[num2] += axis._extent
697 # # needyaxisdist[num2] = 1
699 # def __init__(self, tex, xpos=0, ypos=0, width=None, height=None, depth=None,
700 # phi=30, theta=30, distance=1,
701 # backgroundattrs=None, axesdist=0.8*unit.v_cm, **axes):
702 # canvas.canvas.__init__(self)
706 # self._xpos = unit.topt(xpos)
707 # self._ypos = unit.topt(ypos)
708 # self._width = unit.topt(width)
709 # self._height = unit.topt(height)
710 # self._depth = unit.topt(depth)
712 # self.height = height
714 # if self._width <= 0: raise ValueError("width < 0")
715 # if self._height <= 0: raise ValueError("height < 0")
716 # if self._depth <= 0: raise ValueError("height < 0")
717 # self._distance = distance*math.sqrt(self._width*self._width+
718 # self._height*self._height+
719 # self._depth*self._depth)
720 # phi *= -math.pi/180
721 # theta *= math.pi/180
722 # self.a = (-math.sin(phi), math.cos(phi), 0)
723 # self.b = (-math.cos(phi)*math.sin(theta),
724 # -math.sin(phi)*math.sin(theta),
726 # self.eye = (self._distance*math.cos(phi)*math.cos(theta),
727 # self._distance*math.sin(phi)*math.cos(theta),
728 # self._distance*math.sin(theta))
729 # self.initaxes(axes)
730 # self.axesdist = axesdist
731 # self.backgroundattrs = backgroundattrs
734 # self.domethods = [self.dolayout, self.dobackground, self.doaxes, self.dodata]
736 # self.defaultstyle = {}
740 # return bbox._bbox(self._xpos - 200, self._ypos - 200, self._xpos + 200, self._ypos + 200)