source: trunk/gui/scripts/historesult.tcl @ 822

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