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
27 from pyx
import attr
, deco
, style
, color
, unit
, canvas
, path
28 from pyx
import text
as textmodule
32 """Interface class for graph styles
34 Each graph style must support the methods described in this
35 class. However, since a graph style might not need to perform
36 actions on all the various events, it does not need to overwrite
37 all methods of this base class (e.g. this class is not an abstract
38 class in any respect).
40 A style should never store private data by istance variables
41 (i.e. accessing self), but it should use the sharedata and privatedata
42 instances instead. A style instance can be used multiple times with
43 different sharedata and privatedata instances at the very same time.
44 The sharedata and privatedata instances act as data containers and
45 sharedata allows for sharing information across several styles.
47 Every style contains two class variables, which are not to be
49 - providesdata is a list of variable names a style offers via
50 the sharedata instance. This list is used to determine whether
51 all needs of subsequent styles are fullfilled. Otherwise
52 getdefaultprovider should return a proper style to be used.
53 - needsdata is a list of variable names the style needs to access in the
57 providesdata
= [] # by default, we provide nothing
58 needsdata
= [] # and do not depend on anything
60 def columns(self
, privatedata
, sharedata
, graph
, columns
):
61 """Set column information
63 This method is used setup the column information to be
64 accessible to the style later on. The style should analyse
65 the list of strings columns, which contain the column names
66 of the data. The method should return a list of column names
67 which the style will make use of."""
70 def selectstyle(self
, privatedata
, sharedata
, graph
, selectindex
, selecttotal
):
71 """Select stroke/fill attributes
73 This method is called to allow for the selection of
74 changable attributes of a style."""
77 def adjustaxis(self
, privatedata
, sharedata
, graph
, column
, data
, index
):
80 This method is called in order to adjust the axis range to
81 the provided data. Column is the name of the column (each
82 style is subsequently called for all column names). If index
83 is not None, data is a list of points and index is the index
84 of the column within a point. Otherwise data is already the
85 axis data. Note, that data might be different for different
86 columns, e.i. data might come from various places and is
87 combined without copying but keeping references."""
90 def initdrawpoints(self
, privatedata
, sharedata
, graph
):
91 """Initialize drawing of data
93 This method might be used to initialize the drawing of data."""
96 def drawpoint(self
, privatedata
, sharedata
, graph
):
99 This method is called for each data point. The data is
100 available in the dictionary sharedata.point. The dictionary
101 keys are the column names."""
104 def donedrawpoints(self
, privatedata
, sharedata
, graph
):
105 """Finalize drawing of data
107 This method is called after the last data point was
108 drawn using the drawpoint method above."""
111 def key_pt(self
, privatedata
, sharedata
, graph
, x_pt
, y_pt
, width_pt
, height_pt
, dy_pt
):
114 This method draws a key for the style to graph at the given
115 position x_pt, y_pt indicating the lower left corner of the
116 given area width_pt, height_pt. The style might draw several
117 key entries shifted vertically by dy_pt. The method returns
118 the number of key entries or None, when nothing was drawn."""
122 # The following two methods are used to register and get a default provider
123 # for keys. A key is a variable name in sharedata. A provider is a style
124 # which creates variables in sharedata.
126 _defaultprovider
= {}
128 def registerdefaultprovider(style
, keys
):
129 """sets a style as a default creator for sharedata variables 'keys'"""
130 assert not len(style
.needsdata
), "currently we state, that a style should not depend on other sharedata variables"
132 assert key
in style
.providesdata
, "key not provided by style"
133 # we might allow for overwriting the defaults, i.e. the following is not checked:
134 # assert key in _defaultprovider.keys(), "default provider already registered for key"
135 _defaultprovider
[key
] = style
137 def getdefaultprovider(key
):
138 """returns a style, which acts as a default creator for the
139 sharedata variable 'key'"""
140 return _defaultprovider
[key
]
145 providesdata
= ["vpos", "vposmissing", "vposavailable", "vposvalid"]
147 def __init__(self
, epsilon
=1e-10):
148 self
.epsilon
= epsilon
150 def columns(self
, privatedata
, sharedata
, graph
, columns
):
151 privatedata
.pointposcolumns
= []
152 sharedata
.vposmissing
= []
153 for count
, axisnames
in enumerate(graph
.axesnames
):
154 for axisname
in axisnames
:
155 for column
in columns
:
156 if axisname
== column
:
157 privatedata
.pointposcolumns
.append(column
)
158 if len(privatedata
.pointposcolumns
) + len(sharedata
.vposmissing
) > count
+1:
159 raise ValueError("multiple axes per graph dimension")
160 elif len(privatedata
.pointposcolumns
) + len(sharedata
.vposmissing
) < count
+1:
161 sharedata
.vposmissing
.append(count
)
162 return privatedata
.pointposcolumns
164 def adjustaxis(self
, privatedata
, sharedata
, graph
, column
, data
, index
):
165 if column
in privatedata
.pointposcolumns
:
166 graph
.axes
[column
].adjustrange(data
, index
)
168 def initdrawpoints(self
, privatedata
, sharedata
, graph
):
169 sharedata
.vpos
= [None]*(len(privatedata
.pointposcolumns
) + len(sharedata
.vposmissing
))
170 privatedata
.pointpostmplist
= [[column
, index
, graph
.axes
[column
]] # temporarily used by drawpoint only
171 for index
, column
in enumerate(privatedata
.pointposcolumns
)]
172 for missing
in sharedata
.vposmissing
:
173 for pointpostmp
in privatedata
.pointpostmplist
:
174 if pointpostmp
[1] >= missing
:
177 def drawpoint(self
, privatedata
, sharedata
, graph
):
178 sharedata
.vposavailable
= 1 # valid position (but might be outside of the graph)
179 sharedata
.vposvalid
= 1 # valid position inside the graph
180 for column
, index
, axis
in privatedata
.pointpostmplist
:
182 v
= axis
.convert(sharedata
.point
[column
])
183 except (ArithmeticError, ValueError, TypeError):
184 sharedata
.vposavailable
= sharedata
.vposvalid
= 0
185 sharedata
.vpos
[index
] = None
187 if v
< -self
.epsilon
or v
> 1+self
.epsilon
:
188 sharedata
.vposvalid
= 0
189 sharedata
.vpos
[index
] = v
192 registerdefaultprovider(_pos(), _pos
.providesdata
)
195 class _range(_style
):
197 providesdata
= ["vrange", "vrangemissing", "vrangeminmissing", "vrangemaxmissing"]
207 def __init__(self
, epsilon
=1e-10):
208 self
.epsilon
= epsilon
210 def columns(self
, privatedata
, sharedata
, graph
, columns
):
211 def numberofbits(mask
):
215 return numberofbits(mask
>> 1) + 1
217 return numberofbits(mask
>> 1)
219 privatedata
.rangeposcolumns
= []
220 sharedata
.vrangemissing
= []
221 sharedata
.vrangeminmissing
= []
222 sharedata
.vrangemaxmissing
= []
223 privatedata
.rangeposdeltacolumns
= {} # temporarily used by adjustaxis only
224 for count
, axisnames
in enumerate(graph
.axesnames
):
225 for axisname
in axisnames
:
227 for column
in columns
:
229 if axisname
== column
:
230 mask
+= self
.mask_value
231 elif axisname
+ "min" == column
:
232 mask
+= self
.mask_min
233 elif axisname
+ "max" == column
:
234 mask
+= self
.mask_max
235 elif "d" + axisname
+ "min" == column
:
236 mask
+= self
.mask_dmin
237 elif "d" + axisname
+ "max" == column
:
238 mask
+= self
.mask_dmax
239 elif "d" + axisname
== column
:
244 usecolumns
.append(column
)
245 if mask
& (self
.mask_min | self
.mask_max | self
.mask_dmin | self
.mask_dmax | self
.mask_d
):
246 if (numberofbits(mask
& (self
.mask_min | self
.mask_dmin | self
.mask_d
)) > 1 or
247 numberofbits(mask
& (self
.mask_max | self
.mask_dmax | self
.mask_d
)) > 1):
248 raise ValueError("multiple errorbar definition")
249 if mask
& (self
.mask_dmin | self
.mask_dmax | self
.mask_d
):
250 if not (mask
& self
.mask_value
):
251 raise ValueError("missing value for delta")
252 privatedata
.rangeposdeltacolumns
[axisname
] = {}
253 privatedata
.rangeposcolumns
.append((axisname
, mask
))
254 elif mask
== self
.mask_value
:
255 usecolumns
= usecolumns
[:-1]
256 if len(privatedata
.rangeposcolumns
) + len(sharedata
.vrangemissing
) > count
+1:
257 raise ValueError("multiple axes per graph dimension")
258 elif len(privatedata
.rangeposcolumns
) + len(sharedata
.vrangemissing
) < count
+1:
259 sharedata
.vrangemissing
.append(count
)
261 if not (privatedata
.rangeposcolumns
[-1][1] & (self
.mask_min | self
.mask_dmin | self
.mask_d
)):
262 sharedata
.vrangeminmissing
.append(count
)
263 if not (privatedata
.rangeposcolumns
[-1][1] & (self
.mask_max | self
.mask_dmax | self
.mask_d
)):
264 sharedata
.vrangemaxmissing
.append(count
)
267 def adjustaxis(self
, privatedata
, sharedata
, graph
, column
, data
, index
):
268 if column
in [c
+ "min" for c
, m
in privatedata
.rangeposcolumns
if m
& self
.mask_min
]:
269 graph
.axes
[column
[:-3]].adjustrange(data
, index
)
270 if column
in [c
+ "max" for c
, m
in privatedata
.rangeposcolumns
if m
& self
.mask_max
]:
271 graph
.axes
[column
[:-3]].adjustrange(data
, index
)
273 # delta handling: fill rangeposdeltacolumns
274 if column
in [c
for c
, m
in privatedata
.rangeposcolumns
if m
& (self
.mask_dmin | self
.mask_dmax | self
.mask_d
)]:
275 privatedata
.rangeposdeltacolumns
[column
][self
.mask_value
] = data
, index
276 if column
in ["d" + c
+ "min" for c
, m
in privatedata
.rangeposcolumns
if m
& self
.mask_dmin
]:
277 privatedata
.rangeposdeltacolumns
[column
[1:-3]][self
.mask_dmin
] = data
, index
278 if column
in ["d" + c
+ "max" for c
, m
in privatedata
.rangeposcolumns
if m
& self
.mask_dmax
]:
279 privatedata
.rangeposdeltacolumns
[column
[1:-3]][self
.mask_dmax
] = data
, index
280 if column
in ["d" + c
for c
, m
in privatedata
.rangeposcolumns
if m
& self
.mask_d
]:
281 privatedata
.rangeposdeltacolumns
[column
[1:]][self
.mask_d
] = data
, index
283 # delta handling: process rangeposdeltacolumns
284 for c
, d
in privatedata
.rangeposdeltacolumns
.items():
285 if d
.has_key(self
.mask_value
):
287 if k
!= self
.mask_value
:
288 if k
& (self
.mask_dmin | self
.mask_d
):
289 graph
.axes
[c
].adjustrange(d
[self
.mask_value
][0], d
[self
.mask_value
][1],
290 deltamindata
=d
[k
][0], deltaminindex
=d
[k
][1])
291 if k
& (self
.mask_dmax | self
.mask_d
):
292 graph
.axes
[c
].adjustrange(d
[self
.mask_value
][0], d
[self
.mask_value
][1],
293 deltamaxdata
=d
[k
][0], deltamaxindex
=d
[k
][1])
296 def initdrawpoints(self
, privatedata
, sharedata
, graph
):
297 sharedata
.vrange
= [[None for x
in range(2)] for y
in privatedata
.rangeposcolumns
+ sharedata
.vrangemissing
]
298 privatedata
.rangepostmplist
= [[column
, mask
, index
, graph
.axes
[column
]] # temporarily used by drawpoint only
299 for index
, (column
, mask
) in enumerate(privatedata
.rangeposcolumns
)]
300 for missing
in sharedata
.vrangemissing
:
301 for rangepostmp
in privatedata
.rangepostmplist
:
302 if rangepostmp
[2] >= missing
:
305 def drawpoint(self
, privatedata
, sharedata
, graph
):
306 for column
, mask
, index
, axis
in privatedata
.rangepostmplist
:
308 if mask
& self
.mask_min
:
309 sharedata
.vrange
[index
][0] = axis
.convert(sharedata
.point
[column
+ "min"])
310 if mask
& self
.mask_dmin
:
311 sharedata
.vrange
[index
][0] = axis
.convert(sharedata
.point
[column
] - sharedata
.point
["d" + column
+ "min"])
312 if mask
& self
.mask_d
:
313 sharedata
.vrange
[index
][0] = axis
.convert(sharedata
.point
[column
] - sharedata
.point
["d" + column
])
314 except (ArithmeticError, ValueError, TypeError):
315 sharedata
.vrange
[index
][0] = None
317 if mask
& self
.mask_max
:
318 sharedata
.vrange
[index
][1] = axis
.convert(sharedata
.point
[column
+ "max"])
319 if mask
& self
.mask_dmax
:
320 sharedata
.vrange
[index
][1] = axis
.convert(sharedata
.point
[column
] + sharedata
.point
["d" + column
+ "max"])
321 if mask
& self
.mask_d
:
322 sharedata
.vrange
[index
][1] = axis
.convert(sharedata
.point
[column
] + sharedata
.point
["d" + column
])
323 except (ArithmeticError, ValueError, TypeError):
324 sharedata
.vrange
[index
][1] = None
326 # some range checks for data consistency
327 if (sharedata
.vrange
[index
][0] is not None and sharedata
.vrange
[index
][1] is not None and
328 sharedata
.vrange
[index
][0] > sharedata
.vrange
[index
][1] + self
.epsilon
):
329 raise ValueError("negative errorbar range")
330 #if (sharedata.vrange[index][0] is not None and sharedata.vpos[index] is not None and
331 # sharedata.vrange[index][0] > sharedata.vpos[index] + self.epsilon):
332 # raise ValueError("negative minimum errorbar")
333 #if (sharedata.vrange[index][1] is not None and sharedata.vpos[index] is not None and
334 # sharedata.vrange[index][1] < sharedata.vpos[index] - self.epsilon):
335 # raise ValueError("negative maximum errorbar")
338 registerdefaultprovider(_range(), _range
.providesdata
)
341 def _crosssymbol(c
, x_pt
, y_pt
, size_pt
, attrs
):
342 c
.draw(path
.path(path
.moveto_pt(x_pt
-0.5*size_pt
, y_pt
-0.5*size_pt
),
343 path
.lineto_pt(x_pt
+0.5*size_pt
, y_pt
+0.5*size_pt
),
344 path
.moveto_pt(x_pt
-0.5*size_pt
, y_pt
+0.5*size_pt
),
345 path
.lineto_pt(x_pt
+0.5*size_pt
, y_pt
-0.5*size_pt
)), attrs
)
347 def _plussymbol(c
, x_pt
, y_pt
, size_pt
, attrs
):
348 c
.draw(path
.path(path
.moveto_pt(x_pt
-0.707106781*size_pt
, y_pt
),
349 path
.lineto_pt(x_pt
+0.707106781*size_pt
, y_pt
),
350 path
.moveto_pt(x_pt
, y_pt
-0.707106781*size_pt
),
351 path
.lineto_pt(x_pt
, y_pt
+0.707106781*size_pt
)), attrs
)
353 def _squaresymbol(c
, x_pt
, y_pt
, size_pt
, attrs
):
354 c
.draw(path
.path(path
.moveto_pt(x_pt
-0.5*size_pt
, y_pt
-0.5*size_pt
),
355 path
.lineto_pt(x_pt
+0.5*size_pt
, y_pt
-0.5*size_pt
),
356 path
.lineto_pt(x_pt
+0.5*size_pt
, y_pt
+0.5*size_pt
),
357 path
.lineto_pt(x_pt
-0.5*size_pt
, y_pt
+0.5*size_pt
),
358 path
.closepath()), attrs
)
360 def _trianglesymbol(c
, x_pt
, y_pt
, size_pt
, attrs
):
361 c
.draw(path
.path(path
.moveto_pt(x_pt
-0.759835685*size_pt
, y_pt
-0.438691337*size_pt
),
362 path
.lineto_pt(x_pt
+0.759835685*size_pt
, y_pt
-0.438691337*size_pt
),
363 path
.lineto_pt(x_pt
, y_pt
+0.877382675*size_pt
),
364 path
.closepath()), attrs
)
366 def _circlesymbol(c
, x_pt
, y_pt
, size_pt
, attrs
):
367 c
.draw(path
.path(path
.arc_pt(x_pt
, y_pt
, 0.564189583*size_pt
, 0, 360),
368 path
.closepath()), attrs
)
370 def _diamondsymbol(c
, x_pt
, y_pt
, size_pt
, attrs
):
371 c
.draw(path
.path(path
.moveto_pt(x_pt
-0.537284965*size_pt
, y_pt
),
372 path
.lineto_pt(x_pt
, y_pt
-0.930604859*size_pt
),
373 path
.lineto_pt(x_pt
+0.537284965*size_pt
, y_pt
),
374 path
.lineto_pt(x_pt
, y_pt
+0.930604859*size_pt
),
375 path
.closepath()), attrs
)
378 class _styleneedingpointpos(_style
):
380 needsdata
= ["vposmissing"]
382 def columns(self
, privatedata
, sharedata
, graph
, columns
):
383 if len(sharedata
.vposmissing
):
384 raise ValueError("position columns incomplete")
388 class symbol(_styleneedingpointpos
):
390 needsdata
= ["vpos", "vposmissing", "vposvalid"]
393 # note, that statements like cross = _crosssymbol are
394 # invalid, since the would lead to unbound methods, but
395 # a single entry changeable list does the trick
396 cross
= attr
.changelist([_crosssymbol
])
397 plus
= attr
.changelist([_plussymbol
])
398 square
= attr
.changelist([_squaresymbol
])
399 triangle
= attr
.changelist([_trianglesymbol
])
400 circle
= attr
.changelist([_circlesymbol
])
401 diamond
= attr
.changelist([_diamondsymbol
])
403 changecross
= attr
.changelist([_crosssymbol
, _plussymbol
, _squaresymbol
, _trianglesymbol
, _circlesymbol
, _diamondsymbol
])
404 changeplus
= attr
.changelist([_plussymbol
, _squaresymbol
, _trianglesymbol
, _circlesymbol
, _diamondsymbol
, cross
])
405 changesquare
= attr
.changelist([_squaresymbol
, _trianglesymbol
, _circlesymbol
, _diamondsymbol
, cross
, _plussymbol
])
406 changetriangle
= attr
.changelist([_trianglesymbol
, _circlesymbol
, _diamondsymbol
, cross
, _plussymbol
, _squaresymbol
])
407 changecircle
= attr
.changelist([_circlesymbol
, _diamondsymbol
, cross
, _plussymbol
, _squaresymbol
, _trianglesymbol
])
408 changediamond
= attr
.changelist([_diamondsymbol
, cross
, _plussymbol
, _squaresymbol
, _trianglesymbol
, _circlesymbol
])
409 changesquaretwice
= attr
.changelist([_squaresymbol
, _squaresymbol
, _trianglesymbol
, _trianglesymbol
, _circlesymbol
, _circlesymbol
, _diamondsymbol
, _diamondsymbol
])
410 changetriangletwice
= attr
.changelist([_trianglesymbol
, _trianglesymbol
, _circlesymbol
, _circlesymbol
, _diamondsymbol
, _diamondsymbol
, _squaresymbol
, _squaresymbol
])
411 changecircletwice
= attr
.changelist([_circlesymbol
, _circlesymbol
, _diamondsymbol
, _diamondsymbol
, _squaresymbol
, _squaresymbol
, _trianglesymbol
, _trianglesymbol
])
412 changediamondtwice
= attr
.changelist([_diamondsymbol
, _diamondsymbol
, _squaresymbol
, _squaresymbol
, _trianglesymbol
, _trianglesymbol
, _circlesymbol
, _circlesymbol
])
414 changestrokedfilled
= attr
.changelist([deco
.stroked
, deco
.filled
])
415 changefilledstroked
= attr
.changelist([deco
.filled
, deco
.stroked
])
417 defaultsymbolattrs
= [deco
.stroked
]
419 def __init__(self
, symbol
=changecross
, size
=0.2*unit
.v_cm
, symbolattrs
=[]):
422 self
.symbolattrs
= symbolattrs
424 def selectstyle(self
, privatedata
, sharedata
, graph
, selectindex
, selecttotal
):
425 privatedata
.symbol
= attr
.selectattr(self
.symbol
, selectindex
, selecttotal
)
426 privatedata
.size_pt
= unit
.topt(attr
.selectattr(self
.size
, selectindex
, selecttotal
))
427 if self
.symbolattrs
is not None:
428 privatedata
.symbolattrs
= attr
.selectattrs(self
.defaultsymbolattrs
+ self
.symbolattrs
, selectindex
, selecttotal
)
430 privatedata
.symbolattrs
= None
432 def initdrawpoints(self
, privatedata
, sharedata
, graph
):
433 privatedata
.symbolcanvas
= graph
.insert(canvas
.canvas())
435 def drawpoint(self
, privatedata
, sharedata
, graph
):
436 if sharedata
.vposvalid
and privatedata
.symbolattrs
is not None:
437 xpos
, ypos
= graph
.vpos_pt(*sharedata
.vpos
)
438 privatedata
.symbol(privatedata
.symbolcanvas
, xpos
, ypos
, privatedata
.size_pt
, privatedata
.symbolattrs
)
440 def key_pt(self
, privatedata
, sharedata
, graph
, x_pt
, y_pt
, width_pt
, height_pt
, dy_pt
):
441 if privatedata
.symbolattrs
is not None:
442 privatedata
.symbol(graph
, x_pt
+0.5*width_pt
, y_pt
+0.5*height_pt
, privatedata
.size_pt
, privatedata
.symbolattrs
)
446 class line(_styleneedingpointpos
):
448 needsdata
= ["vpos", "vposmissing", "vposavailable", "vposvalid"]
450 changelinestyle
= attr
.changelist([style
.linestyle
.solid
,
451 style
.linestyle
.dashed
,
452 style
.linestyle
.dotted
,
453 style
.linestyle
.dashdotted
])
455 defaultlineattrs
= [changelinestyle
]
457 def __init__(self
, lineattrs
=[]):
458 self
.lineattrs
= lineattrs
460 def selectstyle(self
, privatedata
, sharedata
, graph
, selectindex
, selecttotal
):
461 privatedata
.lineattrs
= attr
.selectattrs(self
.defaultlineattrs
+ self
.lineattrs
, selectindex
, selecttotal
)
463 def initdrawpoints(self
, privatedata
, sharedata
, graph
):
464 if privatedata
.lineattrs
is not None:
465 privatedata
.linecanvas
= graph
.insert(canvas
.canvas())
466 privatedata
.linecanvas
.set(privatedata
.lineattrs
)
467 privatedata
.path
= path
.path()
468 privatedata
.linebasepoints
= []
469 privatedata
.lastvpos
= None
471 def addpointstopath(self
, privatedata
, sharedata
):
472 # add baselinepoints to privatedata.path
473 if len(privatedata
.linebasepoints
) > 1:
474 privatedata
.path
.append(path
.moveto_pt(*privatedata
.linebasepoints
[0]))
475 if len(privatedata
.linebasepoints
) > 2:
476 privatedata
.path
.append(path
.multilineto_pt(privatedata
.linebasepoints
[1:]))
478 privatedata
.path
.append(path
.lineto_pt(*privatedata
.linebasepoints
[1]))
479 privatedata
.linebasepoints
= []
481 def drawpoint(self
, privatedata
, sharedata
, graph
):
482 # append linebasepoints
483 if sharedata
.vposavailable
:
484 if len(privatedata
.linebasepoints
):
485 # the last point was inside the graph
486 if sharedata
.vposvalid
: # shortcut for the common case
487 privatedata
.linebasepoints
.append(graph
.vpos_pt(*sharedata
.vpos
))
491 for vstart
, vend
in zip(privatedata
.lastvpos
, sharedata
.vpos
):
494 # 1 = vstart + (vend - vstart) * cut
496 newcut
= (1 - vstart
)/(vend
- vstart
)
497 except ArithmeticError:
500 # 0 = vstart + (vend - vstart) * cut
502 newcut
= - vstart
/(vend
- vstart
)
503 except ArithmeticError:
505 if newcut
is not None and newcut
< cut
:
509 for vstart
, vend
in zip(privatedata
.lastvpos
, sharedata
.vpos
):
510 cutvpos
.append(vstart
+ (vend
- vstart
) * cut
)
511 privatedata
.linebasepoints
.append(graph
.vpos_pt(*cutvpos
))
512 self
.addpointstopath(privatedata
, sharedata
)
514 # the last point was outside the graph
515 if privatedata
.lastvpos
is not None:
516 if sharedata
.vposvalid
:
519 for vstart
, vend
in zip(privatedata
.lastvpos
, sharedata
.vpos
):
522 # 1 = vstart + (vend - vstart) * cut
524 newcut
= (1 - vstart
)/(vend
- vstart
)
525 except ArithmeticError:
528 # 0 = vstart + (vend - vstart) * cut
530 newcut
= - vstart
/(vend
- vstart
)
531 except ArithmeticError:
533 if newcut
is not None and newcut
> cut
:
537 for vstart
, vend
in zip(privatedata
.lastvpos
, sharedata
.vpos
):
538 cutvpos
.append(vstart
+ (vend
- vstart
) * cut
)
539 privatedata
.linebasepoints
.append(graph
.vpos_pt(*cutvpos
))
540 privatedata
.linebasepoints
.append(graph
.vpos_pt(*sharedata
.vpos
))
542 # sometimes cut beginning and end
545 for vstart
, vend
in zip(privatedata
.lastvpos
, sharedata
.vpos
):
550 # 1 = vstart + (vend - vstart) * cutfrom
552 newcutfrom
= (1 - vstart
)/(vend
- vstart
)
553 except ArithmeticError:
558 # 0 = vstart + (vend - vstart) * cutfrom
560 newcutfrom
= - vstart
/(vend
- vstart
)
561 except ArithmeticError:
563 if newcutfrom
is not None and newcutfrom
> cutfrom
:
567 # 1 = vstart + (vend - vstart) * cutto
569 newcutto
= (1 - vstart
)/(vend
- vstart
)
570 except ArithmeticError:
573 # 0 = vstart + (vend - vstart) * cutto
575 newcutto
= - vstart
/(vend
- vstart
)
576 except ArithmeticError:
578 if newcutto
is not None and newcutto
< cutto
:
584 for vstart
, vend
in zip(privatedata
.lastvpos
, sharedata
.vpos
):
585 cutfromvpos
.append(vstart
+ (vend
- vstart
) * cutfrom
)
586 cuttovpos
.append(vstart
+ (vend
- vstart
) * cutto
)
587 privatedata
.linebasepoints
.append(graph
.vpos_pt(*cutfromvpos
))
588 privatedata
.linebasepoints
.append(graph
.vpos_pt(*cuttovpos
))
589 self
.addpointstopath(privatedata
, sharedata
)
590 privatedata
.lastvpos
= sharedata
.vpos
[:]
592 if len(privatedata
.linebasepoints
) > 1:
593 self
.addpointstopath(privatedata
, sharedata
)
594 privatedata
.lastvpos
= None
596 def donedrawpoints(self
, privatedata
, sharedata
, graph
):
597 if len(privatedata
.linebasepoints
) > 1:
598 self
.addpointstopath(privatedata
, sharedata
)
599 if privatedata
.lineattrs
is not None and len(privatedata
.path
.path
):
600 privatedata
.linecanvas
.stroke(privatedata
.path
)
602 def key_pt(self
, privatedata
, sharedata
, graph
, x_pt
, y_pt
, width_pt
, height_pt
, dy_pt
):
603 if privatedata
.lineattrs
is not None:
604 graph
.stroke(path
.line_pt(x_pt
, y_pt
+0.5*height_pt
, x_pt
+width_pt
, y_pt
+0.5*height_pt
), privatedata
.lineattrs
)
608 class errorbar(_style
):
610 needsdata
= ["vpos", "vposmissing", "vposavailable", "vposvalid", "vrange", "vrangemissing"]
612 defaulterrorbarattrs
= []
614 def __init__(self
, size
=0.1*unit
.v_cm
,
618 self
.errorbarattrs
= errorbarattrs
619 self
.epsilon
= epsilon
621 def columns(self
, privatedata
, sharedata
, graph
, columns
):
622 for i
in sharedata
.vposmissing
:
623 if i
in sharedata
.vrangemissing
:
624 raise ValueError("position and range for a graph dimension missing")
627 def selectstyle(self
, privatedata
, sharedata
, graph
, selectindex
, selecttotal
):
628 privatedata
.errorsize_pt
= unit
.topt(attr
.selectattr(self
.size
, selectindex
, selecttotal
))
629 privatedata
.errorbarattrs
= attr
.selectattrs(self
.defaulterrorbarattrs
+ self
.errorbarattrs
, selectindex
, selecttotal
)
631 def initdrawpoints(self
, privatedata
, sharedata
, graph
):
632 if privatedata
.errorbarattrs
is not None:
633 privatedata
.errorbarcanvas
= graph
.insert(canvas
.canvas())
634 privatedata
.errorbarcanvas
.set(privatedata
.errorbarattrs
)
635 privatedata
.dimensionlist
= range(len(sharedata
.vpos
))
637 def drawpoint(self
, privatedata
, sharedata
, graph
):
638 if privatedata
.errorbarattrs
is not None:
639 for i
in privatedata
.dimensionlist
:
640 for j
in privatedata
.dimensionlist
:
642 (sharedata
.vpos
[j
] is None or
643 sharedata
.vpos
[j
] < -self
.epsilon
or
644 sharedata
.vpos
[j
] > 1+self
.epsilon
)):
647 if ((sharedata
.vrange
[i
][0] is None and sharedata
.vpos
[i
] is None) or
648 (sharedata
.vrange
[i
][1] is None and sharedata
.vpos
[i
] is None) or
649 (sharedata
.vrange
[i
][0] is None and sharedata
.vrange
[i
][1] is None)):
651 vminpos
= sharedata
.vpos
[:]
652 if sharedata
.vrange
[i
][0] is not None:
653 vminpos
[i
] = sharedata
.vrange
[i
][0]
657 if vminpos
[i
] > 1+self
.epsilon
:
659 if vminpos
[i
] < -self
.epsilon
:
662 vmaxpos
= sharedata
.vpos
[:]
663 if sharedata
.vrange
[i
][1] is not None:
664 vmaxpos
[i
] = sharedata
.vrange
[i
][1]
668 if vmaxpos
[i
] < -self
.epsilon
:
670 if vmaxpos
[i
] > 1+self
.epsilon
:
673 privatedata
.errorbarcanvas
.stroke(graph
.vgeodesic(*(vminpos
+ vmaxpos
)))
674 for j
in privatedata
.dimensionlist
:
677 privatedata
.errorbarcanvas
.stroke(graph
.vcap_pt(j
, privatedata
.errorsize_pt
, *vminpos
))
679 privatedata
.errorbarcanvas
.stroke(graph
.vcap_pt(j
, privatedata
.errorsize_pt
, *vmaxpos
))
682 class text(_styleneedingpointpos
):
684 needsdata
= ["vpos", "vposmissing", "vposvalid"]
686 defaulttextattrs
= [textmodule
.halign
.center
, textmodule
.vshift
.mathaxis
]
688 def __init__(self
, textdx
=0*unit
.v_cm
, textdy
=0.3*unit
.v_cm
, textattrs
=[], **kwargs
):
691 self
.textattrs
= textattrs
693 def columns(self
, privatedata
, sharedata
, graph
, columns
):
694 if "text" not in columns
:
695 raise ValueError("text missing")
696 return ["text"] + _styleneedingpointpos
.columns(self
, privatedata
, sharedata
, graph
, columns
)
698 def selectstyle(self
, privatedata
, sharedata
, graph
, selectindex
, selecttotal
):
699 if self
.textattrs
is not None:
700 privatedata
.textattrs
= attr
.selectattrs(self
.defaulttextattrs
+ self
.textattrs
, selectindex
, selecttotal
)
702 privatedata
.textattrs
= None
704 def initdrawpoints(self
, privatedata
, sharedata
, grap
):
705 privatedata
.textdx_pt
= unit
.topt(self
.textdx
)
706 privatedata
.textdy_pt
= unit
.topt(self
.textdy
)
708 def drawpoint(self
, privatedata
, sharedata
, graph
):
709 if privatedata
.textattrs
is not None and sharedata
.vposvalid
:
710 x_pt
, y_pt
= graph
.vpos_pt(*sharedata
.vpos
)
712 text
= str(sharedata
.point
["text"])
716 graph
.text_pt(x_pt
+ privatedata
.textdx_pt
, y_pt
+ privatedata
.textdy_pt
, text
, privatedata
.textattrs
)
719 class arrow(_styleneedingpointpos
):
721 needsdata
= ["vpos", "vposmissing", "vposvalid"]
723 defaultlineattrs
= []
724 defaultarrowattrs
= []
726 def __init__(self
, linelength
=0.25*unit
.v_cm
, arrowsize
=0.15*unit
.v_cm
, lineattrs
=[], arrowattrs
=[], epsilon
=1e-10):
727 self
.linelength
= linelength
728 self
.arrowsize
= arrowsize
729 self
.lineattrs
= lineattrs
730 self
.arrowattrs
= arrowattrs
731 self
.epsilon
= epsilon
733 def columns(self
, privatedata
, sharedata
, graph
, columns
):
734 if len(graph
.axesnames
) != 2:
735 raise ValueError("arrow style restricted on two-dimensional graphs")
736 if "size" not in columns
:
737 raise ValueError("size missing")
738 if "angle" not in columns
:
739 raise ValueError("angle missing")
740 return ["size", "angle"] + _styleneedingpointpos
.columns(self
, privatedata
, sharedata
, graph
, columns
)
742 def selectstyle(self
, privatedata
, sharedata
, graph
, selectindex
, selecttotal
):
743 if self
.lineattrs
is not None:
744 privatedata
.lineattrs
= attr
.selectattrs(self
.defaultlineattrs
+ self
.lineattrs
, selectindex
, selecttotal
)
746 privatedata
.lineattrs
= None
747 if self
.arrowattrs
is not None:
748 privatedata
.arrowattrs
= attr
.selectattrs(self
.defaultarrowattrs
+ self
.arrowattrs
, selectindex
, selecttotal
)
750 privatedata
.arrowattrs
= None
752 def initdrawpoints(self
, privatedata
, sharedata
, graph
):
753 privatedata
.arrowcanvas
= graph
.insert(canvas
.canvas())
755 def drawpoint(self
, privatedata
, sharedata
, graph
):
756 if privatedata
.lineattrs
is not None and privatedata
.arrowattrs
is not None and sharedata
.vposvalid
:
757 linelength_pt
= unit
.topt(self
.linelength
)
758 x_pt
, y_pt
= graph
.vpos_pt(*sharedata
.vpos
)
760 angle
= sharedata
.point
["angle"] + 0.0
761 size
= sharedata
.point
["size"] + 0.0
765 if sharedata
.point
["size"] > self
.epsilon
:
766 dx
= math
.cos(angle
*math
.pi
/180)
767 dy
= math
.sin(angle
*math
.pi
/180)
768 x1
= x_pt
-0.5*dx
*linelength_pt
*size
769 y1
= y_pt
-0.5*dy
*linelength_pt
*size
770 x2
= x_pt
+0.5*dx
*linelength_pt
*size
771 y2
= y_pt
+0.5*dy
*linelength_pt
*size
772 privatedata
.arrowcanvas
.stroke(path
.line_pt(x1
, y1
, x2
, y2
), privatedata
.lineattrs
+
773 [deco
.earrow(privatedata
.arrowattrs
, size
=self
.arrowsize
*size
)])
775 def key_pt(self
, privatedata
, sharedata
, graph
, x_pt
, y_pt
, width_pt
, height_pt
, dy_pt
):
781 needsdata
= ["vrange", "vrangeminmissing", "vrangemaxmissing"]
783 def __init__(self
, palette
=color
.palette
.Gray
):
784 self
.palette
= palette
786 def columns(self
, privatedata
, sharedata
, graph
, columns
):
787 if len(graph
.axesnames
) != 2:
788 raise TypeError("arrow style restricted on two-dimensional graphs")
789 if "color" not in columns
:
790 raise ValueError("color missing")
791 if len(sharedata
.vrangeminmissing
) + len(sharedata
.vrangemaxmissing
):
792 raise ValueError("range columns incomplete")
795 def initdrawpoints(self
, privatedata
, sharedata
, graph
):
796 privatedata
.rectcanvas
= graph
.insert(canvas
.canvas())
797 privatedata
.lastcolorvalue
= None
799 def drawpoint(self
, privatedata
, sharedata
, graph
):
800 xvmin
= sharedata
.vrange
[0][0]
801 xvmax
= sharedata
.vrange
[0][1]
802 yvmin
= sharedata
.vrange
[1][0]
803 yvmax
= sharedata
.vrange
[1][1]
804 if (xvmin
is not None and xvmin
< 1 and
805 xvmax
is not None and xvmax
> 0 and
806 yvmin
is not None and yvmin
< 1 and
807 yvmax
is not None and yvmax
> 0):
816 p
= graph
.vgeodesic(xvmin
, yvmin
, xvmax
, yvmin
)
817 p
.append(graph
.vgeodesic_el(xvmax
, yvmin
, xvmax
, yvmax
))
818 p
.append(graph
.vgeodesic_el(xvmax
, yvmax
, xvmin
, yvmax
))
819 p
.append(graph
.vgeodesic_el(xvmin
, yvmax
, xvmin
, yvmin
))
820 p
.append(path
.closepath())
821 colorvalue
= sharedata
.point
["color"]
823 if colorvalue
!= privatedata
.lastcolorvalue
:
824 privatedata
.rectcanvas
.set([self
.palette
.getcolor(colorvalue
)])
828 privatedata
.rectcanvas
.fill(p
)
830 def key_pt(self
, privatedata
, sharedata
, graph
, x_pt
, y_pt
, width_pt
, height_pt
, dy_pt
):
834 class barpos(_style
):
836 providesdata
= ["vpos", "vposmissing", "vposavailable", "vposvalid", "barcolumns", "barvalueindex", "vbarpos"]
838 def __init__(self
, fromvalue
=None, subindex
=0, subnames
=None, epsilon
=1e-10):
839 # TODO: vpos configuration ...
840 self
.fromvalue
= fromvalue
841 self
.subnames
= subnames
842 self
.subindex
= subindex
843 self
.epsilon
= epsilon
845 def columns(self
, privatedata
, sharedata
, graph
, columns
):
846 # TODO: we might check whether barcolumns/barvalueindex is already available
847 sharedata
.barcolumns
= []
848 sharedata
.barvalueindex
= None
849 for dimension
, axisnames
in enumerate(graph
.axesnames
):
850 for axisname
in axisnames
:
851 if axisname
in columns
:
852 if sharedata
.barvalueindex
is not None:
853 raise ValueError("multiple values")
854 valuecolumns
= [axisname
]
856 stackedvalue
= "%sstack%i" % (axisname
, len(valuecolumns
))
857 if stackedvalue
in columns
:
858 valuecolumns
.append(stackedvalue
)
861 sharedata
.barcolumns
.append(valuecolumns
)
862 sharedata
.barvalueindex
= dimension
866 for axisname
in axisnames
:
867 if (axisname
+ "name") in columns
:
869 raise ValueError("multiple names")
871 sharedata
.barcolumns
.append(axisname
+ "name")
873 raise ValueError("value/name missing")
874 if sharedata
.barvalueindex
is None:
875 raise ValueError("missing value")
876 if self
.subindex
>= sharedata
.barvalueindex
:
877 privatedata
.barpossubindex
= self
.subindex
+ 1
879 privatedata
.barpossubindex
= self
.subindex
880 sharedata
.vposmissing
= []
881 return sharedata
.barcolumns
[sharedata
.barvalueindex
] + [sharedata
.barcolumns
[i
] for i
in range(len(sharedata
.barcolumns
)) if i
!= sharedata
.barvalueindex
]
883 def selectstyle(self
, privatedata
, sharedata
, graph
, selectindex
, selecttotal
):
885 if self
.subnames
is not None:
886 raise ValueError("subnames set for single-bar data")
887 privatedata
.barpossubname
= []
889 if self
.subnames
is not None:
890 privatedata
.barpossubname
= [self
.subnames
[selectindex
]]
892 privatedata
.barpossubname
= [selectindex
]
894 def adjustaxis(self
, privatedata
, sharedata
, graph
, column
, data
, index
):
895 if column
in sharedata
.barcolumns
[sharedata
.barvalueindex
]:
896 graph
.axes
[sharedata
.barcolumns
[sharedata
.barvalueindex
][0]].adjustrange(data
, index
)
897 if self
.fromvalue
is not None and column
== sharedata
.barcolumns
[sharedata
.barvalueindex
][0]:
898 graph
.axes
[sharedata
.barcolumns
[sharedata
.barvalueindex
][0]].adjustrange([self
.fromvalue
], None)
901 i
= sharedata
.barcolumns
.index(column
)
905 if i
== privatedata
.barpossubindex
:
906 graph
.axes
[column
[:-4]].adjustrange(data
, index
, privatedata
.barpossubname
)
908 graph
.axes
[column
[:-4]].adjustrange(data
, index
)
910 def initdrawpoints(self
, privatedata
, sharedata
, graph
):
911 sharedata
.vpos
= [None]*(len(sharedata
.barcolumns
))
912 sharedata
.vbarpos
= [[None for i
in range(2)] for x
in sharedata
.barcolumns
]
914 if self
.fromvalue
is not None:
915 vfromvalue
= graph
.axes
[sharedata
.barcolumns
[sharedata
.barvalueindex
][0]].convert(self
.fromvalue
)
923 sharedata
.vbarpos
[sharedata
.barvalueindex
] = [vfromvalue
] + [None]*len(sharedata
.barcolumns
[sharedata
.barvalueindex
])
925 def drawpoint(self
, privatedata
, sharedata
, graph
):
926 sharedata
.vposavailable
= sharedata
.vposvalid
= 1
927 for i
, barname
in enumerate(sharedata
.barcolumns
):
928 if i
== sharedata
.barvalueindex
:
929 for j
, valuename
in enumerate(sharedata
.barcolumns
[sharedata
.barvalueindex
]):
931 sharedata
.vbarpos
[i
][j
+1] = graph
.axes
[sharedata
.barcolumns
[i
][0]].convert(sharedata
.point
[valuename
])
932 except (ArithmeticError, ValueError, TypeError):
933 sharedata
.vbarpos
[i
][j
+1] = None
934 sharedata
.vpos
[i
] = sharedata
.vbarpos
[i
][-1]
938 if i
== privatedata
.barpossubindex
:
939 sharedata
.vbarpos
[i
][j
] = graph
.axes
[barname
[:-4]].convert(([sharedata
.point
[barname
]] + privatedata
.barpossubname
+ [j
]))
941 sharedata
.vbarpos
[i
][j
] = graph
.axes
[barname
[:-4]].convert((sharedata
.point
[barname
], j
))
942 except (ArithmeticError, ValueError, TypeError):
943 sharedata
.vbarpos
[i
][j
] = None
945 sharedata
.vpos
[i
] = 0.5*(sharedata
.vbarpos
[i
][0]+sharedata
.vbarpos
[i
][1])
946 except (ArithmeticError, ValueError, TypeError):
947 sharedata
.vpos
[i
] = None
948 if sharedata
.vpos
[i
] is None:
949 sharedata
.vposavailable
= sharedata
.vposvalid
= 0
950 elif sharedata
.vpos
[i
] < -self
.epsilon
or sharedata
.vpos
[i
] > 1+self
.epsilon
:
951 sharedata
.vposvalid
= 0
953 registerdefaultprovider(barpos(), ["barcolumns", "barvalueindex", "vbarpos"])
958 needsdata
= ["barvalueindex", "vbarpos"]
960 defaultfrompathattrs
= []
961 defaultbarattrs
= [color
.palette
.Rainbow
, deco
.stroked([color
.gray
.black
])]
963 def __init__(self
, frompathattrs
=[], barattrs
=[], subnames
=None, multikey
=0, epsilon
=1e-10):
964 self
.frompathattrs
= frompathattrs
965 self
.barattrs
= barattrs
966 self
.subnames
= subnames
967 self
.multikey
= multikey
968 self
.epsilon
= epsilon
970 def selectstyle(self
, privatedata
, sharedata
, graph
, selectindex
, selecttotal
):
972 privatedata
.frompathattrs
= None
974 privatedata
.frompathattrs
= self
.defaultfrompathattrs
+ self
.frompathattrs
976 if self
.barattrs
is not None:
977 privatedata
.barattrs
= attr
.selectattrs(self
.defaultbarattrs
+ self
.barattrs
, selectindex
, selecttotal
)
979 privatedata
.barattrs
= None
981 privatedata
.barattrs
= self
.defaultbarattrs
+ self
.barattrs
982 privatedata
.barselectindex
= selectindex
983 privatedata
.barselecttotal
= selecttotal
984 if privatedata
.barselecttotal
!= 1 and self
.subnames
is not None:
985 raise ValueError("subnames not allowed when iterating over bars")
987 def initdrawpoints(self
, privatedata
, sharedata
, graph
):
988 privatedata
.bartmpvpos
= [None]*4
989 l
= len(sharedata
.vbarpos
[sharedata
.barvalueindex
])
991 privatedata
.bartmplist
= []
992 for i
in xrange(1, l
):
993 barattrs
= attr
.selectattrs(privatedata
.barattrs
, i
-1, l
)
994 if barattrs
is not None:
995 privatedata
.bartmplist
.append((i
, barattrs
))
997 privatedata
.bartmplist
= [(1, privatedata
.barattrs
)]
998 if privatedata
.frompathattrs
is not None:
999 vfromvalue
= sharedata
.vbarpos
[sharedata
.barvalueindex
][0]
1000 if vfromvalue
> self
.epsilon
and vfromvalue
< 1 - self
.epsilon
:
1001 if sharedata
.barvalueindex
:
1002 p
= graph
.vgeodesic(0, vfromvalue
, 1, vfromvalue
)
1004 p
= graph
.vgeodesic(vfromvalue
, 0, vfromvalue
, 1)
1005 graph
.stroke(p
, privatedata
.frompathattrs
)
1006 privatedata
.barcanvas
= graph
.insert(canvas
.canvas())
1008 def drawpoint(self
, privatedata
, sharedata
, graph
):
1009 if privatedata
.barattrs
is not None:
1010 for i
, barattrs
in privatedata
.bartmplist
:
1011 if None not in sharedata
.vbarpos
[1-sharedata
.barvalueindex
]+sharedata
.vbarpos
[sharedata
.barvalueindex
][i
-1:i
+1]:
1012 privatedata
.bartmpvpos
[1-sharedata
.barvalueindex
] = sharedata
.vbarpos
[1-sharedata
.barvalueindex
][0]
1013 privatedata
.bartmpvpos
[ sharedata
.barvalueindex
] = sharedata
.vbarpos
[sharedata
.barvalueindex
][i
-1]
1014 privatedata
.bartmpvpos
[3-sharedata
.barvalueindex
] = sharedata
.vbarpos
[1-sharedata
.barvalueindex
][0]
1015 privatedata
.bartmpvpos
[2+sharedata
.barvalueindex
] = sharedata
.vbarpos
[sharedata
.barvalueindex
][i
]
1016 p
= graph
.vgeodesic(*privatedata
.bartmpvpos
)
1017 privatedata
.bartmpvpos
[1-sharedata
.barvalueindex
] = sharedata
.vbarpos
[1-sharedata
.barvalueindex
][0]
1018 privatedata
.bartmpvpos
[ sharedata
.barvalueindex
] = sharedata
.vbarpos
[sharedata
.barvalueindex
][i
]
1019 privatedata
.bartmpvpos
[3-sharedata
.barvalueindex
] = sharedata
.vbarpos
[1-sharedata
.barvalueindex
][1]
1020 privatedata
.bartmpvpos
[2+sharedata
.barvalueindex
] = sharedata
.vbarpos
[sharedata
.barvalueindex
][i
]
1021 p
.append(graph
.vgeodesic_el(*privatedata
.bartmpvpos
))
1022 privatedata
.bartmpvpos
[1-sharedata
.barvalueindex
] = sharedata
.vbarpos
[1-sharedata
.barvalueindex
][1]
1023 privatedata
.bartmpvpos
[ sharedata
.barvalueindex
] = sharedata
.vbarpos
[sharedata
.barvalueindex
][i
]
1024 privatedata
.bartmpvpos
[3-sharedata
.barvalueindex
] = sharedata
.vbarpos
[1-sharedata
.barvalueindex
][1]
1025 privatedata
.bartmpvpos
[2+sharedata
.barvalueindex
] = sharedata
.vbarpos
[sharedata
.barvalueindex
][i
-1]
1026 p
.append(graph
.vgeodesic_el(*privatedata
.bartmpvpos
))
1027 privatedata
.bartmpvpos
[1-sharedata
.barvalueindex
] = sharedata
.vbarpos
[1-sharedata
.barvalueindex
][1]
1028 privatedata
.bartmpvpos
[ sharedata
.barvalueindex
] = sharedata
.vbarpos
[sharedata
.barvalueindex
][i
-1]
1029 privatedata
.bartmpvpos
[3-sharedata
.barvalueindex
] = sharedata
.vbarpos
[1-sharedata
.barvalueindex
][0]
1030 privatedata
.bartmpvpos
[2+sharedata
.barvalueindex
] = sharedata
.vbarpos
[sharedata
.barvalueindex
][i
-1]
1031 p
.append(graph
.vgeodesic_el(*privatedata
.bartmpvpos
))
1032 p
.append(path
.closepath())
1033 privatedata
.barcanvas
.fill(p
, barattrs
)
1035 def key_pt(self
, privatedata
, sharedata
, c
, x_pt
, y_pt
, width_pt
, height_pt
, dy_pt
):
1038 for i
, barattrs
in privatedata
.bartmplist
:
1039 c
.fill(path
.rect_pt(x_pt
, y_pt
-l
*dy_pt
, width_pt
, height_pt
), barattrs
)
1043 for i
, barattrs
in privatedata
.bartmplist
:
1044 c
.fill(path
.rect_pt(x_pt
+(i
-1)*width_pt
/privatedata
.bartmplist
[-1][0], y_pt
,
1045 width_pt
/privatedata
.bartmplist
[-1][0], height_pt
), barattrs
)
1049 class barpos_new(_style
):
1051 providesdata
= ["vpos", "vposmissing", "vposavailable", "vposvalid", "vrange", "vrangemissing", "vrangemissing", "vrangeminmissing", "vrangemaxmissing", "stacked"]
1053 def __init__(self
, fromvalue
=None, stackname
=None, epsilon
=1e-10):
1054 # TODO: vpos configuration ...
1055 self
.fromvalue
= fromvalue
1056 self
.stackname
= stackname
1057 self
.epsilon
= epsilon
1059 def columns(self
, privatedata
, sharedata
, graph
, columns
):
1060 privatedata
.barcolumns
= []
1061 privatedata
.barvalueindex
= None
1062 for dimension
, axisnames
in enumerate(graph
.axesnames
):
1064 for axisname
in axisnames
:
1065 if axisname
in columns
or axisname
== self
.stackname
:
1066 if privatedata
.barvalueindex
is not None:
1067 raise ValueError("multiple values")
1068 privatedata
.barcolumns
.append(axisname
)
1069 privatedata
.barvalueindex
= dimension
1070 privatedata
.stacked
= (axisname
== self
.stackname
)
1072 if (axisname
+ "name") in columns
:
1073 privatedata
.barcolumns
.append(axisname
+ "name")
1076 raise ValueError("multiple names")
1078 raise ValueError("value/name missing")
1079 if privatedata
.barvalueindex
is None:
1080 raise ValueError("missing value")
1081 sharedata
.vposmissing
= sharedata
.vrangemissing
= sharedata
.vrangeminmissing
= sharedata
.vrangemaxmissing
= []
1082 return privatedata
.barcolumns
1084 # def selectstyle(self, privatedata, sharedata, graph, selectindex, selecttotal):
1085 # if selecttotal == 1:
1086 # if self.subnames is not None:
1087 # raise ValueError("subnames set for single-bar data")
1088 # privatedata.barpossubname = []
1090 # if self.subnames is not None:
1091 # privatedata.barpossubname = [self.subnames[selectindex]]
1093 # privatedata.barpossubname = [selectindex]
1095 def adjustaxis(self
, privatedata
, sharedata
, graph
, column
, data
, index
):
1097 i
= privatedata
.barcolumns
.index(column
)
1101 if i
== privatedata
.barvalueindex
:
1102 if self
.fromvalue
is not None:
1103 graph
.axes
[privatedata
.barcolumns
[i
]].adjustrange([self
.fromvalue
], None)
1104 graph
.axes
[privatedata
.barcolumns
[i
]].adjustrange(data
, index
)
1106 graph
.axes
[privatedata
.barcolumns
[i
][:-4]].adjustrange(data
, index
)
1108 def initdrawpoints(self
, privatedata
, sharedata
, graph
):
1109 sharedata
.vpos
= [None]*(len(privatedata
.barcolumns
))
1110 sharedata
.vrange
= [[None for i
in range(2)] for x
in privatedata
.barcolumns
]
1112 if self
.fromvalue
is not None:
1113 vfromvalue
= graph
.axes
[privatedata
.barcolumns
[privatedata
.barvalueindex
][0]].convert(self
.fromvalue
)
1121 sharedata
.vrange
[privatedata
.barvalueindex
][0] = vfromvalue
1123 def drawpoint(self
, privatedata
, sharedata
, graph
):
1124 sharedata
.vposavailable
= sharedata
.vposvalid
= 1
1125 for i
, barname
in enumerate(privatedata
.barcolumns
):
1126 if i
== privatedata
.barvalueindex
:
1128 sharedata
.vrange
[i
][1] = graph
.axes
[barname
].convert(sharedata
.point
[barname
])
1129 except (ArithmeticError, ValueError, TypeError):
1130 sharedata
.vrange
[i
][1] = None
1132 sharedata
.vpos
[i
] = sharedata
.vrange
[i
][1]
1136 sharedata
.vrange
[i
][j
] = graph
.axes
[barname
[:-4]].convert((sharedata
.point
[barname
], j
))
1137 except (ArithmeticError, ValueError, TypeError):
1138 sharedata
.vrange
[i
][j
] = None
1140 sharedata
.vpos
[i
] = 0.5*(sharedata
.vrange
[i
][0]+sharedata
.vrange
[i
][1])
1141 except (ArithmeticError, ValueError, TypeError):
1142 sharedata
.vpos
[i
] = None
1143 if sharedata
.vpos
[i
] is None:
1144 sharedata
.vposavailable
= sharedata
.vposvalid
= 0
1145 elif sharedata
.vpos
[i
] < -self
.epsilon
or sharedata
.vpos
[i
] > 1+self
.epsilon
:
1146 sharedata
.vposvalid
= 0
1148 #registerdefaultprovider(barpos(), ["barcolumns", "barvalueindex", "vbarpos"])
1151 class bar_new(_style
):
1153 needsdata
= ["vrange", "vrangeminmissing", "vrangemaxmissing"]
1155 def __init__(self
, barattrs
=[deco
.filled([color
.rgb
.red
]), deco
.stroked()]):
1156 self
.barattrs
= barattrs
1158 def columns(self
, privatedata
, sharedata
, graph
, columns
):
1159 if len(graph
.axesnames
) != 2:
1160 raise TypeError("bar style restricted on two-dimensional graphs")
1161 if len(sharedata
.vrangeminmissing
) + len(sharedata
.vrangemaxmissing
):
1162 raise ValueError("range columns incomplete")
1165 def initdrawpoints(self
, privatedata
, sharedata
, graph
):
1166 privatedata
.rectcanvas
= graph
.insert(canvas
.canvas())
1168 def drawpoint(self
, privatedata
, sharedata
, graph
):
1169 xvmin
= sharedata
.vrange
[0][0]
1170 xvmax
= sharedata
.vrange
[0][1]
1171 yvmin
= sharedata
.vrange
[1][0]
1172 yvmax
= sharedata
.vrange
[1][1]
1173 if (xvmin
is not None and xvmin
< 1 and
1174 xvmax
is not None and xvmax
> 0 and
1175 yvmin
is not None and yvmin
< 1 and
1176 yvmax
is not None and yvmax
> 0):
1185 p
= graph
.vgeodesic(xvmin
, yvmin
, xvmax
, yvmin
)
1186 p
.append(graph
.vgeodesic_el(xvmax
, yvmin
, xvmax
, yvmax
))
1187 p
.append(graph
.vgeodesic_el(xvmax
, yvmax
, xvmin
, yvmax
))
1188 p
.append(graph
.vgeodesic_el(xvmin
, yvmax
, xvmin
, yvmin
))
1189 p
.append(path
.closepath())
1190 privatedata
.rectcanvas
.draw(p
, self
.barattrs
)
1192 def key_pt(self
, privatedata
, sharedata
, graph
, x_pt
, y_pt
, width_pt
, height_pt
, dy_pt
):