source: trunk/gui/scripts/curve.tcl @ 57

Last change on this file since 57 was 57, checked in by mmc, 19 years ago
  • Fixed x/y graphs to support multiple axes.
  • Added Rappture::result proc for reporting results.
  • Fixed up app-fermi example to be a little cleaner.
File size: 9.2 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: curve - extracts data from an XML description of a field
3#
4#  This object represents a curve of data in an XML description of
5#  simulator output.  A curve is similar to a field, but a field is
6#  a quantity versus position in device.  A curve is any quantity
7#  versus any other quantity.  This class simplifies the process of
8#  extracting data vectors that represent the curve.
9# ======================================================================
10#  AUTHOR:  Michael McLennan, Purdue University
11#  Copyright (c) 2004-2005
12#  Purdue Research Foundation, West Lafayette, IN
13# ======================================================================
14package require Itcl
15package require BLT
16
17namespace eval Rappture { # forward declaration }
18
19itcl::class Rappture::Curve {
20    constructor {xmlobj path} { # defined below }
21    destructor { # defined below }
22
23    public method components {{pattern *}}
24    public method mesh {{what -overall}}
25    public method values {{what -overall}}
26    public method limits {which}
27    public method hints {{key ""}}
28
29    protected method _build {}
30
31    private variable _xmlobj ""  ;# ref to lib obj with curve data
32    private variable _curve ""   ;# lib obj representing this curve
33    private variable _comp2xy    ;# maps component name => x,y vectors
34    private variable _hints      ;# cache of hints stored in XML
35
36    private common _counter 0    ;# counter for unique vector names
37}
38
39# ----------------------------------------------------------------------
40# CONSTRUCTOR
41# ----------------------------------------------------------------------
42itcl::body Rappture::Curve::constructor {xmlobj path} {
43    if {![Rappture::library isvalid $xmlobj]} {
44        error "bad value \"$xmlobj\": should be LibraryObj"
45    }
46    set _xmlobj $xmlobj
47    set _curve [$xmlobj element -as object $path]
48
49    # build up vectors for various components of the curve
50    _build
51}
52
53# ----------------------------------------------------------------------
54# DESTRUCTOR
55# ----------------------------------------------------------------------
56itcl::body Rappture::Curve::destructor {} {
57    itcl::delete object $_curve
58    # don't destroy the _xmlobj! we don't own it!
59
60    foreach name [array names _comp2xy] {
61        eval blt::vector destroy $_comp2xy($name)
62    }
63}
64
65# ----------------------------------------------------------------------
66# USAGE: components ?<pattern>?
67#
68# Returns a list of names for the various components of this curve.
69# If the optional glob-style <pattern> is specified, then it returns
70# only the component names matching the pattern.
71# ----------------------------------------------------------------------
72itcl::body Rappture::Curve::components {{pattern *}} {
73    set rlist ""
74    foreach name [array names _comp2xy] {
75        if {[string match $pattern $name]} {
76            lappend rlist $name
77        }
78    }
79    return $rlist
80}
81
82# ----------------------------------------------------------------------
83# USAGE: mesh ?<name>?
84#
85# Returns the xvec for the specified curve component <name>.
86# If the name is not specified, then it returns the vectors for the
87# overall curve (sum of all components).
88# ----------------------------------------------------------------------
89itcl::body Rappture::Curve::mesh {{what -overall}} {
90    if {[info exists _comp2xy($what)]} {
91        return [lindex $_comp2xy($what) 0]  ;# return xv
92    }
93    error "bad option \"$what\": should be [join [lsort [array names _comp2xy]] {, }]"
94}
95
96# ----------------------------------------------------------------------
97# USAGE: values ?<name>?
98#
99# Returns the xvec for the specified curve component <name>.
100# If the name is not specified, then it returns the vectors for the
101# overall curve (sum of all components).
102# ----------------------------------------------------------------------
103itcl::body Rappture::Curve::values {{what -overall}} {
104    if {[info exists _comp2xy($what)]} {
105        return [lindex $_comp2xy($what) 1]  ;# return yv
106    }
107    error "bad option \"$what\": should be [join [lsort [array names _comp2xy]] {, }]"
108}
109
110# ----------------------------------------------------------------------
111# USAGE: limits x|xlin|xlog|y|ylin|ylog
112#
113# Returns the {min max} limits for the specified axis.
114# ----------------------------------------------------------------------
115itcl::body Rappture::Curve::limits {which} {
116    set min ""
117    set max ""
118    switch -- $which {
119        x - xlin { set pos 0; set log 0; set axis xaxis }
120        xlog { set pos 0; set log 1; set axis xaxis }
121        y - ylin - v - vlin { set pos 1; set log 0; set axis yaxis }
122        ylog - vlog { set pos 1; set log 1; set axis yaxis }
123        default {
124            error "bad option \"$which\": should be x, xlin, xlog, y, ylin, ylog, v, vlin, vlog"
125        }
126    }
127
128    blt::vector create tmp zero
129    foreach comp [array names _comp2xy] {
130        set vname [lindex $_comp2xy($comp) $pos]
131        $vname variable vec
132
133        if {$log} {
134            # on a log scale, use abs value and ignore 0's
135            $vname dup tmp
136            $vname dup zero
137            zero expr {tmp == 0}            ;# find the 0's
138            tmp expr {abs(tmp)}             ;# get the abs value
139            tmp expr {tmp + zero*max(tmp)}  ;# replace 0's with abs max
140            set vmin [blt::vector expr min(tmp)]
141            set vmax [blt::vector expr max(tmp)]
142        } else {
143            set vmin $vec(min)
144            set vmax $vec(max)
145        }
146
147        if {"" == $min} {
148            set min $vmin
149        } elseif {$vmin < $min} {
150            set min $vmin
151        }
152        if {"" == $max} {
153            set max $vmax
154        } elseif {$vmax > $max} {
155            set max $vmax
156        }
157    }
158    blt::vector destroy tmp zero
159
160    set val [$_curve get $axis.min]
161    if {"" != $val && "" != $min} {
162        if {$val > $min} {
163            # tool specified this min -- don't go any lower
164            set min $val
165        }
166    }
167
168    set val [$_curve get $axis.max]
169    if {"" != $val && "" != $max} {
170        if {$val < $max} {
171            # tool specified this max -- don't go any higher
172            set max $val
173        }
174    }
175
176    return [list $min $max]
177}
178
179# ----------------------------------------------------------------------
180# USAGE: hints ?<keyword>?
181#
182# Returns a list of key/value pairs for various hints about plotting
183# this curve.  If a particular <keyword> is specified, then it returns
184# the hint for that <keyword>, if it exists.
185# ----------------------------------------------------------------------
186itcl::body Rappture::Curve::hints {{keyword ""}} {
187    if {![info exists _hints]} {
188        foreach {key path} {
189            group   about.group
190            label   about.label
191            color   about.color
192            style   about.style
193            xlabel  xaxis.label
194            xunits  xaxis.units
195            xscale  xaxis.scale
196            xmin    xaxis.min
197            xmax    xaxis.max
198            ylabel  yaxis.label
199            yunits  yaxis.units
200            yscale  yaxis.scale
201            ymin    yaxis.min
202            ymax    yaxis.max
203        } {
204            set str [$_curve get $path]
205            if {"" != $str} {
206                set _hints($key) $str
207            }
208        }
209
210        if {[info exists _hints(xlabel)] && "" != $_hints(xlabel)
211              && [info exists _hints(xunits)] && "" != $_hints(xunits)} {
212            set _hints(xlabel) "$_hints(xlabel) ($_hints(xunits))"
213        }
214        if {[info exists _hints(ylabel)] && "" != $_hints(ylabel)
215              && [info exists _hints(yunits)] && "" != $_hints(yunits)} {
216            set _hints(ylabel) "$_hints(ylabel) ($_hints(yunits))"
217        }
218
219        if {[info exists _hints(group)] && [info exists _hints(label)]} {
220            # pop-up help for each curve
221            set _hints(tooltip) $_hints(label)
222        }
223    }
224
225    if {$keyword != ""} {
226        if {[info exists _hints($keyword)]} {
227            return $_hints($keyword)
228        }
229        return ""
230    }
231    return [array get _hints]
232}
233
234# ----------------------------------------------------------------------
235# USAGE: _build
236#
237# Used internally to build up the vector representation for the
238# curve when the object is first constructed, or whenever the curve
239# data changes.  Discards any existing vectors and builds everything
240# from scratch.
241# ----------------------------------------------------------------------
242itcl::body Rappture::Curve::_build {} {
243    # discard any existing data
244    foreach name [array names _comp2xy] {
245        eval blt::vector destroy $_comp2xy($name)
246    }
247    catch {unset _comp2xy}
248
249    #
250    # Scan through the components of the curve and create
251    # vectors for each part.
252    #
253    foreach cname [$_curve children -type component] {
254        set xv ""
255        set yv ""
256
257        set xydata [$_curve get $cname.xy]
258        if {"" != $xydata} {
259            set xv [blt::vector create x$_counter]
260            set yv [blt::vector create y$_counter]
261
262            foreach line [split $xydata \n] {
263                if {[scan $line {%g %g} xval yval] == 2} {
264                    $xv append $xval
265                    $yv append $yval
266                }
267            }
268        }
269
270        if {$xv != "" && $yv != ""} {
271            set _comp2xy($cname) [list $xv $yv]
272            incr _counter
273        }
274    }
275}
Note: See TracBrowser for help on using the repository browser.