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

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