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

Last change on this file since 766 was 766, checked in by mmc, 14 years ago

Fixed the output viewer for numbers/integers to show a plot of
the value versus input parameters. As you change the ResultSet?
control, the x-axis updates to show the number versus values
in the result set.

Fixed the Rappture::result command to include the user's login
in the metadata, so we know who performed the computation.

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