1
## Automatically adapted for scipy Oct 31, 2005 by
3
# Copyright (c) 1996, 1997, The Regents of the University of California.
4
# All rights reserved. See Legal.htm for full text and disclaimer.
8
from numpy.core.umath import *
9
# We need types to check args to some routines
11
from graftypes import *
12
from shapetest import *
13
from gistfuncs import *
14
from string import uppercase
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].
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)]
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.
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)]
46
# Define a simple title function: missing arguments become blanks.
52
def open ( self , filename = ' ' ) :
53
"""open ( string ) opens a connection to Narcisse (if it can)
54
using filename 'string.'
57
if self._file_name == filename :
60
raise self.ConnectException , \
61
"This instance already open with filename '" + \
62
self._file_name + "'."
64
self._file_descr = narcisse.naropen ( filename )
65
if self._file_descr >= 0 :
67
self._file_name = filename
69
raise self.ConnectException , \
70
"Unable to open graphics file '" + filename + "'."
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."
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."
91
self._mono = 0 #defaults to color
93
self.ConnectException = "ConnectException"
94
self.open ( filename )
96
self.set_grid_type ( "axes" )
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.
116
self.set_text_color (2, 0) #black or nearly so
117
self.set_axis_labels () # To English defaults
119
self.set_title_colors ( )
120
self.plot_curve = self.plot_object
121
self.add_curve = self.add_object
123
if kw.has_key ("style") :
124
self._style = kw ["style"]
127
self._next_letter = 0
130
"close () closes the connection to Narcisse."
132
narcisse.narclose ( self._file_descr )
133
self._file_descr = -1
137
def __del__ ( self ) :
140
def new_frame (self) :
143
def set_tosys (self, *x) :
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
154
self.set_3d_options ( color_bar, color_bar_pos, "wm" )
157
def synchronize ( self ) :
159
narcisse.narsync ( self._file_descr )
161
print "synchronize: sorry, nothing is open to synchronize with."
164
if not self._file_open :
167
return narcisse.narquery ( self._file_name )
169
def set_color ( self ) :
170
"""set_color ( ) will allow you to use the color 3d options
171
which are disabled by set_mono ( )."""
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 }
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)."""
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)
195
def set_titles ( self , * vals ):
196
"""set_titles ('bottom', 'top', 'left', 'right')
197
All arguments are optional. Missing ones default to ' '."""
199
if not self._file_open : raise self.ConnectException , \
200
"You are not connected to Narcisse."
203
elif type (vals [0]) == StringType :
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!"
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 )
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 }
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.
241
if type (col) == IntType and 0 <= col <= 63 :
243
if self.gist_to_narcisse_col.has_key (col) :
244
return self.gist_to_narcisse_col [col]
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
253
if not self._file_open : raise self.ConnectException , \
254
"You are not connected to Narcisse."
257
elif type (vals [0]) == IntType :
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."
273
vals = [vals [0]] + [vals [1]] + [vals [2]] + [vals [3]]
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 )
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'."""
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 )
302
raise self.NarError , val [0] + \
303
" is an inappropriate argument for set_grid_type."
304
narcisse.narsetvals ( self._file_descr )
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)."""
313
narcisse.narsetai ( "option_3d_grid_type" , 0 )
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 )
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."""
325
narcisse.narsetai ("option_3d_conv_mode" , val)
326
narcisse.narsetvals ( self._file_descr )
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."""
336
narcisse.narsetai ("parameter_scene", val)
337
narcisse.narsetvals ( self._file_descr )
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."""
344
narcisse.narsetai ("option_3d_z_or_c", val)
345
narcisse.narsetvals ( self._file_descr )
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'."""
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) :
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 )
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."""
378
if not self._file_open : raise self.ConnectException , \
379
"You are not connected to Narcisse."
381
narcisse.narsetai ( "x_axis_log" , 0 )
383
narcisse.narsetai ( "y_axis_log" , 0 )
384
elif ( ax == "yr" ) :
385
narcisse.narsetai ( "yr_axis_log" , 0 )
387
narcisse.narsetai ( "z_axis_log" , 0 )
389
narcisse.narsetai ( "c_axis_log" , 0 )
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 )
397
raise self.NarError , "set_axis_lin: axis must be x, y, yr, z, or c."
398
narcisse.narsetvals ( self._file_descr )
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."""
406
narcisse.narsetai ( "x_axis_log" , 1 )
408
narcisse.narsetai ( "y_axis_log" , 1 )
409
elif ( ax == "yr" ) :
410
narcisse.narsetai ( "yr_axis_log" , 1 )
412
narcisse.narsetai ( "z_axis_log" , 1 )
414
narcisse.narsetai ( "c_axis_log" , 1 )
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 )
422
raise self.NarError , "axis_log: axis must be x, y, yr, z, or c."
423
narcisse.narsetvals ( self._file_descr )
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" )
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" )
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" )
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" )
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
452
if len ( val2 ) == 2 :
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 )
459
narcisse.narsetaii ( "curve_y_axis" , 1 , n )
460
narcisse.narsetvals ( self._file_descr )
462
def set_bytscl ( self, cmin, cmax ) :
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."""
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."""
475
if not self._file_open : raise self.ConnectException , \
476
"You are not connected to Narcisse."
477
if len ( val1 ) == 0 :
482
self._x_axis_max = val
483
narcisse.narsetar ( "x_axis_max" , val )
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 )
491
self._z_axis_max = val
492
narcisse.narsetar ( "z_axis_max" , val )
494
self._c_axis_max = val
495
narcisse.narsetar ( "c_axis_max" , val )
497
raise self.NarError , "set_axis_max: axis must be x, y, yr, z, or c."
498
# narcisse.narsetvals ( self._file_descr )
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.'''
506
if not self._file_open : raise self.ConnectException , \
507
"You are not connected to Narcisse."
508
if len ( val1 ) == 0 :
513
self._x_axis_min = val
514
narcisse.narsetar ( "x_axis_min" , val )
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 )
522
self._z_axis_min = val
523
narcisse.narsetar ( "z_axis_min" , val )
525
self._c_axis_min = val
526
narcisse.narsetar ( "c_axis_min" , val )
528
raise self.NarError , "set_axis_min: axis must be x, y, yr, z, or c."
529
# narcisse.narsetvals ( self._file_descr )
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
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.'''
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
556
self._y_axis_max = self._y_axis_max + xdist - ydist
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 )
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 )
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.'''
582
if not self._file_open : raise self.ConnectException , \
583
"You are not connected to Narcisse."
584
if len ( 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 )
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.'''
598
if not self._file_open : raise self.ConnectException , \
599
"You are not connected to Narcisse."
600
if len ( 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 )
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.'''
614
if not self._file_open : raise self.ConnectException , \
615
"You are not connected to Narcisse."
616
if len ( 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 )
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.'''
630
if not self._file_open : raise self.ConnectException , \
631
"You are not connected to Narcisse."
632
if len ( 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 )
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.'''
646
if not self._file_open : raise self.ConnectException , \
647
"You are not connected to Narcisse."
648
if len ( 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 )
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 } }
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
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."""
694
if not self._file_open : raise self.ConnectException , \
695
"You are not connected to Narcisse."
700
elif is_scalar (vals) :
704
if is_scalar (vals) :
707
raise self.NarError , "set_3d_options: too many arguments"
708
wire_option = -1 # If this ever gets sent, the graph vanishes
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 :
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] + "."
734
option = self.legal_3d_double [vals [0]][vals [1]]
735
else : # cause graph to commit suicide if no args given
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 :
741
if color_bar_pos is not None :
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])
749
narcisse.narsetai ( "height_c_type", c_color_bar )
751
if color_bar_pos is not None :
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])
759
narcisse.narsetai ( "height_z_type", z_color_bar )
761
narcisse.narsetai ( "height_c_type", 0)
762
narcisse.narsetai ( "height_z_type", 0)
763
narcisse.narsetvals ( self._file_descr )
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
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
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 )
785
elif type ( val ) == StringType :
787
narcisse.narsetai ("height_z_log", 1)
788
narcisse.narsetvals ( self._file_descr )
791
narcisse.narsetai ("height_z_log", 0)
792
narcisse.narsetvals ( self._file_descr )
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 )
809
raise self.NarError , "Wrong type of argument to set_z_contours."
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
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
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 )
830
elif type ( val ) == StringType :
832
narcisse.narsetai ("height_c_log", 1)
833
narcisse.narsetvals ( self._file_descr )
836
narcisse.narsetai ("height_c_log", 0)
837
narcisse.narsetvals ( self._file_descr )
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 )
854
raise self.NarError , "Wrong type of argument to set_c_contours."
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
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
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
882
raise self.NarError , val [0] + " is not a valid mask type."
883
narcisse.narsetvals ( self._file_descr )
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."""
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 )
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
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 )
915
narcisse.narsetar ( "height" , 90.0 - val [0] )
916
narcisse.narsetvals ( self._file_descr )
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
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 )
929
narcisse.narsetar ( "theta" , val [0] )
930
narcisse.narsetvals ( self._file_descr )
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)."""
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 )
943
narcisse.narsetar ( "roll" , val [0] )
944
narcisse.narsetvals ( self._file_descr )
946
def set_gnomon (self, val) :
947
"""set_gnomon (val) does nothing in Narcisse."""
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
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. )
962
narcisse.narsetar ( "distance" , val [0] )
963
narcisse.narsetvals ( self._file_descr )
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.
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 (.)."""
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))
1005
narcisse.narsetaii ( "curve_type" , val2 [i] , val1 [i] )
1006
narcisse.narsetvals ( self._file_descr )
1008
raise self.NarError, "bad arguments to curve_type."
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.
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."""
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))
1046
val2 [i] = self._figure_color (val2 [i])
1047
narcisse.narsetaii ( "curve_color" , val2 [i] , val1 [i] )
1048
narcisse.narsetvals ( self._file_descr )
1050
raise self.NarError , "bad parameters to set_curve_color."
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'."""
1058
if ( val == "end" ) :
1059
narcisse.narsetai ( "curve_label_type" , 0 )
1061
narcisse.narsetai ( "curve_label_type" , 1 )
1063
raise self.NarError ,\
1064
"set_label_type: 'end' and 'box' are the allowed options."
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)."""
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))
1087
narcisse.narsetaci ( "curve_label" , val2 [i] , val1 [i] )
1088
narcisse.narsetvals ( self._file_descr )
1090
print "Val1: " , `val1`
1091
print "Val2: " , `val2`
1092
raise self.NarError ,\
1093
"set_curve_label: arguments have inconsistent types or sizes."
1095
def set_xyequal (self) :
1096
"""set_xyequal () sets a parameter that makes the axes equal scale."""
1099
def reset_xyequal (self) :
1100
"""set_xyequal () resets a parameter that makes the axes equal scale."""
1103
narcisse_marks = { "+" : 2 , "*" : 3 , "o" : 4 , "x" : 5 , "." : 6 }
1104
narcisse_types = { "none" : -1 , "hide" : -1 , "line" : 0 ,
1105
"normal" : 0 , "step" : 1 }
1107
def _figure_type ( self , crv ) :
1108
"""_figure_type (crv) makes sure to return a valid type for a
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
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
1135
if type (crv.marker) == IntType and 2 <= crv.marker <= 6 :
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
1147
def plot_object ( self , crv ) :
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.
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
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]
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.
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."
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)
1219
def _send_2d_info ( self ) :
1220
"""_send_2d_info ( ) sends the accumulated curve information
1223
n = len (self._ylist)
1225
raise self.NarError, \
1226
"There is nothing to graph!"
1229
arg2t = self._types [0]
1230
arg2c = self._colors [0]
1231
arg2l = self._labels [0]
1233
arg1 = arange (n, dtype = Int)
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)
1254
def plot_text ( self ) :
1255
"plot_text does nothing in Narcisse."
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 )
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 )
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."""
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 )
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."""
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 )
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."""
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 )
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
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."""
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) )
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 )
1360
narcisse.nar3dtetra ( self._file_descr , x , y , z )
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 )
1372
narcisse.nar4dtetra ( self._file_descr , x , y , z , c )
1375
narcisse.narstructmesh ( self._file_descr , x , y , z , c )
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)
1384
narcisse.narnonstructmesh ( self._file_descr , x , y , z , c , cd , nc)
1388
raise self.NarError ,\
1389
"plot_surface: inappropriate number of arguments: " + `n`
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.
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 )
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 )
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."""
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] )
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 )
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."""
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 )
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."""
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 :
1464
self._send_axes_limits ( )
1465
if self._graph_type == 2 :
1466
self._send_2d_info ( )
1469
narcisse.narsetai ( "plot_now" , 1 )
1470
narcisse.narsetvals ( self._file_descr )
1471
if self._freeze_each :
1472
self.freeze_graph ( )
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
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.
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 )
1489
if is_scalar ( graf._text ) :
1490
if ( graf._text != "" and graf._text != " ") :
1491
self.set_text ( graf._text , 0 )
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 )
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 )
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 )
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 )
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 )
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
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
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])
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])
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
1584
sc = [sc] + ["lin", "lin", "lin", "lin"]
1586
for i in range (5 - no_of_dims (sc)) :
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])
1594
no_color = os.environ["NO_COLOR"]
1597
if no_color == 0 or no_color == "no" or no_color == "n" :
1598
self.set_color_card (graf._color_card , 1)
1600
self.set_phi ( graf._phi )
1601
self.set_theta ( graf._theta )
1602
self.set_roll ( graf._roll )
1605
def quick_plot (self, graf) :
1606
"quick_plot (graf) plots without recomputing."
1607
if graf.type () == Graph2dType :
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 )
1631
self.synchronize ( )
1632
self.send_graph (graf)
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.
1641
# (1) Do graph-generic stuff first
1642
self.do_generic (graf)
1643
# (2) Do the specifically 2d stuff
1644
sc = graf._axis_scales
1646
self.set_xyequal ( )
1648
self.reset_xyequal ( )
1650
if sc == "linlin" or sc == "lin" :
1652
elif sc == "linlog" :
1654
elif sc == "loglin" or sc == "log" :
1656
elif sc == "loglog" :
1660
sc = sc + ["lin", "lin"]
1661
elif len (sc) == 2 :
1663
for n in range (3) :
1664
if sc [n] == "log" :
1665
self.set_axis_log (graf._axes [n])
1667
self.set_axis_lin (graf._axes [n])
1668
for i in range ( graf._c_ln ) :
1670
self.plot_object ( graf._c [i] )
1672
self.add_object ( graf._c [i] )
1674
# Finally do the graph
1676
self.synchronize ( )
1677
self.send_graph (graf)
1679
def split_bytscl (self, val, top) :
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.
1685
retval = ( (val - min (val)).astype(Float) /
1686
max( (val - min (val)).astype(Float)*26. +
1687
0.5)).astype (Int) + top * 26
1690
def plot3d (self, graf) :
1691
"""plot3d (graf) plots a 3d graph object.
1694
# (1) Do graph-generic stuff first
1695
self.do_generic (graf)
1697
self.set_phi ( graf._phi )
1698
self.set_theta ( graf._theta )
1699
self.set_roll ( graf._roll )
1700
self.set_distance ( graf._distance )
1702
if n > 1 and graf._connect :
1703
self.set_connect ( 1)
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
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)
1726
self.set_z_contours (graf._s[0].number_of_z_contours)
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)
1733
self.set_c_contours (graf._s[0].number_of_c_contours)
1735
self.set_c_contours ( graf._s[0].c_contours_array )
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
1744
raise self.NarError, \
1745
"If one component is a Slice, all must be."
1746
for i in range (graf._s_ln) :
1749
if type (opt_3d) != ListType :
1756
if (max (abs (x)) < 10.e-30) :
1758
if (max (abs (y)) < 10.e-30) :
1760
if (max (abs (z)) < 10.e-30) :
1762
if not isosurfaces_present or s.iso is None and \
1764
if "i3" in opt_3d or "s3" in opt_3d or \
1765
"w3" in opt_3d or "f3" in opt_3d :
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))
1775
val = ones (sum (s.nv), Float) * s.iso
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 \
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))))
1789
val = concatenate ( (val, s.val))
1791
val = concatenate ( (val, ones (sum (s.nv), Float) * s.iso))
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)
1799
self.synchronize ( )
1801
self.send_graph (graf)
1803
# got to send out one surface and its characteristics at a time
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,
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 )
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)
1823
self.set_z_contours (graf._s[i].number_of_z_contours)
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)
1830
self.set_c_contours (graf._s[i].number_of_c_contours)
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)
1861
self.synchronize ( )
1862
self.send_graph (graf)
1866
else : # not graf._link
1867
# send out surface characteristics, then each surface
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)
1881
self.set_z_contours (graf._s[n - 1].number_of_z_contours)
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)
1888
self.set_c_contours (graf._s[n - 1].number_of_c_contours)
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
1897
self.plot_surface (array (graf._s[i].z, Float))
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
1903
self.plot_surface ( array ( graf._s[i].x, Float),
1904
array ( graf._s[i].y, Float),
1905
array ( graf._s[i].z, Float))
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 :
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))
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 ()
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 )
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 )
1941
self.synchronize ( )
1943
self.send_graph (graf)
1945
def move_light_source (self, graf, angle, nframes) :
1946
raise self.NarError, \
1947
"Sorry, Narcisse does not yet support a moving light source."
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)
1957
narcisse.narsetai ( "plot_now" , 1 )
1958
narcisse.narsetvals ( self._file_descr )
1959
if self._freeze_each :
1960
self.freeze_graph ( )