# graph-drag.tcl # # Show a graph with value based on vmd frame number. # Clicks and drags in graph window move trajectory. # # To demo: # 1. vmd -e graph-drag.tcl # 2. demo_graph_drag # (makes a trajectory of a rotating molecule # and a sample data set) # 3. In "Animate" window, click 'Forward' button. # 4. Click and drag on graph window to move in trajectory. # # To use: # 1. replace "make_data" proc with one that puts useful data in y_cache # 2. Adjust "mult" and y-scale labels to fit your data set. # 3. Run with: make_data, start_graph # # Still needs: auto scaling, reasonable interface, etc. # # Barry Isralewitz May 2002 set graphWindowTitle "Sample graph" set graphTitle "Value based on cos(frame #) " set graphXlabel "Extension (Angstroms)" set graphYlabel "Force (pN)" set c_width 400 set c_height 310 set x_axis 40 set y_axis 30 set mult 4.8400 set prev_frame -1 proc make_data { {molid top} } { global y_cache x_cache if {! [string compare $molid top]} { set molid [molinfo top] } set numframes [molinfo $molid get numframes] set Pi 3.1415927 for {set i 0} {$i <= $numframes} {incr i} { set x_cache($i) [expr $i] set y_cache($i) [expr 5 + (22.50 * (1 + cos (2* $Pi* ($i+0.0)/$numframes )) )] } } proc clear_graph {} { global g c_width c_height x_axis y_axis prev_frame graph_flag destroy $g.c destroy $g show_graph set graph_flag 1 } proc graph_update {name index op} { # name == vmd_frame # index == molecule id of the newly changed frame # op == w global g global y_cache x_cache graph_flag global prev_frame #puts "in graph" if {$graph_flag == 1} { ## get the new frame number # Tcl doesn't yet have it, but VMD does ... set molid 0 #puts "further" set current_frame [molinfo 0 get frame] #puts "still." #puts "Updating graph, frame $current_frame, prev_frame $prev_frame" # set y_cache($frame) 9 # see if the force data exists in the cache if {[info exists y_cache($current_frame)]} { #puts "info exists for frame $current_frame" #draw from prev_frame to current_frame if {$prev_frame == -1} { #puts "drawing first dot" draw_dot $current_frame } else { #puts "drawing non-first dot" erase_dot graph_from $prev_frame $current_frame draw_dot $current_frame } #display update } else { #display update puts "Info expected not seen in frame $current_frame, reset prev_frame to 0" set prev_frame 0 } set prev_frame $current_frame #puts "set prev_frame to $prev_frame" return } } proc show_graph {} { global g c_width c_height x_axis y_axis prev_frame graph_flag graphWindowTitle graphTitle graphXlabel graphYlabel set graph_flag 1 #create the graph set g [toplevel .vmd-data-graph] wm title $g $graphWindowTitle wm minsize $g 50 50 wm maxsize $g 800 800 label $g.title -text $graphTitle label $g.xlabel -text $graphXlabel label $g.ylabel -text $graphYlabel canvas $g.c -width $c_width -height $c_height pack $g.title $g.c #draw graph $g.c create line $x_axis [expr $c_height - $y_axis] [expr $c_width - 20] [expr $c_height - $y_axis] $g.c create line $x_axis [expr $c_height - $y_axis] $x_axis 20 $g.c create text 35 [expr $c_height - (-20 + $y_axis)] -text " 0" -anchor se $g.c create text 35 [expr $c_height - (121 + $y_axis)] -text "25" -anchor se $g.c create text 35 [expr $c_height - (242+ $y_axis)] -text "50" -anchor se $g.c create text 2 [expr $c_height - (265+ $y_axis)] -text "F(pN)" -anchor sw $g.c create text [expr $x_axis+ 150] [expr $c_height - (-20 + $y_axis)] -text "150" -anchor s $g.c create text [expr $x_axis + 300] [expr $c_height - (-20 + $y_axis)] -text "300" -anchor s $g.c create text [expr $x_axis + 335] [expr $c_height - (-28 + $y_axis)] -text "ext (A)" -anchor s bind $g.c [namespace code {PressedCanvas %x %y %s}] bind $g.c [namespace code {PressedCanvas %x %y %s}] } proc PressedCanvas {x y shiftState} { global x_axis set animFrame [expr $x - $x_axis] if {$animFrame >= 0} { animate goto $animFrame } } proc start_graph { {molid top} } { if {! [string compare $molid top]} { set molid [molinfo top] } global g x_axis y_axis c_height c_width mult global y_cache x_cache vmd_frame prev_frame global graphWindowTitle #puts "just globalled" show_graph #create the graph #set g [toplevel .vmd-data-graph] #wm title $g $graphWindowTitle set prev_frame -1 make_data # set a trace to detect when an animation frame changes trace vdelete vmd_frame($molid) w graph_update trace variable vmd_frame($molid) w graph_update puts "tracing this:" puts [trace vinfo vmd_frame($molid)] puts "just traced for mol $molid" return } # when the frame changes, trace calls this function proc graph_from {prev_frame current_frame} { global y_cache x_cache x_axis y_axis g c_width c_height mult #puts "in graph from, for $prev_frame to $current_frame" #puts $current_frame if {$prev_frame == -1} { #do nothing right now } else { set prev_plot_frame $prev_frame set diff [expr abs($current_frame - $prev_frame)] set add [expr ($current_frame - $prev_frame) / abs ( $current_frame - $prev_frame)] set pos $prev_frame #puts "start for" if {$diff == 1} { for {set i 1} {$i <= $diff} {incr i} { set y_data ($y_cache($pos)) set x_data ($x_cache($pos)) #puts "pos is $pos" set pos [expr $pos + $add] set prev_y [expr -($y_axis) + $c_height - $mult * ($y_cache($prev_plot_frame))] set cur_y [expr -($y_axis) + $c_height - $mult * ($y_cache($pos) )] set prev_x [expr $x_axis + $x_cache($prev_plot_frame)] set cur_x [expr $x_axis + $x_cache($pos)] #puts "report from:" #puts "pos is $pos, i is $i, prev_y = $prev_y, cur_y = $cur_y, prev_x = $prev_x , cur_x = $cur_x\n Real x is $x_data, real y is $y_data" $g.c create line $prev_x $prev_y $cur_x $cur_y set $prev_plot_frame $pos } } } return } proc draw_dot {the_frame} { global g global y_cache x_cache global mult c_width c_height global x_axis y_axis dot vert_line set data $y_cache($the_frame) set y [expr -($y_axis) + $c_height - $mult * ($y_cache($the_frame) )] set x [expr $x_axis + $x_cache($the_frame)] #puts "drawing dot for frame $the_frame, x= $x, y = $y)" set dotsize 2 set vert_line [ $g.c create rectangle [expr $x ] [expr $c_height - $y_axis] [expr $x ] 20 -width 1 -outline red -fill blue] set dot [ $g.c create rectangle [expr $x - $dotsize] [expr $y - $dotsize] [expr $x + $dotsize] [expr $y + $dotsize] -width 2 -outline red] #puts "dot drawn" } proc hide_graph {} { global g graph_flag set graph_flag 0 #hide graph and stop watch destroy $g.c destroy $g trace vdelete vmd_frame(0) w graph_update } proc erase_dot {} { global g y_cache dot vert_line mult #puts "erasing dot" $g.c delete $dot $g.c delete $vert_line #puts "erased" } proc demo_traj {numframes } { #set molid [mol load pdb alanin.pdb ] mol pdbload 1bpt set molid [molinfo top] set sel [atomselect $molid "all"] set rot [expr 360.0/$numframes] for {set i 1} {$i < $numframes} {incr i} { animate goto 0 display update animate dup $molid animate goto $i display update $sel move [transaxis y [expr $i * $rot] ] #just to provide user feedback on progress... display update } } # a button box for graph window hide/refresh # Create the window set f [toplevel .favorite_actions] wm title $f "Graph commands" set i 0 button $f.b$i -text {refresh graph} -command {clear_graph} incr i button $f.b$i -text {hide graph} -command {hide_graph} # arrange them for {set j 0} {$j <= $i} {incr j} { pack $f.b$j } proc demo_graph_drag {} { demo_traj 300 make_data start_graph animate goto 0 }