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

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