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

Last change on this file since 738 was 736, checked in by dkearney, 17 years ago

adding capabilities for xy scatter plots by adding curve.about.type = scatter to your run.xml file

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