[3330] | 1 | # -*- mode: tcl; indent-tabs-mode: nil -*- |
---|
[1127] | 2 | |
---|
| 3 | # ---------------------------------------------------------------------- |
---|
| 4 | # COMPONENT: xylegend - X/Y plot legend. |
---|
| 5 | # |
---|
| 6 | # This widget is a legend for an X/Y plot, meant to view line graphs produced |
---|
| 7 | # as output from the run of a Rappture tool. Use the "add" and |
---|
| 8 | # "delete" methods to control the curves showing on the plot. |
---|
| 9 | # ====================================================================== |
---|
| 10 | # AUTHOR: Michael McLennan, Purdue University |
---|
[3177] | 11 | # Copyright (c) 2004-2012 HUBzero Foundation, LLC |
---|
[1127] | 12 | # |
---|
| 13 | # See the file "license.terms" for information on usage and |
---|
| 14 | # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
---|
| 15 | # ====================================================================== |
---|
| 16 | package require Itk |
---|
| 17 | package require BLT |
---|
| 18 | |
---|
[1129] | 19 | option add *Xylegend.font \ |
---|
| 20 | -*-helvetica-medium-r-normal-*-8-* widgetDefault |
---|
[1127] | 21 | |
---|
[1129] | 22 | option add *Xylegend.Button.font \ |
---|
| 23 | -*-helvetica-medium-r-normal-*-9-* widgetDefault |
---|
| 24 | |
---|
[1127] | 25 | itcl::class ::Rappture::XyLegend { |
---|
| 26 | inherit itk::Widget |
---|
| 27 | |
---|
[1943] | 28 | private variable _autocolors { |
---|
[1694] | 29 | #0000cd |
---|
| 30 | #cd0000 |
---|
| 31 | #00cd00 |
---|
| 32 | #3a5fcd |
---|
| 33 | #cdcd00 |
---|
| 34 | #cd1076 |
---|
| 35 | #009acd |
---|
| 36 | #00c5cd |
---|
| 37 | #a2b5cd |
---|
| 38 | #7ac5cd |
---|
| 39 | #66cdaa |
---|
| 40 | #a2cd5a |
---|
| 41 | #cd9b9b |
---|
| 42 | #cdba96 |
---|
| 43 | #cd3333 |
---|
| 44 | #cd6600 |
---|
| 45 | #cd8c95 |
---|
| 46 | #cd00cd |
---|
| 47 | #9a32cd |
---|
| 48 | #6ca6cd |
---|
| 49 | #9ac0cd |
---|
| 50 | #9bcd9b |
---|
| 51 | #00cd66 |
---|
| 52 | #cdc673 |
---|
| 53 | #cdad00 |
---|
| 54 | #cd5555 |
---|
| 55 | #cd853f |
---|
| 56 | #cd7054 |
---|
| 57 | #cd5b45 |
---|
| 58 | #cd6889 |
---|
| 59 | #cd69c9 |
---|
| 60 | #551a8b |
---|
[1152] | 61 | } |
---|
[1943] | 62 | private variable _lastColorIndex "" |
---|
[1127] | 63 | private variable _dispatcher "" ;# dispatcher for !events |
---|
[2744] | 64 | private variable _graph "" |
---|
| 65 | private variable _tree "" |
---|
| 66 | private variable _diff ""; # Polygon marker used for difference. |
---|
| 67 | private variable _rename ""; # Node selected to be renamed. |
---|
[1943] | 68 | private variable _diffelements |
---|
[2695] | 69 | private variable _unmapHidden 0 |
---|
[1127] | 70 | |
---|
[1943] | 71 | constructor {graph args} {} |
---|
[1127] | 72 | destructor {} |
---|
| 73 | |
---|
[3765] | 74 | public method reset { list } |
---|
[2695] | 75 | |
---|
| 76 | private method Add { elem label {flags ""}} |
---|
| 77 | private method Average {} |
---|
| 78 | private method BuildPopup { popup } |
---|
[2699] | 79 | private method Check {} |
---|
[2695] | 80 | private method Delete { args } |
---|
| 81 | private method Difference {} |
---|
| 82 | private method Editor { option args } |
---|
[1127] | 83 | private method GetData { elem what } |
---|
[2695] | 84 | private method Hide { args } |
---|
| 85 | private method Lower { args } |
---|
| 86 | private method Raise { args } |
---|
| 87 | private method PopupMenu { x y } |
---|
| 88 | private method Rename {} |
---|
[1127] | 89 | private method SelectAll {} |
---|
[2695] | 90 | private method Show { args } |
---|
| 91 | private method Toggle { args } |
---|
| 92 | private method UnmapHidden {} |
---|
[1127] | 93 | } |
---|
[1694] | 94 | |
---|
[1127] | 95 | itk::usual XyLegend { |
---|
[1129] | 96 | keep -background -foreground -cursor |
---|
[1127] | 97 | } |
---|
| 98 | |
---|
| 99 | itk::usual TreeView { |
---|
[1129] | 100 | keep -background -foreground -cursor |
---|
[1127] | 101 | } |
---|
| 102 | |
---|
| 103 | blt::bitmap define dot1 { |
---|
| 104 | #define dot1_width 8 |
---|
| 105 | #define dot1_height 8 |
---|
| 106 | static unsigned char dot1_bits[] = { |
---|
| 107 | 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa}; |
---|
| 108 | } |
---|
| 109 | |
---|
| 110 | # ---------------------------------------------------------------------- |
---|
| 111 | # CONSTRUCTOR |
---|
| 112 | # ---------------------------------------------------------------------- |
---|
| 113 | itcl::body Rappture::XyLegend::constructor { graph args } { |
---|
| 114 | option add hull.width hull.height |
---|
[1252] | 115 | pack propagate $itk_component(hull) no |
---|
[1127] | 116 | itk_component add scrollbars { |
---|
[1694] | 117 | Rappture::Scroller $itk_interior.scrl \ |
---|
| 118 | -xscrollmode auto -yscrollmode auto \ |
---|
| 119 | -width 200 -height 100 |
---|
[1127] | 120 | } |
---|
[1943] | 121 | set _tree [blt::tree create] |
---|
[1127] | 122 | itk_component add legend { |
---|
[1694] | 123 | blt::treeview $itk_component(scrollbars).legend -linewidth 0 \ |
---|
| 124 | -bg white -selectmode multiple \ |
---|
| 125 | -highlightthickness 0 \ |
---|
[1943] | 126 | -tree $_tree \ |
---|
[1694] | 127 | -font "Arial 9" \ |
---|
| 128 | -flat yes -separator / |
---|
[1127] | 129 | } |
---|
| 130 | $itk_component(scrollbars) contents $itk_component(legend) |
---|
[1128] | 131 | $itk_component(legend) column insert 0 "show" \ |
---|
[1694] | 132 | -text "" -weight 0.0 -pad 0 -borderwidth 0 |
---|
[1127] | 133 | $itk_component(legend) style checkbox "check" -showvalue no \ |
---|
[1694] | 134 | -onvalue 0 -offvalue 1 \ |
---|
| 135 | -boxcolor grey50 -checkcolor black -activebackground grey90 |
---|
[1128] | 136 | $itk_component(legend) column configure "treeView" -justify left \ |
---|
[2977] | 137 | -weight 1.0 -text "" -pad 0 -borderwidth 0 -edit no |
---|
[1128] | 138 | $itk_component(legend) column configure "show" -style "check" -pad {0 0} \ |
---|
[1694] | 139 | -edit yes |
---|
[1127] | 140 | itk_component add controls { |
---|
[1694] | 141 | frame $itk_component(hull).controls -width 100 -relief sunken -bd 2 |
---|
[1127] | 142 | } |
---|
| 143 | set controls $itk_component(controls) |
---|
| 144 | grid $itk_component(controls) -column 0 -row 1 -sticky nsew |
---|
[1140] | 145 | grid columnconfigure $itk_component(hull) 0 -weight 1 |
---|
[1141] | 146 | grid rowconfigure $itk_component(hull) 1 \ |
---|
[1694] | 147 | -minsize [winfo reqheight $itk_component(scrollbars)] |
---|
[1127] | 148 | grid rowconfigure $itk_component(hull) 0 -weight 1 |
---|
| 149 | grid $itk_component(scrollbars) -column 0 -row 0 -sticky nsew |
---|
| 150 | set commands { |
---|
[1694] | 151 | hide "" |
---|
| 152 | show "" |
---|
| 153 | toggle "" |
---|
| 154 | raise findup |
---|
| 155 | lower finddn |
---|
| 156 | average "" |
---|
| 157 | difference "" |
---|
| 158 | delete "" |
---|
| 159 | rename "" |
---|
[1127] | 160 | } |
---|
| 161 | foreach { but icon} $commands { |
---|
[1694] | 162 | set title [string totitle $but] |
---|
| 163 | button $controls.$but -text $title \ |
---|
| 164 | -relief flat -pady 0 -padx 0 -font "Arial 9" \ |
---|
| 165 | -command [itcl::code $this $title] -overrelief flat \ |
---|
| 166 | -activebackground grey90 |
---|
[1127] | 167 | } |
---|
[1132] | 168 | grid $controls.hide -column 0 -row 0 -sticky w |
---|
| 169 | grid $controls.show -column 0 -row 1 -sticky w |
---|
[1127] | 170 | grid $controls.toggle -column 0 -row 2 -sticky w |
---|
| 171 | grid $controls.raise -column 0 -row 3 -sticky w |
---|
| 172 | grid $controls.lower -column 0 -row 4 -sticky w |
---|
| 173 | grid $controls.difference -column 1 -row 0 -sticky w |
---|
| 174 | grid $controls.average -column 1 -row 1 -sticky w |
---|
[1132] | 175 | grid $controls.rename -column 1 -row 2 -sticky w |
---|
| 176 | grid $controls.delete -column 1 -row 3 -sticky w |
---|
[1127] | 177 | |
---|
| 178 | grid columnconfigure $controls 0 -weight 1 |
---|
| 179 | grid columnconfigure $controls 1 -weight 1 |
---|
| 180 | |
---|
[1943] | 181 | set _graph $graph |
---|
[1127] | 182 | set cmd [itcl::code $this Toggle current] |
---|
| 183 | $itk_component(legend) bind CheckBoxStyle <ButtonRelease-1> \ |
---|
[1694] | 184 | [itcl::code [subst -nocommands { |
---|
| 185 | if { [%W edit -root -test %X %Y] } { |
---|
| 186 | %W edit -root %X %Y |
---|
| 187 | $this Toggle [%W nearest -root %X %Y] |
---|
| 188 | break |
---|
| 189 | } |
---|
| 190 | }]] |
---|
[1128] | 191 | bind $itk_component(legend) <Enter> { focus %W } |
---|
[1127] | 192 | $itk_component(legend) bind Entry <Control-KeyRelease-a> \ |
---|
[1694] | 193 | [itcl::code $this SelectAll] |
---|
[1128] | 194 | $itk_component(legend) bind Entry <KeyRelease-Return> \ |
---|
[1694] | 195 | +[itcl::code $this Toggle focus] |
---|
[1127] | 196 | $itk_component(legend) bind Entry <Escape> \ |
---|
[1694] | 197 | "$itk_component(legend) selection clearall" |
---|
[1127] | 198 | $itk_component(legend) configure -selectcommand \ |
---|
[1694] | 199 | [itcl::code $this Check] |
---|
[1132] | 200 | |
---|
| 201 | itk_component add editor { |
---|
[1694] | 202 | Rappture::Editor $itk_interior.editor \ |
---|
| 203 | -activatecommand [itcl::code $this Editor activate] \ |
---|
| 204 | -validatecommand [itcl::code $this Editor validate] \ |
---|
| 205 | -applycommand [itcl::code $this Editor apply] |
---|
[1132] | 206 | } |
---|
[1943] | 207 | set _lastColorIndex [llength $_autocolors] |
---|
[1127] | 208 | Check |
---|
| 209 | eval itk_initialize $args |
---|
| 210 | } |
---|
| 211 | |
---|
| 212 | # ---------------------------------------------------------------------- |
---|
| 213 | # DESTRUCTOR |
---|
| 214 | # ---------------------------------------------------------------------- |
---|
| 215 | itcl::body Rappture::XyLegend::destructor {} { |
---|
[1943] | 216 | foreach node [$_tree children root] { |
---|
| 217 | $_tree delete $node |
---|
[1152] | 218 | } |
---|
[1943] | 219 | if { $_diff != "" } { |
---|
| 220 | catch { $_graph marker delete $_diff } |
---|
[1152] | 221 | } |
---|
[1127] | 222 | } |
---|
| 223 | |
---|
| 224 | itcl::body Rappture::XyLegend::Add { elem label {flags ""} } { |
---|
[1943] | 225 | set hide [$_graph element cget $elem -hide] |
---|
[1127] | 226 | set im [image create photo] |
---|
[1943] | 227 | $_graph legend icon $elem $im |
---|
[1127] | 228 | set data(show) $hide |
---|
| 229 | set data(delete) [expr { $flags == "-delete" }] |
---|
[1943] | 230 | set node [$_tree insert root -at 0 -label $elem -data [array get data]] |
---|
[1128] | 231 | $itk_component(legend) entry configure $node -label $label -icon $im \ |
---|
[1694] | 232 | -activeicon $im |
---|
[1152] | 233 | update idletasks |
---|
[1128] | 234 | return $node |
---|
[1127] | 235 | } |
---|
| 236 | |
---|
| 237 | # ---------------------------------------------------------------------- |
---|
[3765] | 238 | # USAGE: reset |
---|
[1127] | 239 | # |
---|
| 240 | # Clients use this to add a curve to the plot. The optional <settings> |
---|
| 241 | # are used to configure the plot. Allowed settings are -color, |
---|
| 242 | # -brightness, -width, -linestyle and -raise. |
---|
| 243 | # ---------------------------------------------------------------------- |
---|
[3765] | 244 | itcl::body Rappture::XyLegend::reset { list } { |
---|
[1943] | 245 | foreach node [$_tree children root] { |
---|
| 246 | $_tree delete $node |
---|
[1152] | 247 | } |
---|
[3765] | 248 | foreach elem $list { |
---|
[2943] | 249 | if {[catch {$_graph element cget $elem -label} label] == 0} { |
---|
| 250 | if {$label eq ""} { |
---|
| 251 | set label $elem |
---|
| 252 | } |
---|
| 253 | Add $elem $label |
---|
[1694] | 254 | } |
---|
[1127] | 255 | } |
---|
| 256 | $itk_component(legend) open -recurse root |
---|
[1152] | 257 | Check |
---|
[1127] | 258 | } |
---|
| 259 | |
---|
| 260 | itcl::body Rappture::XyLegend::Hide { args } { |
---|
| 261 | if { $args == "" } { |
---|
[1694] | 262 | set nodes [$itk_component(legend) curselection] |
---|
[1127] | 263 | } else { |
---|
[1694] | 264 | set nodes $args |
---|
[1127] | 265 | } |
---|
| 266 | foreach node $nodes { |
---|
[1943] | 267 | set elem [$_tree label $node] |
---|
| 268 | if { ![$_graph element exists $elem] } { |
---|
[1694] | 269 | continue |
---|
| 270 | } |
---|
[1943] | 271 | $_graph element configure $elem -hide yes |
---|
| 272 | $_tree set $node "show" 1 |
---|
[1127] | 273 | } |
---|
| 274 | } |
---|
| 275 | |
---|
| 276 | itcl::body Rappture::XyLegend::Show { args } { |
---|
| 277 | if { $args == "" } { |
---|
[1694] | 278 | set nodes [$itk_component(legend) curselection] |
---|
[1127] | 279 | } else { |
---|
[1694] | 280 | set nodes $args |
---|
[1127] | 281 | } |
---|
| 282 | foreach node $nodes { |
---|
[1943] | 283 | set elem [$_tree label $node] |
---|
| 284 | if { ![$_graph element exists $elem] } { |
---|
[1694] | 285 | continue |
---|
| 286 | } |
---|
[1943] | 287 | $_graph element configure $elem -hide no |
---|
| 288 | $_tree set $node "show" 0 |
---|
[1127] | 289 | } |
---|
| 290 | } |
---|
| 291 | |
---|
| 292 | itcl::body Rappture::XyLegend::Toggle { args } { |
---|
| 293 | if { $args == "" } { |
---|
[1694] | 294 | set nodes [$itk_component(legend) curselection] |
---|
[1127] | 295 | } else { |
---|
[1694] | 296 | set nodes $args |
---|
[1127] | 297 | } |
---|
| 298 | foreach node $nodes { |
---|
[1943] | 299 | set elem [$_tree label $node] |
---|
| 300 | if { ![$_graph element exists $elem] } { |
---|
[1694] | 301 | continue |
---|
| 302 | } |
---|
[1943] | 303 | set hide [$_graph element cget $elem -hide] |
---|
[1694] | 304 | set hide [expr $hide==0] |
---|
[1943] | 305 | $_tree set $node "show" $hide |
---|
| 306 | $_graph element configure $elem -hide $hide |
---|
[1127] | 307 | } |
---|
| 308 | } |
---|
| 309 | |
---|
| 310 | itcl::body Rappture::XyLegend::Raise { args } { |
---|
| 311 | if { $args == "" } { |
---|
[1694] | 312 | set nodes [$itk_component(legend) curselection] |
---|
[1127] | 313 | } else { |
---|
[1694] | 314 | set nodes $args |
---|
[1127] | 315 | } |
---|
| 316 | set elements {} |
---|
| 317 | foreach node $nodes { |
---|
[1943] | 318 | set elem [$_tree label $node] |
---|
[1694] | 319 | set found($elem) 1 |
---|
| 320 | set elements [linsert $elements 0 $elem] |
---|
[1127] | 321 | } |
---|
| 322 | foreach elem $elements { |
---|
[1943] | 323 | $_tree move [$_tree index $elem] 0 -at 0 |
---|
[1127] | 324 | } |
---|
| 325 | set list {} |
---|
[1943] | 326 | foreach elem [$_graph element show] { |
---|
[1694] | 327 | if { [info exists found($elem)] } { |
---|
| 328 | continue |
---|
| 329 | } |
---|
| 330 | lappend list $elem |
---|
[1127] | 331 | } |
---|
[1943] | 332 | $_graph element show [concat $list $elements] |
---|
[1127] | 333 | } |
---|
| 334 | |
---|
| 335 | itcl::body Rappture::XyLegend::Lower { args } { |
---|
| 336 | if { $args == "" } { |
---|
[1694] | 337 | set nodes [$itk_component(legend) curselection] |
---|
[1127] | 338 | } else { |
---|
[1694] | 339 | set nodes $args |
---|
[1127] | 340 | } |
---|
| 341 | set elements {} |
---|
| 342 | foreach node $nodes { |
---|
[1943] | 343 | set elem [$_tree label $node] |
---|
[1694] | 344 | set found($elem) 1 |
---|
| 345 | set elements [linsert $elements 0 $elem] |
---|
[1127] | 346 | } |
---|
[1943] | 347 | set pos [$_tree degree 0] |
---|
[1130] | 348 | |
---|
[1127] | 349 | foreach elem $elements { |
---|
[1694] | 350 | incr pos -1 |
---|
[1943] | 351 | $_tree move [$_tree index $elem] 0 -at $pos |
---|
[1127] | 352 | } |
---|
[1130] | 353 | |
---|
[1127] | 354 | set list {} |
---|
[1943] | 355 | foreach elem [$_graph element show] { |
---|
[1694] | 356 | if { [info exists found($elem)] } { |
---|
| 357 | continue |
---|
| 358 | } |
---|
| 359 | lappend list $elem |
---|
[1127] | 360 | } |
---|
[1943] | 361 | $_graph element show [concat $elements $list] |
---|
[1127] | 362 | } |
---|
| 363 | |
---|
| 364 | itcl::body Rappture::XyLegend::Delete { args } { |
---|
| 365 | if { $args == "" } { |
---|
[1694] | 366 | set nodes [$itk_component(legend) curselection] |
---|
[1127] | 367 | } else { |
---|
[1694] | 368 | set nodes $args |
---|
[1127] | 369 | } |
---|
| 370 | set elements {} |
---|
| 371 | set delnodes {} |
---|
| 372 | foreach node $nodes { |
---|
[1943] | 373 | if { ![$_tree get $node "delete" 0] } { |
---|
[1694] | 374 | continue |
---|
| 375 | } |
---|
[1943] | 376 | set elem [$_tree label $node] |
---|
[1694] | 377 | lappend elements $elem |
---|
| 378 | lappend delnodes $node |
---|
[1943] | 379 | if { $_diff != "" && [info exists _diffelements($elem)] } { |
---|
| 380 | $_graph marker delete $_diff |
---|
| 381 | array unset _diffelements |
---|
| 382 | set _diff "" |
---|
[1694] | 383 | } |
---|
[1127] | 384 | } |
---|
| 385 | if { [llength $delnodes] > 0 } { |
---|
[1943] | 386 | eval $_tree delete $delnodes |
---|
[1127] | 387 | } |
---|
| 388 | $itk_component(legend) selection clearall |
---|
[1943] | 389 | eval $_graph element delete $elements |
---|
[1127] | 390 | } |
---|
| 391 | |
---|
| 392 | itcl::body Rappture::XyLegend::Check {} { |
---|
| 393 | set nodes [$itk_component(legend) curselection] |
---|
[1132] | 394 | foreach n { hide show toggle raise lower |
---|
[3800] | 395 | rename average difference delete } { |
---|
[1694] | 396 | $itk_component(controls).$n configure -state disabled |
---|
[1127] | 397 | } |
---|
| 398 | foreach node $nodes { |
---|
[1943] | 399 | if { [$_tree get $node "delete" 0] } { |
---|
[1694] | 400 | $itk_component(controls).delete configure -state normal |
---|
| 401 | break |
---|
| 402 | } |
---|
[1127] | 403 | } |
---|
[1943] | 404 | if { [$_tree degree 0] > 1 && [llength $nodes] > 0 } { |
---|
[1694] | 405 | foreach n { raise lower } { |
---|
| 406 | $itk_component(controls).$n configure -state normal |
---|
| 407 | } |
---|
[1127] | 408 | } |
---|
| 409 | switch -- [llength $nodes] { |
---|
[1694] | 410 | 0 { |
---|
| 411 | } |
---|
| 412 | 1 { |
---|
[3800] | 413 | foreach n { hide show toggle rename } { |
---|
[1694] | 414 | $itk_component(controls).$n configure -state normal |
---|
| 415 | } |
---|
| 416 | } |
---|
| 417 | 2 { |
---|
[3800] | 418 | foreach n { hide show toggle difference average } { |
---|
[1694] | 419 | $itk_component(controls).$n configure -state normal |
---|
| 420 | } |
---|
| 421 | } |
---|
| 422 | default { |
---|
[3800] | 423 | foreach n { hide show toggle average } { |
---|
[1694] | 424 | $itk_component(controls).$n configure -state normal |
---|
| 425 | } |
---|
| 426 | } |
---|
[1127] | 427 | } |
---|
| 428 | } |
---|
| 429 | |
---|
| 430 | itcl::body Rappture::XyLegend::GetData { elem what } { |
---|
[1943] | 431 | set y [$_graph element cget $elem $what] |
---|
[1127] | 432 | if { [blt::vector names $y] == $y } { |
---|
[1694] | 433 | set y [$y range 0 end] |
---|
[1127] | 434 | } |
---|
| 435 | return $y |
---|
| 436 | } |
---|
| 437 | |
---|
| 438 | itcl::body Rappture::XyLegend::Average {} { |
---|
| 439 | set nodes [$itk_component(legend) curselection] |
---|
| 440 | if { $nodes == "" } { |
---|
[1694] | 441 | return |
---|
[1127] | 442 | } |
---|
| 443 | set elements {} |
---|
| 444 | set sum [blt::vector create \#auto -command ""] |
---|
| 445 | |
---|
| 446 | set xcoords [blt::vector create \#auto -command ""] |
---|
| 447 | set ycoords [blt::vector create \#auto -command ""] |
---|
| 448 | |
---|
[1152] | 449 | blt::busy hold $itk_component(hull) |
---|
| 450 | update |
---|
[1127] | 451 | # Step 1. Get the x-values for each curve, then sort them to get the |
---|
[2744] | 452 | # unique values. |
---|
[1127] | 453 | |
---|
[2743] | 454 | set labels {} |
---|
[1127] | 455 | foreach node $nodes { |
---|
[1943] | 456 | set elem [$_tree label $node] |
---|
[2743] | 457 | set label [$_graph element cget $elem -label] |
---|
[1694] | 458 | $xcoords append [GetData $elem -x] |
---|
| 459 | set elements [linsert $elements 0 $elem] |
---|
[2743] | 460 | set labels [linsert $labels 0 $label] |
---|
[1127] | 461 | } |
---|
| 462 | # Sort the abscissas keeping unique values. |
---|
| 463 | $xcoords sort -uniq |
---|
| 464 | |
---|
| 465 | # Step 2. Now for each curve, generate a cubic spline of that curve |
---|
[2744] | 466 | # and interpolate to get the corresponding y-values for each |
---|
| 467 | # abscissa. Normally the abscissa are the same, so we're |
---|
| 468 | # interpolation the knots. |
---|
[1127] | 469 | |
---|
| 470 | set x [blt::vector create \#auto -command ""] |
---|
| 471 | set y [blt::vector create \#auto -command ""] |
---|
| 472 | $sum length [$xcoords length] |
---|
| 473 | |
---|
| 474 | foreach node $nodes { |
---|
[1943] | 475 | set elem [$_tree label $node] |
---|
[1694] | 476 | $x set [GetData $elem -x] |
---|
| 477 | $y set [GetData $elem -y] |
---|
| 478 | blt::spline natural $x $y $xcoords $ycoords |
---|
[1127] | 479 | |
---|
[1694] | 480 | # Sum the interpolated y-coordinate values. |
---|
| 481 | $sum expr "$sum + $ycoords" |
---|
[1127] | 482 | } |
---|
| 483 | blt::vector destroy $x $y |
---|
| 484 | |
---|
| 485 | # Get the average |
---|
| 486 | $sum expr "$sum / [llength $elements]" |
---|
| 487 | |
---|
| 488 | # Step 3. Create a new curve which is the average. Append it to the |
---|
[2744] | 489 | # the end. |
---|
[1127] | 490 | |
---|
| 491 | set count 0 |
---|
[1943] | 492 | while {[$_graph element exists avg$count] } { |
---|
[1694] | 493 | incr count |
---|
[1127] | 494 | } |
---|
[2743] | 495 | set labels [lsort -dictionary $labels] |
---|
[1127] | 496 | set name "avg$count" |
---|
[2743] | 497 | set label "Avg. [join $labels ,]" |
---|
[1127] | 498 | |
---|
| 499 | # Don't use the vector because we don't know when it will be cleaned up. |
---|
| 500 | |
---|
[1943] | 501 | if { $_lastColorIndex == 0 } { |
---|
| 502 | set _lastColorIndex [llength $_autocolors] |
---|
[1152] | 503 | } |
---|
[1943] | 504 | incr _lastColorIndex -1 |
---|
| 505 | set color [lindex $_autocolors $_lastColorIndex] |
---|
| 506 | $_graph element create $name -label $label -x [$xcoords range 0 end]\ |
---|
[1694] | 507 | -y [$sum range 0 end] -symbol scross -pixels 3 -color $color |
---|
[1127] | 508 | blt::vector destroy $xcoords $ycoords $sum |
---|
| 509 | set node [Add $name $label -delete] |
---|
| 510 | Raise $node |
---|
[1152] | 511 | blt::busy forget $itk_component(hull) |
---|
[1127] | 512 | } |
---|
| 513 | |
---|
| 514 | itcl::body Rappture::XyLegend::Difference {} { |
---|
| 515 | |
---|
[1943] | 516 | if { $_diff != "" } { |
---|
| 517 | $_graph marker delete $_diff |
---|
| 518 | set _diff "" |
---|
[1127] | 519 | } |
---|
| 520 | set nodes [$itk_component(legend) curselection] |
---|
[1943] | 521 | set elem1 [$_tree label [lindex $nodes 0]] |
---|
| 522 | set elem2 [$_tree label [lindex $nodes 1]] |
---|
| 523 | if { [info exists _diffelements($elem1)] && |
---|
| 524 | [info exists _diffelements($elem2)] } { |
---|
[2744] | 525 | array unset _diffelements; # Toggle the difference. |
---|
| 526 | return; |
---|
[1127] | 527 | } |
---|
[1943] | 528 | array unset _diffelements |
---|
[1127] | 529 | set x [blt::vector create \#auto -command ""] |
---|
| 530 | set y [blt::vector create \#auto -command ""] |
---|
| 531 | set m [blt::vector create \#auto -command ""] |
---|
| 532 | |
---|
| 533 | $x append [GetData $elem1 -x] |
---|
| 534 | $y append [GetData $elem1 -y] |
---|
| 535 | $x sort -reverse $y |
---|
| 536 | $x append [GetData $elem2 -x] |
---|
| 537 | $y append [GetData $elem2 -y] |
---|
| 538 | $m merge $x $y |
---|
[1943] | 539 | set _diff [$_graph marker create polygon \ |
---|
[1694] | 540 | -coords [$m range 0 end] \ |
---|
| 541 | -element $elem1 \ |
---|
| 542 | -stipple dot1 \ |
---|
| 543 | -outline "" -fill "#cd69c9"] |
---|
[1127] | 544 | blt::vector destroy $m $x $y |
---|
[1943] | 545 | set _diffelements($elem1) 1 |
---|
| 546 | set _diffelements($elem2) 1 |
---|
[1127] | 547 | } |
---|
| 548 | |
---|
| 549 | |
---|
[2743] | 550 | itcl::body Rappture::XyLegend::UnmapHidden {} { |
---|
| 551 | $_graph configure -unmaphiddenelements $_unmapHidden |
---|
| 552 | } |
---|
| 553 | |
---|
[1127] | 554 | itcl::body Rappture::XyLegend::SelectAll { } { |
---|
[1943] | 555 | foreach node [$_tree children 0] { |
---|
[1694] | 556 | $itk_component(legend) selection set $node |
---|
[1127] | 557 | } |
---|
| 558 | } |
---|
[1132] | 559 | |
---|
| 560 | itcl::body Rappture::XyLegend::Rename {} { |
---|
| 561 | Editor popup |
---|
| 562 | } |
---|
| 563 | |
---|
| 564 | # ---------------------------------------------------------------------- |
---|
| 565 | # USAGE: Editor popup |
---|
| 566 | # USAGE: Editor activate |
---|
| 567 | # USAGE: Editor validate <value> |
---|
| 568 | # USAGE: Editor apply <value> |
---|
| 569 | # USAGE: Editor menu <rootx> <rooty> |
---|
| 570 | # |
---|
| 571 | # Used internally to handle the various functions of the pop-up |
---|
| 572 | # editor for the value of this gauge. |
---|
| 573 | # ---------------------------------------------------------------------- |
---|
| 574 | itcl::body Rappture::XyLegend::Editor {option args} { |
---|
| 575 | switch -- $option { |
---|
[1694] | 576 | popup { |
---|
| 577 | $itk_component(editor) activate |
---|
| 578 | } |
---|
| 579 | activate { |
---|
[1943] | 580 | set _rename [$itk_component(legend) curselection] |
---|
| 581 | if { $_rename == "" } { |
---|
[1694] | 582 | return; |
---|
| 583 | } |
---|
[1943] | 584 | set label [$itk_component(legend) entry cget $_rename -label] |
---|
| 585 | foreach { l r w h } [$itk_component(legend) bbox $_rename] break |
---|
[1694] | 586 | set info(text) $label |
---|
| 587 | set info(x) [expr $l + [winfo rootx $itk_component(legend)]] |
---|
| 588 | set info(y) [expr $r + [winfo rooty $itk_component(legend)]] |
---|
| 589 | set info(w) $w |
---|
| 590 | set info(h) $h |
---|
| 591 | return [array get info] |
---|
| 592 | } |
---|
| 593 | validate { |
---|
| 594 | if {[llength $args] != 1} { |
---|
| 595 | error "wrong # args: should be \"editor validate value\"" |
---|
| 596 | } |
---|
| 597 | } |
---|
| 598 | apply { |
---|
| 599 | if {[llength $args] != 1} { |
---|
| 600 | error "wrong # args: should be \"editor apply value\"" |
---|
| 601 | } |
---|
| 602 | set label [lindex $args 0] |
---|
[1943] | 603 | $itk_component(legend) entry configure $_rename -label $label |
---|
| 604 | set elem [$_tree label $_rename] |
---|
| 605 | $_graph element configure $elem -label $label |
---|
[1694] | 606 | } |
---|
| 607 | menu { |
---|
| 608 | eval tk_popup $itk_component(emenu) $args |
---|
| 609 | } |
---|
| 610 | default { |
---|
| 611 | error "bad option \"$option\": should be popup, activate, validate, apply, and menu" |
---|
| 612 | } |
---|
[1132] | 613 | } |
---|
| 614 | } |
---|