source: trunk/gui/scripts/numberresult.tcl @ 1930

Last change on this file since 1930 was 1929, checked in by gah, 14 years ago
File size: 52.6 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: numberresult - plot of numbers in a ResultSet
3#
4#  This widget is an X/Y plot, meant to points produced as <number>
5#  or <integer> outputs from the run of a Rappture tool.  Use the
6#  "add" and "delete" methods to control the points showing on the
7#  plot.  One interesting thing that this result does is configure
8#  the x-axis according to the current result control (simulation
9#  number or other active parameter).
10# ======================================================================
11#  AUTHOR:  Michael McLennan, Purdue University
12#  Copyright (c) 2004-2007  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 Itk
18package require BLT
19
20option add *NumberResult.width 3i widgetDefault
21option add *NumberResult.height 3i widgetDefault
22option add *NumberResult.gridColor #d9d9d9 widgetDefault
23option add *NumberResult.activeColor blue widgetDefault
24option add *NumberResult.dimColor gray widgetDefault
25option add *NumberResult.controlBackground gray widgetDefault
26option add *NumberResult.font \
27    -*-helvetica-medium-r-normal-*-12-* widgetDefault
28
29option add *NumberResult*Balloon*Entry.background white widgetDefault
30
31itcl::class Rappture::NumberResult {
32    inherit itk::Widget
33
34    itk_option define -gridcolor gridColor GridColor ""
35    itk_option define -activecolor activeColor ActiveColor ""
36    itk_option define -dimcolor dimColor DimColor ""
37
38    constructor {args} { # defined below }
39    destructor { # defined below }
40
41    public method add {dataobj {settings ""}}
42    public method get {}
43    public method delete {args}
44    public method scale {args}
45    public method parameters {title args}
46    public method download {option args}
47
48    protected method _rebuild {}
49    protected method _resetLimits {}
50    protected method _zoom {option args}
51    protected method _hilite {state x y}
52    protected method _axis {option args}
53    protected method _getAxes {xydata}
54    protected method _getValue {xydata {which both}}
55    protected method _getInfo {what xydata {which both}}
56
57    private variable _dispatcher "" ;# dispatcher for !events
58
59    private variable _dlist ""     ;# list of data objects
60    private variable _dobj2color   ;# maps data object => plotting color
61    private variable _dobj2width   ;# maps data object => line width
62    private variable _dobj2raise   ;# maps data object => raise flag 0/1
63    private variable _dobj2desc    ;# maps data object => description of data
64    private variable _dobj2param   ;# maps data object => x-axis value
65    private variable _elem2dobj    ;# maps graph element => data object
66    private variable _label2axis   ;# maps axis label => axis ID
67    private variable _params ""    ;# complete description of x-axis
68    private variable _xval2label   ;# maps x-axis value => tick label
69    private variable _xlabels 0    ;# non-zero => use _xval2label
70    private variable _limits       ;# axis limits:  x-min, x-max, etc.
71
72    private variable _hilite       ;# info for element currently highlighted
73    private variable _axis         ;# info for axis manipulations
74    private variable _axisPopup    ;# info for axis being edited in popup
75    common _downloadPopup          ;# download options from popup
76}
77
78itk::usual NumberResult {
79    keep -background -foreground -cursor -font
80}
81
82# ----------------------------------------------------------------------
83# CONSTRUCTOR
84# ----------------------------------------------------------------------
85itcl::body Rappture::NumberResult::constructor {args} {
86    Rappture::dispatcher _dispatcher
87    $_dispatcher register !rebuild
88    $_dispatcher dispatch $this !rebuild "[itcl::code $this _rebuild]; list"
89
90    array set _downloadPopup {
91        format csv
92    }
93
94    option add hull.width hull.height
95    pack propagate $itk_component(hull) no
96
97    itk_component add controls {
98        frame $itk_interior.cntls
99    } {
100        usual
101        rename -background -controlbackground controlBackground Background
102    }
103    pack $itk_component(controls) -side right -fill y
104
105    itk_component add reset {
106        button $itk_component(controls).reset \
107            -borderwidth 1 -padx 1 -pady 1 \
108            -bitmap [Rappture::icon reset] \
109            -command [itcl::code $this _zoom reset]
110    } {
111        usual
112        ignore -borderwidth
113        rename -highlightbackground -controlbackground controlBackground Background
114    }
115    pack $itk_component(reset) -padx 4 -pady 4
116    Rappture::Tooltip::for $itk_component(reset) "Reset the view to the default zoom level"
117
118
119    itk_component add plot {
120        blt::graph $itk_interior.plot \
121            -highlightthickness 0 -plotpadx 0 -plotpady 0 \
122            -rightmargin 10
123    } {
124        keep -background -foreground -cursor -font
125    }
126    pack $itk_component(plot) -expand yes -fill both
127    $itk_component(plot) pen configure activeLine \
128        -symbol square -pixels 3 -linewidth 2 -color black
129
130    #
131    # Add bindings so you can mouse over points to see values:
132    #
133    bind $itk_component(plot) <Motion> \
134        [itcl::code $this _hilite at %x %y]
135    bind $itk_component(plot) <Leave> \
136        [itcl::code $this _hilite off %x %y]
137
138    #
139    # Add support for editing axes:
140    #
141    Rappture::Balloon $itk_component(hull).axes -title "Axis Options"
142    set inner [$itk_component(hull).axes component inner]
143
144    label $inner.labell -text "Label:"
145    entry $inner.label -width 15 -highlightbackground $itk_option(-background)
146    grid $inner.labell -row 1 -column 0 -sticky e
147    grid $inner.label -row 1 -column 1 -sticky ew -pady 4
148
149    label $inner.minl -text "Minimum:"
150    entry $inner.min -width 15 -highlightbackground $itk_option(-background)
151    grid $inner.minl -row 2 -column 0 -sticky e
152    grid $inner.min -row 2 -column 1 -sticky ew -pady 4
153
154    label $inner.maxl -text "Maximum:"
155    entry $inner.max -width 15 -highlightbackground $itk_option(-background)
156    grid $inner.maxl -row 3 -column 0 -sticky e
157    grid $inner.max -row 3 -column 1 -sticky ew -pady 4
158
159    label $inner.formatl -text "Format:"
160    Rappture::Combobox $inner.format -width 15 -editable no
161    $inner.format choices insert end \
162        "%.3g"  "Auto"         \
163        "%.0f"  "X"          \
164        "%.1f"  "X.X"          \
165        "%.2f"  "X.XX"         \
166        "%.3f"  "X.XXX"        \
167        "%.6f"  "X.XXXXXX"     \
168        "%.1e"  "X.Xe+XX"      \
169        "%.2e"  "X.XXe+XX"     \
170        "%.3e"  "X.XXXe+XX"    \
171        "%.6e"  "X.XXXXXXe+XX"
172    grid $inner.formatl -row 4 -column 0 -sticky e
173    grid $inner.format -row 4 -column 1 -sticky ew -pady 4
174
175    label $inner.scalel -text "Scale:"
176    frame $inner.scales
177    radiobutton $inner.scales.linear -text "Linear" \
178        -variable [itcl::scope _axisPopup(scale)] -value "linear"
179    pack $inner.scales.linear -side left
180    radiobutton $inner.scales.log -text "Logarithmic" \
181        -variable [itcl::scope _axisPopup(scale)] -value "log"
182    pack $inner.scales.log -side left
183    grid $inner.scalel -row 5 -column 0 -sticky e
184    grid $inner.scales -row 5 -column 1 -sticky ew -pady 4
185
186    foreach axis {x y} {
187        set _axisPopup(format-$axis) "%.3g"
188    }
189    _axis scale x linear
190    _axis scale y linear
191
192    # quick-and-dirty zoom functionality, for now...
193    Blt_ZoomStack $itk_component(plot)
194    $itk_component(plot) legend configure -hide yes
195
196    eval itk_initialize $args
197
198    set _hilite(elem) ""
199}
200
201# ----------------------------------------------------------------------
202# DESTRUCTOR
203# ----------------------------------------------------------------------
204itcl::body Rappture::NumberResult::destructor {} {
205}
206
207# ----------------------------------------------------------------------
208# USAGE: add <dataObj> ?<settings>?
209#
210# Clients use this to add a data object to the plot.  The optional
211# <settings> are used to configure the plot.  Allowed settings are
212# -color, -brightness, -width, -linestyle and -raise.
213# ----------------------------------------------------------------------
214itcl::body Rappture::NumberResult::add {dataobj {settings ""}} {
215    array set params {
216        -color auto
217        -brightness 0
218        -width 1
219        -type "line"
220        -raise 0
221        -linestyle solid
222        -description ""
223        -param ""
224    }
225    foreach {opt val} $settings {
226        if {![info exists params($opt)]} {
227            error "bad setting \"$opt\": should be [join [lsort [array names params]] {, }]"
228        }
229        set params($opt) $val
230    }
231
232    # if type is set to "scatter", then override the width
233    if {"scatter" == $params(-type)} {
234        set params(-width) 0
235    }
236
237    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
238        set params(-color) #0000ff
239    }
240
241    # if -brightness is set, then update the color
242    if {$params(-brightness) != 0} {
243        set params(-color) [Rappture::color::brightness \
244            $params(-color) $params(-brightness)]
245
246        set bg [$itk_component(plot) cget -plotbackground]
247        foreach {h s v} [Rappture::color::RGBtoHSV $bg] break
248        if {$v > 0.5} {
249            set params(-color) [Rappture::color::brightness_max \
250                $params(-color) 0.8]
251        } else {
252            set params(-color) [Rappture::color::brightness_min \
253                $params(-color) 0.2]
254        }
255    }
256
257    set pos [lsearch -exact $dataobj $_dlist]
258    if {$pos < 0} {
259        lappend _dlist $dataobj
260        set _dobj2color($dataobj) $params(-color)
261        set _dobj2width($dataobj) $params(-width)
262        set _dobj2raise($dataobj) $params(-raise)
263        set _dobj2desc($dataobj) $params(-description)
264        set _dobj2param($dataobj) $params(-param)
265
266        $_dispatcher event -idle !rebuild
267    }
268}
269
270# ----------------------------------------------------------------------
271# USAGE: get
272#
273# Clients use this to query the list of objects being plotted, in
274# order from bottom to top of this result.
275# ----------------------------------------------------------------------
276itcl::body Rappture::NumberResult::get {} {
277    # put the dataobj list in order according to -raise options
278    set dlist $_dlist
279    foreach obj $dlist {
280        if {[info exists _dobj2raise($obj)] && $_dobj2raise($obj)} {
281            set i [lsearch -exact $dlist $obj]
282            if {$i >= 0} {
283                set dlist [lreplace $dlist $i $i]
284                lappend dlist $obj
285            }
286        }
287    }
288    return $dlist
289}
290
291# ----------------------------------------------------------------------
292# USAGE: delete ?<dobj2> <dobj2> ...?
293#
294# Clients use this to delete a data object from the plot.  If no
295# objects are specified, then all objects are deleted.
296# ----------------------------------------------------------------------
297itcl::body Rappture::NumberResult::delete {args} {
298    if {[llength $args] == 0} {
299        set args $_dlist
300    }
301
302    # delete all specified data objects
303    set changed 0
304    foreach dataobj $args {
305        set pos [lsearch -exact $_dlist $dataobj]
306        if {$pos >= 0} {
307            set _dlist [lreplace $_dlist $pos $pos]
308            catch {unset _dobj2color($dataobj)}
309            catch {unset _dobj2width($dataobj)}
310            catch {unset _dobj2raise($dataobj)}
311            catch {unset _dobj2desc($dataobj)}
312            catch {unset _dobj2param($dataobj)}
313            foreach elem [array names _elem2dobj] {
314                if {$_elem2dobj($elem) == $dataobj} {
315                    unset _elem2dobj($elem)
316                }
317            }
318            set changed 1
319        }
320    }
321
322    # if anything changed, then rebuild the plot
323    if {$changed} {
324        $_dispatcher event -idle !rebuild
325    }
326}
327
328# ----------------------------------------------------------------------
329# USAGE: scale ?<dobj1> <dobj2> ...?
330#
331# Sets the default limits for the overall plot according to the
332# limits of the data for all of the given data objects.  This
333# accounts for all objects--even those not showing on the screen.
334# Because of this, the limits are appropriate for all objects as
335# the user scans through data in the ResultSet viewer.
336# ----------------------------------------------------------------------
337itcl::body Rappture::NumberResult::scale {args} {
338    set allx [$itk_component(plot) x2axis use]
339    lappend allx x  ;# fix main x-axis too
340    foreach axis $allx {
341        _axis scale $axis linear
342    }
343
344    set ally [$itk_component(plot) y2axis use]
345    lappend ally y  ;# fix main y-axis too
346    foreach axis $ally {
347        _axis scale $axis linear
348    }
349
350    catch {unset _limits}
351    foreach xydata $args {
352        # find the axes for this data object (e.g., {x y2})
353        foreach {map(x) map(y)} [_getAxes $xydata] break
354
355        foreach axis {x y} {
356            # get defaults for both linear and log scales
357            foreach type {lin log} {
358                # store results -- ex: _limits(x2log-min)
359                set id $map($axis)$type
360                if {$axis == "x"} {
361                    set min [set max ""]
362                    foreach {xlab xval} [lrange $_params 1 end] {
363                        if {$type == "log"} {
364                            set xval [expr {abs($xval)}]
365                            if {$xval == 0} {
366                                continue
367                            }
368                        }
369                        if {"" == $min} {
370                            set min [set max $xval]
371                        } else {
372                            if {$xval < $min} { set min $xval }
373                            if {$xval > $max} { set max $xval }
374                        }
375                    }
376                } else {
377                    set min [set max [_getValue $xydata y]]
378                }
379
380                if {"" != $min && "" != $max} {
381                    if {![info exists _limits($id-min)]} {
382                        set _limits($id-min) $min
383                        set _limits($id-max) $max
384                    } else {
385                        if {$min < $_limits($id-min)} {
386                            set _limits($id-min) $min
387                        }
388                        if {$max > $_limits($id-max)} {
389                            set _limits($id-max) $max
390                        }
391                    }
392                }
393            }
394        }
395    }
396    _resetLimits
397}
398
399# ----------------------------------------------------------------------
400# USAGE: parameters <title> <label1> <value1> <label2> <value2> ...
401#
402# Called when the resultset changes to convey information about the
403# current set of results being displayed.  The <title> is the name
404# of the parameter being explored, and each <label>/<value> represents
405# a data point.
406# ----------------------------------------------------------------------
407itcl::body Rappture::NumberResult::parameters {args} {
408    set _params $args
409
410    #
411    # Fix up the x-axis limits for the primary axis.
412    #
413    foreach type {lin log} {
414        # store results -- ex: _limits(x2log-min)
415        set id x$type
416
417        set min [set max ""]
418        foreach {xlab xval} [lrange $_params 1 end] {
419            if {$type == "log"} {
420                set xval [expr {abs($xval)}]
421                if {$xval == 0} {
422                    continue
423                }
424            }
425            if {"" == $min} {
426                set min [set max $xval]
427            } else {
428                if {$xval < $min} { set min $xval }
429                if {$xval > $max} { set max $xval }
430            }
431        }
432
433        if {"" != $min && "" != $max} {
434            set _limits($id-min) $min
435            set _limits($id-max) $max
436        }
437    }
438    _resetLimits
439
440    #
441    # Figure out a good set of ticks for the x-axis.
442    # If this is a numeric axis, then labels will be like
443    #   0.3V <=> 0.3, 0.4V <=> 0.4, etc.
444    # Otherwise, they will be more like
445    #   red <=> 0, green <=> 1, etc.
446    #
447    set havenums 1
448    catch {unset _xval2label}
449    foreach {xlab xval} [lrange $_params 1 end] {
450        set _xval2label($xval) $xlab
451        if {![string match $xval* $xlab]} {
452            set havenums 0
453        }
454    }
455    if {$havenums} {
456        set _xlabels 0
457        $itk_component(plot) xaxis configure -command "" -majorticks ""
458        if {![$itk_component(plot) axis cget x -logscale]} {
459            $itk_component(plot) xaxis configure \
460                -command [itcl::code $this _axis format x]
461        }
462    } else {
463        set _xlabels 1
464        $itk_component(plot) xaxis configure \
465            -command [itcl::code $this _axis format x] \
466            -majorticks [lsort -real [array names _xval2label]]
467    }
468
469    $_dispatcher event -idle !rebuild
470}
471
472# ----------------------------------------------------------------------
473# USAGE: download coming
474# USAGE: download controls <downloadCommand>
475# USAGE: download now
476#
477# Clients use this method to create a downloadable representation
478# of the plot.  Returns a list of the form {ext string}, where
479# "ext" is the file extension (indicating the type of data) and
480# "string" is the data itself.
481# ----------------------------------------------------------------------
482itcl::body Rappture::NumberResult::download {option args} {
483    switch $option {
484        coming {
485            # nothing to do
486        }
487        controls {
488            set popup .xyresultdownload
489            if {![winfo exists .xyresultdownload]} {
490                # if we haven't created the popup yet, do it now
491                Rappture::Balloon $popup -title "[Rappture::filexfer::label downloadWord] as..."
492                set inner [$popup component inner]
493                label $inner.summary -text "" -anchor w
494                pack $inner.summary -side top
495                radiobutton $inner.csv -text "Data as Comma-Separated Values" \
496                    -variable Rappture::NumberResult::_downloadPopup(format) \
497                    -value csv
498                pack $inner.csv -anchor w
499                radiobutton $inner.pdf -text "Image as PDF/PostScript" \
500                    -variable Rappture::NumberResult::_downloadPopup(format) \
501                    -value pdf
502                pack $inner.pdf -anchor w
503                button $inner.go -text [Rappture::filexfer::label download] \
504                    -command [lindex $args 0]
505                pack $inner.go -pady 4
506            } else {
507                set inner [$popup component inner]
508            }
509            set num [llength [get]]
510            set num [expr {($num == 1) ? "1 result" : "$num results"}]
511            $inner.summary configure -text "[Rappture::filexfer::label downloadWord] $num in the following format:"
512            update idletasks ;# fix initial sizes
513            return $popup
514        }
515        now {
516            set popup .xyresultdownload
517            if {[winfo exists .xyresultdownload]} {
518                $popup deactivate
519            }
520            switch -- $_downloadPopup(format) {
521              csv {
522                # March through the values in order and report
523                # all data points
524                set csvdata ""
525                set xtitle [$itk_component(plot) xaxis cget -title]
526                set ytitle [$itk_component(plot) yaxis cget -title]
527
528                set desc ""
529                set dataobj [lindex [get] end]
530
531                # the "Simulation" axis shows all values
532                # -- no need for assumptions
533                if {$xtitle != "Simulation"
534                      && [info exists _dobj2desc($dataobj)]} {
535                    foreach line [split $_dobj2desc($dataobj) \n] {
536                        # skip the current axis and the Simulation axis
537                        # Other values show assumptions about values reported
538                        if {[string match "$xtitle =*" $line]
539                              || [string match "Simulation =*" $line]} {
540                            continue
541                        }
542                        set indent [expr {("" == $desc) ? "for:" : "    "}]
543                        append desc " $indent $line\n"
544                    }
545                }
546                if {[string length $desc] > 0} {
547                    append csvdata "[string repeat - 60]\n"
548                    append csvdata $desc
549                    append csvdata "[string repeat - 60]\n"
550                }
551
552                append csvdata "$xtitle, $ytitle\n"
553                foreach xval [lsort -real [array names _xval2label]] {
554                    set dataobj ""
555                    set param [list $_xval2label($xval) $xval]
556                    foreach obj $_dlist {
557                        if {[info exists _dobj2param($obj)]
558                              && [string equal $_dobj2param($obj) $param]} {
559                            set dataobj $obj
560                            break
561                        }
562                    }
563                    if {"" != $dataobj} {
564                        set yval [$dataobj get current]
565                        append csvdata "$_xval2label($xval), $yval\n"
566                    }
567                }
568                return [list .txt $csvdata]
569              }
570              pdf {
571                set psdata [$itk_component(plot) postscript output -decorations no -maxpect 1]
572
573                set cmds {
574                    set fout "xy[pid].pdf"
575                    exec ps2pdf - $fout << $psdata
576
577                    set fid [open $fout r]
578                    fconfigure $fid -translation binary -encoding binary
579                    set pdfdata [read $fid]
580                    close $fid
581
582                    file delete -force $fout
583                }
584                if {[catch $cmds result] == 0} {
585                    return [list .pdf $pdfdata]
586                }
587                return [list .ps $psdata]
588              }
589            }
590        }
591        default {
592            error "bad option \"$option\": should be coming, controls, now"
593        }
594    }
595}
596
597# ----------------------------------------------------------------------
598# USAGE: _rebuild
599#
600# Called automatically whenever something changes that affects the
601# data in the widget.  Clears any existing data and rebuilds the
602# widget to display new data.
603# ----------------------------------------------------------------------
604itcl::body Rappture::NumberResult::_rebuild {} {
605    set g $itk_component(plot)
606
607    # first clear out the widget
608    eval $g element delete [$g element names]
609    foreach axis [$g axis names] {
610        $g axis configure $axis -hide yes -checklimits no
611    }
612    catch {unset _label2axis}
613
614    #
615    # Scan through all objects and create a list of all axes.
616    # The first x-axis gets mapped to "x".  The second, to "x2".
617    # Beyond that, we must create new axes "x3", "x4", etc.
618    # We do the same for y.
619    #
620    set anum(x) 0
621    set anum(y) 0
622    foreach xydata [get] {
623        foreach ax {x y} {
624            set label [_getInfo about.label $xydata ${ax}]
625            if {"" != $label} {
626                if {![info exists _label2axis($ax-$label)]} {
627                    switch [incr anum($ax)] {
628                        1 { set axis $ax }
629                        2 { set axis ${ax}2 }
630                        default {
631                            set axis $ax$anum($ax)
632                            catch {$g axis create $axis}
633                        }
634                    }
635                    $g axis configure $axis -title $label -hide no \
636                        -checklimits no
637                    set _label2axis($ax-$label) $axis
638
639                    # if this axis has a description, add it as a tooltip
640                    set desc [string trim [_getInfo about.description $xydata ${ax}]]
641                    Rappture::Tooltip::text $g-$axis $desc
642                }
643            }
644        }
645    }
646
647    #
648    # All of the extra axes get mapped to the x2/y2 (top/right)
649    # position.
650    #
651    set all ""
652    foreach ax {x y} {
653        lappend all $ax
654
655        set extra ""
656        for {set i 2} {$i <= $anum($ax)} {incr i} {
657            lappend extra ${ax}$i
658        }
659        eval lappend all $extra
660        $g ${ax}2axis use $extra
661        if {$ax == "y"} {
662            $g configure -rightmargin [expr {($extra == "") ? 10 : 0}]
663        }
664    }
665
666    foreach axis $all {
667        set _axisPopup(format-$axis) "%.3g"
668
669        $g axis bind $axis <Enter> \
670            [itcl::code $this _axis hilite $axis on]
671        $g axis bind $axis <Leave> \
672            [itcl::code $this _axis hilite $axis off]
673        $g axis bind $axis <ButtonPress> \
674            [itcl::code $this _axis click $axis %x %y]
675        $g axis bind $axis <B1-Motion> \
676            [itcl::code $this _axis drag $axis %x %y]
677        $g axis bind $axis <ButtonRelease> \
678            [itcl::code $this _axis release $axis %x %y]
679        $g axis bind $axis <KeyPress> \
680            [list ::Rappture::Tooltip::tooltip cancel]
681    }
682
683    #
684    # Plot all of the data objects.
685    #
686    set count 0
687    foreach xydata $_dlist {
688        set label [$xydata get about.label]
689        foreach {mapx mapy} [_getAxes $xydata] break
690
691        foreach {xv yv} [_getValue $xydata] break
692
693        if {[info exists _dobj2color($xydata)]} {
694            set color $_dobj2color($xydata)
695        } else {
696            set color [$xydata get about.color]
697            if {"" == $color} {
698                set color $itk_option(-activecolor)
699            }
700        }
701
702        set sym square
703        set pixels 6
704
705        set elem "elem[incr count]"
706        set _elem2dobj($elem) $xydata
707
708        $g element create $elem -x $xv -y $yv \
709            -symbol $sym -pixels $pixels -label $label \
710            -color $color -mapx $mapx -mapy $mapy
711    }
712}
713
714# ----------------------------------------------------------------------
715# USAGE: _resetLimits
716#
717# Used internally to apply automatic limits to the axes for the
718# current plot.
719# ----------------------------------------------------------------------
720itcl::body Rappture::NumberResult::_resetLimits {} {
721    set g $itk_component(plot)
722
723    #
724    # HACK ALERT!
725    # Use this code to fix up the y-axis limits for the BLT graph.
726    # The auto-limits don't always work well.  We want them to be
727    # set to a "nice" number slightly above or below the min/max
728    # limits.
729    #
730    foreach axis [$g axis names] {
731        if {[info exists _limits(${axis}lin-min)]} {
732            set log [$g axis cget $axis -logscale]
733            if {$log} {
734                set min $_limits(${axis}log-min)
735                if {$min == 0} { set min 1 }
736                set max $_limits(${axis}log-max)
737                if {$max == 0} { set max 1 }
738
739                if {$min == $max} {
740                    set logmin [expr {floor(log10(abs(0.9*$min)))}]
741                    set logmax [expr {ceil(log10(abs(1.1*$max)))}]
742                } else {
743                    set logmin [expr {floor(log10(abs($min)))}]
744                    set logmax [expr {ceil(log10(abs($max)))}]
745                    if {[string match y* $axis]} {
746                        # add a little padding
747                        set delta [expr {$logmax-$logmin}]
748                        if {$delta == 0} { set delta 1 }
749                        set logmin [expr {$logmin-0.05*$delta}]
750                        set logmax [expr {$logmax+0.05*$delta}]
751                    }
752                }
753                if {$logmin < -300} {
754                    set min 1e-300
755                } elseif {$logmin > 300} {
756                    set min 1e+300
757                } else {
758                    set min [expr {pow(10.0,$logmin)}]
759                }
760
761                if {$logmax < -300} {
762                    set max 1e-300
763                } elseif {$logmax > 300} {
764                    set max 1e+300
765                } else {
766                    set max [expr {pow(10.0,$logmax)}]
767                }
768            } else {
769                set min $_limits(${axis}lin-min)
770                set max $_limits(${axis}lin-max)
771
772                # add a little padding
773                set delta [expr {$max-$min}]
774                set min [expr {$min-0.05*$delta}]
775                set max [expr {$max+0.05*$delta}]
776            }
777            if {$min < $max} {
778                $g axis configure $axis -min $min -max $max
779            } else {
780                $g axis configure $axis -min "" -max ""
781            }
782        } else {
783            $g axis configure $axis -min "" -max ""
784        }
785    }
786}
787
788# ----------------------------------------------------------------------
789# USAGE: _zoom reset
790#
791# Called automatically when the user clicks on one of the zoom
792# controls for this widget.  Changes the zoom for the current view.
793# ----------------------------------------------------------------------
794itcl::body Rappture::NumberResult::_zoom {option args} {
795    switch -- $option {
796        reset {
797            _resetLimits
798        }
799    }
800}
801
802# ----------------------------------------------------------------------
803# USAGE: _hilite <state> <x> <y>
804#
805# Called automatically when the user brushes one of the elements
806# on the plot.  Causes the element to highlight and a tooltip to
807# pop up with element info.
808# ----------------------------------------------------------------------
809itcl::body Rappture::NumberResult::_hilite {state x y} {
810    set g $itk_component(plot)
811    set elem ""
812    if {$state == "at"} {
813        if {[$g element closest $x $y info -interpolate yes]} {
814            # for dealing with xy line plots
815            set elem $info(name)
816            foreach {mapx mapy} [_getAxes $_elem2dobj($elem)] break
817
818            # search again for an exact point -- this time don't interpolate
819            set tip ""
820            if {[$g element closest $x $y info -interpolate no]
821                  && $info(name) == $elem} {
822                set x [$g axis transform $mapx $info(x)]
823                set y [$g axis transform $mapy $info(y)]
824
825                if {[info exists _elem2dobj($elem)]} {
826                    set dataobj $_elem2dobj($elem)
827                    set tip [_getInfo about.label $dataobj y]
828                    if {[info exists info(y)]} {
829                        set val [_axis format y dummy $info(y)]
830                        set units [_getInfo units $dataobj y]
831                        append tip "\n$val$units"
832
833                        if {[info exists _dobj2param($dataobj)]} {
834                            set val [lindex $_dobj2param($dataobj) 0]
835                            append tip " @ $val"
836                        }
837                    }
838                    set tip [string trim $tip]
839                }
840            }
841            set state 1
842        } elseif {[$g element closest $x $y info -interpolate no]} {
843            # for dealing with xy scatter plot
844            set elem $info(name)
845            foreach {mapx mapy} [_getAxes $_elem2dobj($elem)] break
846
847            # search again for an exact point -- this time don't interpolate
848            set tip ""
849            if {$info(name) == $elem} {
850                set x [$g axis transform $mapx $info(x)]
851                set y [$g axis transform $mapy $info(y)]
852
853                if {[info exists _elem2dobj($elem)]} {
854                    set dataobj $_elem2dobj($elem)
855                    set tip [_getInfo about.label $dataobj y]
856                    if {[info exists info(y)]} {
857                        set val [_axis format y dummy $info(y)]
858                        set units [_getInfo units $dataobj y]
859                        append tip "\n$val$units"
860
861                        if {[info exists _dobj2param($dataobj)]} {
862                            set val [lindex $_dobj2param($dataobj) 0]
863                            append tip " @ $val"
864                        }
865                    }
866                    set tip [string trim $tip]
867                }
868            }
869            set state 1
870        } else {
871            set state 0
872        }
873    }
874
875    if {$state} {
876        #
877        # Highlight ON:
878        # - activate trace
879        # - multiple axes? dim other axes
880        # - pop up tooltip about data
881        #
882        if {$_hilite(elem) != "" && $_hilite(elem) != $elem} {
883            $g element deactivate $_hilite(elem)
884            $g crosshairs configure -hide yes
885            Rappture::Tooltip::tooltip cancel
886        }
887        $g element activate $elem
888        set _hilite(elem) $elem
889
890        set dlist [$g element show]
891        set i [lsearch -exact $dlist $elem]
892        if {$i >= 0} {
893            set dlist [lreplace $dlist $i $i]
894            lappend dlist $elem
895            $g element show $dlist
896        }
897
898        foreach {mapx mapy} [_getAxes $_elem2dobj($elem)] break
899
900        set allx [$g x2axis use]
901        if {[llength $allx] > 0} {
902            lappend allx x  ;# fix main x-axis too
903            foreach axis $allx {
904                if {$axis == $mapx} {
905                    $g axis configure $axis -color $itk_option(-foreground) \
906                        -titlecolor $itk_option(-foreground)
907                } else {
908                    $g axis configure $axis -color $itk_option(-dimcolor) \
909                        -titlecolor $itk_option(-dimcolor)
910                }
911            }
912        }
913        set ally [$g y2axis use]
914        if {[llength $ally] > 0} {
915            lappend ally y  ;# fix main y-axis too
916            foreach axis $ally {
917                if {$axis == $mapy} {
918                    $g axis configure $axis -color $itk_option(-foreground) \
919                        -titlecolor $itk_option(-foreground)
920                } else {
921                    $g axis configure $axis -color $itk_option(-dimcolor) \
922                        -titlecolor $itk_option(-dimcolor)
923                }
924            }
925        }
926
927        if {"" != $tip} {
928            $g crosshairs configure -hide no -position @$x,$y
929
930            if {$x > 0.5*[winfo width $g]} {
931                if {$x < 4} {
932                    set tipx "-0"
933                } else {
934                    set tipx "-[expr {$x-4}]"  ;# move tooltip to the left
935                }
936            } else {
937                if {$x < -4} {
938                    set tipx "+0"
939                } else {
940                    set tipx "+[expr {$x+4}]"  ;# move tooltip to the right
941                }
942            }
943            if {$y > 0.5*[winfo height $g]} {
944                if {$y < 4} {
945                    set tipy "-0"
946                } else {
947                    set tipy "-[expr {$y-4}]"  ;# move tooltip to the top
948                }
949            } else {
950                if {$y < -4} {
951                    set tipy "+0"
952                } else {
953                    set tipy "+[expr {$y+4}]"  ;# move tooltip to the bottom
954                }
955            }
956            Rappture::Tooltip::text $g $tip
957            Rappture::Tooltip::tooltip show $g $tipx,$tipy
958        }
959    } else {
960        #
961        # Highlight OFF:
962        # - deactivate (color back to normal)
963        # - put all axes back to normal color
964        # - take down tooltip
965        #
966        if {"" != $_hilite(elem)} {
967            $g element deactivate $_hilite(elem)
968
969            set allx [$g x2axis use]
970            if {[llength $allx] > 0} {
971                lappend allx x  ;# fix main x-axis too
972                foreach axis $allx {
973                    $g axis configure $axis -color $itk_option(-foreground) \
974                        -titlecolor $itk_option(-foreground)
975                }
976            }
977
978            set ally [$g y2axis use]
979            if {[llength $ally] > 0} {
980                lappend ally y  ;# fix main y-axis too
981                foreach axis $ally {
982                    $g axis configure $axis -color $itk_option(-foreground) \
983                        -titlecolor $itk_option(-foreground)
984                }
985            }
986        }
987
988        $g crosshairs configure -hide yes
989
990        # only cancel in plotting area or we'll mess up axes
991        if {[$g inside $x $y]} {
992            Rappture::Tooltip::tooltip cancel
993        }
994
995        # there is no currently highlighted element
996        set _hilite(elem) ""
997    }
998}
999
1000# ----------------------------------------------------------------------
1001# USAGE: _axis hilite <axis> <state>
1002#
1003# USAGE: _axis click <axis> <x> <y>
1004# USAGE: _axis drag <axis> <x> <y>
1005# USAGE: _axis release <axis> <x> <y>
1006#
1007# USAGE: _axis edit <axis>
1008# USAGE: _axis changed <axis> <what>
1009# USAGE: _axis format <axis> <widget> <value>
1010# USAGE: _axis scale <axis> linear|log
1011#
1012# Used internally to handle editing of the x/y axes.  The hilite
1013# operation causes the axis to light up.  The edit operation pops
1014# up a panel with editing options.  The changed operation applies
1015# changes from the panel.
1016# ----------------------------------------------------------------------
1017itcl::body Rappture::NumberResult::_axis {option args} {
1018    set inner [$itk_component(hull).axes component inner]
1019
1020    switch -- $option {
1021        hilite {
1022            if {[llength $args] != 2} {
1023                error "wrong # args: should be \"_axis hilite axis state\""
1024            }
1025            set g $itk_component(plot)
1026            set axis [lindex $args 0]
1027            set state [lindex $args 1]
1028
1029            if {$state} {
1030                $g axis configure $axis \
1031                    -color $itk_option(-activecolor) \
1032                    -titlecolor $itk_option(-activecolor)
1033
1034                set x [expr {[winfo pointerx $g]+4}]
1035                set y [expr {[winfo pointery $g]+4}]
1036                Rappture::Tooltip::tooltip pending $g-$axis @$x,$y
1037            } else {
1038                $g axis configure $axis \
1039                    -color $itk_option(-foreground) \
1040                    -titlecolor $itk_option(-foreground)
1041                Rappture::Tooltip::tooltip cancel
1042            }
1043        }
1044        click {
1045            if {[llength $args] != 3} {
1046                error "wrong # args: should be \"_axis click axis x y\""
1047            }
1048            set axis [lindex $args 0]
1049            set x [lindex $args 1]
1050            set y [lindex $args 2]
1051            set g $itk_component(plot)
1052
1053            set _axis(moved) 0
1054            set _axis(click-x) $x
1055            set _axis(click-y) $y
1056            foreach {min max} [$g axis limits $axis] break
1057            set _axis(min0) $min
1058            set _axis(max0) $max
1059            Rappture::Tooltip::tooltip cancel
1060        }
1061        drag {
1062            if {[llength $args] != 3} {
1063                error "wrong # args: should be \"_axis drag axis x y\""
1064            }
1065            if {![info exists _axis(moved)]} {
1066                return  ;# must have skipped click event -- ignore
1067            }
1068            set axis [lindex $args 0]
1069            set x [lindex $args 1]
1070            set y [lindex $args 2]
1071            set g $itk_component(plot)
1072
1073            if {[info exists _axis(click-x)] && [info exists _axis(click-y)]} {
1074                foreach {x0 y0 pw ph} [$g extents plotarea] break
1075                switch -glob $axis {
1076                  x* {
1077                    set pix $x
1078                    set pix0 $_axis(click-x)
1079                    set pixmin $x0
1080                    set pixmax [expr {$x0+$pw}]
1081                  }
1082                  y* {
1083                    set pix $y
1084                    set pix0 $_axis(click-y)
1085                    set pixmin [expr {$y0+$ph}]
1086                    set pixmax $y0
1087                  }
1088                }
1089                set log [$g axis cget $axis -logscale]
1090                set min $_axis(min0)
1091                set max $_axis(max0)
1092                set dpix [expr {abs($pix-$pix0)}]
1093                set v0 [$g axis invtransform $axis $pixmin]
1094                set v1 [$g axis invtransform $axis [expr {$pixmin+$dpix}]]
1095                if {$log} {
1096                    set v0 [expr {log10($v0)}]
1097                    set v1 [expr {log10($v1)}]
1098                    set min [expr {log10($min)}]
1099                    set max [expr {log10($max)}]
1100                }
1101
1102                if {$pix > $pix0} {
1103                    set delta [expr {$v1-$v0}]
1104                } else {
1105                    set delta [expr {$v0-$v1}]
1106                }
1107                set min [expr {$min-$delta}]
1108                set max [expr {$max-$delta}]
1109                if {$log} {
1110                    set min [expr {pow(10.0,$min)}]
1111                    set max [expr {pow(10.0,$max)}]
1112                }
1113                $g axis configure $axis -min $min -max $max
1114
1115                # move axis, don't edit on release
1116                set _axis(move) 1
1117            }
1118        }
1119        release {
1120            if {[llength $args] != 3} {
1121                error "wrong # args: should be \"_axis release axis x y\""
1122            }
1123            if {![info exists _axis(moved)]} {
1124                return  ;# must have skipped click event -- ignore
1125            }
1126            set axis [lindex $args 0]
1127            set x [lindex $args 1]
1128            set y [lindex $args 2]
1129
1130            if {!$_axis(moved)} {
1131                # small movement? then treat as click -- pop up axis editor
1132                set dx [expr {abs($x-$_axis(click-x))}]
1133                set dy [expr {abs($y-$_axis(click-y))}]
1134                if {$dx < 2 && $dy < 2} {
1135                    _axis edit $axis
1136                }
1137            } else {
1138                # one last movement
1139                _axis drag $axis $x $y
1140            }
1141            catch {unset _axis}
1142        }
1143        edit {
1144            if {[llength $args] != 1} {
1145                error "wrong # args: should be \"_axis edit axis\""
1146            }
1147            set axis [lindex $args 0]
1148            set _axisPopup(current) $axis
1149
1150            # apply last value when deactivating
1151            $itk_component(hull).axes configure -deactivatecommand \
1152                [itcl::code $this _axis changed $axis focus]
1153
1154            # fix axis label controls...
1155            set label [$itk_component(plot) axis cget $axis -title]
1156            $inner.label delete 0 end
1157            $inner.label insert end $label
1158            bind $inner.label <KeyPress-Return> \
1159                [itcl::code $this _axis changed $axis label]
1160            bind $inner.label <FocusOut> \
1161                [itcl::code $this _axis changed $axis label]
1162
1163            # fix min/max controls...
1164            foreach {min max} [$itk_component(plot) axis limits $axis] break
1165            $inner.min delete 0 end
1166            $inner.min insert end $min
1167            bind $inner.min <KeyPress-Return> \
1168                [itcl::code $this _axis changed $axis min]
1169            bind $inner.min <FocusOut> \
1170                [itcl::code $this _axis changed $axis min]
1171
1172            $inner.max delete 0 end
1173            $inner.max insert end $max
1174            bind $inner.max <KeyPress-Return> \
1175                [itcl::code $this _axis changed $axis max]
1176            bind $inner.max <FocusOut> \
1177                [itcl::code $this _axis changed $axis max]
1178
1179            # fix format control...
1180            set fmts [$inner.format choices get -value]
1181            set i [lsearch -exact $fmts $_axisPopup(format-$axis)]
1182            if {$i < 0} { set i 0 }  ;# use Auto choice
1183            $inner.format value [$inner.format choices get -label $i]
1184
1185            bind $inner.format <<Value>> \
1186                [itcl::code $this _axis changed $axis format]
1187
1188            # fix scale control...
1189            if {[$itk_component(plot) axis cget $axis -logscale]} {
1190                set _axisPopup(scale) "log"
1191                $inner.format configure -state disabled
1192            } else {
1193                set _axisPopup(scale) "linear"
1194                $inner.format configure -state normal
1195            }
1196            $inner.scales.linear configure \
1197                -command [itcl::code $this _axis changed $axis scale]
1198            $inner.scales.log configure \
1199                -command [itcl::code $this _axis changed $axis scale]
1200
1201            #
1202            # Figure out where the window should pop up.
1203            #
1204            set x [winfo rootx $itk_component(plot)]
1205            set y [winfo rooty $itk_component(plot)]
1206            set w [winfo width $itk_component(plot)]
1207            set h [winfo height $itk_component(plot)]
1208            foreach {x0 y0 pw ph} [$itk_component(plot) extents plotarea] break
1209            switch -glob -- $axis {
1210                x {
1211                    set x [expr {round($x + $x0+0.5*$pw)}]
1212                    set y [expr {round($y + $y0+$ph + 0.5*($h-$y0-$ph))}]
1213                    set dir "above"
1214                }
1215                x* {
1216                    set x [expr {round($x + $x0+0.5*$pw)}]
1217                    set dir "below"
1218                    set allx [$itk_component(plot) x2axis use]
1219                    set max [llength $allx]
1220                    set i [lsearch -exact $allx $axis]
1221                    set y [expr {round($y + ($i+0.5)*$y0/double($max))}]
1222                }
1223                y {
1224                    set x [expr {round($x + 0.5*$x0)}]
1225                    set y [expr {round($y + $y0+0.5*$ph)}]
1226                    set dir "right"
1227                }
1228                y* {
1229                    set y [expr {round($y + $y0+0.5*$ph)}]
1230                    set dir "left"
1231                    set ally [$itk_component(plot) y2axis use]
1232                    set max [llength $ally]
1233                    set i [lsearch -exact $ally $axis]
1234                    set y [expr {round($y + ($i+0.5)*$y0/double($max))}]
1235                    set x [expr {round($x+$x0+$pw + ($i+0.5)*($w-$x0-$pw)/double($max))}]
1236                }
1237            }
1238            $itk_component(hull).axes activate @$x,$y $dir
1239        }
1240        changed {
1241            if {[llength $args] != 2} {
1242                error "wrong # args: should be \"_axis changed axis what\""
1243            }
1244            set axis [lindex $args 0]
1245            set what [lindex $args 1]
1246            if {$what == "focus"} {
1247                set what [focus]
1248                if {[winfo exists $what]} {
1249                    set what [winfo name $what]
1250                }
1251            }
1252
1253            switch -- $what {
1254                label {
1255                    set val [$inner.label get]
1256                    $itk_component(plot) axis configure $axis -title $val
1257                }
1258                min {
1259                    set val [$inner.min get]
1260                    if {![string is double -strict $val]} {
1261                        Rappture::Tooltip::cue $inner.min "Must be a number"
1262                        bell
1263                        return
1264                    }
1265
1266                    set max [lindex [$itk_component(plot) axis limits $axis] 1]
1267                    if {$val >= $max} {
1268                        Rappture::Tooltip::cue $inner.min "Must be <= max ($max)"
1269                        bell
1270                        return
1271                    }
1272                    catch {
1273                        # can fail in log mode
1274                        $itk_component(plot) axis configure $axis -min $val
1275                    }
1276                    foreach {min max} [$itk_component(plot) axis limits $axis] break
1277                    $inner.min delete 0 end
1278                    $inner.min insert end $min
1279                }
1280                max {
1281                    set val [$inner.max get]
1282                    if {![string is double -strict $val]} {
1283                        Rappture::Tooltip::cue $inner.max "Should be a number"
1284                        bell
1285                        return
1286                    }
1287
1288                    set min [lindex [$itk_component(plot) axis limits $axis] 0]
1289                    if {$val <= $min} {
1290                        Rappture::Tooltip::cue $inner.max "Must be >= min ($min)"
1291                        bell
1292                        return
1293                    }
1294                    catch {
1295                        # can fail in log mode
1296                        $itk_component(plot) axis configure $axis -max $val
1297                    }
1298                    foreach {min max} [$itk_component(plot) axis limits $axis] break
1299                    $inner.max delete 0 end
1300                    $inner.max insert end $max
1301                }
1302                format {
1303                    set fmt [$inner.format translate [$inner.format value]]
1304                    set _axisPopup(format-$axis) $fmt
1305
1306                    # force a refresh
1307                    $itk_component(plot) axis configure $axis -min \
1308                        [$itk_component(plot) axis cget $axis -min]
1309                }
1310                scale {
1311                    _axis scale $axis $_axisPopup(scale)
1312
1313                    if {$_axisPopup(scale) == "log"} {
1314                        $inner.format configure -state disabled
1315                    } else {
1316                        $inner.format configure -state normal
1317                    }
1318
1319                    foreach {min max} [$itk_component(plot) axis limits $axis] break
1320                    $inner.min delete 0 end
1321                    $inner.min insert end $min
1322                    $inner.max delete 0 end
1323                    $inner.max insert end $max
1324                }
1325                default {
1326                    # be lenient so we can handle the "focus" case
1327                }
1328            }
1329        }
1330        format {
1331            if {[llength $args] != 3} {
1332                error "wrong # args: should be \"_axis format axis widget value\""
1333            }
1334            set axis [lindex $args 0]
1335            set value [lindex $args 2]
1336
1337            if {$axis == "x" && $_xlabels
1338                  && [info exists _xval2label($value)]} {
1339                return $_xval2label($value)
1340            }
1341            if {[$itk_component(plot) axis cget $axis -logscale]} {
1342                set fmt "%.3g"
1343            } else {
1344                set fmt $_axisPopup(format-$axis)
1345            }
1346            return [format $fmt $value]
1347        }
1348        scale {
1349            if {[llength $args] != 2} {
1350                error "wrong # args: should be \"_axis scale axis type\""
1351            }
1352            set axis [lindex $args 0]
1353            set type [lindex $args 1]
1354
1355            if {$type == "log"} {
1356                catch {$itk_component(plot) axis configure $axis -logscale 1}
1357                # leave format alone in log mode
1358                $itk_component(plot) axis configure $axis -command ""
1359            } else {
1360                catch {$itk_component(plot) axis configure $axis -logscale 0}
1361                # use special formatting for linear mode
1362                $itk_component(plot) axis configure $axis -command \
1363                    [itcl::code $this _axis format $axis]
1364            }
1365        }
1366        default {
1367            error "bad option \"$option\": should be changed, edit, hilite, or format"
1368        }
1369    }
1370}
1371
1372# ----------------------------------------------------------------------
1373# USAGE: _getAxes <dataObj>
1374#
1375# Used internally to figure out the axes used to plot the given
1376# <dataObj>.  Returns a list of the form {x y}, where x is the
1377# x-axis name (x, x2, x3, etc.), and y is the y-axis name.
1378# ----------------------------------------------------------------------
1379itcl::body Rappture::NumberResult::_getAxes {xydata} {
1380    # rebuild if needed, so we know about the axes
1381    if {[$_dispatcher ispending !rebuild]} {
1382        $_dispatcher cancel !rebuild
1383        $_dispatcher event -now !rebuild
1384    }
1385
1386    # what is the x axis?  x? x2? x3? ...
1387    set xlabel "Simulation #"
1388    if {[info exists _label2axis(x-$xlabel)]} {
1389        set mapx $_label2axis(x-$xlabel)
1390    } else {
1391        set mapx "x"
1392    }
1393
1394    # what is the y axis?  y? y2? y3? ...
1395    set ylabel [$xydata get about.label]
1396    if {[info exists _label2axis(y-$ylabel)]} {
1397        set mapy $_label2axis(y-$ylabel)
1398    } else {
1399        set mapy "y"
1400    }
1401
1402    return [list $mapx $mapy]
1403}
1404
1405# ----------------------------------------------------------------------
1406# USAGE: _getValue <dataObj> ?<axis>?
1407#
1408# Used internally to get the {x y} value from this <dataObj>.
1409# Returns x, y, or {x y} in the expected units for this object.
1410# ----------------------------------------------------------------------
1411itcl::body Rappture::NumberResult::_getValue {xydata {which both}} {
1412    if {[info exists _dobj2param($xydata)]} {
1413        set x [lindex $_dobj2param($xydata) 1]
1414    } else {
1415        set x 0
1416    }
1417
1418    set y [$xydata get current]
1419    set units [$xydata get units]
1420    if {$units != ""} {
1421        set y [Rappture::Units::convert $y -context $units -to $units -units off]
1422    }
1423    if {![string is double -strict $y]} {
1424        set y 0
1425    }
1426
1427    switch -- $which {
1428        x { return $x }
1429        y { return $y }
1430        both { return [list $x $y] }
1431        default { error "bad value \"$which\": should be x, y, both" }
1432    }
1433}
1434
1435# ----------------------------------------------------------------------
1436# USAGE: _getInfo <what> <dataObj> ?<axis>?
1437#
1438# Used internally to get the {x y} labels from this <dataObj>.
1439# Returns xlabel, ylabel, or {xlabel ylabel}.
1440# ----------------------------------------------------------------------
1441itcl::body Rappture::NumberResult::_getInfo {what xydata {which both}} {
1442    set x [lindex $_params 0]
1443    set y [$xydata get $what]
1444    if {$what == "about.label"} {
1445        set units [$xydata get units]
1446        if {"" != $units} {
1447            append y " ($units)"
1448        }
1449    }
1450
1451    switch -- $which {
1452        x { return $x }
1453        y { return $y }
1454        both { return [list $x $y] }
1455        default { error "bad value \"$which\": should be x, y, both" }
1456    }
1457}
1458
1459# ----------------------------------------------------------------------
1460# CONFIGURATION OPTION: -gridcolor
1461# ----------------------------------------------------------------------
1462itcl::configbody Rappture::NumberResult::gridcolor {
1463    if {"" == $itk_option(-gridcolor)} {
1464        $itk_component(plot) grid off
1465    } else {
1466        $itk_component(plot) grid configure -color $itk_option(-gridcolor)
1467        $itk_component(plot) grid on
1468    }
1469}
Note: See TracBrowser for help on using the repository browser.