source: trunk/gui/scripts/resultviewer.tcl @ 2257

Last change on this file since 2257 was 2257, checked in by gah, 13 years ago

temporary: don't use

File size: 18.7 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: ResultViewer - plots a collection of related results
3#
4#  This widget plots a collection of results that all represent
5#  the same quantity, but for various ranges of input values.  It
6#  is normally used as part of an Analyzer, to plot the various
7#  results selected by a ResultSet.
8# ======================================================================
9#  AUTHOR:  Michael McLennan, Purdue University
10#  Copyright (c) 2004-2005  Purdue Research Foundation
11#
12#  See the file "license.terms" for information on usage and
13#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14# ======================================================================
15package require Itk
16
17itcl::class Rappture::ResultViewer {
18    inherit itk::Widget
19
20    itk_option define -width width Width 4i
21    itk_option define -height height Height 4i
22    itk_option define -colors colors Colors ""
23    itk_option define -clearcommand clearCommand ClearCommand ""
24    itk_option define -simulatecommand simulateCommand SimulateCommand ""
25
26    constructor {args} { # defined below }
27    destructor { # defined below }
28
29    public method add {index xmlobj path}
30    public method clear {{index ""}}
31    public method value {xmlobj}
32
33    public method plot {option args}
34    public method download {option args}
35
36    protected method _plotAdd {xmlobj {settings ""}}
37    protected method _fixScale {args}
38    protected proc _xml2data {xmlobj path}
39
40    private variable _dispatcher ""  ;# dispatchers for !events
41    private variable _mode ""        ;# current plotting mode (xy, etc.)
42    private variable _mode2widget    ;# maps plotting mode => widget
43    private variable _dataslots ""   ;# list of all data objects in this widget
44}
45
46itk::usual ResultViewer {
47    keep -background -foreground -cursor -font
48}
49
50# ----------------------------------------------------------------------
51# CONSTRUCTOR
52# ----------------------------------------------------------------------
53itcl::body Rappture::ResultViewer::constructor {args} {
54    # create a dispatcher for events
55    Rappture::dispatcher _dispatcher
56    $_dispatcher register !scale
57    $_dispatcher dispatch $this !scale \
58        [itcl::code $this _fixScale]
59
60    eval itk_initialize $args
61}
62
63# ----------------------------------------------------------------------
64# DESTRUCTOR
65# ----------------------------------------------------------------------
66itcl::body Rappture::ResultViewer::destructor {} {
67    foreach slot $_dataslots {
68        foreach obj $slot {
69            itcl::delete object $obj
70        }
71    }
72}
73
74# ----------------------------------------------------------------------
75# USAGE: add <index> <xmlobj> <path>
76#
77# Adds a new result to this result viewer at the specified <index>.
78# Data is taken from the <xmlobj> object at the <path>.
79# ----------------------------------------------------------------------
80itcl::body Rappture::ResultViewer::add {index xmlobj path} {
81    set dobj [_xml2data $xmlobj $path]
82
83    #
84    # If the index doesn't exist, then fill in empty slots and
85    # make it exist.
86    #
87    for {set i [llength $_dataslots]} {$i <= $index} {incr i} {
88        lappend _dataslots ""
89    }
90    set slot [lindex $_dataslots $index]
91    lappend slot $dobj
92    set _dataslots [lreplace $_dataslots $index $index $slot]
93
94    $_dispatcher event -idle !scale
95}
96
97# ----------------------------------------------------------------------
98# USAGE: clear ?<index>?
99#
100# Clears one or all results in this result viewer.
101# ----------------------------------------------------------------------
102itcl::body Rappture::ResultViewer::clear {{index ""}} {
103    if {"" != $index} {
104        # clear one result
105        if {$index >= 0 && $index < [llength $_dataslots]} {
106            set slot [lindex $_dataslots $index]
107            foreach dobj $slot {
108                itcl::delete object $dobj
109            }
110            set _dataslots [lreplace $_dataslots $index $index ""]
111        }
112    } else {
113        # clear all results
114        plot clear
115        foreach slot $_dataslots {
116            foreach dobj $slot {
117                itcl::delete object $dobj
118            }
119        }
120        set _dataslots ""
121    }
122}
123
124# ----------------------------------------------------------------------
125# USAGE: value <xmlobj>
126#
127# Convenience method for showing a single value.  Loads the value
128# into the widget via add/clear, then immediately plots the value.
129# This makes the widget consistent with other widgets, such as
130# the DeviceEditor, etc.
131# ----------------------------------------------------------------------
132itcl::body Rappture::ResultViewer::value {xmlobj} {
133    clear
134    if {"" != $xmlobj} {
135        add 0 $xmlobj ""
136        plot add 0 ""
137    }
138}
139
140# ----------------------------------------------------------------------
141# USAGE: plot add ?<index> <settings> <index> <settings> ...?
142# USAGE: plot clear
143#
144# Used to manipulate the contents of this viewer.  The "plot clear"
145# command clears the current viewer.  Data is still stored in the
146# widget, but the results are not shown on screen.  The "plot add"
147# command adds the data at the specified <index> to the plot.  If
148# the optional <settings> are specified, then they are applied
149# to the plot; otherwise, default settings are used.
150# ----------------------------------------------------------------------
151itcl::body Rappture::ResultViewer::plot {option args} {
152    switch -- $option {
153        add {
154            set params ""
155            foreach {index opts} $args {
156                if {$index == "params"} {
157                    set params $opts
158                    continue
159                }
160                set reset "-color autoreset"
161                set slot [lindex $_dataslots $index]
162                foreach dobj $slot {
163                    set settings ""
164                    # start with color reset, only for first object in series
165                    if {"" != $reset} {
166                        set settings $reset
167                        set reset ""
168                    }
169                    # add default settings from data object
170                    if {[catch {$dobj hints style} style] == 0} {
171                        eval lappend settings $style
172                    }
173                    if {[catch {$dobj hints type} type] == 0} {
174                        if {"" != $type} {
175                            eval lappend settings "-type $type"
176                        }
177                    }
178                    # add override settings passed in here
179                    eval lappend settings $opts
180                    _plotAdd $dobj $settings
181                }
182            }
183            if {"" != $params && "" != $_mode} {
184                eval $_mode2widget($_mode) parameters $params
185            }
186        }
187        clear {
188            # clear the contents of the current mode
189            if {"" != $_mode} {
190                $_mode2widget($_mode) delete
191            }
192        }
193        default {
194            error "bad option \"$option\": should be add or clear"
195        }
196    }
197}
198
199# ----------------------------------------------------------------------
200# USAGE: _plotAdd <dataobj> <settings>
201#
202# Used internally to add a <dataobj> representing some data to
203# the plot at the top of this widget.  The data is added to the
204# current plot.  Use the "clear" function to clear before adding
205# new data.
206# ----------------------------------------------------------------------
207itcl::body Rappture::ResultViewer::_plotAdd {dataobj {settings ""}} {
208    switch -- [$dataobj info class] {
209        ::Rappture::DataTable {
210            set mode "datatable"
211            if {![info exists _mode2widget($mode)]} {
212                set w $itk_interior.datatable
213                Rappture::DataTableResult $w
214                set _mode2widget($mode) $w
215            }
216        }
217        ::Rappture::Drawing1 {
218            set mode "vtkviewer"
219            if {![info exists _mode2widget($mode)]} {
220                set w $itk_interior.vtkviewer1
221                Rappture::VtkViewer $w
222                set _mode2widget($mode) $w
223            }
224        }
225        ::Rappture::Drawing2 {
226            set mode "vtkviewer2"
227            if {![info exists _mode2widget($mode)]} {
228                set servers [Rappture::VisViewer::GetServerList "vtkvis"]
229                set w $itk_interior.vtkviewer2
230                catch { Rappture::VtkViewer2 $w $servers } errs
231                puts stderr errs=$errs
232                set _mode2widget($mode) $w
233            }
234        }
235        ::Rappture::Histogram {
236            set mode "histogram"
237            if {![info exists _mode2widget($mode)]} {
238                set w $itk_interior.histogram
239                Rappture::HistogramResult $w
240                set _mode2widget($mode) $w
241            }
242        }
243        ::Rappture::Curve {
244            set type [$dataobj hints type]
245            set mode "xy"
246            if { $type == "bars" } {
247                if {![info exists _mode2widget($mode)]} {
248                    set w $itk_interior.xy
249                    Rappture::BarResult $w
250                    set _mode2widget($mode) $w
251                }
252            } else {
253                if {![info exists _mode2widget($mode)]} {
254                    set w $itk_interior.xy
255                    Rappture::XyResult $w
256                    set _mode2widget($mode) $w
257                }
258            }
259        }
260        ::Rappture::Field {
261            set dims [lindex [lsort [$dataobj components -dimensions]] end]
262            switch -- $dims {
263                1D {
264                    set mode "xy"
265                    if {![info exists _mode2widget($mode)]} {
266                        set w $itk_interior.xy
267                        Rappture::XyResult $w
268                        set _mode2widget($mode) $w
269                    }
270                }
271                2D {
272                    set mode "contour"
273                    if {![info exists _mode2widget($mode)]} {
274                        if { [$dataobj isunirect2d] } {
275                            if { [$dataobj hints type] == "contour" } {
276                                set resultMode "vtkcontour"
277                            } else {
278                                set resultMode "heightmap"
279                            }
280                        } else {
281                            set resultMode "vtk"
282                        }
283                        set extents [$dataobj extents]
284                        if { $extents > 1 } {
285                            set resultMode "flowvis"
286                        }
287                        set w $itk_interior.contour
288                        if { ![winfo exists $w] } {
289                            Rappture::Field2DResult $w -mode $resultMode
290                        }
291                        set _mode2widget($mode) $w
292                    }
293                }
294                3D {
295                    set mode "field3D"
296                    if {![info exists _mode2widget($mode)]} {
297                        set mesh [$dataobj mesh]
298                        set fmt [expr {("" != $mesh) ? "vtk" : "nanovis"}]
299                        set extents [$dataobj extents]
300                        if { $extents > 1 } {
301                            set fmt "flowvis"
302                        }
303                        set w $itk_interior.field3D
304                        Rappture::Field3DResult $w -mode $fmt
305                        set _mode2widget($mode) $w
306                    }
307                }
308                default {
309                    error "can't handle \"$dims\" dimension field"
310                }
311            }
312        }
313        ::Rappture::Mesh {
314            switch -- [$dataobj dimensions] {
315                2 {
316                    set mode "mesh"
317                    if {![info exists _mode2widget($mode)]} {
318                        set w $itk_interior.mesh
319                        Rappture::MeshResult $w
320                        set _mode2widget($mode) $w
321                    }
322                }
323                default {
324                    error "can't handle [$dataobj dimensions]D field"
325                }
326            }
327        }
328        ::Rappture::Table {
329            set cols [Rappture::EnergyLevels::columns $dataobj]
330            if {"" != $cols} {
331                set mode "energies"
332                if {![info exists _mode2widget($mode)]} {
333                    set w $itk_interior.energies
334                    Rappture::EnergyLevels $w
335                    set _mode2widget($mode) $w
336                }
337            }
338        }
339        ::Rappture::LibraryObj {
340            switch -- [$dataobj element -as type] {
341                string - log {
342                    set mode "log"
343                    if {![info exists _mode2widget($mode)]} {
344                        set w $itk_interior.log
345                        Rappture::TextResult $w
346                        set _mode2widget($mode) $w
347                    }
348                }
349                structure {
350                    set mode "structure"
351                    if {![info exists _mode2widget($mode)]} {
352                        set w $itk_interior.struct
353                        Rappture::DeviceResult $w
354                        set _mode2widget($mode) $w
355                    }
356                }
357                number - integer {
358                    set mode "number"
359                    if {![info exists _mode2widget($mode)]} {
360                        set w $itk_interior.number
361                        Rappture::NumberResult $w
362                        set _mode2widget($mode) $w
363                    }
364                }
365                boolean - choice {
366                    set mode "value"
367                    if {![info exists _mode2widget($mode)]} {
368                        set w $itk_interior.value
369                        Rappture::ValueResult $w
370                        set _mode2widget($mode) $w
371                    }
372                }
373            }
374        }
375        ::Rappture::Image {
376            set mode "image"
377            if {![info exists _mode2widget($mode)]} {
378                set w $itk_interior.image
379                Rappture::ImageResult $w
380                set _mode2widget($mode) $w
381            }
382        }
383        ::Rappture::Sequence {
384            set mode "sequence"
385            if {![info exists _mode2widget($mode)]} {
386                set w $itk_interior.image
387                Rappture::SequenceResult $w
388                set _mode2widget($mode) $w
389            }
390        }
391        default {
392            error "don't know how to plot <$type> data"
393        }
394    }
395
396    if {$mode != $_mode && $_mode != ""} {
397        set nactive [llength [$_mode2widget($_mode) get]]
398        if {$nactive > 0} {
399            return  ;# mixing data that doesn't mix -- ignore it!
400        }
401    }
402
403    # Are we plotting in a new mode? then change widgets
404    if {$_mode2widget($mode) != [pack slaves $itk_interior]} {
405        # remove any current window
406        foreach w [pack slaves $itk_interior] {
407            pack forget $w
408        }
409        pack $_mode2widget($mode) -expand yes -fill both
410
411        set _mode $mode
412        $_dispatcher event -idle !scale
413    }
414    $_mode2widget($mode) add $dataobj $settings
415}
416
417# ----------------------------------------------------------------------
418# USAGE: _fixScale ?<eventArgs>...?
419#
420# Invoked automatically whenever a new dataset is added to fix the
421# overall scales of the viewer.  This makes the visualizer consistent
422# across all <dataobj> in this widget, so that it can plot all
423# available data.
424# ----------------------------------------------------------------------
425itcl::body Rappture::ResultViewer::_fixScale {args} {
426    if {"" != $_mode} {
427        set dlist ""
428        foreach slot $_dataslots {
429            foreach dobj $slot {
430                lappend dlist $dobj
431            }
432        }
433        eval $_mode2widget($_mode) scale $dlist
434    }
435}
436
437# ----------------------------------------------------------------------
438# USAGE: download coming
439# USAGE: download controls <downloadCommand>
440# USAGE: download now
441#
442# Clients use this method to create a downloadable representation
443# of the plot.  Returns a list of the form {ext string}, where
444# "ext" is the file extension (indicating the type of data) and
445# "string" is the data itself.
446# ----------------------------------------------------------------------
447itcl::body Rappture::ResultViewer::download {option args} {
448    if {"" == $_mode} {
449        return ""
450    }
451    return [eval $_mode2widget($_mode) download $option $args]
452}
453
454# ----------------------------------------------------------------------
455# USAGE: _xml2data <xmlobj> <path>
456#
457# Used internally to create a data object for the data at the
458# specified <path> in the <xmlobj>.
459# ----------------------------------------------------------------------
460itcl::body Rappture::ResultViewer::_xml2data {xmlobj path} {
461    set type [$xmlobj element -as type $path]
462    switch -- $type {
463        curve {
464            return [Rappture::Curve ::#auto $xmlobj $path]
465        }
466        datatable {
467            return [Rappture::DataTable ::#auto $xmlobj $path]
468        }
469        histogram {
470            return [Rappture::Histogram ::#auto $xmlobj $path]
471        }
472        field {
473            return [Rappture::Field ::#auto $xmlobj $path]
474        }
475        mesh {
476            return [Rappture::Mesh ::#auto $xmlobj $path]
477        }
478        table {
479            return [Rappture::Table ::#auto $xmlobj $path]
480        }
481        image {
482            return [Rappture::Image ::#auto $xmlobj $path]
483        }
484        sequence {
485            return [Rappture::Sequence ::#auto $xmlobj $path]
486        }
487        string - log {
488            return [$xmlobj element -as object $path]
489        }
490        structure {
491            return [$xmlobj element -as object $path]
492        }
493        number - integer - boolean - choice {
494            return [$xmlobj element -as object $path]
495        }
496        drawing1 {
497            return [Rappture::Drawing1 ::#auto $xmlobj $path]
498        }
499        drawing2 {
500            return [Rappture::Drawing2 ::#auto $xmlobj $path]
501        }
502        time - status {
503            return ""
504        }
505    }
506    error "don't know how to plot <$type> data"
507}
508
509# ----------------------------------------------------------------------
510# CONFIGURATION OPTION: -width
511# ----------------------------------------------------------------------
512itcl::configbody Rappture::ResultViewer::width {
513    set w [winfo pixels $itk_component(hull) $itk_option(-width)]
514    set h [winfo pixels $itk_component(hull) $itk_option(-height)]
515    if {$w == 0 || $h == 0} {
516        pack propagate $itk_component(hull) yes
517    } else {
518        component hull configure -width $w -height $h
519        pack propagate $itk_component(hull) no
520    }
521}
522
523# ----------------------------------------------------------------------
524# CONFIGURATION OPTION: -height
525# ----------------------------------------------------------------------
526itcl::configbody Rappture::ResultViewer::height {
527    set h [winfo pixels $itk_component(hull) $itk_option(-height)]
528    set w [winfo pixels $itk_component(hull) $itk_option(-width)]
529    if {$w == 0 || $h == 0} {
530        pack propagate $itk_component(hull) yes
531    } else {
532        component hull configure -width $w -height $h
533        pack propagate $itk_component(hull) no
534    }
535}
Note: See TracBrowser for help on using the repository browser.