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

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