source: trunk/gui/scripts/meshresult.tcl @ 111

Last change on this file since 111 was 64, checked in by mmc, 19 years ago

Lots of fixes for app-pntoy and other tools:

  • Fixed plotting to recognize "-color name" in the style section, and to use auto colors for overlayed plots.
  • Fixed x-y plotting to keep axes instead of resetting when flipping back and forth between plots.
  • Fixed 1D fields to support new lin/log limits queries, so it plots properly.
  • Added support for <string> output values.
  • Fixed molecular viewer so that 3D rotation is unconstrained and more intuitive.
  • Fixed Rappture::exec to handle newlines properly. Sometimes output would get all mixed together without newlines. Works better now.
File size: 16.6 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: meshresult - mesh plot in a ResultSet
3#
4#  This widget is a mesh plot, meant to view grid structures produced
5#  as output from the run of a Rappture tool.  Use the "add" and
6#  "delete" methods to control the meshes showing on the plot.
7# ======================================================================
8#  AUTHOR:  Michael McLennan, Purdue University
9#  Copyright (c) 2004-2005
10#  Purdue Research Foundation, West Lafayette, IN
11# ======================================================================
12package require Itk
13package require BLT
14
15option add *MeshResult.width 4i widgetDefault
16option add *MeshResult.height 4i widgetDefault
17option add *MeshResult.gridColor #d9d9d9 widgetDefault
18option add *MeshResult.regionColors {green yellow orange red magenta} widgetDefault
19option add *MeshResult.controlBackground gray widgetDefault
20option add *MeshResult.font \
21    -*-helvetica-medium-r-normal-*-*-120-* widgetDefault
22
23blt::bitmap define MeshResult-reset {
24#define reset_width 12
25#define reset_height 12
26static unsigned char reset_bits[] = {
27   0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02,
28   0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00};
29}
30
31itcl::class Rappture::MeshResult {
32    inherit itk::Widget
33
34    itk_option define -gridcolor gridColor GridColor ""
35    itk_option define -regioncolors regionColors RegionColors ""
36
37    constructor {args} { # defined below }
38    destructor { # defined below }
39
40    public method add {dataobj {settings ""}}
41    public method get {}
42    public method delete {args}
43    public method scale {args}
44    public method download {}
45
46    protected method _rebuild {}
47    protected method _fixLimits {}
48    protected method _zoom {option args}
49    protected method _hilite {state x y}
50
51    private variable _dlist ""     ;# list of dataobj objects
52    private variable _dobj2color   ;# maps dataobj => plotting color
53    private variable _dobj2width   ;# maps dataobj => line width
54    private variable _dobj2dashes  ;# maps dataobj => BLT -dashes list
55    private variable _dobj2raise   ;# maps dataobj => raise flag 0/1
56    private variable _mrkr2tip     ;# maps graph element => tooltip
57    private variable _xmin ""      ;# autoscale min for x-axis
58    private variable _xmax ""      ;# autoscale max for x-axis
59    private variable _ymin ""      ;# autoscale min for y-axis
60    private variable _ymax ""      ;# autoscale max for y-axis
61}
62                                                                               
63itk::usual MeshResult {
64    keep -background -foreground -cursor -font
65}
66
67# ----------------------------------------------------------------------
68# CONSTRUCTOR
69# ----------------------------------------------------------------------
70itcl::body Rappture::MeshResult::constructor {args} {
71    option add hull.width hull.height
72    pack propagate $itk_component(hull) no
73
74    itk_component add controls {
75        frame $itk_interior.cntls
76    } {
77        usual
78        rename -background -controlbackground controlBackground Background
79    }
80    pack $itk_component(controls) -side right -fill y
81
82    itk_component add reset {
83        button $itk_component(controls).reset \
84            -borderwidth 1 -padx 1 -pady 1 \
85            -bitmap MeshResult-reset \
86            -command [itcl::code $this _zoom reset]
87    } {
88        usual
89        ignore -borderwidth
90        rename -highlightbackground -controlbackground controlBackground Background
91    }
92    pack $itk_component(reset) -padx 4 -pady 4
93    Rappture::Tooltip::for $itk_component(reset) "Reset the view to the default zoom level"
94
95    itk_component add plot {
96        blt::graph $itk_interior.plot \
97            -highlightthickness 0 -plotpadx 0 -plotpady 0 \
98            -rightmargin 10 -invertxy 1
99    } {
100        keep -background -foreground -cursor -font
101    }
102    pack $itk_component(plot) -expand yes -fill both
103
104    # special pen for highlighting active traces
105    $itk_component(plot) marker bind all <Enter> \
106        [itcl::code $this _hilite on %x %y]
107    $itk_component(plot) marker bind all <Leave> \
108        [itcl::code $this _hilite off %x %y]
109
110    bind $itk_component(plot) <Leave> \
111        [list Rappture::Tooltip::tooltip cancel]
112
113    Blt_ZoomStack $itk_component(plot)
114    $itk_component(plot) legend configure -hide yes
115
116    eval itk_initialize $args
117}
118
119# ----------------------------------------------------------------------
120# DESTRUCTOR
121# ----------------------------------------------------------------------
122itcl::body Rappture::MeshResult::destructor {} {
123}
124
125# ----------------------------------------------------------------------
126# USAGE: add <dataobj> ?<settings>?
127#
128# Clients use this to add a dataobj to the plot.  The optional <settings>
129# are used to configure the plot.  Allowed settings are -color,
130# -brightness, -width, -linestyle and -raise.
131# ----------------------------------------------------------------------
132itcl::body Rappture::MeshResult::add {dataobj {settings ""}} {
133    array set params {
134        -color auto
135        -brightness 0
136        -width 1
137        -raise 0
138        -linestyle solid
139    }
140    foreach {opt val} $settings {
141        if {![info exists params($opt)]} {
142            error "bad setting \"$opt\": should be [join [lsort [array names params]] {, }]"
143        }
144        set params($opt) $val
145    }
146    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
147        # can't handle -autocolors yet
148        set params(-color) black
149    }
150
151    # convert -linestyle to BLT -dashes
152    switch -- $params(-linestyle) {
153        dashed { set params(-linestyle) {4 4} }
154        dotted { set params(-linestyle) {2 4} }
155        default { set params(-linestyle) {} }
156    }
157
158    # if -brightness is set, then update the color
159    if {$params(-brightness) != 0} {
160        set params(-color) [Rappture::color::brightness \
161            $params(-color) $params(-brightness)]
162    }
163
164    set pos [lsearch -exact $dataobj $_dlist]
165    if {$pos < 0} {
166        lappend _dlist $dataobj
167        set _dobj2color($dataobj) $params(-color)
168        set _dobj2width($dataobj) $params(-width)
169        set _dobj2dashes($dataobj) $params(-linestyle)
170        #set _dobj2raise($dataobj) $params(-raise)
171        set _dobj2raise($dataobj) 0
172
173        after cancel [itcl::code $this _rebuild]
174        after idle [itcl::code $this _rebuild]
175    }
176}
177
178# ----------------------------------------------------------------------
179# USAGE: get
180#
181# Clients use this to query the list of objects being plotted, in
182# order from bottom to top of this result.
183# ----------------------------------------------------------------------
184itcl::body Rappture::MeshResult::get {} {
185    # put the dataobj list in order according to -raise options
186    set dlist $_dlist
187    foreach obj $dlist {
188        if {[info exists _dobj2raise($obj)] && $_dobj2raise($obj)} {
189            set i [lsearch -exact $dlist $obj]
190            if {$i >= 0} {
191                set dlist [lreplace $dlist $i $i]
192                lappend dlist $obj
193            }
194        }
195    }
196    return $dlist
197}
198
199# ----------------------------------------------------------------------
200# USAGE: delete ?<dataobj> <dataobj> ...?
201#
202# Clients use this to delete a dataobj from the plot.  If no dataobjs
203# are specified, then all dataobjs are deleted.
204# ----------------------------------------------------------------------
205itcl::body Rappture::MeshResult::delete {args} {
206    if {[llength $args] == 0} {
207        set args $_dlist
208    }
209
210    # delete all specified dataobjs
211    set changed 0
212    foreach dataobj $args {
213        set pos [lsearch -exact $_dlist $dataobj]
214        if {$pos >= 0} {
215            set _dlist [lreplace $_dlist $pos $pos]
216            catch {unset _dobj2color($dataobj)}
217            catch {unset _dobj2width($dataobj)}
218            catch {unset _dobj2dashes($dataobj)}
219            catch {unset _dobj2raise($dataobj)}
220            set changed 1
221        }
222    }
223
224    # if anything changed, then rebuild the plot
225    if {$changed} {
226        after cancel [itcl::code $this _rebuild]
227        after idle [itcl::code $this _rebuild]
228    }
229}
230
231# ----------------------------------------------------------------------
232# USAGE: scale ?<dataobj1> <dataobj2> ...?
233#
234# Sets the default limits for the overall plot according to the
235# limits of the data for all of the given <dataobj> objects.  This
236# accounts for all dataobjs--even those not showing on the screen.
237# Because of this, the limits are appropriate for all dataobjs as
238# the user scans through data in the ResultSet viewer.
239# ----------------------------------------------------------------------
240itcl::body Rappture::MeshResult::scale {args} {
241    set _xmin ""
242    set _xmax ""
243    set _ymin ""
244    set _ymax ""
245    foreach obj $args {
246        foreach axis {x y} {
247            foreach {min max} [$obj limits $axis] break
248            if {"" != $min && "" != $max} {
249                if {"" == [set _${axis}min]} {
250                    set _${axis}min $min
251                    set _${axis}max $max
252                } else {
253                    if {$min < [set _${axis}min]} {
254                        set _${axis}min $min
255                    }
256                    if {$max > [set _${axis}max]} {
257                        set _${axis}max $max
258                    }
259                }
260            }
261        }
262    }
263    _fixLimits
264}
265
266# ----------------------------------------------------------------------
267# USAGE: download
268#
269# Clients use this method to create a downloadable representation
270# of the plot.  Returns a list of the form {ext string}, where
271# "ext" is the file extension (indicating the type of data) and
272# "string" is the data itself.
273# ----------------------------------------------------------------------
274itcl::body Rappture::MeshResult::download {} {
275    set psdata [$itk_component(plot) postscript output -maxpect 1]
276
277    set cmds {
278        set fout "mesh[pid].pdf"
279        exec ps2pdf - $fout << $psdata
280
281        set fid [open $fout r]
282        fconfigure $fid -translation binary -encoding binary
283        set pdfdata [read $fid]
284        close $fid
285
286        file delete -force $fout
287    }
288    if {[catch $cmds result] == 0} {
289        return [list .pdf $pdfdata]
290    }
291    return [list .ps $psdata]
292}
293
294# ----------------------------------------------------------------------
295# USAGE: _rebuild
296#
297# Called automatically whenever something changes that affects the
298# data in the widget.  Clears any existing data and rebuilds the
299# widget to display new data.
300# ----------------------------------------------------------------------
301itcl::body Rappture::MeshResult::_rebuild {} {
302    set g $itk_component(plot)
303    blt::busy hold [winfo toplevel $g]; update
304
305    # first clear out the widget
306    eval $g marker delete [$g marker names]
307    $g axis configure x -min "" -max "" -loose yes -descending yes
308    $g axis configure y -min "" -max "" -loose yes
309
310    # extract axis information from the first dataobj
311    set dlist [get]
312    set xydata [lindex $dlist 0]
313    if {$xydata != ""} {
314        set legend [$xydata hints legend]
315        if {"" != $legend} {
316            if {$legend == "off"} {
317                $g legend configure -hide yes
318            } else {
319                $g legend configure -hide no \
320                    -position plotarea -anchor $legend -borderwidth 0
321            }
322        }
323
324        set xlabel [$xydata hints xlabel]
325        if {"" != $xlabel} {
326            $g xaxis configure -title $xlabel
327        }
328
329        set ylabel [$xydata hints ylabel]
330        if {"" != $ylabel} {
331            $g yaxis configure -title $ylabel
332        }
333    }
334
335    set multiple [expr {[llength $dlist] > 1}]
336    catch {unset _mrkr2tip}
337
338    # plot all of the dataobjs
339    set count 0
340    foreach xydata $dlist {
341        if {$multiple} {
342            if {[info exists _dobj2color($xydata)]} {
343                set color $_dobj2color($xydata)
344            } else {
345                set color [$xydata hints color]
346                if {"" == $color} {
347                    set color black
348                }
349            }
350
351            if {[info exists _dobj2width($xydata)]} {
352                set lwidth $_dobj2width($xydata)
353            } else {
354                set lwidth 2
355            }
356        } else {
357            set color black
358            set lwidth 1
359        }
360
361        if {[info exists _dobj2dashes($xydata)]} {
362            set dashes $_dobj2dashes($xydata)
363        } else {
364            set dashes ""
365        }
366
367        foreach {plist r} [$xydata elements] {
368            if {$count == 0} {
369                if {$r == "unknown"} {
370                    set fill gray
371                } elseif {![info exists colors($r)]} {
372                    set i [array size colors]
373                    set fill [lindex $itk_option(-regioncolors) $i]
374                    set colors($r) $fill
375                } else {
376                    set fill $colors($r)
377                }
378                set mrkr [$g marker create polygon -coords $plist -fill $fill]
379                set _mrkr2tip($mrkr) $r
380            }
381            set mrkr [$g marker create line -coords $plist \
382                -linewidth $lwidth -outline $color -dashes $dashes]
383            set _mrkr2tip($mrkr) $r
384        }
385        incr count
386    }
387
388    _fixLimits
389    blt::busy release [winfo toplevel $g]
390}
391
392# ----------------------------------------------------------------------
393# USAGE: _fixLimits
394#
395# Used internally to apply automatic limits to the axes for the
396# current plot.
397# ----------------------------------------------------------------------
398itcl::body Rappture::MeshResult::_fixLimits {} {
399    set g $itk_component(plot)
400
401    #
402    # HACK ALERT!
403    # Use this code to fix up the y-axis limits for the BLT graph.
404    # The auto-limits don't always work well.  We want them to be
405    # set to a "nice" number slightly above or below the min/max
406    # limits.
407    #
408    if {$_xmin != $_xmax} {
409        $g axis configure x -min $_xmin -max $_xmax
410    } else {
411        $g axis configure x -min "" -max ""
412    }
413
414    if {"" != $_ymin && "" != $_ymax} {
415        set min $_ymin
416        set max $_ymax
417        set log [$g axis cget y -logscale]
418        if {$log} {
419            if {$min == $max} {
420                set min [expr {0.9*$min}]
421                set max [expr {1.1*$max}]
422            }
423            set min [expr {pow(10.0,floor(log10($min)))}]
424            set max [expr {pow(10.0,ceil(log10($max)))}]
425        } else {
426            if {$min > 0} {
427                set min [expr {0.95*$min}]
428            } else {
429                set min [expr {1.05*$min}]
430            }
431            if {$max > 0} {
432                set max [expr {1.05*$max}]
433            } else {
434                set max [expr {0.95*$max}]
435            }
436        }
437        if {$min != $max} {
438            $g axis configure y -min $min -max $max
439        } else {
440            $g axis configure y -min "" -max ""
441        }
442    } else {
443        $g axis configure y -min "" -max ""
444    }
445}
446
447# ----------------------------------------------------------------------
448# USAGE: _zoom reset
449#
450# Called automatically when the user clicks on one of the zoom
451# controls for this widget.  Changes the zoom for the current view.
452# ----------------------------------------------------------------------
453itcl::body Rappture::MeshResult::_zoom {option args} {
454    switch -- $option {
455        reset {
456            _fixLimits
457        }
458    }
459}
460
461# ----------------------------------------------------------------------
462# USAGE: _hilite <state> <x> <y>
463#
464# Called automatically when the user brushes one of the elements
465# on the plot.  Causes the element to highlight and a tooltip to
466# pop up with element info.
467# ----------------------------------------------------------------------
468itcl::body Rappture::MeshResult::_hilite {state x y} {
469    set mrkr [$itk_component(plot) marker get current]
470    if {$state} {
471        #
472        # Highlight ON:
473        # - pop up tooltip about data
474        #
475        set tip ""
476        if {[info exists _mrkr2tip($mrkr)]} {
477            set tip $_mrkr2tip($mrkr)
478        }
479        if {"" != $tip} {
480            set x [expr {$x+4}]  ;# move the tooltip over a bit
481            set y [expr {$y+4}]
482            Rappture::Tooltip::text $itk_component(plot) $tip
483            Rappture::Tooltip::tooltip show $itk_component(plot) +$x,$y
484        }
485    } else {
486        #
487        # Highlight OFF:
488        # - take down tooltip
489        #
490        Rappture::Tooltip::tooltip cancel
491    }
492}
493
494# ----------------------------------------------------------------------
495# CONFIGURATION OPTION: -gridcolor
496# ----------------------------------------------------------------------
497itcl::configbody Rappture::MeshResult::gridcolor {
498    if {"" == $itk_option(-gridcolor)} {
499        $itk_component(plot) grid off
500    } else {
501        $itk_component(plot) grid configure -color $itk_option(-gridcolor)
502        $itk_component(plot) grid on
503    }
504}
Note: See TracBrowser for help on using the repository browser.