~ubuntu-branches/ubuntu/raring/python-scipy/raring-proposed

« back to all changes in this revision

Viewing changes to Lib/sandbox/xplt/NarPlotter.orig

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-01-07 14:12:12 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070107141212-mm0ebkh5b37hcpzn
* Remove build dependency on python-numpy-dev.
* python-scipy: Depend on python-numpy instead of python-numpy-dev.
* Package builds on other archs than i386. Closes: #402783.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
## Automatically adapted for scipy Oct 31, 2005 by
 
2
 
 
3
# Copyright (c) 1996, 1997, The Regents of the University of California.
 
4
# All rights reserved.  See Legal.htm for full text and disclaimer.
 
5
 
 
6
import narcisse
 
7
from scipy import *
 
8
from numpy.core.umath import *
 
9
# We need types to check args to some routines
 
10
from types import *
 
11
from graftypes import *
 
12
from shapetest import *
 
13
from gistfuncs import *
 
14
from string import uppercase
 
15
import os
 
16
 
 
17
def minmax1 ( x ) :
 
18
    """minmax1 (x) where x is a one-dimensional array computes the minimum and
 
19
    maximum values in the array and returns them as a list [min, max].
 
20
    """
 
21
    max = x [0]
 
22
    min = x [0]
 
23
    for i in range (len (x)) :
 
24
        if x [i] > max : max = x[i]
 
25
        if x [i] < min : min = x [i]
 
26
    return [floor (min), ceil (max)]
 
27
 
 
28
 
 
29
def minmax2 ( x ) :
 
30
    """minmax2 (x) where x is a two-dimensional array computes the minimum and
 
31
    maximum values in the array and returns them as a list [min, max]. I use
 
32
    this routine because there are apparently some circumstances in which Gist
 
33
    fails to calculate default axis limits correctly.
 
34
    """
 
35
    max = x [0, 0]
 
36
    min = x [0, 0]
 
37
    for i in range (shape (x) [0]) :
 
38
        for j in range (shape (x) [1]) :
 
39
            if x [i, j] > max : max = x [i, j]
 
40
            if x [i, j] < min : min = x [i, j]
 
41
    return [floor (min), ceil (max)]
 
42
 
 
43
NarFloat = 'f'
 
44
NarInt = 'i'
 
45
 
 
46
# Define a simple title function: missing arguments become blanks.
 
47
class Plotter :
 
48
 
 
49
    def type (self) :
 
50
        return NarType
 
51
 
 
52
    def open ( self , filename = ' ' ) :
 
53
        """open ( string ) opens a connection to Narcisse (if it can)
 
54
        using filename 'string.'
 
55
        """
 
56
        if self._file_open :
 
57
            if self._file_name == filename :
 
58
                return # quietly
 
59
            else :
 
60
                raise self.ConnectException , \
 
61
                    "This instance already open with filename '" + \
 
62
                    self._file_name + "'."
 
63
        else :
 
64
            self._file_descr = narcisse.naropen ( filename )
 
65
            if self._file_descr >= 0 :
 
66
                self._file_open = 1
 
67
                self._file_name = filename
 
68
            else :
 
69
                raise self.ConnectException , \
 
70
                    "Unable to open graphics file '" + filename + "'."
 
71
 
 
72
    _cgm_warning = 0
 
73
    _ps_warning = 0
 
74
 
 
75
    def __init__ ( self , filename = ' ' , ** kw ) :
 
76
        self.NarError = "NarError"
 
77
        if filename == "none" :
 
78
            if not self._cgm_warning :
 
79
                print "Sorry, Narcisse does not write cgm files."
 
80
                print "...This will be your only warning."
 
81
                self._cgm_warning = 1
 
82
        elif len (filename) >= 3 and filename [-3:] == ".ps" :
 
83
            if not self._ps_warning :
 
84
                print "Sorry, Narcisse does not write postscript files"
 
85
                print "except from the graphical user interface."
 
86
                print "...This will be your only warning."
 
87
                self._ps_warning = 1
 
88
        self._file_open = 0
 
89
        self._frozen = 0
 
90
        self._freeze_each = 0
 
91
        self._mono = 0    #defaults to color
 
92
        self._file_descr = -1
 
93
        self.ConnectException = "ConnectException"
 
94
        self.open ( filename )
 
95
        self.freeze_graph ( )
 
96
        self.set_grid_type ( "axes" )
 
97
        self._xyequal = 0
 
98
        self.set_default_axes_limits () # let Narcisse determine limits
 
99
        self.set_axis_lin ("all")       # all axes linear scales
 
100
        narcisse.narsetar ( "curve_label_x_min", 0.2 )
 
101
        narcisse.narsetar ( "curve_label_x_max", 0.2 )
 
102
        narcisse.narsetar ( "curve_label_y_min", 0.2 )
 
103
        narcisse.narsetar ( "curve_label_y_max", 0.2 )
 
104
        narcisse.narsetvals ( self._file_descr )
 
105
        self._x_axis_min = 0.
 
106
        self._y_axis_min = 0.
 
107
        self._yr_axis_min = 0.
 
108
        self._z_axis_min = 0.
 
109
        self._c_axis_min = 0.
 
110
        self._x_axis_max = 0.
 
111
        self._y_axis_max = 0.
 
112
        self._yr_axis_max = 0.
 
113
        self._z_axis_max = 0.
 
114
        self._c_axis_max = 0.
 
115
        self.clear_text ( )
 
116
        self.set_text_color (2, 0) #black or nearly so
 
117
        self.set_axis_labels ()         # To English defaults
 
118
        self.set_titles ( )
 
119
        self.set_title_colors ( )
 
120
        self.plot_curve = self.plot_object
 
121
        self.add_curve = self.add_object
 
122
        self._graph_type = 0
 
123
        if kw.has_key ("style") :
 
124
            self._style = kw ["style"]
 
125
        else :
 
126
            self._style = " "
 
127
        self._next_letter = 0
 
128
 
 
129
    def close ( self ) :
 
130
        "close () closes the connection to Narcisse."
 
131
        if self._file_open :
 
132
            narcisse.narclose ( self._file_descr )
 
133
            self._file_descr = -1
 
134
            self._file_open = 0
 
135
            self._file_name = ""
 
136
 
 
137
    def __del__ ( self ) :
 
138
        self.close ( )
 
139
 
 
140
    def new_frame (self) :
 
141
        return
 
142
 
 
143
    def set_tosys (self, *x) :
 
144
        return
 
145
 
 
146
    def set_mono ( self ) :
 
147
        """set_mono () will set the 3d display mode permanently to
 
148
        monochrome mesh. This is the only meaningful display
 
149
        mode if you are only displaying 3d data on a monochrome
 
150
        monitor. Calls to set_3d_options will do nothing
 
151
        (silently). Call set_color () to allow color options
 
152
        again."""
 
153
 
 
154
        self.set_3d_options ( color_bar, color_bar_pos, "wm" )
 
155
        self._mono = 1
 
156
 
 
157
    def synchronize ( self ) :
 
158
        if self._file_open :
 
159
            narcisse.narsync ( self._file_descr )
 
160
        else :
 
161
            print "synchronize: sorry, nothing is open to synchronize with."
 
162
 
 
163
    def query ( self ) :
 
164
        if not self._file_open :
 
165
            return -1
 
166
        else :
 
167
            return narcisse.narquery ( self._file_name )
 
168
 
 
169
    def set_color ( self ) :
 
170
        """set_color ( ) will allow you to use the color 3d options
 
171
        which are disabled by set_mono ( )."""
 
172
 
 
173
        self._mono = 0
 
174
 
 
175
    # Everything on a 2d graph shares the same color card:
 
176
    # (This dictionary is used to convert Narcisse color card names
 
177
    # to the numbers required by the plotting routines. It will also
 
178
    # convert Gist names.)
 
179
    narcisse_color_card_dict = { "absolute" : 0 , "binary" : 1 ,
 
180
    "bluegreen" : 2 , "default" : 6 , "negative" : 4 , "positive" : 5 ,
 
181
    "rainbow" : 6 , "rainbowhls" : 7 , "random" : 8 , "redblue" : 9 ,
 
182
    "redgreen" : 10 , "shifted" : 11 ,"earth.gp" : 8 , "stern.gp" : 2 ,
 
183
    "rainbow.gp" : 7 , "heat.gp" : 10 , "gray.gp" : 0 , "yarg.gp" : 4 }
 
184
 
 
185
    def set_color_card ( self , h , now = 0) :
 
186
        """set_color_card ( n ) indicates a predefined color card
 
187
        for a plot. See the manual for the values of n and the
 
188
        color card selected (sec. 4.2.134, parametre_map)."""
 
189
 
 
190
        if self.narcisse_color_card_dict.has_key (h) :
 
191
            h = self.narcisse_color_card_dict [h]
 
192
        narcisse.narsetai ("parameter_map", h)
 
193
        narcisse.narsetvals (self._file_descr)
 
194
 
 
195
    def set_titles ( self , * vals ):
 
196
        """set_titles ('bottom', 'top', 'left', 'right')
 
197
          All arguments are optional. Missing ones default to ' '."""
 
198
 
 
199
        if not self._file_open : raise self.ConnectException , \
 
200
           "You are not connected to Narcisse."
 
201
        if len (vals) == 0 :
 
202
            vals = []
 
203
        elif type (vals [0]) == StringType :
 
204
            vals = [vals [0]]
 
205
        else :
 
206
            vals = vals [0]
 
207
        if len (vals) == 0 :
 
208
            vals = [ " " , " " , " " , " " ]
 
209
        elif len (vals) == 1 :
 
210
            vals = vals + [ " " , " " , " " ]
 
211
        elif len (vals) == 2 :
 
212
            vals = vals + [ " " , " " ]
 
213
        elif len (vals) == 3 :
 
214
            vals = vals + [ " " ]
 
215
        elif len (vals) <> 4 :
 
216
            print "titles must be one string or a list of up to four strings!"
 
217
            return
 
218
        narcisse.narsetac ( "title_value_bottom" , vals [0] )
 
219
        narcisse.narsetac ( "title_value_top" , vals [1] )
 
220
        narcisse.narsetac ( "title_value_left" , vals [2] )
 
221
        narcisse.narsetac ( "title_value_right" , vals [3] )
 
222
        narcisse.narsetvals ( self._file_descr )
 
223
 
 
224
    # Translation table from color names to Narcisse (only works for rainbowhls)
 
225
    gist_to_narcisse_col = { "bg" : 0, "background" : 0, "fg" : 1,
 
226
                             "foreground" : 1, "blue" : 2, "green" : 3,
 
227
                             "yellow" : 4 , "orange" : 5 , "red" : 6,
 
228
                             "magenta" : 7, "purple" : 7, "black" : 8,
 
229
                             "white" : 9, "cyan" : 20 , "yellowgreen" : 39,
 
230
                             "gold" : 42 , "orangered" : 47, "redorange" : 48,
 
231
                             -1 : 0 , -2 : 1 , -3 : 8 , -4 : 9 , -5 : 6 ,
 
232
                             -6 : 3 , -7 : 2 , -8 : 20 , -9 : 7 , -10 : 4 }
 
233
 
 
234
    def _figure_color (self , col) :
 
235
        """_figure_color ( col ) does the best job it can to return
 
236
        a correct color. If the value is legal for Narcisse (even though
 
237
        it may mean something else in another system) then it is
 
238
        returned unchanged. If it is a Gist value, it is converted
 
239
        to Narcisse if possible. In all other cases, return 1.
 
240
        """
 
241
        if type (col) == IntType and 0 <= col <= 63 :
 
242
            return col
 
243
        if self.gist_to_narcisse_col.has_key (col) :
 
244
            return self.gist_to_narcisse_col [col]
 
245
        return 1
 
246
 
 
247
    def set_title_colors ( self , * vals ) :
 
248
        """set_title_colors (bottom_color, top_color, left_color, right_color)
 
249
          All arguments are optional, integers from 0 to 63 representing
 
250
          a color in some color map. Missing arguments default
 
251
          to foreground."""
 
252
 
 
253
        if not self._file_open : raise self.ConnectException , \
 
254
           "You are not connected to Narcisse."
 
255
        if len (vals) == 0 :
 
256
            vals = []
 
257
        elif type (vals [0]) == IntType :
 
258
            vals = [vals [0]]
 
259
        else :
 
260
            vals = vals [0]
 
261
        if len (vals) == 0 :
 
262
            vals = [ 1 , 1 , 1 , 1 ]
 
263
        elif len (vals) == 1 :
 
264
            vals = [vals [0]] + [ 1 , 1 , 1 ]
 
265
        elif len (vals) == 2 :
 
266
            vals = [vals [0]] + [vals [1]] + [ 1 , 1 ]
 
267
        elif len (vals) == 3 :
 
268
            vals = [vals [0]] + [vals [1]] + [vals [2]] + [ 1 ]
 
269
        elif len (vals) <> 4 :
 
270
            raise self.NarError ,\
 
271
               "Title color must be list of size 4 or less."
 
272
        else :
 
273
            vals = [vals [0]] + [vals [1]] + [vals [2]] + [vals [3]]
 
274
        for i in range (4) :
 
275
            vals[i] = self._figure_color (vals [i])
 
276
        narcisse.narsetai ( "title_color_bottom" , vals [0] )
 
277
        narcisse.narsetai ( "title_color_top" , vals [1] )
 
278
        narcisse.narsetai ( "title_color_left" , vals [2] )
 
279
        narcisse.narsetai ( "title_color_right" , vals [3] )
 
280
        narcisse.narsetvals ( self._file_descr )
 
281
 
 
282
    def set_grid_type ( self , * val ) :
 
283
        """set_grid_type ( string ) determines how intrusive the axes
 
284
        and grids are. The legal arguments are:
 
285
        'none'--no axes and grids are drawn.
 
286
        'axes'--axes with tick marks.
 
287
        'wide'--widely spaced grid in x and y (2d or 3d).
 
288
        'full'--narrowly spaced grid in x and y (2d or 3d).
 
289
        If no argument is specified, the default is 'axes'."""
 
290
 
 
291
        if len ( val ) > 1 :
 
292
            raise self.NarError , "Too many arguments to set_grid_type."
 
293
        if len ( val ) == 0 or val [0] == "axes" :
 
294
            narcisse.narsetai ( "grid_type" , 1 )
 
295
        elif val [0] == "none" :
 
296
            narcisse.narsetai ( "grid_type" , 0 )
 
297
        elif val [0] == "wide" :
 
298
            narcisse.narsetai ( "grid_type" , 2 )
 
299
        elif val [0] == "full" :
 
300
            narcisse.narsetai ( "grid_type" , 3 )
 
301
        else :
 
302
            raise self.NarError , val [0] + \
 
303
               " is an inappropriate argument for set_grid_type."
 
304
        narcisse.narsetvals ( self._file_descr )
 
305
 
 
306
    def set_3d_grid_type ( self , val ) :
 
307
        """set_3d_grid_type (gt) sets what the wire grid will look like
 
308
        in a 3d surface plot in one of the wire modes. The choices
 
309
        for gt are 'x' (x lines only), 'y' (y lines only) and 'xy'
 
310
        (both x and y lines)."""
 
311
 
 
312
        if val == "x" :
 
313
            narcisse.narsetai ( "option_3d_grid_type" , 0 )
 
314
        elif val == "y" :
 
315
            narcisse.narsetai ( "option_3d_grid_type" , 1 )
 
316
        else : # You'll get "xy" if you goof.
 
317
            narcisse.narsetai ( "option_3d_grid_type" , 2 )
 
318
        narcisse.narsetvals ( self._file_descr )
 
319
 
 
320
    def set_connect ( self , val ) :
 
321
        """set_connect (cn) tells whether to connect two or more
 
322
        surface plots, which presumably improves masking.
 
323
        cn=1 to connect, cn=0 to disconnect."""
 
324
 
 
325
        narcisse.narsetai ("option_3d_conv_mode" , val)
 
326
        narcisse.narsetvals ( self._file_descr )
 
327
 
 
328
    def set_link ( self , val ) :
 
329
        """set_link (ln) tells whether to link two or more surfaces
 
330
        plotted with different 3d options into one plot (otherwise
 
331
        all surfaces will have the same options). ln=1 to link,
 
332
        ln = 0 not to link. This needs to be set to 1 for all surfaces
 
333
        except the last. Connection must not be set (see set_connect ()).
 
334
        The axes must not be plotted for surfaces after the first."""
 
335
 
 
336
        narcisse.narsetai ("parameter_scene", val)
 
337
        narcisse.narsetvals ( self._file_descr )
 
338
 
 
339
    def set_z_c_switch ( self , val ) :
 
340
        """set_z_c_switch (sw) tells whether to switch the roles
 
341
        of the z and c variables in a 4d plot. sw=1 to do the
 
342
        switch, sw=0 not to do it."""
 
343
 
 
344
        narcisse.narsetai ("option_3d_z_or_c", val)
 
345
        narcisse.narsetvals ( self._file_descr )
 
346
 
 
347
    # routine to label the axes
 
348
    def set_axis_labels ( self , * vals ):
 
349
        """set_axis_labels ('x_label', 'y_label', 'z_label', 'yr_label')
 
350
          All arguments are optional. Default values (from right):
 
351
          ' ', 'Z axis', 'Y axis', 'X axis'."""
 
352
 
 
353
        if not self._file_open : raise self.ConnectException , \
 
354
           "You are not connected to Narcisse."
 
355
        if len (vals) == 1 and (type (vals [0]) == TupleType or
 
356
                                type (vals [0]) == ListType) :
 
357
            valsin = vals[0]
 
358
        else :
 
359
            valsin = vals
 
360
        vals = [ "X axis" , "Y axis" , "Z axis" , " " ]
 
361
        if len (valsin) >= 1 :
 
362
            vals [0] = valsin [0]
 
363
        if len (valsin) >= 2 :
 
364
            vals [1] = valsin [1]
 
365
        if len (valsin) >= 3 :
 
366
            vals [2] = valsin [2]
 
367
        narcisse.narsetac ( "x_axis_title" , vals [0] )
 
368
        narcisse.narsetac ( "y_axis_title" , vals [1] )
 
369
        narcisse.narsetac ( "z_axis_title" , vals [2] )
 
370
        narcisse.narsetac ( "yr_axis_title" , vals [3] )
 
371
        narcisse.narsetvals ( self._file_descr )
 
372
 
 
373
    # routines to set axis scales -- linear scales
 
374
    def set_axis_lin ( self , ax ) :
 
375
        """set_axis_lin (ax) where ax can be 'x', 'y', 'yr', 'z', 'c', or 'all'.
 
376
           The specified axis will have a linear scale."""
 
377
 
 
378
        if not self._file_open : raise self.ConnectException , \
 
379
           "You are not connected to Narcisse."
 
380
        if ( ax == "x" ) :
 
381
            narcisse.narsetai ( "x_axis_log" , 0 )
 
382
        elif ( ax == "y" ) :
 
383
            narcisse.narsetai ( "y_axis_log" , 0 )
 
384
        elif ( ax == "yr" ) :
 
385
            narcisse.narsetai ( "yr_axis_log" , 0 )
 
386
        elif ( ax == "z" ) :
 
387
            narcisse.narsetai ( "z_axis_log" , 0 )
 
388
        elif ( ax == "c" ) :
 
389
            narcisse.narsetai ( "c_axis_log" , 0 )
 
390
        elif ax == "all" :
 
391
            narcisse.narsetai ( "x_axis_log" , 0 )
 
392
            narcisse.narsetai ( "y_axis_log" , 0 )
 
393
            narcisse.narsetai ( "yr_axis_log" , 0 )
 
394
            narcisse.narsetai ( "z_axis_log" , 0 )
 
395
            narcisse.narsetai ( "c_axis_log" , 0 )
 
396
        else :
 
397
            raise self.NarError , "set_axis_lin: axis must be x, y, yr, z, or c."
 
398
        narcisse.narsetvals ( self._file_descr )
 
399
 
 
400
    # routines to set axis scales -- log scales
 
401
    def set_axis_log ( self , ax ) :
 
402
        """set_axis_log (ax) where ax can be 'x', 'y', 'yr', 'z', 'c', or 'all'.
 
403
           The specified axis will have a logarithmic scale."""
 
404
 
 
405
        if ( ax == "x" ) :
 
406
            narcisse.narsetai ( "x_axis_log" , 1 )
 
407
        elif ( ax == "y" ) :
 
408
            narcisse.narsetai ( "y_axis_log" , 1 )
 
409
        elif ( ax == "yr" ) :
 
410
            narcisse.narsetai ( "yr_axis_log" , 1 )
 
411
        elif ( ax == "z" ) :
 
412
            narcisse.narsetai ( "z_axis_log" , 1 )
 
413
        elif ( ax == "c" ) :
 
414
            narcisse.narsetai ( "c_axis_log" , 1 )
 
415
        elif ax == "all" :
 
416
            narcisse.narsetai ( "x_axis_log" , 1 )
 
417
            narcisse.narsetai ( "y_axis_log" , 1 )
 
418
            narcisse.narsetai ( "yr_axis_log" , 1 )
 
419
            narcisse.narsetai ( "z_axis_log" , 1 )
 
420
            narcisse.narsetai ( "c_axis_log" , 1 )
 
421
        else :
 
422
            raise self.NarError , "axis_log: axis must be x, y, yr, z, or c."
 
423
        narcisse.narsetvals ( self._file_descr )
 
424
 
 
425
    # special routines to set both x and y scales at once
 
426
    def set_linlin ( self ) :
 
427
        "set_linlin () sets both x and y axes to linear scale."
 
428
        self.set_axis_lin ( "x" )
 
429
        self.set_axis_lin ( "y" )
 
430
 
 
431
    def set_linlog ( self ) :
 
432
        'set_linlog () sets x axis to linear, y axis to logarithmic.'
 
433
        self.set_axis_lin ( "x" )
 
434
        self.set_axis_log ( "y" )
 
435
 
 
436
    def set_loglin ( self ) :
 
437
        'set_loglin () sets x axis to logarithmic, y axis to linear.'
 
438
        self.set_axis_log ( "x" )
 
439
        self.set_axis_lin ( "y" )
 
440
 
 
441
    def set_loglog ( self ) :
 
442
        'set_loglog () sets both x and y axes to logarithmic scale.'
 
443
        self.set_axis_log ( "x" )
 
444
        self.set_axis_log ( "y" )
 
445
 
 
446
    #determine which y axis to use for a curve
 
447
    def set_y_axis ( self , val1 , * val2 ) :
 
448
        """use set_y_axis ( 'left' , n ) or set_y_axis ( 'right' , n )
 
449
        to cause curve number n to be associated with the left or
 
450
        right y axis."""
 
451
 
 
452
        if len ( val2 ) == 2 :
 
453
            n = val2 [1]
 
454
        else :
 
455
            n = 0       # set for curve 0 if not specified
 
456
        if len ( val2 ) == 0 or val2 [0] == "left" or val2 [0] != "right" :
 
457
            narcisse.narsetaii ( "curve_y_axis" , 0 , n )
 
458
        else :
 
459
            narcisse.narsetaii ( "curve_y_axis" , 1 , n )
 
460
        narcisse.narsetvals ( self._file_descr )
 
461
 
 
462
    def set_bytscl ( self, cmin, cmax ) :
 
463
        return
 
464
 
 
465
    def add_text (self, str, x, y, size, color="fg", tosys = 1) :
 
466
        """add_text (str, x, y, size [, color]) adds a text to a graph."""
 
467
        return
 
468
 
 
469
    # set the maximum value of an axis
 
470
    def set_axis_max ( self , ax , * val1 ) :
 
471
        """set_axis_max (ax, val) where ax is 'x', 'y', 'z', 'yr', or 'c'.
 
472
           The maximum of the specified axis will be set to val.
 
473
           val should be a PyFloat object."""
 
474
 
 
475
        if not self._file_open : raise self.ConnectException , \
 
476
           "You are not connected to Narcisse."
 
477
        if len ( val1 ) == 0 :
 
478
            val = 0.0
 
479
        else :
 
480
            val = val1 [0]
 
481
        if ( ax == "x" ) :
 
482
            self._x_axis_max = val
 
483
            narcisse.narsetar ( "x_axis_max" , val )
 
484
        elif ( ax == "y" ) :
 
485
            self._y_axis_max = val
 
486
            narcisse.narsetar ( "y_axis_max" , val )
 
487
        elif ( ax == "yr" ) :
 
488
            self._yr_axis_max = val
 
489
            narcisse.narsetar ( "yr_axis_max" , val )
 
490
        elif ( ax == "z" ) :
 
491
            self._z_axis_max = val
 
492
            narcisse.narsetar ( "z_axis_max" , val )
 
493
        elif ( ax == "c" ) :
 
494
            self._c_axis_max = val
 
495
            narcisse.narsetar ( "c_axis_max" , val )
 
496
        else :
 
497
            raise self.NarError , "set_axis_max: axis must be x, y, yr, z, or c."
 
498
#      narcisse.narsetvals ( self._file_descr )
 
499
 
 
500
    # set the minimum value of an axis
 
501
    def set_axis_min ( self , ax , * val1 ) :
 
502
        '''set_axis_min (ax, val) where ax is "x", "y", "z", "yr", or "c".
 
503
           The minimum of the specified axis will be set to val.
 
504
           val should be a PyFloat object.'''
 
505
 
 
506
        if not self._file_open : raise self.ConnectException , \
 
507
           "You are not connected to Narcisse."
 
508
        if len ( val1 ) == 0 :
 
509
            val = 0.0
 
510
        else :
 
511
            val = val1 [0]
 
512
        if ( ax == "x" ) :
 
513
            self._x_axis_min = val
 
514
            narcisse.narsetar ( "x_axis_min" , val )
 
515
        elif ( ax == "y" ) :
 
516
            self._y_axis_min = val
 
517
            narcisse.narsetar ( "y_axis_min" , val )
 
518
        elif ( ax == "yr" ) :
 
519
            self._yr_axis_min = val
 
520
            narcisse.narsetar ( "yr_axis_min" , val )
 
521
        elif ( ax == "z" ) :
 
522
            self._z_axis_min = val
 
523
            narcisse.narsetar ( "z_axis_min" , val )
 
524
        elif ( ax == "c" ) :
 
525
            self._c_axis_min = val
 
526
            narcisse.narsetar ( "c_axis_min" , val )
 
527
        else :
 
528
            raise self.NarError , "set_axis_min: axis must be x, y, yr, z, or c."
 
529
#      narcisse.narsetvals ( self._file_descr )
 
530
 
 
531
    # Send axes limits at the last moment before a plot
 
532
    def _send_axes_limits ( self ) :
 
533
        narcisse.narsetar ( "x_axis_max" , self._x_axis_max )
 
534
        narcisse.narsetar ( "x_axis_min" , self._x_axis_min )
 
535
        narcisse.narsetar ( "y_axis_max" , self._y_axis_max )
 
536
        narcisse.narsetar ( "y_axis_min" , self._y_axis_min )
 
537
        narcisse.narsetar ( "yr_axis_max" , self._yr_axis_max )
 
538
        narcisse.narsetar ( "yr_axis_min" , self._yr_axis_min )
 
539
        narcisse.narsetar ( "z_axis_max" , self._z_axis_max )
 
540
        narcisse.narsetar ( "z_axis_min" , self._z_axis_min )
 
541
        narcisse.narsetar ( "c_axis_max" , self._c_axis_max )
 
542
        narcisse.narsetar ( "c_axis_min" , self._c_axis_min )
 
543
        # narsetvals will be done in send_graph
 
544
 
 
545
    # Allow Narcisse to calculate the axis limits
 
546
    def set_default_axes_limits ( self , * h ) :
 
547
        '''set_default_axes_limits () sets narcisse to compute the maximum
 
548
        and minimum of the axes depending on the data.'''
 
549
 
 
550
        if not self._file_open : raise self.ConnectException , \
 
551
           "You are not connected to Narcisse."
 
552
        if self._xyequal : # compute xy limits myself
 
553
            xdist = self._x_axis_max - self._x_axis_min
 
554
            ydist = self._y_axis_max - self._y_axis_min
 
555
            if xdist > ydist :
 
556
                self._y_axis_max = self._y_axis_max + xdist - ydist
 
557
            elif ydist > xdist :
 
558
                self._x_axis_max = self._x_axis_max + ydist - xdist
 
559
            narcisse.narsetar ( "x_axis_max" , self._x_axis_max )
 
560
            narcisse.narsetar ( "y_axis_max" , self._y_axis_max )
 
561
            narcisse.narsetar ( "x_axis_min" , self._x_axis_min )
 
562
            narcisse.narsetar ( "y_axis_min" , self._y_axis_min )
 
563
#         narcisse.narsetvals ( self._file_descr )
 
564
        else :
 
565
            narcisse.narsetar ( "x_axis_max" , 0.0 )
 
566
            narcisse.narsetar ( "y_axis_max" , 0.0 )
 
567
            narcisse.narsetar ( "yr_axis_max" , 0.0 )
 
568
            narcisse.narsetar ( "z_axis_max" , 0.0 )
 
569
            narcisse.narsetar ( "c_axis_max" , 0.0 )
 
570
            narcisse.narsetar ( "x_axis_min" , 0.0 )
 
571
            narcisse.narsetar ( "y_axis_min" , 0.0 )
 
572
            narcisse.narsetar ( "yr_axis_min" , 0.0 )
 
573
            narcisse.narsetar ( "z_axis_min" , 0.0 )
 
574
            narcisse.narsetar ( "c_axis_min" , 0.0 )
 
575
#         narcisse.narsetvals ( self._file_descr )
 
576
 
 
577
    # routines to set the limits on individual axes
 
578
    def set_x_axis_limits ( self , val1 , * val2i ) :
 
579
        '''set_x_axis_limits (min, max) sets the limits on the x axis to
 
580
        the specified (pyFloat) sizes.'''
 
581
 
 
582
        if not self._file_open : raise self.ConnectException , \
 
583
           "You are not connected to Narcisse."
 
584
        if len ( val2i ) == 0 :
 
585
            val2 = 0.0
 
586
        else :
 
587
            val2 = val2i [0]
 
588
        self._x_axis_min = val1
 
589
        self._x_axis_max = val2
 
590
        narcisse.narsetar ( "x_axis_max" , val2)
 
591
        narcisse.narsetar ( "x_axis_min" , val1 )
 
592
#      narcisse.narsetvals ( self._file_descr )
 
593
 
 
594
    def set_y_axis_limits ( self , val1 , * val2i ) :
 
595
        '''set_y_axis_limits (min, max) sets the limits on the y axis to
 
596
        the specified (pyFloat) sizes.'''
 
597
 
 
598
        if not self._file_open : raise self.ConnectException , \
 
599
           "You are not connected to Narcisse."
 
600
        if len ( val2i ) == 0 :
 
601
            val2 = 0.0
 
602
        else :
 
603
            val2 = val2i [0]
 
604
        self._y_axis_min = val1
 
605
        self._y_axis_max = val2
 
606
        narcisse.narsetar ( "y_axis_max" , val2)
 
607
        narcisse.narsetar ( "y_axis_min" , val1 )
 
608
#      narcisse.narsetvals ( self._file_descr )
 
609
 
 
610
    def set_yr_axis_limits ( self , val1 , * val2i ) :
 
611
        '''set_yr_axis_limits (min, max) sets the limits on the yr axis to
 
612
        the specified (pyFloat) sizes.'''
 
613
 
 
614
        if not self._file_open : raise self.ConnectException , \
 
615
           "You are not connected to Narcisse."
 
616
        if len ( val2i ) == 0 :
 
617
            val2 = 0.0
 
618
        else :
 
619
            val2 = val2i [0]
 
620
        self._yr_axis_min = val1
 
621
        self._yr_axis_max = val2
 
622
        narcisse.narsetar ( "yr_axis_max" , val2)
 
623
        narcisse.narsetar ( "yr_axis_min" , val1 )
 
624
#      narcisse.narsetvals ( self._file_descr )
 
625
 
 
626
    def set_z_axis_limits ( self , val1 , * val2i ) :
 
627
        '''set_z_axis_limits (min, max) sets the limits on the z axis to
 
628
        the specified (pyFloat) sizes.'''
 
629
 
 
630
        if not self._file_open : raise self.ConnectException , \
 
631
           "You are not connected to Narcisse."
 
632
        if len ( val2i ) == 0 :
 
633
            val2 = 0.0
 
634
        else :
 
635
            val2 = val2i [0]
 
636
        self._z_axis_min = val1
 
637
        self._z_axis_max = val2
 
638
        narcisse.narsetar ( "z_axis_max" , val2)
 
639
        narcisse.narsetar ( "z_axis_min" , val1 )
 
640
#      narcisse.narsetvals ( self._file_descr )
 
641
 
 
642
    def set_c_axis_limits ( self , val1 , * val2i ) :
 
643
        '''set_c_axis_limits (min, max) sets the limits on the c axis to
 
644
        the specified (pyFloat) sizes.'''
 
645
 
 
646
        if not self._file_open : raise self.ConnectException , \
 
647
           "You are not connected to Narcisse."
 
648
        if len ( val2i ) == 0 :
 
649
            val2 = 0.0
 
650
        else :
 
651
            val2 = val2i [0]
 
652
        self._c_axis_min = val1
 
653
        self._c_axis_max = val2
 
654
        narcisse.narsetar ( "c_axis_max" , val2)
 
655
        narcisse.narsetar ( "c_axis_min" , val1 )
 
656
#      narcisse.narsetvals ( self._file_descr )
 
657
 
 
658
    # stuff to help set 3d options
 
659
    # (1) These are the legal arguments and their values if wire shows
 
660
    legal_3d_options = { 'wm' : 0 , 'w3' : 1 , 'w4' : 3 , 'f3' : 8 , \
 
661
                         'f4' : 16 , 'i3' : 32 , 'i4' : 64 , 's3' : 128 , \
 
662
                         's4' : 256 , 'none' : 0}
 
663
    # (2) These are the values of the other arguments if there is no wire
 
664
    legal_3d_no_wire = { 'f3' : 7 , 'f4' : 15 ,  'i3' : 31 , 'i4' : 63 , \
 
665
                         's3' : 127 , 's4' : 255 }
 
666
    # (3) The following arguments can occur together; the values given
 
667
    #     are used if there is no wire showing. (If wire is present,
 
668
    #     the values in legal_3d_options are simply or'ed.
 
669
    legal_3d_double = { 'f3' : { 'i3' : 39 , 'i4' : 71 } ,
 
670
                        'f4' : { 'i3' : 47 , 'i4' : 79 } ,
 
671
                        'i3' : { 'f3' : 39 , 'f4' : 47 } ,
 
672
                        'i4' : { 'f3' : 71 , 'f4' : 79 } }
 
673
 
 
674
    def set_3d_options ( self , color_bar , color_bar_pos , * vals ) :
 
675
        """set_3d_options (args) may be called with no argument,
 
676
        a single string argument, or a sequence of up to three strings.
 
677
        If called with no arguments, the graph display is erased.
 
678
        A surface is colored by height in z if a 3d option is
 
679
        specified, and by the value of a given function if a 4d
 
680
        option is specified. With a wire grid option, the grid
 
681
        is colored; with a flat option, the quadrilaterals set
 
682
        off by grid lines are colored; with a smooth option,
 
683
        the surface itself is colored by height; and with an iso
 
684
        option, the contour lines are colored. flat and iso options
 
685
        may be used together in any combination. wire grid options
 
686
        are independent of the other options. Legal arguments for
 
687
        set_3d_options are:
 
688
        'wm'--monochrome wire grid; 'w3' and 'w4'--3d and 4d
 
689
              coloring of wire grid.
 
690
        'f3' and 'f4'--flat 3d and 4d coloring options.
 
691
        'i3' and 'i4'--3d and 4d isoline (contour line) options.
 
692
        's3' and 's4'--3d and 4d smooth coloring options."""
 
693
 
 
694
        if not self._file_open : raise self.ConnectException , \
 
695
           "You are not connected to Narcisse."
 
696
        if self._mono == 1 :
 
697
            return
 
698
        if len (vals) == 0 :
 
699
            vals = ["wm"]
 
700
        elif is_scalar (vals) :
 
701
            vals = [vals [0]]
 
702
        else :
 
703
            vals = vals [0]
 
704
            if is_scalar (vals) :
 
705
                vals = [vals]
 
706
        if len (vals) > 3 :
 
707
            raise self.NarError , "set_3d_options: too many arguments"
 
708
        wire_option = -1 # If this ever gets sent, the graph vanishes
 
709
        option = 0
 
710
        c_color_bar = 0
 
711
        z_color_bar = 0
 
712
        for i in range ( len (vals) ) :
 
713
            if vals [i] == "s4" or vals [i] == "i4" :
 
714
                c_color_bar = color_bar
 
715
            if vals [i] == "s3" or vals [i] == "i3" :
 
716
                z_color_bar = color_bar
 
717
            if not self.legal_3d_options.has_key ( vals [i] ) :
 
718
                raise self.NarError , "set_3d_options: "\
 
719
                      + vals [i] + " is an illegal option."
 
720
            if self.legal_3d_options [vals [i]] <= 3 :
 
721
                wire_option = self.legal_3d_options [vals [i]]
 
722
        if wire_option != -1 :
 
723
            for i in range ( len (vals) ) :
 
724
                option = option | self.legal_3d_options [vals [i]]
 
725
        elif len (vals) >= 1 :
 
726
            if len (vals) == 1 :
 
727
                option = self.legal_3d_no_wire [vals [0]]
 
728
            elif not self.legal_3d_double.has_key [vals [0]] or \
 
729
                 not self.legal_3d_double [vals [0]].has_key (vals [1]) :
 
730
                print "set_3d_options: illegal combination of options: " \
 
731
                       + vals [0] + " and " + vals [1] + "."
 
732
                return
 
733
            else :
 
734
                option = self.legal_3d_double [vals [0]][vals [1]]
 
735
        else : # cause graph to commit suicide if no args given
 
736
            option = -1
 
737
        # at this point the arguments were legal and 'option' has been set.
 
738
        narcisse.narsetai ( "option_3d" , option )
 
739
        # check out whether a color bar is wanted :
 
740
        if c_color_bar :
 
741
            if color_bar_pos is not None :
 
742
                c_color_bar = 1
 
743
                narcisse.narsetai ( "height_c_x_min", color_bar_pos [0, 0])
 
744
                narcisse.narsetai ( "height_c_y_min", color_bar_pos [0, 1])
 
745
                narcisse.narsetai ( "height_c_x_max", color_bar_pos [1, 0])
 
746
                narcisse.narsetai ( "height_c_x_max", color_bar_pos [1, 1])
 
747
            else :
 
748
                c_color_bar = 2
 
749
            narcisse.narsetai ( "height_c_type", c_color_bar )
 
750
        elif z_color_bar :
 
751
            if color_bar_pos is not None :
 
752
                z_color_bar = 1
 
753
                narcisse.narsetai ( "height_z_x_min", color_bar_pos [0, 0])
 
754
                narcisse.narsetai ( "height_z_y_min", color_bar_pos [0, 1])
 
755
                narcisse.narsetai ( "height_z_x_max", color_bar_pos [1, 0])
 
756
                narcisse.narsetai ( "height_z_x_max", color_bar_pos [1, 1])
 
757
            else :
 
758
                z_color_bar = 2
 
759
            narcisse.narsetai ( "height_z_type", z_color_bar )
 
760
        else :
 
761
            narcisse.narsetai ( "height_c_type", 0)
 
762
            narcisse.narsetai ( "height_z_type", 0)
 
763
        narcisse.narsetvals ( self._file_descr )
 
764
 
 
765
    # Some other routines to set stuff relating to 3d options
 
766
    def set_z_contours ( self , val ) :
 
767
        """set_z_contours (arg) sets various properties when doing 3d contour
 
768
        (iso), smooth, or flat plots. It accepts one argument, as
 
769
        follows:
 
770
           if an integer n, sets the number of contours to n. This also
 
771
                        clears the contour levels array. Countour levels
 
772
                        will be computed automatically from the data.
 
773
           if a string: 'lin' plots the contours linearly spaced.
 
774
                        'log' plots the contours logarithmically spaced.
 
775
           if an array NarFloat: sets the contour levels to the values in the
 
776
                        array."""
 
777
 
 
778
        if not self._file_open : raise self.ConnectException , \
 
779
           "You are not connected to Narcisse."
 
780
        if type ( val ) == IntType :
 
781
            for i in range ( val ) :
 
782
                narcisse.narsetari ("height_z", 0.0 , i )
 
783
            narcisse.narsetvals ( self._file_descr )
 
784
            return
 
785
        elif type ( val ) == StringType :
 
786
            if val == "log" :
 
787
                narcisse.narsetai ("height_z_log", 1)
 
788
                narcisse.narsetvals ( self._file_descr )
 
789
                return
 
790
            elif val == "lin" :
 
791
                narcisse.narsetai ("height_z_log", 0)
 
792
                narcisse.narsetvals ( self._file_descr )
 
793
                return
 
794
        elif type ( val ) == ArrayType :
 
795
            val = val.astype (NarFloat)
 
796
            if len (val.shape) == 1 :
 
797
                # Note: when setting a Narcisse array you must do a narsetvals
 
798
                # after setting each element. If instead you send a whole list
 
799
                # of values all at once, then only the last takes effect and
 
800
                # all lower values in the table are cleared.
 
801
                for i in range (val.shape [0]) :
 
802
                    narcisse.narsetari ("height_z", val [i] , i)
 
803
                    narcisse.narsetvals ( self._file_descr )
 
804
                narcisse.narsetar ("height_z_h_min", val [0])
 
805
                narcisse.narsetar ("height_z_h_max", val [val.shape [0]-1])
 
806
                narcisse.narsetvals ( self._file_descr )
 
807
                return
 
808
 
 
809
        raise self.NarError , "Wrong type of argument to set_z_contours."
 
810
 
 
811
    def set_c_contours ( self , val ) :
 
812
        """set_c_contours (arg) sets various properties when doing 4d contour
 
813
        (iso), smooth, or flat plots. It accepts one argument, as
 
814
        follows:
 
815
           if an integer n, sets the number of contours to n. This also
 
816
                        clears the contour levels array. Countour levels
 
817
                        will be computed automatically from the data.
 
818
           if a string: 'lin' plots the contours linearly spaced.
 
819
                        'log' plots the contours logarithmically spaced.
 
820
           if an Array NarFloat: sets the contour levels to the values in the
 
821
                        array."""
 
822
 
 
823
        if not self._file_open : raise self.ConnectException , \
 
824
           "You are not connected to Narcisse."
 
825
        if type ( val ) == IntType :
 
826
            for i in range (val) :
 
827
                narcisse.narsetari ("height_c", 0.0 , i )
 
828
            narcisse.narsetvals ( self._file_descr )
 
829
            return
 
830
        elif type ( val ) == StringType :
 
831
            if val == "log" :
 
832
                narcisse.narsetai ("height_c_log", 1)
 
833
                narcisse.narsetvals ( self._file_descr )
 
834
                return
 
835
            elif val == "lin" :
 
836
                narcisse.narsetai ("height_c_log", 0)
 
837
                narcisse.narsetvals ( self._file_descr )
 
838
                return
 
839
        elif type ( val ) == ArrayType :
 
840
            val = val.astype (NarFloat)
 
841
            if len (val.shape) == 1 :
 
842
                # Note: when setting a Narcisse array you must do a narsetvals
 
843
                # after setting each element. If instead you send a whole list
 
844
                # of values all at once, then only the last takes effect and
 
845
                # all lower values in the table are cleared.
 
846
                for i in range (val.shape [0]) :
 
847
                    narcisse.narsetari ("height_c", val [i] , i)
 
848
                    narcisse.narsetvals ( self._file_descr )
 
849
                narcisse.narsetar ("height_c_h_min", val [0])
 
850
                narcisse.narsetar ("height_c_h_max", val [val.shape [0]-1])
 
851
                narcisse.narsetvals ( self._file_descr )
 
852
                return
 
853
 
 
854
        raise self.NarError , "Wrong type of argument to set_c_contours."
 
855
 
 
856
    # set the mask (hidden line remover) for 3d
 
857
    def set_mask ( self , * val ) :
 
858
        """set_mask (arg) determines whether hidden parts of the surface
 
859
        will be shown on the graph, and if not, what algorithm
 
860
        will be used to determine what is hidden. The allowed
 
861
        arguments and masking algorithm are as follows:
 
862
        'none'--no masking. in wire grid mode, all grid lines
 
863
                are visible.
 
864
        'min'--the surface is traced beginning in the corner
 
865
               closest to the observer.
 
866
        'max'--the surface is traced beginning in the corner
 
867
               farthest from the observer.
 
868
        'sort'--a cell sorting is carried out to determine the
 
869
                masking."""
 
870
 
 
871
        if not self._file_open : raise self.ConnectException , \
 
872
           "You are not connected to Narcisse."
 
873
        if len ( val ) == 0 or val [0] == "none" :
 
874
            narcisse.narsetai ( "option_3d_mask_type" , 0 ) # default: no mask
 
875
        elif val [0] == "min" :
 
876
            narcisse.narsetai ( "option_3d_mask_type" , 1 ) # minimum mask
 
877
        elif val [0] == "max" :
 
878
            narcisse.narsetai ( "option_3d_mask_type" , 2 ) # maximum mask
 
879
        elif val [0] == "sort" :
 
880
            narcisse.narsetai ( "option_3d_mask_type" , 3 ) # sorted mask
 
881
        else :
 
882
            raise self.NarError , val [0] + " is not a valid mask type."
 
883
        narcisse.narsetvals ( self._file_descr )
 
884
 
 
885
    # Set language
 
886
    def set_language ( self , * val ) :
 
887
        """set_language (arg) determines what language the Narcisse GUI will
 
888
        be displayed in. Called with no argument, it sets the language
 
889
        to English. Otherwise it may be called with 'English', 'French',
 
890
        'anglais', or 'francaise'. In a concession to the lazy among us,
 
891
        'english' and 'french' are also allowed."""
 
892
 
 
893
        if not self._file_open : raise self.ConnectException , \
 
894
           "You are not connected to Narcisse."
 
895
        if len ( val ) == 0 or val [0] == "English" or val [0] == "english" :
 
896
            narcisse.narsetac ( "language" , "anglais" )
 
897
        elif val [0] == "French" or val [0] == "french" :
 
898
            narcisse.narsetac ( "language" , "francais" )
 
899
        else : # let the user commit suicide
 
900
            narcisse.narsetac ( "language" , val [0] )
 
901
        narcisse.narsetvals ( self._file_descr )
 
902
 
 
903
    # commands to set the angle of view:
 
904
    def set_phi ( self , * val ) :
 
905
        """set_phi (arg) sets the angle of view, measured from the positive z
 
906
        axis. If called with no argument, phi is set to 45 degrees.
 
907
        Otherwise it should be called with an integer argument (the angle
 
908
        in degrees)."""
 
909
 
 
910
        if not self._file_open : raise self.ConnectException , \
 
911
           "You are not connected to Narcisse."
 
912
        if len ( val ) == 0 or val [0] is None :
 
913
            narcisse.narsetar ( "height" , 30.0 )
 
914
        else :
 
915
            narcisse.narsetar ( "height" , 90.0 - val [0] )
 
916
        narcisse.narsetvals ( self._file_descr )
 
917
 
 
918
    def set_theta ( self , * val ) :
 
919
        """set_theta (arg) sets the angle of view, measured from the positive x
 
920
        axis. If called with no argument, theta is set to 45 degrees.
 
921
        Otherwise it should be called with an integer argument (the angle
 
922
        in degrees)."""
 
923
 
 
924
        if not self._file_open : raise self.ConnectException , \
 
925
           "You are not connected to Narcisse."
 
926
        if len ( val ) == 0 or val [0] is None :
 
927
            narcisse.narsetar ( "theta" , -45.0 )
 
928
        else :
 
929
            narcisse.narsetar ( "theta" , val [0] )
 
930
        narcisse.narsetvals ( self._file_descr )
 
931
 
 
932
    def set_roll ( self , * val ) :
 
933
        """set_roll (arg) is the angle of rotation around the line determined
 
934
        by set_phi and set_theta. If called with no argument, roll
 
935
        is set to zero degrees. Otherwise it should be called with
 
936
        an integer argument (the angle in degrees)."""
 
937
 
 
938
        if not self._file_open : raise self.ConnectException , \
 
939
           "You are not connected to Narcisse."
 
940
        if len ( val ) == 0 or val [0] is None :
 
941
            narcisse.narsetar ( "roll" , 0.0 )
 
942
        else :
 
943
            narcisse.narsetar ( "roll" , val [0] )
 
944
        narcisse.narsetvals ( self._file_descr )
 
945
 
 
946
    def set_gnomon (self, val) :
 
947
        """set_gnomon (val) does nothing in Narcisse."""
 
948
        return
 
949
 
 
950
    # set the distance of view
 
951
    def set_distance ( self , * val ) :
 
952
        """set_distance (arg) sets the distance of the view point from a 3d
 
953
        graph. If called with no argument, or 0.0, this distance is
 
954
        effectively infinite. Otherwise it should be called with a
 
955
        real number."""
 
956
 
 
957
        if not self._file_open : raise self.ConnectException , \
 
958
           "You are not connected to Narcisse."
 
959
        if len ( val ) == 0 :
 
960
            narcisse.narsetar ( "distance" , 0. )
 
961
        else :
 
962
            narcisse.narsetar ( "distance" , val [0] )
 
963
        narcisse.narsetvals ( self._file_descr )
 
964
 
 
965
    # set whether a curve is drawn as a line, step, or one of a set
 
966
    # of symbols. val1 specifies the curve(s) and val2 the type(s).
 
967
    # If they're both scalars, set that one curve. If they are both
 
968
    # vectors, the shorter length will be used. If val1 is a vector
 
969
    # and val2 a scalar, then set all curves to the same type.
 
970
    # Note: narsetvals has to be called after each call to one of
 
971
    # the indexed routines, or else only the last one set is effective.
 
972
    # Bug or feature? I don't know.
 
973
    ###################NOTE:
 
974
    # Currently val2 is an integer value. Eventually I want to replace
 
975
    # it with a character designation.
 
976
    ###################
 
977
    def set_curve_type ( self , val1 , val2 ) :
 
978
        """set_curve_type (arg1, arg2) is used to determine how one or a family of
 
979
        curves is to be plotted. It must be called with two arguments.
 
980
        The first argument is an integer scalar or array Int giving
 
981
        the curve number(s) and the second is an integer scalar
 
982
        or array Int describing how the curve(s) should be graphed.
 
983
        Curves are numbered starting with 0. The allowed values for
 
984
        the second argument are: -1 (do not graph), 0 (normal graph),
 
985
        1 (graph as a step function), or else a number of options
 
986
        to draw the graph as a set of points denoted by symbols:
 
987
        2 (+), 3 (*), 4 (o) , 5 (x) , 6 (.)."""
 
988
 
 
989
        if not self._file_open : raise self.ConnectException , \
 
990
           "You are not connected to Narcisse."
 
991
        if type (val1) == IntType and type (val2) == IntType :
 
992
            narcisse.narsetaii ( "curve_type" , val2 , val1 )
 
993
            narcisse.narsetvals ( self._file_descr )
 
994
        elif type (val1) == ArrayType and val1.dtype == Int \
 
995
                                    and type (val2) == IntType :
 
996
            for i in range (len (val2)) :
 
997
                narcisse.narsetaii ( "curve_type" , val2 , val1 [i] )
 
998
                narcisse.narsetvals ( self._file_descr )
 
999
        elif not is_scalar (val1) and not is_scalar (val2) :
 
1000
            # both must be > 1 in length
 
1001
            r = range (len (val1))
 
1002
            if len (val2) < len (val1) :
 
1003
                r = range (len (val2))
 
1004
            for i in r :
 
1005
                narcisse.narsetaii ( "curve_type" , val2 [i] , val1 [i] )
 
1006
                narcisse.narsetvals ( self._file_descr )
 
1007
        else :
 
1008
            raise self.NarError, "bad arguments to curve_type."
 
1009
 
 
1010
    # set the curve color(s) for one or a set of curves.
 
1011
    # val1 specifies the curve(s) and val2 the color(s).
 
1012
    # If they're both scalars, set that one curve. If they are both
 
1013
    # vectors, the shorter length will be used. If val1 is a vector
 
1014
    # and val2 a scalar, then set all curves to the same color.
 
1015
    ###################NOTE:
 
1016
    # Currently val2 is an integer value. Eventually I want to replace
 
1017
    # it with a character designation.
 
1018
    ###################
 
1019
    def set_curve_color ( self , val1 , val2 ) :
 
1020
        """set_curve_color (arg1, arg2) is used to determine how one or a family of
 
1021
        curves is to be colored. It must be called with two arguments.
 
1022
        The first argument is an integer scalar or array Int giving
 
1023
        the curve number(s) and the second is an integer scalar
 
1024
        or array Int describing how the curve(s) should be colored.
 
1025
        Curves are numbered starting with 0. The allowed values for
 
1026
        the second argument are 0 to 63, denoting the index into
 
1027
        the current palette."""
 
1028
 
 
1029
        if not self._file_open : raise self.ConnectException , \
 
1030
           "You are not connected to Narcisse."
 
1031
        if is_scalar (val1) and is_scalar (val2) :
 
1032
            val2 = self._figure_color (val2)
 
1033
            narcisse.narsetaii ( "curve_color" , val2 , val1 )
 
1034
            narcisse.narsetvals ( self._file_descr )
 
1035
        elif not is_scalar (val1) and len (val1) > 1 and is_scalar (val2) :
 
1036
            val2 = self._figure_color (val2)
 
1037
            for i in range (len (val2)) :
 
1038
                narcisse.narsetaii ( "curve_color" , val2 , val1 [i] )
 
1039
                narcisse.narsetvals ( self._file_descr )
 
1040
        elif not is_scalar (val1) and not is_scalar (val2) :
 
1041
            # both must be > 1 in length
 
1042
            r = range (len (val1))
 
1043
            if len (val2) < len (val1) :
 
1044
                r = range (len (val2))
 
1045
            for i in r :
 
1046
                val2 [i] = self._figure_color (val2 [i])
 
1047
                narcisse.narsetaii ( "curve_color" , val2 [i] , val1 [i] )
 
1048
                narcisse.narsetvals ( self._file_descr )
 
1049
        else :
 
1050
            raise self.NarError , "bad parameters to set_curve_color."
 
1051
 
 
1052
    # set the label type for the curves. "end" and "box".
 
1053
    def set_label_type ( self , val ) :
 
1054
        """set_label_type (arg) determines whether curve labels will be attached
 
1055
        to the ends of curves, or enclosed in a box. The allowed
 
1056
        arguments are thus 'end' and 'box'."""
 
1057
 
 
1058
        if ( val == "end" ) :
 
1059
            narcisse.narsetai ( "curve_label_type" , 0 )
 
1060
        elif val == "box" :
 
1061
            narcisse.narsetai ( "curve_label_type" , 1 )
 
1062
        else :
 
1063
            raise self.NarError ,\
 
1064
                     "set_label_type: 'end' and 'box' are the allowed options."
 
1065
 
 
1066
    # set the curve label(s) for one or a set of curves.
 
1067
    # val1 specifies the curve(s) and val2 the label(s).
 
1068
    # If they're both scalars, set that one curve. If they are both
 
1069
    # vectors, choose the shorter of the two lengths.
 
1070
    def set_curve_label ( self , val1 , val2 ) :
 
1071
        """set_curve_label (arg1, arg2) is used to label one or a set of curves.
 
1072
        It requires two arguments. The first is an integer scalar or
 
1073
        array specifying the curve numbers (starting with 1). The
 
1074
        second is a scalar string or list of strings specifying
 
1075
        the label(s) of the curve(s)."""
 
1076
 
 
1077
        if not self._file_open : raise self.ConnectException , \
 
1078
           "You are not connected to Narcisse."
 
1079
        if type (val1) == IntType and type (val2) == StringType :
 
1080
            narcisse.narsetaci ( "curve_label" , val2 , val1 )
 
1081
        elif type (val1) == ArrayType and val1.dtype == Int and \
 
1082
             type (val2) == ListType and type (val2 [0]) == StringType :
 
1083
            r = range (len (val1))
 
1084
            if len (val2) < len (val1) :
 
1085
                r = range (len (val2))
 
1086
            for i in r :
 
1087
                narcisse.narsetaci ( "curve_label" , val2 [i] , val1 [i] )
 
1088
                narcisse.narsetvals ( self._file_descr )
 
1089
        else :
 
1090
            print "Val1: " , `val1`
 
1091
            print "Val2: " , `val2`
 
1092
            raise self.NarError ,\
 
1093
                 "set_curve_label: arguments have inconsistent types or sizes."
 
1094
 
 
1095
    def set_xyequal (self) :
 
1096
        """set_xyequal () sets a parameter that makes the axes equal scale."""
 
1097
        self._xyequal = 1
 
1098
 
 
1099
    def reset_xyequal (self) :
 
1100
        """set_xyequal () resets a parameter that makes the axes equal scale."""
 
1101
        self._xyequal = 0
 
1102
 
 
1103
    narcisse_marks = { "+" : 2 , "*" : 3 , "o" : 4 , "x" : 5 , "." : 6 }
 
1104
    narcisse_types = { "none" : -1 , "hide" : -1 , "line" : 0 ,
 
1105
                       "normal" : 0 , "step" : 1 }
 
1106
 
 
1107
    def _figure_type ( self , crv ) :
 
1108
        """_figure_type (crv) makes sure to return a valid type for a
 
1109
        Narcisse curve.
 
1110
        """
 
1111
        if crv.hide :
 
1112
            return -1
 
1113
        if crv.marks and crv.marker is None :
 
1114
            if (type (crv.line_type) == IntType and \
 
1115
               crv.line_type == 0 or \
 
1116
               type (crv.line_type) == StringType and \
 
1117
               (crv.line_type == "line" or crv.line_type == "normal" or \
 
1118
               crv.line_type == "solid")) :
 
1119
                if crv.label == " " :
 
1120
                    crv.label = uppercase [self._next_letter]
 
1121
                    self._next_letter = (self._next_letter + 1) % 26
 
1122
                return 0
 
1123
        if crv.marks and crv.marker is not None :
 
1124
            # if a marker is specified but a curve is desired, set the
 
1125
            # curve's label to the marker
 
1126
            if type (crv.marker) == StringType and \
 
1127
               (type (crv.line_type) == IntType and \
 
1128
               crv.line_type == 0 or \
 
1129
               type (crv.line_type) == StringType and \
 
1130
               (crv.line_type == "line" or crv.line_type == "normal" or \
 
1131
               crv.line_type == "solid")) :
 
1132
                if crv.label == " " :
 
1133
                    crv.label = crv.marker
 
1134
                return 0
 
1135
            if type (crv.marker) == IntType and 2 <= crv.marker <= 6 :
 
1136
                return crv.marker
 
1137
            if type (crv.marker) == StringType and \
 
1138
               self.narcisse_marks.has_key (crv.marker) :
 
1139
                return self.narcisse_marks [crv.marker]
 
1140
        if type (crv.line_type) == IntType and -1 <= crv.line_type <= 6 :
 
1141
            return crv.line_type
 
1142
        if type (crv.line_type) == StringType and \
 
1143
           self.narcisse_types.has_key (crv.line_type) :
 
1144
            return self.narcisse_types [crv.line_type]
 
1145
        return 0 # incomprehensible so draw a line
 
1146
 
 
1147
    def plot_object ( self , crv ) :
 
1148
 
 
1149
        """plot_object (crv) is a general purpose plotting routine. It should
 
1150
        be called with one argument, a curve (all that Narcisse currently
 
1151
        accepts). In the case of multiple objects on one graph, the
 
1152
        first call only should be to this routine, subsequent calls to
 
1153
        add_object. For Narcisse, plot_object and add_object accumulate
 
1154
        information about the various curves, then send all the freight
 
1155
        when send_graph is called.
 
1156
        """
 
1157
        try :
 
1158
            dum = crv.type ()
 
1159
        except :
 
1160
            raise self.NarError , \
 
1161
               "Unknown object has been sent to Narcisse."
 
1162
        if dum != CurveType :
 
1163
            raise self.NarError , \
 
1164
               "Narcisse does not know how to graph a " + dum + "."
 
1165
        if not self._file_open : raise self.ConnectException , \
 
1166
           "You are not connected to Narcisse."
 
1167
        self._graph_type = 2
 
1168
        # We compute new axis limits if user wants equal scales
 
1169
        if self._xyequal :
 
1170
            new_x_limits = minmax (crv.x)
 
1171
            new_y_limits = minmax (crv.y)
 
1172
            self._x_axis_min = new_x_limits [0]
 
1173
            self._x_axis_max = new_x_limits [1]
 
1174
            self._y_axis_min = new_y_limits [0]
 
1175
            self._y_axis_max = new_y_limits [1]
 
1176
        # start a list of attributes for curves
 
1177
        self._types = [self._figure_type (crv)]
 
1178
        self._labels = [crv.label]
 
1179
        self._colors = [crv.color]
 
1180
        self._axispref = [crv.axis]
 
1181
        self._ylist = [crv.y]
 
1182
        self._xlist = [crv.x]
 
1183
 
 
1184
    # add a curve to an existing plot
 
1185
    def add_object ( self , crv ) :
 
1186
        """add_object (crv) will add a curve to an existing graph.
 
1187
        The curve's attributes are saved up; nothing is sent to Narcisse
 
1188
        until send_graph is called.
 
1189
        """
 
1190
        try :
 
1191
            dum = crv.type ()
 
1192
        except :
 
1193
            raise self.NarError , \
 
1194
               "Unknown object has been sent to Narcisse."
 
1195
        if dum != CurveType :
 
1196
            raise self.NarError , \
 
1197
               "Narcisse does not know how to graph a " + dum + "."
 
1198
        if self._graph_type != 2 :
 
1199
            raise self.NarError , \
 
1200
               "plot_object must be called for the first curve on a graph."
 
1201
        if self._xyequal :
 
1202
            new_x_limits = minmax (crv.x)
 
1203
            new_y_limits = minmax (crv.y)
 
1204
            if self._x_axis_min > new_x_limits [0] :
 
1205
                self._x_axis_min = new_x_limits [0]
 
1206
            if self._x_axis_max < new_x_limits [1] :
 
1207
                self._x_axis_max = new_x_limits [1]
 
1208
            if self._y_axis_min > new_y_limits [0] :
 
1209
                self._y_axis_min = new_y_limits [0]
 
1210
            if self._y_axis_max < new_y_limits [1] :
 
1211
                self._y_axis_max = new_y_limits [1]
 
1212
        self._types.append (self._figure_type (crv))
 
1213
        self._labels.append (crv.label)
 
1214
        self._colors.append (crv.color)
 
1215
        self._ylist.append (crv.y)
 
1216
        self._xlist.append (crv.x)
 
1217
        self._axispref.append (crv.axis)
 
1218
 
 
1219
    def _send_2d_info ( self ) :
 
1220
        """_send_2d_info ( ) sends the accumulated curve information
 
1221
        out to Narcisse.
 
1222
        """
 
1223
        n = len (self._ylist)
 
1224
        if n <= 0 :
 
1225
            raise self.NarError, \
 
1226
               "There is nothing to graph!"
 
1227
        elif n == 1 :
 
1228
            arg1 = 0
 
1229
            arg2t = self._types [0]
 
1230
            arg2c = self._colors [0]
 
1231
            arg2l = self._labels [0]
 
1232
        else :
 
1233
            arg1 = arange (n, dtype = Int)
 
1234
            arg2t = self._types
 
1235
            arg2c = self._colors
 
1236
            arg2l = self._labels
 
1237
        y = self._ylist [0].astype (NarFloat)
 
1238
        x = self._xlist [0].astype (NarFloat)
 
1239
        narcisse.nar1curve (self._file_descr, y, x)
 
1240
        self.set_y_axis (0, self._axispref [0])
 
1241
        for i in range (1, n) :
 
1242
            y = self._ylist [i].astype (NarFloat)
 
1243
            x = self._xlist [i].astype (NarFloat)
 
1244
            narcisse.narsetai ( "option_2d_concatenate" , 1 )
 
1245
            narcisse.narsetvals ( self._file_descr )
 
1246
            narcisse.nar1curve (self._file_descr, y, x)
 
1247
            narcisse.narsetai ( "option_2d_concatenate" , 0 )
 
1248
            narcisse.narsetvals ( self._file_descr )
 
1249
            self.set_y_axis (i, self._axispref [i])
 
1250
        self.set_curve_type (arg1, arg2t)
 
1251
        self.set_curve_color (arg1, arg2c)
 
1252
        self.set_curve_label (arg1, arg2l)
 
1253
 
 
1254
    def plot_text ( self ) :
 
1255
        "plot_text does nothing in Narcisse."
 
1256
        return
 
1257
 
 
1258
    def set_text ( self , txt , n ) :
 
1259
        "set_text (str, ix) sets the ix'th text to str."
 
1260
        if not self._file_open : raise self.ConnectException , \
 
1261
           "You are not connected to Narcisse."
 
1262
        if txt == " " : txt = ""
 
1263
        narcisse.narsetaci ( "text_value" , txt , n )
 
1264
        narcisse.narsetvals ( self._file_descr )
 
1265
 
 
1266
    def clear_text (self) :
 
1267
        "clear_text ( ) sets the number of texts to 0."
 
1268
        if not self._file_open : raise self.ConnectException , \
 
1269
           "You are not connected to Narcisse."
 
1270
        narcisse.narsetaci ( "text_value" , "" , 0 )
 
1271
        narcisse.narsetai ( "text_number" , 0 )
 
1272
        narcisse.narsetvals ( self._file_descr )
 
1273
 
 
1274
    def set_text_color ( self , txt , n ) :
 
1275
        """set_text_color (col, ix) sets the ix'th text color to col,
 
1276
        which is a number between 0 and 63 associated with a color table."""
 
1277
 
 
1278
        if not self._file_open : raise self.ConnectException , \
 
1279
           "You are not connected to Narcisse."
 
1280
        txt = self._figure_color (txt)
 
1281
        narcisse.narsetaii ( "text_color" , txt , n )
 
1282
        narcisse.narsetvals ( self._file_descr )
 
1283
 
 
1284
    def set_text_size ( self , txt , n ) :
 
1285
        """set_text_size (sz, ix) sets the ix'th text size to sz.
 
1286
        sz represents essentially the number of characters that
 
1287
        will fill the width of the graphics screen, so the larger
 
1288
        the number, the smaller the text."""
 
1289
 
 
1290
        if not self._file_open : raise self.ConnectException , \
 
1291
           "You are not connected to Narcisse."
 
1292
        narcisse.narsetaii ( "text_size" , txt , n )
 
1293
        narcisse.narsetvals ( self._file_descr )
 
1294
 
 
1295
    def set_text_pos ( self , x , y , ix ) :
 
1296
        """set_text_pos (x, y, ix) positions the ix'th text at (x, y),
 
1297
        which are real numbers between 0 and 1 giving relative
 
1298
        position in the graphics window."""
 
1299
 
 
1300
        if not self._file_open : raise self.ConnectException , \
 
1301
           "You are not connected to Narcisse."
 
1302
        narcisse.narsetari ("text_pos_x", x, ix)
 
1303
        narcisse.narsetari ("text_pos_y", y, ix)
 
1304
        narcisse.narsetvals ( self._file_descr )
 
1305
 
 
1306
 
 
1307
    # Here's the grandaddy of them all, a perfectly general surface
 
1308
    # plotting routine. Note that it passes a lot of information
 
1309
    # to narcissemodule for error checking.
 
1310
    ###############################################################
 
1311
    # Eventually these routines should probably all be rewritten
 
1312
    # to accept numerical sequences of any kind as inputs,
 
1313
    # convert them to array types as appropriate, check for
 
1314
    # appropriate dimensions, etc. The problem is that anybody
 
1315
    # can call the low level routines directly from Python, so they
 
1316
    # need to do error checking anyhow, just in case.
 
1317
    ###############################################################
 
1318
    def plot_surface ( self , arg1 , * args2 ) :
 
1319
        """plot_surface (args) is a general-purpose 3d/4d plotting routine.
 
1320
        The type of plot depends on the numbers and types of the
 
1321
        arguments (which all must be of type array NarFloat except for the
 
1322
        cell information for unstructured grids). Here we go:
 
1323
           1. single argument, two dimensional array z: Plot z as a
 
1324
              surface versus equally spaced x and y coordinates.
 
1325
           2. three arguments, two vectors x and y and a two dimensional
 
1326
              matrix z: plot z as a surface versus the given x and y.
 
1327
           3. three arguments, matrices x, y, and z (whose dimensions
 
1328
              must match): plot z as a surface versus the given x and y.
 
1329
           4. four arguments, two vectors x and y and two two dimensional
 
1330
              matrices z and c: plot z as a surface versus the given x
 
1331
              and y; use the variable c to color the graph.
 
1332
           5. four arguments, matrices x, y, z, and c (whose dimensions
 
1333
              must match): plot z as a surface versus the given x and y;
 
1334
              use the variable c to color the graph.
 
1335
           6. four arguments, three vectors x, y, and z specifying a
 
1336
              structured grid, and a three-dimensional array c defined
 
1337
              at each grid point: draw the grid and color according to
 
1338
              the variable c.
 
1339
           7. six arguments, vectors x, y, and z of the same size
 
1340
              specifying a nonstructured grid, and c of the same size
 
1341
              specifying a value at each point; cd, an integer vector
 
1342
              specifying connectivity (see the Narcisse manual for
 
1343
              details), and nc an integer specifying the number of
 
1344
              cells in the grid, draw the nonstructured grid and color
 
1345
              according to the variable c."""
 
1346
 
 
1347
        if not self._file_open : raise self.ConnectException , \
 
1348
           "You are not connected to Narcisse."
 
1349
        if len ( args2 ) == 0 :
 
1350
            narcisse.narsurf ( self._file_descr , arg1.astype (NarFloat) )
 
1351
            return
 
1352
        if len ( args2 ) == 2 or len ( args2 ) > 2 and args2 [2] is None :
 
1353
            x = arg1.astype (NarFloat)
 
1354
            y = args2 [0].astype (NarFloat)
 
1355
            z = args2 [1].astype (NarFloat)
 
1356
            if len (x.shape) == 1 and len (y.shape) == 1 :
 
1357
                narcisse.nar3drect ( self._file_descr , x , y , z )
 
1358
                return
 
1359
            else :
 
1360
                narcisse.nar3dtetra ( self._file_descr , x , y , z )
 
1361
                return
 
1362
        if len ( args2 ) == 3 :
 
1363
            x = arg1.astype (NarFloat)
 
1364
            y = args2 [0].astype (NarFloat)
 
1365
            z = args2 [1].astype (NarFloat)
 
1366
            c = args2 [2].astype (NarFloat)
 
1367
            if ( len ( z.shape ) == 2 ) :
 
1368
                if len ( x.shape ) == 1 :
 
1369
                    narcisse.nar4drect ( self._file_descr , x , y , z , c )
 
1370
                    return
 
1371
                else :
 
1372
                    narcisse.nar4dtetra ( self._file_descr , x , y , z , c )
 
1373
                    return
 
1374
            else :
 
1375
                narcisse.narstructmesh ( self._file_descr , x , y , z , c )
 
1376
                return
 
1377
        if len ( args2 ) == 5 :
 
1378
            x = arg1.astype (NarFloat)
 
1379
            y = args2 [0].astype (NarFloat)
 
1380
            z = args2 [1].astype (NarFloat)
 
1381
            c = args2 [2].astype (NarFloat)
 
1382
            cd = args2 [3].astype (Int)
 
1383
            nc = args2 [4]
 
1384
            narcisse.narnonstructmesh ( self._file_descr , x , y , z , c , cd , nc)
 
1385
            return
 
1386
        else :
 
1387
            n=1+len (args2)
 
1388
            raise self.NarError ,\
 
1389
                     "plot_surface: inappropriate number of arguments: " + `n`
 
1390
 
 
1391
    def set_palette (self, col) :
 
1392
        """set_palette (col) sets the color palette to col. The first
 
1393
        entry in col tells how long the rest of the array is; then
 
1394
        there are col [0] / 3 entries for red, followed by the same
 
1395
        number of greens, followed by the same number of blues.
 
1396
        """
 
1397
        for i in range (col [0]) :
 
1398
            narcisse.narsetaii ("parameter_map_pal", col [i + 1], i)
 
1399
        narcisse.narsetai ("parameter_map", -1)
 
1400
        narcisse.narsetvals ( self._file_descr )
 
1401
 
 
1402
    def set_no_concat ( self ) : #called by a graphics object initially
 
1403
        "set_no_concat () turns off the 2d and 3d concatenation mode."
 
1404
        narcisse.narsetai ("option_3d_concatenate", 0)
 
1405
        narcisse.narsetai ("option_2d_concatenate", 0)
 
1406
        narcisse.narsetvals ( self._file_descr )
 
1407
 
 
1408
    # add a surface to an existing plot
 
1409
    def add_surface ( self , arg1 , * args2 ) :
 
1410
        """add_surface (args) will add one or more surfaces to an existing graph.
 
1411
        Its arguments are the same form as the arguments of
 
1412
        plot_surface. See plot_surface documentation for details."""
 
1413
 
 
1414
        if not self._file_open : raise self.ConnectException , \
 
1415
           "You are not connected to Narcisse."
 
1416
        narcisse.narsetai ("option_3d_concatenate" , 1 )
 
1417
        narcisse.narsetvals ( self._file_descr )
 
1418
        if len (args2) == 0 :
 
1419
            self.plot_surface ( arg1 )
 
1420
        elif len (args2) == 2 :
 
1421
            self.plot_surface ( arg1 , args2 [0] , args2 [1] )
 
1422
        elif len (args2) == 3 :
 
1423
            self.plot_surface ( arg1 , args2 [0] , args2 [1] , args2 [2] )
 
1424
        elif len (args2) == 5 :
 
1425
            self.plot_surface ( arg1 , args2 [0] , args2 [1] , args2 [2] , args2 [3] , args2 [4] )
 
1426
        else :
 
1427
            raise self.NarError , "add_surface: inappropriate number of arguments ("\
 
1428
                              + `len (args2)` + ")."
 
1429
        narcisse.narsetai ("option_3d_concatenate" , 0 )
 
1430
        narcisse.narsetvals ( self._file_descr )
 
1431
 
 
1432
    # routine to freeze the graph
 
1433
    # i. e., arguments and graphs sent will not be plotted until
 
1434
    # send_graph is called.
 
1435
    def freeze_graph ( self ) :
 
1436
        """freeze_graph () keeps a graph from being plotted until
 
1437
        send_graph () is called."""
 
1438
 
 
1439
        if not self._file_open : raise self.ConnectException , \
 
1440
           "You are not connected to Narcisse."
 
1441
        if not self._frozen :
 
1442
            narcisse.narsetai ( "plot_now" , 0 )
 
1443
            narcisse.narsetvals ( self._file_descr )
 
1444
            self._frozen = 1
 
1445
 
 
1446
 
 
1447
    # routine to release the graph
 
1448
    # The current graph will be plotted and any arguments will
 
1449
    # be sent. if _freeze_each has been set, then the next graph
 
1450
    # will be _frozen too.
 
1451
    def send_graph ( self, graf ) :
 
1452
        """send_graph () causes a plot that has been accumulated
 
1453
        after freeze_graph () was called, to be plotted."""
 
1454
 
 
1455
        if not self._file_open : raise self.ConnectException , \
 
1456
           "You are not connected to Narcisse."
 
1457
        if self._graph_type == 0 :
 
1458
            raise self.NarError, \
 
1459
               "There is nothing to graph!"
 
1460
        if graf.type () == Graph3dType :
 
1461
            self._dims = 3
 
1462
        else :
 
1463
            self.dims = 2
 
1464
        self._send_axes_limits ( )
 
1465
        if self._graph_type == 2 :
 
1466
            self._send_2d_info ( )
 
1467
        if self._frozen :
 
1468
            self._frozen = 0
 
1469
            narcisse.narsetai ( "plot_now" , 1 )
 
1470
        narcisse.narsetvals ( self._file_descr )
 
1471
        if self._freeze_each :
 
1472
            self.freeze_graph ( )
 
1473
 
 
1474
    def set_freeze_each ( self , val ) :
 
1475
        """set_freeze_each ( fe ) tells whether or not to re-freeze the
 
1476
        graphics after each send_graph call. 1 to re-freeze, 0 not to."""
 
1477
        self._freeze_each = val
 
1478
 
 
1479
    def send_generics (self, graf) :
 
1480
        """send_generics ( graf ) sets up all the things that are generic to any
 
1481
        graph. It does not actually do any plotting yet.
 
1482
        """
 
1483
        self.set_titles ( graf._titles )
 
1484
        self.set_title_colors ( graf._title_colors )
 
1485
        # The following line is redundant for Gist. Not sure about Narcisse.
 
1486
        # self._plot_titles ( )
 
1487
        self.set_grid_type ( graf._grid_type )
 
1488
        self.clear_text ( )
 
1489
        if is_scalar ( graf._text ) :
 
1490
            if ( graf._text != "" and graf._text != " ") :
 
1491
                self.set_text ( graf._text , 0 )
 
1492
        else :
 
1493
            for i in range ( len ( graf._text ) ) :
 
1494
                self.set_text ( graf._text [i] , i )
 
1495
        if is_scalar ( graf._text_color ) :
 
1496
            self.set_text_color ( graf._text_color , 0 )
 
1497
        else :
 
1498
            for i in range ( len ( graf._text_color ) ) :
 
1499
                self.set_text_color ( graf._text_color [i] , i )
 
1500
        if is_scalar ( graf._text_size ) :
 
1501
            self.set_text_size ( graf._text_size , 0 )
 
1502
        else :
 
1503
            for i in range ( len ( graf._text_size ) ) :
 
1504
                self.set_text_size ( graf._text_size [i] , i )
 
1505
        if is_scalar ( graf._tosys ) :
 
1506
            self.set_tosys ( graf._tosys , 0 )
 
1507
        else :
 
1508
            for i in range ( len ( graf._tosys ) ) :
 
1509
                self.set_tosys ( graf._tosys [i] , i )
 
1510
        if is_scalar ( graf._text_pos ) :
 
1511
            raise graf._GraphSpecError , \
 
1512
               "Text position must be a point or an array of points."
 
1513
        if len ( shape ( graf._text_pos )) == 1:
 
1514
            self.set_text_pos ( graf._text_pos [0] , graf._text_pos [1] , 0 )
 
1515
        else :
 
1516
            for i in range (shape (graf._text_pos) [0] ) :
 
1517
                self.set_text_pos ( graf._text_pos [i][0] ,
 
1518
                                  graf._text_pos [i][1] , i )
 
1519
 
 
1520
    # The following is the equivalent of the Gist split palette.
 
1521
    # The lower half is the rainbow, the upper half is greyscale.
 
1522
    split_palette = array ([162, # The last 54 colors of the palette
 
1523
                            #27 reds, 27 greys:
 
1524
                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
1525
                            19, 67, 115, 163, 211,
 
1526
                            255, 255, 255, 255, 255, 255,
 
1527
                            255, 255, 255, 255, 255,
 
1528
                            0, 9, 19,  29,  39,  49,  58,  68,
 
1529
                            78,  88,  98, 107, 117, 127, 137,
 
1530
                            147, 156, 166, 176, 186, 196, 205,
 
1531
                            215, 225, 235, 245, 255,
 
1532
                            #27, greens, 27 greys:
 
1533
                            24, 72, 120, 168, 216,
 
1534
                            255, 255, 255, 255, 255, 255,
 
1535
                            255, 255, 255, 255, 255,
 
1536
                            226, 178, 129, 81, 33, 0, 0, 0, 0, 0, 0,
 
1537
                            0, 9, 19,  29,  39,  49,  58,  68,
 
1538
                            78,  88,  98, 107, 117, 127, 137,
 
1539
                            147, 156, 166, 176, 186, 196, 205,
 
1540
                            215, 225, 235, 245, 255,
 
1541
                            #27 blues, 27 greys:
 
1542
                            255, 255, 255, 255, 255,
 
1543
                            245, 197, 149, 101, 52, 4,
 
1544
                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
1545
                            14, 62, 110, 158, 206, 255,
 
1546
                            0, 9, 19,  29,  39,  49,  58,  68,
 
1547
                            78,  88,  98, 107, 117, 127, 137,
 
1548
                            147, 156, 166, 176, 186, 196, 205,
 
1549
                            215, 225, 235, 245, 255
 
1550
                           ], Int)
 
1551
 
 
1552
    def do_generic (self, graf) :
 
1553
        self.set_freeze_each (1)
 
1554
        self.freeze_graph ( ) #freeze everything until entire graph is sent
 
1555
        self.set_no_concat ( )
 
1556
        self.send_generics ( graf )
 
1557
        self.set_axis_labels ( graf._axis_labels )
 
1558
        self.set_x_axis_limits (graf._axis_limits [0][0],
 
1559
                                graf._axis_limits [0][1])
 
1560
        self.set_y_axis_limits (graf._axis_limits [1][0],
 
1561
                                graf._axis_limits [1][1])
 
1562
        if self._dims == 2 :
 
1563
            self.set_yr_axis_limits (graf._axis_limits [2][0],
 
1564
                                    graf._axis_limits [2][1])
 
1565
        elif self._dims == 3 :
 
1566
            self.set_z_axis_limits (graf._axis_limits [2][0],
 
1567
                                    graf._axis_limits [2][1])
 
1568
            self.set_c_axis_limits (graf._axis_limits [3][0],
 
1569
                                    graf._axis_limits [3][1])
 
1570
            self.set_yr_axis_limits (graf._axis_limits [4][0],
 
1571
                                    graf._axis_limits [4][1])
 
1572
        if self._dims == 2:
 
1573
            for i in range (graf._no_of_axes) :
 
1574
                if graf._axis_scales [i] == "lin" :
 
1575
                    self.set_axis_lin (graf._axes [i])
 
1576
                elif graf._axis_scales [i] == "log" :
 
1577
                    self.set_axis_log (graf._axes [i])
 
1578
                else :
 
1579
                    raise graf._AxisSpecError , \
 
1580
                       graf._axis_scales [i] + " is not a valid axis scale."
 
1581
        elif self._dims == 3:
 
1582
            sc = graf._axis_scales
 
1583
            if is_scalar (sc) :
 
1584
                sc = [sc] + ["lin", "lin", "lin", "lin"]
 
1585
            else :
 
1586
                for i in range (5 - no_of_dims (sc)) :
 
1587
                    sc = sc + ["lin"]
 
1588
            for i in range (5) :
 
1589
                if sc [i] == "log" :
 
1590
                    self.set_axis_log (graf._axes [i])
 
1591
                else : # anything else will be lin
 
1592
                    self.set_axis_lin (graf._axes [i])
 
1593
        try:
 
1594
            no_color = os.environ["NO_COLOR"]
 
1595
        except KeyError:
 
1596
            no_color = 0
 
1597
        if no_color == 0 or no_color == "no" or no_color == "n" :
 
1598
            self.set_color_card (graf._color_card , 1)
 
1599
        if self._dims == 3:
 
1600
            self.set_phi ( graf._phi )
 
1601
            self.set_theta ( graf._theta )
 
1602
            self.set_roll ( graf._roll )
 
1603
        return
 
1604
 
 
1605
    def quick_plot (self, graf) :
 
1606
        "quick_plot (graf) plots without recomputing."
 
1607
        if graf.type () == Graph2dType :
 
1608
            self._dims = 2
 
1609
        else :
 
1610
            self._dims = 3
 
1611
        self.do_generic (graf)
 
1612
        if hasattr (graf, "n") and self._dims == 3 :
 
1613
            if graf.opt_3d_change :
 
1614
                self.set_3d_options ( graf._color_bar,
 
1615
                                      graf._color_bar_pos,
 
1616
                                      graf._s [graf.n - 1].opt_3d )
 
1617
            if graf.mask_change :
 
1618
                self.set_mask ( graf._s [graf.n - 1].mask )
 
1619
            if graf.mesh_type_change :
 
1620
                self.set_3d_grid_type ( graf._s [graf.n - 1].mesh_type )
 
1621
        if hasattr (graf, "n") and self._dims == 2 :
 
1622
            if graf.type_change :
 
1623
                self.set_curve_type ( graf.n - 1 , graf._c[graf.n - 1].line_type )
 
1624
            if graf.color_change :
 
1625
                self.set_curve_color ( graf.n - 1 , graf._c[graf.n - 1].color )
 
1626
            if graf.label_change :
 
1627
                self.set_curve_label ( graf.n - 1 , graf._c[graf.n - 1].label )
 
1628
        if graf._label_type != " " :
 
1629
            self.set_label_type ( graf._label_type )
 
1630
        if (graf._sync) :
 
1631
            self.synchronize ( )
 
1632
        self.send_graph (graf)
 
1633
 
 
1634
    def plot2d (self, graf) :
 
1635
        """A Graph2d object calls plot2d with itself as argument.
 
1636
        plot2d sorts out everything for the graph and then does the plot.
 
1637
        The bulk of this work used to be done in Graph and Graph2d,
 
1638
        but I decided it was too graphics-dependent.
 
1639
        """
 
1640
        self._dims = 2
 
1641
        # (1) Do graph-generic stuff first
 
1642
        self.do_generic (graf)
 
1643
        # (2) Do the specifically 2d stuff
 
1644
        sc = graf._axis_scales
 
1645
        if graf._xyequal :
 
1646
            self.set_xyequal ( )
 
1647
        else :
 
1648
            self.reset_xyequal ( )
 
1649
        if is_scalar (sc) :
 
1650
            if sc == "linlin" or sc == "lin" :
 
1651
                self.set_linlin ( )
 
1652
            elif sc == "linlog" :
 
1653
                self.set_linlog ( )
 
1654
            elif sc == "loglin" or sc == "log" :
 
1655
                self.set_loglin ( )
 
1656
            elif sc == "loglog" :
 
1657
                self.set_loglog ( )
 
1658
        else :
 
1659
            if len (sc) == 1 :
 
1660
                sc = sc + ["lin", "lin"]
 
1661
            elif len (sc) == 2 :
 
1662
                sc = sc + ["lin"]
 
1663
            for n in range (3) :
 
1664
                if sc [n] == "log" :
 
1665
                    self.set_axis_log (graf._axes [n])
 
1666
                else :
 
1667
                    self.set_axis_lin (graf._axes [n])
 
1668
        for i in range ( graf._c_ln ) :
 
1669
            if i == 0 :
 
1670
                self.plot_object ( graf._c [i] )
 
1671
            else :
 
1672
                self.add_object ( graf._c [i] )
 
1673
        self.plot_text ( )
 
1674
        # Finally do the graph
 
1675
        if (graf._sync) :
 
1676
            self.synchronize ( )
 
1677
        self.send_graph (graf)
 
1678
 
 
1679
    def split_bytscl (self, val, top) :
 
1680
        """
 
1681
        split_bytscl (val, top) scales the values in val to the top
 
1682
        half of the palette (values 27 to 53) if top = 1, and to
 
1683
        the bottom half (values 0 to 26) if top = 0.
 
1684
        """
 
1685
        retval = ( (val - min (val)).astype(Float) /
 
1686
                   max( (val - min (val)).astype(Float)*26. +
 
1687
                   0.5)).astype (Int) + top * 26
 
1688
 
 
1689
 
 
1690
    def plot3d (self, graf) :
 
1691
        """plot3d (graf) plots a 3d graph object.
 
1692
        """
 
1693
        self._dims = 3
 
1694
        # (1) Do graph-generic stuff first
 
1695
        self.do_generic (graf)
 
1696
 
 
1697
        self.set_phi ( graf._phi )
 
1698
        self.set_theta ( graf._theta )
 
1699
        self.set_roll ( graf._roll )
 
1700
        self.set_distance ( graf._distance )
 
1701
        n = graf._s_ln
 
1702
        if n > 1 and graf._connect :
 
1703
            self.set_connect ( 1)
 
1704
        else :
 
1705
            self.set_connect ( 0)
 
1706
        if graf._s [0].type () == Slice3dType :
 
1707
            # This is a graph of one or more isosurface and/or plane slices.
 
1708
            # Basically, we just need to put the vertices and cell
 
1709
            # information into the form recognized by SpxNonStruct4d.
 
1710
            # For now, Narcisse will not allow slices to be combined
 
1711
            # with other surfaces.
 
1712
            # send out surface characteristics, then each surface
 
1713
            self.set_link ( 0 )
 
1714
            self.set_mask ( graf.mask )
 
1715
            self.set_3d_options ( graf._color_bar,
 
1716
                                  graf._color_bar_pos,
 
1717
                                  graf._s [0].opt_3d )
 
1718
            self.set_3d_grid_type ( graf._s[0].mesh_type )
 
1719
            self.set_z_c_switch ( graf._s[0].z_c_switch )
 
1720
            self.set_z_contours ( graf._s[0].z_contours_scale )
 
1721
            self.set_c_contours ( graf._s[0].c_contours_scale )
 
1722
            if graf._s[0].z_contours_array is None :
 
1723
                if graf._s[0].number_of_z_contours is None :
 
1724
                    self.set_z_contours (20)
 
1725
                else :
 
1726
                    self.set_z_contours (graf._s[0].number_of_z_contours)
 
1727
            else :
 
1728
                self.set_z_contours ( graf._s[0].z_contours_array )
 
1729
            if graf._s[0].c_contours_array is None :
 
1730
                if graf._s[0].number_of_c_contours is None :
 
1731
                    self.set_c_contours (20)
 
1732
                else :
 
1733
                    self.set_c_contours (graf._s[0].number_of_c_contours)
 
1734
            else :
 
1735
                self.set_c_contours ( graf._s[0].c_contours_array )
 
1736
 
 
1737
            isosurfaces_present = 0
 
1738
            self._graph_type = 4
 
1739
            for i in range (graf._s_ln) :
 
1740
                if graf._s [i].type () == Slice3dType :
 
1741
                    if graf._s [i].plane is None and graf._s [i].iso is not None :
 
1742
                        isosurfaces_present = 1
 
1743
                else :
 
1744
                    raise self.NarError, \
 
1745
                       "If one component is a Slice, all must be."
 
1746
            for i in range (graf._s_ln) :
 
1747
                s = graf._s [i]
 
1748
                opt_3d = s.opt_3d
 
1749
                if type (opt_3d) != ListType :
 
1750
                    opt_3d = [opt_3d]
 
1751
                if i == 0 :
 
1752
                    nv = s.nv
 
1753
                    x = s.xyzv [:, 0]
 
1754
                    y = s.xyzv [:, 1]
 
1755
                    z = s.xyzv [:, 2]
 
1756
                    if (max (abs (x)) < 10.e-30) :
 
1757
                        x [0: len(x)] = 0.
 
1758
                    if (max (abs (y)) < 10.e-30) :
 
1759
                        y [0: len(y)] = 0.
 
1760
                    if (max (abs (z)) < 10.e-30) :
 
1761
                        z [0: len(z)] = 0.
 
1762
                    if not isosurfaces_present or s.iso is None and \
 
1763
                       s.plane is None :
 
1764
                        if "i3" in opt_3d or "s3" in opt_3d or \
 
1765
                           "w3" in opt_3d or "f3" in opt_3d :
 
1766
                            val = z
 
1767
                        else :
 
1768
                            val = s.val
 
1769
                    elif s.plane is not None :
 
1770
                        if len(s.val) == len (s.nv) :
 
1771
                            val = to_corners (s.val, s.nv, sum (s.nv))
 
1772
                        else :
 
1773
                            val = s.val
 
1774
                    else :
 
1775
                        val = ones (sum (s.nv), Float) * s.iso
 
1776
                else :
 
1777
                    nv = concatenate ( (nv, s.nv))
 
1778
                    x = concatenate ( (x, s.xyzv [:, 0]))
 
1779
                    y = concatenate ( (y, s.xyzv [:, 1]))
 
1780
                    z = concatenate ( (z, s.xyzv [:, 2]))
 
1781
                    if not isosurfaces_present or s.iso is None and \
 
1782
                       s.plane is None :
 
1783
                        val = concatenate ( (val, s.val))
 
1784
                    elif s.plane is not None :
 
1785
                        if len(s.val) == len (s.nv) :
 
1786
                            val = concatenate ( (val,
 
1787
                               to_corners (s.val, s.nv, sum (s.nv))))
 
1788
                        else :
 
1789
                            val = concatenate ( (val, s.val))
 
1790
                    else :
 
1791
                        val = concatenate ( (val, ones (sum (s.nv), Float) * s.iso))
 
1792
            nc = len (nv)
 
1793
            nv = concatenate ( (cumsum (nv), arange (len (x))))
 
1794
##        if isosurfaces_present :
 
1795
##           self.set_palette (self.split_palette)
 
1796
            self.set_color_card (graf._color_card)
 
1797
            self.plot_surface (x, y, z, val, nv, nc)
 
1798
            if (graf._sync) :
 
1799
                self.synchronize ( )
 
1800
            self.plot_text ( )
 
1801
            self.send_graph (graf)
 
1802
        elif graf._link :
 
1803
            # got to send out one surface and its characteristics at a time
 
1804
            self.set_link ( 1 )
 
1805
            for i in range ( n ) :
 
1806
                # Do not replot axes for subsequent components
 
1807
                if i > 0 : self.set_grid_type ("none")
 
1808
                self.set_mask ( graf._s[i].mask )
 
1809
                self.set_3d_options ( graf._color_bar,
 
1810
                                      graf._color_bar_pos,
 
1811
                                      graf._s[i].opt_3d )
 
1812
                self.set_3d_grid_type ( graf._s[i].mesh_type )
 
1813
                if graf._s[i].z_c_switch :
 
1814
                    self.set_z_c_switch ( 1 )
 
1815
                else :
 
1816
                    self.set_z_c_switch ( 0 )
 
1817
                self.set_z_contours ( graf._s[i].z_contours_scale )
 
1818
                self.set_c_contours ( graf._s[i].c_contours_scale )
 
1819
                if graf._s[i].z_contours_array is None :
 
1820
                    if graf._s[i].number_of_z_contours is None :
 
1821
                        self.set_z_contours (20)
 
1822
                    else :
 
1823
                        self.set_z_contours (graf._s[i].number_of_z_contours)
 
1824
                else :
 
1825
                    self.set_z_contours ( graf._s[i].z_contours_array )
 
1826
                if graf._s[i].c_contours_array is None :
 
1827
                    if graf._s[i].number_of_c_contours is None :
 
1828
                        self.set_c_contours (20)
 
1829
                    else :
 
1830
                        self.set_c_contours (graf._s[i].number_of_c_contours)
 
1831
                else :
 
1832
                    self.set_c_contours ( graf._s[i].c_contours_array )
 
1833
                # always send coordinates of linked surfaces
 
1834
                if not hasattr (graf._s[i], "x") or \
 
1835
                   graf._s[i].x is None : # just graphing z
 
1836
                    self._graph_type = 3
 
1837
                    self.plot_surface ( array ( graf._s[i].z, Float))
 
1838
                elif graf._s[i].c is None : #surface alone
 
1839
                    self._graph_type = 3
 
1840
                    self.plot_surface ( array ( graf._s[i].x, Float),
 
1841
                                     array ( graf._s[i].y, Float),
 
1842
                                     array ( graf._s[i].z, Float))
 
1843
                else : # 4d plot (surface or structured mesh plot)
 
1844
                    self._graph_type = 4
 
1845
                    if graf._s[i].type () == SurfaceType or \
 
1846
                       graf._s[i].structured :
 
1847
                        # (surface or structured mesh plot)
 
1848
                        self.plot_surface ( array ( graf._s[i].x, Float),
 
1849
                                         array ( graf._s[i].y, Float),
 
1850
                                         array ( graf._s[i].z, Float),
 
1851
                                         array ( graf._s[i].c, Float))
 
1852
                    else : # Nonstructured mesh
 
1853
                        graf._s[i].create_Narcisse_format ()
 
1854
                        self.plot_surface ( array ( graf._s[i].x, Float),
 
1855
                            array ( graf._s[i].y, Float),
 
1856
                            array ( graf._s[i].z, Float),
 
1857
                            array ( graf._s[i].c, Float),
 
1858
                            array ( graf._s[i].cell_descr, Int ),
 
1859
                            graf._s[i].number_of_cells)
 
1860
                if (graf._sync) :
 
1861
                    self.synchronize ( )
 
1862
                self.send_graph (graf)
 
1863
                if i == 0 :
 
1864
                    self.plot_text ( )
 
1865
                    self.set_link (0)
 
1866
        else : # not graf._link
 
1867
            # send out surface characteristics, then each surface
 
1868
            self.set_link ( 0 )
 
1869
            self.set_mask ( graf._s[n - 1].mask )
 
1870
            self.set_3d_options ( graf._color_bar,
 
1871
                                  graf._color_bar_pos,
 
1872
                                  graf._s[n - 1].opt_3d )
 
1873
            self.set_3d_grid_type ( graf._s[n - 1].mesh_type )
 
1874
            self.set_z_c_switch ( graf._s[n - 1].z_c_switch )
 
1875
            self.set_z_contours ( graf._s[n - 1].z_contours_scale )
 
1876
            self.set_c_contours ( graf._s[n - 1].c_contours_scale )
 
1877
            if graf._s[n - 1].z_contours_array is None :
 
1878
                if graf._s[n - 1].number_of_z_contours is None :
 
1879
                    self.set_z_contours (20)
 
1880
                else :
 
1881
                    self.set_z_contours (graf._s[n - 1].number_of_z_contours)
 
1882
            else :
 
1883
                self.set_z_contours ( graf._s[n - 1].z_contours_array )
 
1884
            if graf._s[n - 1].c_contours_array is None :
 
1885
                if graf._s[n - 1].number_of_c_contours is None :
 
1886
                    self.set_c_contours (20)
 
1887
                else :
 
1888
                    self.set_c_contours (graf._s[n - 1].number_of_c_contours)
 
1889
            else :
 
1890
                self.set_c_contours ( graf._s[n - 1].c_contours_array )
 
1891
            if graf._send_coordinates :
 
1892
                for i in range ( n ) : # now send out surfaces
 
1893
                    if not hasattr (graf._s[i], "x") or \
 
1894
                       graf._s[i].x is None : # just graphing z
 
1895
                        self._graph_type = 3
 
1896
                        if i == 0 :
 
1897
                            self.plot_surface (array (graf._s[i].z, Float))
 
1898
                        else :
 
1899
                            self.add_surface (array (graf._s[i].z, Float))
 
1900
                    elif graf._s[i].c is None : # 3d plot
 
1901
                        self._graph_type = 3
 
1902
                        if i == 0 :
 
1903
                            self.plot_surface ( array ( graf._s[i].x, Float),
 
1904
                                             array ( graf._s[i].y, Float),
 
1905
                                             array ( graf._s[i].z, Float))
 
1906
                        else :
 
1907
                            self.add_surface ( array ( graf._s[i].x, Float),
 
1908
                                             array ( graf._s[i].y, Float),
 
1909
                                             array ( graf._s[i].z, Float))
 
1910
                    else : # 4d plot (surface or structured mesh plot)
 
1911
                        self._graph_type = 4
 
1912
                        if graf._s[i].type () == SurfaceType or \
 
1913
                           graf._s[i].structured :
 
1914
                            if i == 0 :
 
1915
                                self.plot_surface ( array ( graf._s[i].x, Float),
 
1916
                                                 array ( graf._s[i].y, Float),
 
1917
                                                 array ( graf._s[i].z, Float),
 
1918
                                                 array ( graf._s[i].c, Float))
 
1919
                            else :
 
1920
                                self.add_surface ( array ( graf._s[i].x, Float),
 
1921
                                                 array ( graf._s[i].y, Float),
 
1922
                                                 array ( graf._s[i].z, Float),
 
1923
                                                 array ( graf._s[i].c, Float))
 
1924
                        else : # Nonstructured mesh plot
 
1925
                            graf._s[i].create_Narcisse_format ()
 
1926
                            if i == 0 :
 
1927
                                self.plot_surface ( array ( graf._s[i].x, Float),
 
1928
                                    array ( graf._s[i].y, Float),
 
1929
                                    array ( graf._s[i].z, Float),
 
1930
                                    array ( graf._s[i].c, Float),
 
1931
                                    array ( graf._s[i].cell_descr, Int),
 
1932
                                    graf._s[i].number_of_cells )
 
1933
                            else :
 
1934
                                self.add_surface ( array ( graf._s[i].x, Float),
 
1935
                                    array ( graf._s[i].y, Float),
 
1936
                                    array ( graf._s[i].z, Float),
 
1937
                                    array ( graf._s[i].c, Float),
 
1938
                                    array ( graf._s[i].cell_descr, Int),
 
1939
                                    graf._s[i].number_of_cells )
 
1940
            if (graf._sync) :
 
1941
                self.synchronize ( )
 
1942
            self.plot_text ( )
 
1943
            self.send_graph (graf)
 
1944
 
 
1945
    def move_light_source (self, graf, angle, nframes) :
 
1946
        raise self.NarError, \
 
1947
           "Sorry, Narcisse does not yet support a moving light source."
 
1948
 
 
1949
    def rotate_graph (self, axis, angle, nframes) :
 
1950
        # In Narcisse, only the angle counts.
 
1951
        narcisse.narsetai ("animation_number", nframes)
 
1952
        angle = angle * 180. / pi
 
1953
        narcisse.narsetai ("animation_azimuth", angle)
 
1954
        narcisse.narsetai ("animation_elevation", angle)
 
1955
        if self._frozen :
 
1956
            self._frozen = 0
 
1957
            narcisse.narsetai ( "plot_now" , 1 )
 
1958
        narcisse.narsetvals ( self._file_descr )
 
1959
        if self._freeze_each :
 
1960
            self.freeze_graph ( )