/[escript]/trunk/pyvisi/pyvisi/renderers/vtk/line_plot.py
ViewVC logotype

Contents of /trunk/pyvisi/pyvisi/renderers/vtk/line_plot.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 422 - (show annotations)
Fri Jan 6 03:10:54 2006 UTC (13 years, 5 months ago) by cochrane
File MIME type: text/x-python
File size: 14281 byte(s)
Implemented plotting of escript Data objects.  This only works with the vtk
renderer module at this stage.


1 # Copyright (C) 2004-2005 Paul Cochrane
2 #
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
17 # $Id: line_plot.py,v 1.2 2005/12/22 07:08:13 paultcochrane Exp $
18
19 """
20 Class and functions associated with a pyvisi LinePlot objects
21 """
22
23 # generic imports
24 from pyvisi.renderers.vtk.common import debugMsg
25 import Numeric
26 import os
27 import copy
28
29 # module specific imports
30 from pyvisi.renderers.vtk.plot import Plot
31
32 __revision__ = '$Revision: 1.2 $'
33
34 class LinePlot(Plot):
35 """
36 Line plot
37 """
38 def __init__(self, scene):
39 """
40 Initialisation of the LinePlot class
41
42 @param scene: The Scene to render the plot in
43 @type scene: Scene object
44 """
45 debugMsg("Called LinePlot.__init__()")
46 Plot.__init__(self, scene)
47
48 self.renderer = scene.renderer
49 self.renderer.addToInitStack("# LinePlot.__init__()")
50 self.renderer.addToInitStack("_plot = vtk.vtkXYPlotActor()")
51
52 # offset the data in the lineplot?
53 self.offset = False
54
55 # default values for stuff to be passed around
56 self.fname = None
57 self.format = None
58 self.scalars = None
59
60 self.escriptData = False
61 self.otherData = False
62
63 # add the plot to the scene
64 scene.add(self)
65
66 def setData(self, *dataList, **options):
67 """
68 Set data to the plot
69
70 @param dataList: List of data to set to the plot
71 @type dataList: tuple
72
73 @param options: Dictionary of extra options
74 @type options: dict
75
76 @param offset: whether or not to offset the lines from one another
77 @type offset: boolean
78
79 @param fname: Filename of the input vtk file
80 @type fname: string
81
82 @param format: format of the input vtk file ('vtk' or 'vtk-xml')
83 @type format: string
84
85 @param scalars: the name of the scalar data in the vtk file to use
86 @type scalars: string
87 """
88 debugMsg("Called setData() in LinePlot()")
89
90 self.renderer.runString("# LinePlot.setData()")
91
92 # process the options, if any
93 ## offset
94 if options.has_key('offset'):
95 self.offset = options['offset']
96 else:
97 self.offset = False
98 ## fname
99 if options.has_key('fname'):
100 fname = options['fname']
101 else:
102 fname = None
103 ## format
104 if options.has_key('format'):
105 format = options['format']
106 else:
107 format = None
108 ## scalars
109 if options.has_key('scalars'):
110 scalars = options['scalars']
111 else:
112 scalars = None
113
114 # we want to pass this info around
115 self.fname = fname
116 self.format = format
117 self.scalars = scalars
118
119 # reset the default values for shared info
120 self.escriptData = False
121 self.otherData = False
122
123 # do some sanity checking on the inputs
124 if len(dataList) == 0 and fname is None:
125 raise ValueError, \
126 "You must specify a data list or an input filename"
127
128 if len(dataList) != 0 and fname is not None:
129 raise ValueError, \
130 "You cannot specify a data list as well as an input file"
131
132 if fname is not None and vectors is None:
133 debugMsg("No vectors specified; using default in vtk")
134
135 if fname is not None and format is None:
136 raise ValueError, "You must specify an input file format"
137
138 if fname is None and format is not None:
139 raise ValueError, "Format specified, but no input filename"
140
141 # if have just a data list, check the objects passed in to see if
142 # they are escript data objects or not
143 if len(dataList) != 0:
144 for obj in dataList:
145 try:
146 obj.convertToNumArray()
147 # ok, we've got escript data, set the flag
148 self.escriptData = True
149 except AttributeError:
150 self.otherData = True
151
152 # if we have both escript and other data, barf as can't handle that
153 # just yet
154 if self.escriptData and self.otherData:
155 raise TypeError, \
156 "Sorry can't handle both escript and other data yet"
157
158 # now generate the code for the case when we have just escript data
159 # passed into setData()
160 if self.escriptData:
161 # get the relevant bits of data
162 if len(dataList) == 1:
163 # only one data variable, will need to get the domain from it
164 escriptY = dataList[0]
165 escriptX = escriptY.getDomain().getX()
166 elif len(dataList) == 2:
167 # ok, have two data variables, first is x data
168 escriptX = dataList[0]
169 escriptY = dataList[1]
170 else:
171 errorString = \
172 "Expecting 1 or 2 elements in data list. I got %d" \
173 % len(dataList)
174 raise ValueError, errorString
175
176 # convert the data to numarrays
177 xData = escriptX[0].convertToNumArray()
178 yData = escriptY.convertToNumArray()
179
180 # handle the x data
181
182 # check the shape of the xData
183 if len(xData.shape) != 1:
184 errorString = "xData array needs to be 1D. "
185 errorString += "I got %d dimensions" % len(xData.shape)
186 raise ValueError, errorString
187
188 xDataLen = xData.shape[0]
189
190 # pass around the x data
191 self.renderer.renderDict['_x'] = copy.deepcopy(xData)
192
193 # set up the vtkDataArray object for the x data
194 self.renderer.runString(
195 "_xData = vtk.vtkDataArray.CreateDataArray(vtk.VTK_FLOAT)")
196 self.renderer.runString(
197 "_xData.SetNumberOfTuples(len(_x))")
198
199 # now handle the y data
200
201 # make sure that the shape of the yData is either 1D or 2D, if
202 # it is 2D then split up the dims into different _y data objects
203 if len(yData.shape) < 1 or len(yData.shape) > 2:
204 errorString = "yData array needs to be 1D or 2D. "
205 errorString += "I got %d dimensions" % len(yData.shape)
206 raise ValueError, errorString
207
208 # share around the y data
209 for i in range(len(yData.shape)):
210 if len(yData.shape) == 1:
211 if len(yData) != xDataLen:
212 errorString = "yData array length not compatible with "
213 errorString += "xData array length"
214 raise ValueError, errorString
215 yDataVar = "_y%d" % i
216 self.renderer.renderDict[yDataVar] = copy.deepcopy(yData)
217 else:
218 if len(yData[i]) != xDataLen:
219 errorString = "yData array length not compatible with "
220 errorString += "xData array length"
221 raise ValueError, errorString
222 yDataVar = "_y%d" % i
223 self.renderer.renderDict[yDataVar] = \
224 copy.deepcopy(yData[i])
225
226 elif self.otherData:
227 # do some sanity checking on the data
228 for i in range(len(dataList)):
229 if len(dataList[0]) != len(dataList[i]):
230 raise ValueError, \
231 "Input vectors must all be the same length"
232
233 # if have more than one array to plot, the first one is the x data
234 if len(dataList) > 1:
235 xData = dataList[0]
236 ## pass the x data around
237 self.renderer.renderDict['_x'] = copy.deepcopy(xData)
238 # don't need the first element of the dataList, so get rid of it
239 dataList = dataList[1:]
240 # if only have one array input, then autogenerate xData
241 elif len(dataList) == 1:
242 xData = range(1, len(dataList[0])+1)
243 if len(xData) != len(dataList[0]):
244 errorString = "Autogenerated xData array length not "
245 errorString += "equal to input array length"
246 raise ValueError, errorString
247 ## pass the x data around
248 self.renderer.renderDict['_x'] = copy.deepcopy(xData)
249
250 # set up the vtkDataArray object for the x data
251 self.renderer.runString(
252 "_xData = vtk.vtkDataArray.CreateDataArray(vtk.VTK_FLOAT)")
253 self.renderer.runString(
254 "_xData.SetNumberOfTuples(len(_x))")
255
256 ## now to handle the y data
257
258 # share around the y data
259 for i in range(len(dataList)):
260 # check that the data here is a 1-D array
261 if len(dataList[i].shape) != 1:
262 raise ValueError, "Can only handle 1D arrays at present"
263
264 yDataVar = "_y%d" % i
265 self.renderer.renderDict[yDataVar] = copy.deepcopy(dataList[i])
266
267 elif fname is not None and not self.escriptData and not self.otherData:
268 # now handle the case when we have a file as input
269 raise ImplementationError, "Sorry, can't handle file input yet"
270
271 # if offset is true then shift the data
272 if self.offset:
273 # concatenate the data
274 evalString = "_yAll = concatenate(["
275 for i in range(len(dataList)-1):
276 evalString += "_y%d," % i
277 evalString += "_y%d])" % int(len(dataList)-1)
278 self.renderer.runString(evalString)
279
280 # grab the min and max values
281 self.renderer.runString("_yMax = max(_yAll)")
282 self.renderer.runString("_yMin = min(_yAll)")
283
284 # keep the data apart a bit
285 self.renderer.runString("_const = 0.1*(_yMax - _yMin)")
286
287 # now shift the data
288 self.renderer.runString("_shift = _yMax - _yMin + _const")
289 for i in range(len(dataList)):
290 evalString = "_y%d = _y%d + %d*_shift" % (i, i, i)
291 self.renderer.runString(evalString)
292
293 # set up the vtkDataArray objects
294 for i in range(len(dataList)):
295 evalString = \
296 "_y%dData = vtk.vtkDataArray.CreateDataArray(vtk.VTK_FLOAT)\n" % i
297 evalString += "_y%dData.SetNumberOfTuples(len(_y%d))" % (i, i)
298 self.renderer.runString(evalString)
299
300 ## x data
301 # put the data into the data arrays
302 self.renderer.runString("for _i in range(len(_x)):")
303 # need to be careful here to remember to indent the code properly
304 evalString = " _xData.SetTuple1(_i,_x[_i])"
305 self.renderer.runString(evalString)
306
307 ## y data
308 # put the data into the data arrays
309 self.renderer.runString("for _i in range(len(_x)):")
310 # need to be careful here to remember to indent the code properly
311 for i in range(len(dataList)):
312 evalString = " _y%dData.SetTuple1(_i,_y%d[_i])" % (i, i)
313 self.renderer.runString(evalString)
314
315 for i in range(len(dataList)):
316 # create the field data object
317 evalString = "_fieldData%d = vtk.vtkFieldData()" % i
318 self.renderer.runString(evalString)
319 evalString = "_fieldData%d.AllocateArrays(2)" % i
320 self.renderer.runString(evalString)
321 evalString = "_fieldData%d.AddArray(_xData)" % i
322 self.renderer.runString(evalString)
323 evalString = "_fieldData%d.AddArray(_y%dData)" % (i, i)
324 self.renderer.runString(evalString)
325
326 for i in range(len(dataList)):
327 # now put the field data into a data object
328 evalString = "_dataObject%d = vtk.vtkDataObject()\n" % i
329 evalString += "_dataObject%d.SetFieldData(_fieldData%d)\n" % (i, i)
330
331 # the actor should be set up, so add the data object to the actor
332 evalString += "_plot.AddDataObjectInput(_dataObject%d)" % i
333 self.renderer.runString(evalString)
334
335 # tell the actor to use the x values for the x values (rather than
336 # the index)
337 self.renderer.runString("_plot.SetXValuesToValue()")
338
339 # set which parts of the data object are to be used for which axis
340 self.renderer.runString("_plot.SetDataObjectXComponent(0,0)")
341 for i in range(len(dataList)):
342 evalString = "_plot.SetDataObjectYComponent(%d,1)" % i
343 self.renderer.runString(evalString)
344
345 # note: am ignoring zlabels as vtk xyPlot doesn't support that
346 # dimension for line plots (I'll have to do something a lot more
347 # funky if I want that kind of functionality)
348
349 # should this be here or elsewhere?
350 evalString = "_plot.GetXAxisActor2D().GetProperty().SetColor(0, 0, 0)\n"
351 evalString += \
352 "_plot.GetYAxisActor2D().GetProperty().SetColor(0, 0, 0)\n"
353 evalString += "_renderer.SetBackground(1.0, 1.0, 1.0)"
354 self.renderer.runString(evalString)
355
356 # set up the lookup table for the appropriate range of colours
357 evalString = "_lut = vtk.vtkLookupTable()\n"
358 evalString += "_lut.Build()\n"
359 evalString += "_colours = []\n"
360 # need to handle the case when only have one element in dataList
361 if len(dataList) == 1:
362 evalString += "_colours.append(_lut.GetColor(0))\n"
363 else:
364 for i in range(len(dataList)):
365 evalString += "_colours.append(_lut.GetColor(%f))\n" \
366 % (float(i)/float(len(dataList)-1),)
367 self.renderer.runString(evalString)
368
369 # change the colour of the separate lines
370 for i in range(len(dataList)):
371 evalString = "_plot.SetPlotColor(%d, _colours[%d][0], " % (i, i)
372 evalString += "_colours[%d][1], _colours[%d][2])" % (i, i)
373 self.renderer.runString(evalString)
374
375 # make sure the plot is a decent size
376 # the size of the actor should be 80% of the render window
377 evalString = "_plot.SetPosition(0.1, 0.1)\n" # (0.1 = (1.0 - 0.8)/2)
378 evalString += "_plot.SetWidth(0.8)\n"
379 evalString += "_plot.SetHeight(0.8)"
380 self.renderer.runString(evalString)
381
382 return
383
384 def render(self):
385 """
386 Does LinePlot object specific (pre)rendering stuff
387 """
388 debugMsg("Called LinePlot.render()")
389
390 self.renderer.runString("# LinePlot.render()")
391 self.renderer.runString("_renderer.AddActor2D(_plot)")
392
393 # set the title if set
394 if self.title is not None:
395 evalString = "_plot.SetTitle(\'%s\')" % self.title
396 self.renderer.runString(evalString)
397
398 # if an xlabel is set, add it
399 if self.xlabel is not None:
400 evalString = "_plot.SetXTitle(\'%s\')" % self.xlabel
401 self.renderer.runString(evalString)
402
403 # if an ylabel is set, add it
404 if self.ylabel is not None:
405 evalString = "_plot.SetYTitle(\'%s\')" % self.ylabel
406 self.renderer.runString(evalString)
407
408 return
409
410
411 # vim: expandtab shiftwidth=4:

  ViewVC Help
Powered by ViewVC 1.1.26