source: branches/blt4/gui/scripts/numberresult.tcl @ 1676

Last change on this file since 1676 was 1650, checked in by gah, 14 years ago
File size: 43.1 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]
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        set results [$g element closest $x $y -interpolate yes]
814        if { $results != "" } {
815            array set info $results
816            # for dealing with xy line plots
817            set elem $info(name)
818            foreach {mapx mapy} [_getAxes $_elem2dobj($elem)] break
819
820            # search again for an exact point -- this time don't interpolate
821            set tip ""
822            array unset info
823            set results [$g element closest $x $y -interpolate no]
824            array set info $results
825            if { [info exists info(name)] && $info(name) == $elem } {
826
827                set x [$g axis transform $mapx $info(x)]
828                set y [$g axis transform $mapy $info(y)]
829
830                if {[info exists _elem2dobj($elem)]} {
831                    set dataobj $_elem2dobj($elem)
832                    set tip [_getInfo about.label $dataobj y]
833                    if {[info exists info(y)]} {
834                        set val [_axis format y dummy $info(y)]
835                        set units [_getInfo units $dataobj y]
836                        append tip "\n$val$units"
837
838                        if {[info exists _dobj2param($dataobj)]} {
839                            set val [lindex $_dobj2param($dataobj) 0]
840                            append tip " @ $val"
841                        }
842                    }
843                    set tip [string trim $tip]
844                }
845            }
846            set state 1
847        } else {
848            set results [$g element closest $x $y -interpolate no]
849            if { $results != ""  } {
850                array unset info
851                array set info $results
852
853                # for dealing with xy scatter plot
854                set elem $info(name)
855                foreach {mapx mapy} [_getAxes $_elem2dobj($elem)] break
856               
857                # search again for an exact point -- this time don't interpolate
858                set tip ""
859                if {$info(name) == $elem} {
860                    set x [$g axis transform $mapx $info(x)]
861                    set y [$g axis transform $mapy $info(y)]
862                   
863                    if {[info exists _elem2dobj($elem)]} {
864                        set dataobj $_elem2dobj($elem)
865                        set tip [_getInfo about.label $dataobj y]
866                        if {[info exists info(y)]} {
867                            set val [_axis format y dummy $info(y)]
868                            set units [_getInfo units $dataobj y]
869                            append tip "\n$val$units"
870                           
871                            if {[info exists _dobj2param($dataobj)]} {
872                                set val [lindex $_dobj2param($dataobj) 0]
873                                append tip " @ $val"
874                            }
875                        }
876                        set tip [string trim $tip]
877                    }
878                }
879                set state 1
880            } else {
881                set state 0
882            }
883        }
884    }
885    if {$state} {
886        #
887        # Highlight ON:
888        # - activate trace
889        # - multiple axes? dim other axes
890        # - pop up tooltip about data
891        #
892        if {$_hilite(elem) != "" && $_hilite(elem) != $elem} {
893            $g element deactivate $_hilite(elem)
894            $g crosshairs configure -hide yes
895            Rappture::Tooltip::tooltip cancel
896        }
897        $g element activate $elem
898        set _hilite(elem) $elem
899
900        set dlist [$g element show]
901        set i [lsearch -exact $dlist $elem]
902        if {$i >= 0} {
903            set dlist [lreplace $dlist $i $i]
904            lappend dlist $elem
905            $g element show $dlist
906        }
907
908        foreach {mapx mapy} [_getAxes $_elem2dobj($elem)] break
909
910        set allx [$g x2axis use]
911        if {[llength $allx] > 0} {
912            lappend allx x  ;# fix main x-axis too
913            foreach axis $allx {
914                if {$axis == $mapx} {
915                    $g axis configure $axis -color $itk_option(-foreground) \
916                        -titlecolor $itk_option(-foreground)
917                } else {
918                    $g axis configure $axis -color $itk_option(-dimcolor) \
919                        -titlecolor $itk_option(-dimcolor)
920                }
921            }
922        }
923        set ally [$g y2axis use]
924        if {[llength $ally] > 0} {
925            lappend ally y  ;# fix main y-axis too
926            foreach axis $ally {
927                if {$axis == $mapy} {
928                    $g axis configure $axis -color $itk_option(-foreground) \
929                        -titlecolor $itk_option(-foreground)
930                } else {
931                    $g axis configure $axis -color $itk_option(-dimcolor) \
932                        -titlecolor $itk_option(-dimcolor)
933                }
934            }
935        }
936
937        if {"" != $tip} {
938            $g crosshairs configure -hide no -position @$x,$y
939
940            if {$x > 0.5*[winfo width $g]} {
941                if {$x < 4} {
942                    set tipx "-0"
943                } else {
944                    set tipx "-[expr {$x-4}]"  ;# move tooltip to the left
945                }
946            } else {
947                if {$x < -4} {
948                    set tipx "+0"
949                } else {
950                    set tipx "+[expr {$x+4}]"  ;# move tooltip to the right
951                }
952            }
953            if {$y > 0.5*[winfo height $g]} {
954                if {$y < 4} {
955                    set tipy "-0"
956                } else {
957                    set tipy "-[expr {$y-4}]"  ;# move tooltip to the top
958                }
959            } else {
960                if {$y < -4} {
961                    set tipy "+0"
962                } else {
963                    set tipy "+[expr {$y+4}]"  ;# move tooltip to the bottom
964                }
965            }
966            Rappture::Tooltip::text $g $tip
967            Rappture::Tooltip::tooltip show $g $tipx,$tipy
968        }
969    } else {
970        #
971        # Highlight OFF:
972        # - deactivate (color back to normal)
973        # - put all axes back to normal color
974        # - take down tooltip
975        #
976        if {"" != $_hilite(elem)} {
977            $g element deactivate $_hilite(elem)
978
979            set allx [$g x2axis use]
980            if {[llength $allx] > 0} {
981                lappend allx x  ;# fix main x-axis too
982                foreach axis $allx {
983                    $g axis configure $axis -color $itk_option(-foreground) \
984                        -titlecolor $itk_option(-foreground)
985                }
986            }
987
988            set ally [$g y2axis use]
989            if {[llength $ally] > 0} {
990                lappend ally y  ;# fix main y-axis too
991                foreach axis $ally {
992                    $g axis configure $axis -color $itk_option(-foreground) \
993                        -titlecolor $itk_option(-foreground)
994                }
995            }
996        }
997
998        $g crosshairs configure -hide yes
999
1000        # only cancel in plotting area or we'll mess up axes
1001        if {[$g inside $x $y]} {
1002            Rappture::Tooltip::tooltip cancel
1003        }
1004
1005        # there is no currently highlighted element
1006        set _hilite(elem) ""
1007    }
1008}
1009
1010# ----------------------------------------------------------------------
1011# USAGE: _axis hilite <axis> <state>
1012#
1013# USAGE: _axis click <axis> <x> <y>
1014# USAGE: _axis drag <axis> <x> <y>
1015# USAGE: _axis release <axis> <x> <y>
1016#
1017# USAGE: _axis edit <axis>
1018# USAGE: _axis changed <axis> <what>
1019# USAGE: _axis format <axis> <widget> <value>
1020# USAGE: _axis scale <axis> linear|log
1021#
1022# Used internally to handle editing of the x/y axes.  The hilite
1023# operation causes the axis to light up.  The edit operation pops
1024# up a panel with editing options.  The changed operation applies
1025# changes from the panel.
1026# ----------------------------------------------------------------------
1027itcl::body Rappture::NumberResult::_axis {option args} {
1028    set inner [$itk_component(hull).axes component inner]
1029
1030    switch -- $option {
1031        hilite {
1032            if {[llength $args] != 2} {
1033                error "wrong # args: should be \"_axis hilite axis state\""
1034            }
1035            set g $itk_component(plot)
1036            set axis [lindex $args 0]
1037            set state [lindex $args 1]
1038
1039            if {$state} {
1040                $g axis configure $axis \
1041                    -color $itk_option(-activecolor) \
1042                    -titlecolor $itk_option(-activecolor)
1043
1044                set x [expr {[winfo pointerx $g]+4}]
1045                set y [expr {[winfo pointery $g]+4}]
1046                Rappture::Tooltip::tooltip pending $g-$axis @$x,$y
1047            } else {
1048                $g axis configure $axis \
1049                    -color $itk_option(-foreground) \
1050                    -titlecolor $itk_option(-foreground)
1051                Rappture::Tooltip::tooltip cancel
1052            }
1053        }
1054        click {
1055            if {[llength $args] != 3} {
1056                error "wrong # args: should be \"_axis click axis x y\""
1057            }
1058            set axis [lindex $args 0]
1059            set x [lindex $args 1]
1060            set y [lindex $args 2]
1061            set g $itk_component(plot)
1062
1063            set _axis(moved) 0
1064            set _axis(click-x) $x
1065            set _axis(click-y) $y
1066            foreach {min max} [$g axis limits $axis] break
1067            set _axis(min0) $min
1068            set _axis(max0) $max
1069            Rappture::Tooltip::tooltip cancel
1070        }
1071        drag {
1072            if {[llength $args] != 3} {
1073                error "wrong # args: should be \"_axis drag axis x y\""
1074            }
1075            if {![info exists _axis(moved)]} {
1076                return  ;# must have skipped click event -- ignore
1077            }
1078            set axis [lindex $args 0]
1079            set x [lindex $args 1]
1080            set y [lindex $args 2]
1081            set g $itk_component(plot)
1082
1083            if {[info exists _axis(click-x)] && [info exists _axis(click-y)]} {
1084                foreach {x0 y0 pw ph} [$g extents plotarea] break
1085                switch -glob $axis {
1086                  x* {
1087                    set pix $x
1088                    set pix0 $_axis(click-x)
1089                    set pixmin $x0
1090                    set pixmax [expr {$x0+$pw}]
1091                  }
1092                  y* {
1093                    set pix $y
1094                    set pix0 $_axis(click-y)
1095                    set pixmin [expr {$y0+$ph}]
1096                    set pixmax $y0
1097                  }
1098                }
1099                set log [$g axis cget $axis -logscale]
1100                set min $_axis(min0)
1101                set max $_axis(max0)
1102                set dpix [expr {abs($pix-$pix0)}]
1103                set v0 [$g axis invtransform $axis $pixmin]
1104                set v1 [$g axis invtransform $axis [expr {$pixmin+$dpix}]]
1105                if {$log} {
1106                    set v0 [expr {log10($v0)}]
1107                    set v1 [expr {log10($v1)}]
1108                    set min [expr {log10($min)}]
1109                    set max [expr {log10($max)}]
1110                }
1111
1112                if {$pix > $pix0} {
1113                    set delta [expr {$v1-$v0}]
1114                } else {
1115                    set delta [expr {$v0-$v1}]
1116                }
1117                set min [expr {$min-$delta}]
1118                set max [expr {$max-$delta}]
1119                if {$log} {
1120                    set min [expr {pow(10.0,$min)}]
1121                    set max [expr {pow(10.0,$max)}]
1122                }
1123                $g axis configure $axis -min $min -max $max
1124
1125                # move axis, don't edit on release
1126                set _axis(move) 1
1127            }
1128        }
1129        release {
1130            if {[llength $args] != 3} {
1131                error "wrong # args: should be \"_axis release axis x y\""
1132            }
1133            if {![info exists _axis(moved)]} {
1134                return  ;# must have skipped click event -- ignore
1135            }
1136            set axis [lindex $args 0]
1137            set x [lindex $args 1]
1138            set y [lindex $args 2]
1139
1140            if {!$_axis(moved)} {
1141                # small movement? then treat as click -- pop up axis editor
1142                set dx [expr {abs($x-$_axis(click-x))}]
1143                set dy [expr {abs($y-$_axis(click-y))}]
1144                if {$dx < 2 && $dy < 2} {
1145                    _axis edit $axis
1146                }
1147            } else {
1148                # one last movement
1149                _axis drag $axis $x $y
1150            }
1151            catch {unset _axis}
1152        }
1153        edit {
1154            if {[llength $args] != 1} {
1155                error "wrong # args: should be \"_axis edit axis\""
1156            }
1157            set axis [lindex $args 0]
1158            set _axisPopup(current) $axis
1159
1160            # apply last value when deactivating
1161            $itk_component(hull).axes configure -deactivatecommand \
1162                [itcl::code $this _axis changed $axis focus]
1163
1164            # fix axis label controls...
1165            set label [$itk_component(plot) axis cget $axis -title]
1166            $inner.label delete 0 end
1167            $inner.label insert end $label
1168            bind $inner.label <KeyPress-Return> \
1169                [itcl::code $this _axis changed $axis label]
1170            bind $inner.label <FocusOut> \
1171                [itcl::code $this _axis changed $axis label]
1172
1173            # fix min/max controls...
1174            foreach {min max} [$itk_component(plot) axis limits $axis] break
1175            $inner.min delete 0 end
1176            $inner.min insert end $min
1177            bind $inner.min <KeyPress-Return> \
1178                [itcl::code $this _axis changed $axis min]
1179            bind $inner.min <FocusOut> \
1180                [itcl::code $this _axis changed $axis min]
1181
1182            $inner.max delete 0 end
1183            $inner.max insert end $max
1184            bind $inner.max <KeyPress-Return> \
1185                [itcl::code $this _axis changed $axis max]
1186            bind $inner.max <FocusOut> \
1187                [itcl::code $this _axis changed $axis max]
1188
1189            # fix format control...
1190            set fmts [$inner.format choices get -value]
1191            set i [lsearch -exact $fmts $_axisPopup(format-$axis)]
1192            if {$i < 0} { set i 0 }  ;# use Auto choice
1193            $inner.format value [$inner.format choices get -label $i]
1194
1195            bind $inner.format <<Value>> \
1196                [itcl::code $this _axis changed $axis format]
1197
1198            # fix scale control...
1199            if {[$itk_component(plot) axis cget $axis -logscale]} {
1200                set _axisPopup(scale) "log"
1201                $inner.format configure -state disabled
1202            } else {
1203                set _axisPopup(scale) "linear"
1204                $inner.format configure -state normal
1205            }
1206            $inner.scales.linear configure \
1207                -command [itcl::code $this _axis changed $axis scale]
1208            $inner.scales.log configure \
1209                -command [itcl::code $this _axis changed $axis scale]
1210
1211            #
1212            # Figure out where the window should pop up.
1213            #
1214            set x [winfo rootx $itk_component(plot)]
1215            set y [winfo rooty $itk_component(plot)]
1216            set w [winfo width $itk_component(plot)]
1217            set h [winfo height $itk_component(plot)]
1218            foreach {x0 y0 pw ph} [$itk_component(plot) extents plotarea] break
1219            switch -glob -- $axis {
1220                x {
1221                    set x [expr {round($x + $x0+0.5*$pw)}]
1222                    set y [expr {round($y + $y0+$ph + 0.5*($h-$y0-$ph))}]
1223                    set dir "above"
1224                }
1225                x* {
1226                    set x [expr {round($x + $x0+0.5*$pw)}]
1227                    set dir "below"
1228                    set allx [$itk_component(plot) x2axis use]
1229                    set max [llength $allx]
1230                    set i [lsearch -exact $allx $axis]
1231                    set y [expr {round($y + ($i+0.5)*$y0/double($max))}]
1232                }
1233                y {
1234                    set x [expr {round($x + 0.5*$x0)}]
1235                    set y [expr {round($y + $y0+0.5*$ph)}]
1236                    set dir "right"
1237                }
1238                y* {
1239                    set y [expr {round($y + $y0+0.5*$ph)}]
1240                    set dir "left"
1241                    set ally [$itk_component(plot) y2axis use]
1242                    set max [llength $ally]
1243                    set i [lsearch -exact $ally $axis]
1244                    set y [expr {round($y + ($i+0.5)*$y0/double($max))}]
1245                    set x [expr {round($x+$x0+$pw + ($i+0.5)*($w-$x0-$pw)/double($max))}]
1246                }
1247            }
1248            $itk_component(hull).axes activate @$x,$y $dir
1249        }
1250        changed {
1251            if {[llength $args] != 2} {
1252                error "wrong # args: should be \"_axis changed axis what\""
1253            }
1254            set axis [lindex $args 0]
1255            set what [lindex $args 1]
1256            if {$what == "focus"} {
1257                set what [focus]
1258                if {[winfo exists $what]} {
1259                    set what [winfo name $what]
1260                }
1261            }
1262
1263            switch -- $what {
1264                label {
1265                    set val [$inner.label get]
1266                    $itk_component(plot) axis configure $axis -title $val
1267                }
1268                min {
1269                    set val [$inner.min get]
1270                    if {![string is double -strict $val]} {
1271                        Rappture::Tooltip::cue $inner.min "Must be a number"
1272                        bell
1273                        return
1274                    }
1275
1276                    set max [lindex [$itk_component(plot) axis limits $axis] 1]
1277                    if {$val >= $max} {
1278                        Rappture::Tooltip::cue $inner.min "Must be <= max ($max)"
1279                        bell
1280                        return
1281                    }
1282                    catch {
1283                        # can fail in log mode
1284                        $itk_component(plot) axis configure $axis -min $val
1285                    }
1286                    foreach {min max} [$itk_component(plot) axis limits $axis] break
1287                    $inner.min delete 0 end
1288                    $inner.min insert end $min
1289                }
1290                max {
1291                    set val [$inner.max get]
1292                    if {![string is double -strict $val]} {
1293                        Rappture::Tooltip::cue $inner.max "Should be a number"
1294                        bell
1295                        return
1296                    }
1297
1298                    set min [lindex [$itk_component(plot) axis limits $axis] 0]
1299                    if {$val <= $min} {
1300                        Rappture::Tooltip::cue $inner.max "Must be >= min ($min)"
1301                        bell
1302                        return
1303                    }
1304                    catch {
1305                        # can fail in log mode
1306                        $itk_component(plot) axis configure $axis -max $val
1307                    }
1308                    foreach {min max} [$itk_component(plot) axis limits $axis] break
1309                    $inner.max delete 0 end
1310                    $inner.max insert end $max
1311                }
1312                format {
1313                    set fmt [$inner.format translate [$inner.format value]]
1314                    set _axisPopup(format-$axis) $fmt
1315
1316                    # force a refresh
1317                    $itk_component(plot) axis configure $axis -min \
1318                        [$itk_component(plot) axis cget $axis -min]
1319                }
1320                scale {
1321                    _axis scale $axis $_axisPopup(scale)
1322
1323                    if {$_axisPopup(scale) == "log"} {
1324                        $inner.format configure -state disabled
1325                    } else {
1326                        $inner.format configure -state normal
1327                    }
1328
1329                    foreach {min max} [$itk_component(plot) axis limits $axis] break
1330                    $inner.min delete 0 end
1331                    $inner.min insert end $min
1332                    $inner.max delete 0 end
1333                    $inner.max insert end $max
1334                }
1335                default {
1336                    # be lenient so we can handle the "focus" case
1337                }
1338            }
1339        }
1340        format {
1341            if {[llength $args] != 3} {
1342                error "wrong # args: should be \"_axis format axis widget value\""
1343            }
1344            set axis [lindex $args 0]
1345            set value [lindex $args 2]
1346
1347            if {$axis == "x" && $_xlabels
1348                  && [info exists _xval2label($value)]} {
1349                return $_xval2label($value)
1350            }
1351            if {[$itk_component(plot) axis cget $axis -logscale]} {
1352                set fmt "%.3g"
1353            } else {
1354                set fmt $_axisPopup(format-$axis)
1355            }
1356            return [format $fmt $value]
1357        }
1358        scale {
1359            if {[llength $args] != 2} {
1360                error "wrong # args: should be \"_axis scale axis type\""
1361            }
1362            set axis [lindex $args 0]
1363            set type [lindex $args 1]
1364
1365            if {$type == "log"} {
1366                catch {$itk_component(plot) axis configure $axis -logscale 1}
1367                # leave format alone in log mode
1368                $itk_component(plot) axis configure $axis -command ""
1369            } else {
1370                catch {$itk_component(plot) axis configure $axis -logscale 0}
1371                # use special formatting for linear mode
1372                $itk_component(plot) axis configure $axis -command \
1373                    [itcl::code $this _axis format $axis]
1374            }
1375        }
1376        default {
1377            error "bad option \"$option\": should be changed, edit, hilite, or format"
1378        }
1379    }
1380}
1381
1382# ----------------------------------------------------------------------
1383# USAGE: _getAxes <dataObj>
1384#
1385# Used internally to figure out the axes used to plot the given
1386# <dataObj>.  Returns a list of the form {x y}, where x is the
1387# x-axis name (x, x2, x3, etc.), and y is the y-axis name.
1388# ----------------------------------------------------------------------
1389itcl::body Rappture::NumberResult::_getAxes {xydata} {
1390    # rebuild if needed, so we know about the axes
1391    if {[$_dispatcher ispending !rebuild]} {
1392        $_dispatcher cancel !rebuild
1393        $_dispatcher event -now !rebuild
1394    }
1395
1396    # what is the x axis?  x? x2? x3? ...
1397    set xlabel "Simulation #"
1398    if {[info exists _label2axis(x-$xlabel)]} {
1399        set mapx $_label2axis(x-$xlabel)
1400    } else {
1401        set mapx "x"
1402    }
1403
1404    # what is the y axis?  y? y2? y3? ...
1405    set ylabel [$xydata get about.label]
1406    if {[info exists _label2axis(y-$ylabel)]} {
1407        set mapy $_label2axis(y-$ylabel)
1408    } else {
1409        set mapy "y"
1410    }
1411
1412    return [list $mapx $mapy]
1413}
1414
1415# ----------------------------------------------------------------------
1416# USAGE: _getValue <dataObj> ?<axis>?
1417#
1418# Used internally to get the {x y} value from this <dataObj>.
1419# Returns x, y, or {x y} in the expected units for this object.
1420# ----------------------------------------------------------------------
1421itcl::body Rappture::NumberResult::_getValue {xydata {which both}} {
1422    if {[info exists _dobj2param($xydata)]} {
1423        set x [lindex $_dobj2param($xydata) 1]
1424    } else {
1425        set x 0
1426    }
1427
1428    set y [$xydata get current]
1429    set units [$xydata get units]
1430    if {$units != ""} {
1431        set y [Rappture::Units::convert $y -context $units -to $units -units off]
1432    }
1433    if {![string is double -strict $y]} {
1434        set y 0
1435    }
1436
1437    switch -- $which {
1438        x { return $x }
1439        y { return $y }
1440        both { return [list $x $y] }
1441        default { error "bad value \"$which\": should be x, y, both" }
1442    }
1443}
1444
1445# ----------------------------------------------------------------------
1446# USAGE: _getInfo <what> <dataObj> ?<axis>?
1447#
1448# Used internally to get the {x y} labels from this <dataObj>.
1449# Returns xlabel, ylabel, or {xlabel ylabel}.
1450# ----------------------------------------------------------------------
1451itcl::body Rappture::NumberResult::_getInfo {what xydata {which both}} {
1452    set x [lindex $_params 0]
1453    set y [$xydata get $what]
1454    if {$what == "about.label"} {
1455        set units [$xydata get units]
1456        if {"" != $units} {
1457            append y " ($units)"
1458        }
1459    }
1460
1461    switch -- $which {
1462        x { return $x }
1463        y { return $y }
1464        both { return [list $x $y] }
1465        default { error "bad value \"$which\": should be x, y, both" }
1466    }
1467}
1468
1469# ----------------------------------------------------------------------
1470# CONFIGURATION OPTION: -gridcolor
1471# ----------------------------------------------------------------------
1472itcl::configbody Rappture::NumberResult::gridcolor {
1473    if { "" == $itk_option(-gridcolor) } {
1474        foreach axis [$itk_component(plot) axis names] {
1475            $itk_component(plot) axis configure $axis -grid off
1476        }
1477    } else {
1478        foreach axis [$itk_component(plot) axis names] {
1479            $itk_component(plot) axis configure $axis \
1480                -gridcolor $itk_option(-gridcolor) -grid on
1481        }
1482    }
1483}
Note: See TracBrowser for help on using the repository browser.