source: trunk/gui/scripts/histogram.tcl @ 818

Last change on this file since 818 was 818, checked in by gah, 16 years ago

still in development

File size: 10.5 KB
Line 
1
2# ----------------------------------------------------------------------
3#  COMPONENT: histogram - extracts data from an XML description of a field
4#
5#  This object represents a histogram of data in an XML description of
6#  simulator output.  A histogram is similar to a field, but a field is
7#  a quantity versus position in device.  A histogram is any quantity
8#  versus any other quantity.  This class simplifies the process of
9#  extracting data vectors that represent the histogram.
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 { # forward declaration }
21
22itcl::class Rappture::Histogram {
23    constructor {xmlobj path} { # defined below }
24    destructor { # defined below }
25
26    public method components {{pattern *}}
27    public method locations {}
28    public method heights {}
29    public method widths {}
30    public method limits {which}
31    public method xmarkers {}
32    public method ymarkers {}
33    public method hints {{key ""}}
34
35    protected method _build {}
36
37    private variable _xmlobj ""  ;# ref to lib obj with histogram data
38    private variable _hist ""    ;# lib obj representing this histogram
39    private variable _widths ""  ;# vector of bin widths (may be empty string).
40    private variable _heights ""  ;# vector of bin heights along y-axis.
41    private variable _locations "" ;# vector of bin locations along x-axis.
42
43    private variable _hints      ;# cache of hints stored in XML
44    private variable _xmarkers "";# list of {x,label,options} triplets.
45    private variable _ymarkers "";# list of {y,label,options} triplets.
46    private common _counter 0    ;# counter for unique vector names
47}
48
49# ----------------------------------------------------------------------
50# CONSTRUCTOR
51# ----------------------------------------------------------------------
52itcl::body Rappture::Histogram::constructor {xmlobj path} {
53    if {![Rappture::library isvalid $xmlobj]} {
54        error "bad value \"$xmlobj\": should be LibraryObj"
55    }
56    set _xmlobj $xmlobj
57    set _hist [$xmlobj element -as object $path]
58
59    # build up vectors for various components of the histogram
60    _build
61}
62
63# ----------------------------------------------------------------------
64# DESTRUCTOR
65# ----------------------------------------------------------------------
66itcl::body Rappture::Histogram::destructor {} {
67    itcl::delete object $_hist
68    # don't destroy the _xmlobj! we don't own it!
69    blt::vector destroy $_widths _$heights $_locations
70}
71
72# ----------------------------------------------------------------------
73# USAGE: locations
74#
75# Returns the vector for the histogram bin locations along the
76# x-axis.
77# ----------------------------------------------------------------------
78itcl::body Rappture::Histogram::locations {} {
79    return $_locations
80}
81
82# ----------------------------------------------------------------------
83# USAGE: heights
84#
85# Returns the vector for the histogram bin heights along the y-axis.
86# ----------------------------------------------------------------------
87itcl::body Rappture::Histogram::heights {} {
88    return $_heights
89}
90
91# ----------------------------------------------------------------------
92# USAGE: widths
93#
94# Returns the vector for the specified histogram component <name>.
95# If the name is not specified, then it returns the vectors for the
96# overall histogram (sum of all components).
97# ----------------------------------------------------------------------
98itcl::body Rappture::Histogram::widths {} {
99    return $_widths
100}
101
102# ----------------------------------------------------------------------
103# USAGE: xmarkers
104#
105# Returns the list of settings for each marker on the x-axis.
106# If no markers have been specified the empty string is returned.
107# ----------------------------------------------------------------------
108itcl::body Rappture::Histogram::xmarkers {} {
109    return $_xmarkers;
110}
111
112# ----------------------------------------------------------------------
113# USAGE: ymarkers
114#
115# Returns the list of settings for each marker on the y-axis.
116# If no markers have been specified the empty string is returned.
117# ----------------------------------------------------------------------
118itcl::body Rappture::Histogram::ymarkers {} {
119    return $_ymarkers;
120}
121
122# ----------------------------------------------------------------------
123# USAGE: limits x|xlin|xlog|y|ylin|ylog
124#
125# Returns the {min max} limits for the specified axis.
126#
127# What does it mean to view a distribution (the bins) as log scale?
128#
129# ----------------------------------------------------------------------
130itcl::body Rappture::Histogram::limits {which} {
131    set min ""
132    set max ""
133    switch -- $which {
134        x - xlin { set vname $_locations; set log 0; set axis xaxis }
135        xlog { set vname $_locations; set log 1; set axis xaxis }
136        y - ylin - v - vlin { set vname $_heights; set log 0; set axis yaxis }
137        ylog - vlog { set vname $_heights; set log 1; set axis yaxis }
138        default {
139            error "bad option \"$which\": should be x, xlin, xlog, y, ylin, ylog, v, vlin, vlog"
140        }
141    }
142
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    blt::vector destroy tmp zero
170
171    set val [$_hist get $axis.min]
172    if {"" != $val && "" != $min} {
173        if {$val > $min} {
174            # tool specified this min -- don't go any lower
175            set min $val
176        }
177    }
178
179    set val [$_hist get $axis.max]
180    if {"" != $val && "" != $max} {
181        if {$val < $max} {
182            # tool specified this max -- don't go any higher
183            set max $val
184        }
185    }
186
187    return [list $min $max]
188}
189
190# ----------------------------------------------------------------------
191# USAGE: hints ?<keyword>?
192#
193# Returns a list of key/value pairs for various hints about plotting
194# this histogram.  If a particular <keyword> is specified, then it returns
195# the hint for that <keyword>, if it exists.
196# ----------------------------------------------------------------------
197itcl::body Rappture::Histogram::hints {{keyword ""}} {
198    if {![info exists _hints]} {
199        foreach {key path} {
200            group   about.group
201            label   about.label
202            color   about.color
203            style   about.style
204            type    about.type
205            xlabel  xaxis.label
206            xdesc   xaxis.description
207            xunits  xaxis.units
208            xscale  xaxis.scale
209            xmin    xaxis.min
210            xmax    xaxis.max
211            ylabel  yaxis.label
212            ydesc   yaxis.description
213            yunits  yaxis.units
214            yscale  yaxis.scale
215            ymin    yaxis.min
216            ymax    yaxis.max
217        } {
218            set str [$_hist get $path]
219            if {"" != $str} {
220                set _hints($key) $str
221            }
222        }
223
224        if {[info exists _hints(xlabel)] && "" != $_hints(xlabel)
225              && [info exists _hints(xunits)] && "" != $_hints(xunits)} {
226            set _hints(xlabel) "$_hints(xlabel) ($_hints(xunits))"
227        }
228        if {[info exists _hints(ylabel)] && "" != $_hints(ylabel)
229              && [info exists _hints(yunits)] && "" != $_hints(yunits)} {
230            set _hints(ylabel) "$_hints(ylabel) ($_hints(yunits))"
231        }
232
233        if {[info exists _hints(group)] && [info exists _hints(label)]} {
234            # pop-up help for each histogram
235            set _hints(tooltip) $_hints(label)
236        }
237    }
238
239    if {$keyword != ""} {
240        if {[info exists _hints($keyword)]} {
241            return $_hints($keyword)
242        }
243        return ""
244    }
245    return [array get _hints]
246}
247
248# ----------------------------------------------------------------------
249# USAGE: _build
250#
251# Used internally to build up the vector representation for the
252# histogram when the object is first constructed, or whenever the histogram
253# data changes.  Discards any existing vectors and builds everything
254# from scratch.
255# ----------------------------------------------------------------------
256itcl::body Rappture::Histogram::_build {} {
257    # discard any existing data
258    if { $_locations != "" } {
259        blt::vector destroy $_locations
260        set _locations ""
261    }
262    if { $_widths != "" } {
263        blt::vector destroy $_widths
264        set _widths ""
265    }
266    if { $_heights != "" } {
267        blt::vector destroy $_heights
268        set _heights ""
269    }
270
271    #
272    # Scan through the components of the histogram and create
273    # vectors for each part.  Right now there's only one
274    # component.  I left in the component tag in case future
275    # enhancements require more than one component.
276    #
277    set xhwdata [$_hist get component.xhw]
278    if {"" != $xhwdata} {
279        set _widths [blt::vector create x]
280        set _heights [blt::vector create y]
281        set _locations [blt::vector create w]
282
283        foreach line [split $xhwdata \n] {
284            set n [scan $line {%s %s %s} x h w]
285            if { $n == 2 } {
286                $_locations append $x
287                $_heights append $h
288            } elseif { $n == 3 } {
289                $_locations append $x
290                $_heights append $h
291                $_widths append $w
292            }
293        }
294        # FIXME:  There must be a width specified for each bin location.
295        #         If this isn't true, we default to uniform widths
296        #         (zero-length _widths vector == uniform).
297        if { [$_locations length] != [$_widths length] } {
298            $_widths set {}
299        }
300    }
301
302    # Creates lists of x and y marker data.
303    set _xmarkers {}
304    set _ymarkers {}
305    foreach cname [$_hist children -type "marker" xaxis] {
306        set at     [$_hist get "$parent.$cname.at"]
307        set label  [$_hist get "$parent.$cname.label"]
308        set styles [$_hist get "$parent.$cname.style"]
309        set data [list $at $label $styles]
310        lappend _xmarkers $data
311    }
312    foreach cname [$_hist children -type "marker" yaxis] {
313        set at     [$_hist get "$parent.$cname.at"]
314        set label  [$_hist get "$parent.$cname.label"]
315        set styles [$_hist get "$parent.$cname.style"]
316        set data [list $at $label $styles]
317        lappend _xmarkers $data
318    }
319}
Note: See TracBrowser for help on using the repository browser.