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

Last change on this file since 1613 was 1613, checked in by dkearney, 15 years ago

fix for rappture automatic ticket #256452. if we receive no data in the xy
curve object, we don't add empty data to the list of curves. this also affects
xvector and yvector objects that have unequal lengths. if this is encountered,
we don't add the curve to the list of curves. we also no not tell the user
there was an error.

adding file nodata.xml which showed the error described in the automatic
ticket.

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