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

Last change on this file since 844 was 844, checked in by gah, 16 years ago

change HistoResult? to HistogramResult?

File size: 16.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
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::Histogram {
212            set mode "histogram"
213            if {![info exists _mode2widget($mode)]} {
214                set w $itk_interior.xy
215                Rappture::HistogramResult $w
216                set _mode2widget($mode) $w
217            }
218        }
219        ::Rappture::Curve {
220            set mode "xy"
221            if {![info exists _mode2widget($mode)]} {
222                set w $itk_interior.xy
223                Rappture::XyResult $w
224                set _mode2widget($mode) $w
225            }
226        }
227        ::Rappture::Field {
228            set dims [lindex [lsort [$dataobj components -dimensions]] end]
229            switch -- $dims {
230                1D {
231                    set mode "xy"
232                    if {![info exists _mode2widget($mode)]} {
233                        set w $itk_interior.xy
234                        Rappture::XyResult $w
235                        set _mode2widget($mode) $w
236                    }
237                }
238                2D {
239                    set mode "contour"
240                    if {![info exists _mode2widget($mode)]} {
241                        set mesh [$dataobj mesh]
242                        set fmt [expr {("" != $mesh) ? "vtk" : "heightmap"}]
243                        set w $itk_interior.contour
244                        Rappture::Field2DResult $w -mode $fmt
245                        set _mode2widget($mode) $w
246                    }
247                }
248                3D {
249                    set mode "field3D"
250                    if {![info exists _mode2widget($mode)]} {
251                        set mesh [$dataobj mesh]
252                        set fmt [expr {("" != $mesh) ? "vtk" : "nanovis"}]
253                        set w $itk_interior.field3D
254                        Rappture::Field3DResult $w -mode $fmt
255                        set _mode2widget($mode) $w
256                    }
257                }
258                default {
259                    error "can't handle [$dataobj components -dimensions] field"
260                }
261            }
262        }
263        ::Rappture::Mesh {
264            switch -- [$dataobj dimensions] {
265                2 {
266                    set mode "mesh"
267                    if {![info exists _mode2widget($mode)]} {
268                        set w $itk_interior.mesh
269                        Rappture::MeshResult $w
270                        set _mode2widget($mode) $w
271                    }
272                }
273                default {
274                    error "can't handle [$dataobj dimensions]D field"
275                }
276            }
277        }
278        ::Rappture::Table {
279            set cols [Rappture::EnergyLevels::columns $dataobj]
280            if {"" != $cols} {
281                set mode "energies"
282                if {![info exists _mode2widget($mode)]} {
283                    set w $itk_interior.energies
284                    Rappture::EnergyLevels $w
285                    set _mode2widget($mode) $w
286                }
287            }
288        }
289        ::Rappture::LibraryObj {
290            switch -- [$dataobj element -as type] {
291                string - log {
292                    set mode "log"
293                    if {![info exists _mode2widget($mode)]} {
294                        set w $itk_interior.log
295                        Rappture::TextResult $w
296                        set _mode2widget($mode) $w
297                    }
298                }
299                structure {
300                    set mode "structure"
301                    if {![info exists _mode2widget($mode)]} {
302                        set w $itk_interior.struct
303                        Rappture::DeviceResult $w
304                        set _mode2widget($mode) $w
305                    }
306                }
307                number - integer {
308                    set mode "number"
309                    if {![info exists _mode2widget($mode)]} {
310                        set w $itk_interior.number
311                        Rappture::NumberResult $w
312                        set _mode2widget($mode) $w
313                    }
314                }
315                boolean - choice {
316                    set mode "value"
317                    if {![info exists _mode2widget($mode)]} {
318                        set w $itk_interior.value
319                        Rappture::ValueResult $w
320                        set _mode2widget($mode) $w
321                    }
322                }
323            }
324        }
325        ::Rappture::Image {
326            set mode "image"
327            if {![info exists _mode2widget($mode)]} {
328                set w $itk_interior.image
329                Rappture::ImageResult $w
330                set _mode2widget($mode) $w
331            }
332        }
333        ::Rappture::Sequence {
334            set mode "sequence"
335            if {![info exists _mode2widget($mode)]} {
336                set w $itk_interior.image
337                Rappture::SequenceResult $w
338                set _mode2widget($mode) $w
339            }
340        }
341        default {
342            error "don't know how to plot <$type> data"
343        }
344    }
345
346    if {$mode != $_mode && $_mode != ""} {
347        set nactive [llength [$_mode2widget($_mode) get]]
348        if {$nactive > 0} {
349            return  ;# mixing data that doesn't mix -- ignore it!
350        }
351    }
352
353    # are we plotting in a new mode? then change widgets
354    if {$_mode2widget($mode) != [pack slaves $itk_interior]} {
355        # remove any current window
356        foreach w [pack slaves $itk_interior] {
357            pack forget $w
358        }
359        pack $_mode2widget($mode) -expand yes -fill both
360
361        set _mode $mode
362        $_dispatcher event -idle !scale
363    }
364    $_mode2widget($mode) add $dataobj $settings
365}
366
367# ----------------------------------------------------------------------
368# USAGE: _fixScale ?<eventArgs>...?
369#
370# Invoked automatically whenever a new dataset is added to fix the
371# overall scales of the viewer.  This makes the visualizer consistent
372# across all <dataobj> in this widget, so that it can plot all
373# available data.
374# ----------------------------------------------------------------------
375itcl::body Rappture::ResultViewer::_fixScale {args} {
376    if {"" != $_mode} {
377        set dlist ""
378        foreach slot $_dataslots {
379            foreach dobj $slot {
380                lappend dlist $dobj
381            }
382        }
383        eval $_mode2widget($_mode) scale $dlist
384    }
385}
386
387# ----------------------------------------------------------------------
388# USAGE: download coming
389# USAGE: download controls <downloadCommand>
390# USAGE: download now
391#
392# Clients use this method to create a downloadable representation
393# of the plot.  Returns a list of the form {ext string}, where
394# "ext" is the file extension (indicating the type of data) and
395# "string" is the data itself.
396# ----------------------------------------------------------------------
397itcl::body Rappture::ResultViewer::download {option args} {
398    if {"" == $_mode} {
399        return ""
400    }
401    return [eval $_mode2widget($_mode) download $option $args]
402}
403
404# ----------------------------------------------------------------------
405# USAGE: _xml2data <xmlobj> <path>
406#
407# Used internally to create a data object for the data at the
408# specified <path> in the <xmlobj>.
409# ----------------------------------------------------------------------
410itcl::body Rappture::ResultViewer::_xml2data {xmlobj path} {
411    set type [$xmlobj element -as type $path]
412    switch -- $type {
413        curve {
414            return [Rappture::Curve ::#auto $xmlobj $path]
415        }
416        histogram {
417            return [Rappture::Histogram ::#auto $xmlobj $path]
418        }
419        field {
420            return [Rappture::Field ::#auto $xmlobj $path]
421        }
422        mesh {
423            return [Rappture::Mesh ::#auto $xmlobj $path]
424        }
425        table {
426            return [Rappture::Table ::#auto $xmlobj $path]
427        }
428        image {
429            return [Rappture::Image ::#auto $xmlobj $path]
430        }
431        sequence {
432            return [Rappture::Sequence ::#auto $xmlobj $path]
433        }
434        string - log {
435            return [$xmlobj element -as object $path]
436        }
437        structure {
438            return [$xmlobj element -as object $path]
439        }
440        number - integer - boolean - choice {
441            return [$xmlobj element -as object $path]
442        }
443        time - status {
444            return ""
445        }
446    }
447    error "don't know how to plot <$type> data"
448}
449
450# ----------------------------------------------------------------------
451# CONFIGURATION OPTION: -width
452# ----------------------------------------------------------------------
453itcl::configbody Rappture::ResultViewer::width {
454    set w [winfo pixels $itk_component(hull) $itk_option(-width)]
455    set h [winfo pixels $itk_component(hull) $itk_option(-height)]
456    if {$w == 0 || $h == 0} {
457        pack propagate $itk_component(hull) yes
458    } else {
459        component hull configure -width $w -height $h
460        pack propagate $itk_component(hull) no
461    }
462}
463
464# ----------------------------------------------------------------------
465# CONFIGURATION OPTION: -height
466# ----------------------------------------------------------------------
467itcl::configbody Rappture::ResultViewer::height {
468    set h [winfo pixels $itk_component(hull) $itk_option(-height)]
469    set w [winfo pixels $itk_component(hull) $itk_option(-width)]
470    if {$w == 0 || $h == 0} {
471        pack propagate $itk_component(hull) yes
472    } else {
473        component hull configure -width $w -height $h
474        pack propagate $itk_component(hull) no
475    }
476}
Note: See TracBrowser for help on using the repository browser.