#!/usr/bin/wish ## ##+######################################################################## ## Linux/Unix NOTE: ## If the 'wish' interpreter is in a different directory, such as ## /usr/local/bin, you can make a soft-link from 'wish' there to ## /usr/bin/wish, as root, with a command like ## ln -s /usr/local/bin/wish /usr/bin/wish ##+######################################################################## ## Tk SCRIPT NAME: plotquik_LinesPoints_mathExprYatX.tk ## ## --- adapted from the script 'plot_quik_xy_expr.tk' ## in the 'feHandyTools' subsystem of the 'Freedom Environment' ## subsystems at www.freedomenv.com --- adapted for putting a ## 'standalone' utility (with no 'source' statements) in the ## FE 'tkGooies' system. ## ##+####################################################################### ## PURPOSE: An intuitive, easy-to-use X-Y-AXIS LINE-PLOT utility that ## generates data points from an ALGEBRAIC EXPRESSION --- ## to make 'presentation quality' plots QUICKLY. ## ## Oriented toward plots of many data points (hundreds of them) ## --- via connecting lines rather than data point markers ## (but with the option of showing the points with markers). ## _____________________________________________________________ ## ## This Tk script presents a GUI with a canvas widget showing ## a 2-D line plot --- with titles and labels that can be ## dragged with the mouse. ## ## This script presents entry fields in the GUI to prompt for ## algebraic expression and plot title and axis titles and limits. ## _____________________________________________________________ ## ## This is a plotting-utility implementation using BASIC ## Tcl-Tk commands, i.e. not requiring an 'extension' of Tcl or Tk. ## ## Unfortunately, there do not seem to be any FAIRLY GENERAL, yet ## RELATIVELY SIMPLE, xy-point plotting scripts at Tcl-Tk archive ## sites --- even in 2013, more than 20 years after the development ## of the necessary Tk canvas facilities to support plotting. ## ## Nor are such general, easy-to-use xy point/line plotting Tk scripts ## available via web searches on keyword strings such as ## 'bin wish canvas' or 'bin wish line' or 'bin wish oval'. ## ## Even searches on 'canvas' and 'line' on the wiki.tcl.tk site, ## in early 2013, yield only simplistic line plot 'demos' that are ## not suited to general and FAST point/line plots --- with entry ## fields for quick entry of user data. ## ## This script is meant to fill that long-time void. ## ## _____________________________________________________________ ## ## SOURCES and CREDITS: ## ## The technique of dragging canvas items came from the Tcl-Tk demo in ## /usr/local/lib/tk4.0/demos/plot.tcl (on SGI-IRIX Unix, 1995). ## However, that script allowed the user to drag the data points. ## This script allows the user to drag titles and tic-mark labels. ## ## On Linux (for example, Ubuntu 9.10, circa 2009), see ## /usr/share/doc/tk8.4/examples/plot.tcl ## or /usr/share/doc/tk8.5/examples/plot.tcl ## There are 60-plus other Tcl-Tk code examples in the ## 'examples' directory. ## ## See also 'create oval' plot scripts like ## 'items.tcl' and 'twind.tcl' in /usr/share/doc/tk8.x/examples/. ## These scripts provide examples of procs to move 'items' around ## on the canvas with a mouse. ## ##+##################################################################### ## ## INPUTS (via entry fields on the GUI): ## plot title, xy-axis titles, xy-axis min-max, and an ## algebraic expression of the kind f(x) giving y values. ## ## OUTPUT: Intended for screen/window capture to an image file with a ## screen-capture tool (such as 'gnome-screenshot' on Linux). ## ## The image could be cropped with an image editor (such as ## 'mtpaint' on Linux) and the cropped image could be printed ## using an image view-print utility (such as 'eog' = Eye of ## Gnome, on Linux) --- or a web browser. ## ## If you are going to print the image, you will probably ## want to change the background color to white, via the ## 'CanvasColor' button at the top of the GUI. ## ## (For an alternative, a Postscript-Print button and proc ## could be implemented.) ## ##+################# ## THE GUI WIDGETS: ## ## The options available to the user are indicated by ## the following 'sketch' of the GUI. ## ## In the sketch of the GUI below: ## ## SQUARE BRACKETS indicate a comment (not to be placed on the GUI). ## BRACES indicate a Tk 'button' widget. ## A COLON indicates that the text before the colon is on a 'label' widget. ## UNDERSCORES indicate a Tk 'entry' widget. ## ## CAPITAL-X indicates a Tk 'checkbutton' widget. ## CAPITAL-O indicates a Tk 'radiobutton' widget (if any). ## <----O----> indicates a Tk 'scale' widget (if any). ## ## ------------------------------------------------------------------------------------------------------- ## ## FRAMEnames ## VVVVVVVVVV ## ----------------------------------------------------------------------------------- ## tkPlotQuik - XY Data from an Algebraic Expression ## [window title] ## ----------------------------------------------------------------------------------- ## ## .fRbuttons {Exit}{Help} X Points X Border {CanvasColor}{UpdatePlot}{GetImg}{DwnCan}{UpCan}{PrtPreview}{Print} [entry field here shows a print command] ## ## .fRtitle_main PlotTitle:_____________________________________________________________________________________________________ ## ## .fRtitles_xy XaxisTitle:__________________________________________ YaxisTitle: _____________________________________________ ## ## .fRlims_xy XaxisMin:__________ XaxisMax:__________ XticDist:_____ YaxisMin: __________ YaxisMax: __________ YticDist:_____ ## ## .fRexpr Expression: ___________________________________________________________________________________________________ ## 2 1000 ## .fRexpr_opts Number of X vals to generate: <---------------------------------O--------------------------------------------> ## ## .fRlow .fRlow.fRmsg .fRlow.fRplot ## [ an area here contains a brief [ an area here ## guide in a text or label widget contains a canvas widget ## ... ... ## many to be populated with ## ... ... ## lines 'items' whenever the 'UpdatePlot' button ## ... ... ## deep. in frame 'fRbuttons' is poked. ## ] ] ## ## --------------------------------------------------------------------------------------------------------------- ## ##+############## ## GUI components: ## ## From the GUI 'sketch' above, it is seen that the GUI consists of about ## ## - 9 button widgets ## - 11 label widgets ## - 10 entry widgets ## - 1 text widget (with scroll bars someday?) (or one more label instead) ## - 1 canvas widget (with scroll bars someday?) ## - 2 checkbutton widgets ## - 1 scale widget ## - 0 radiobutton widgets ## - 0 listbox widgets ## ##+##################################################################### ## STRUCTURE OF THIS CODE: ## ## 0) Set general window parms (win-name, win-position, win-color-scheme, ## fonts, widget-geom-parms, text-array-for-labels-etc, win-size-control). ## 1a) Define ALL frames (and sub-frames, if any). ## 1b) Pack ALL frames and sub-frames. ## 2) Define & pack ALL widgets within frames, frame by frame. ## Define all widgets in a frame, then pack them. ## 3) Define key and mouse/touchpad/touch-sensitive-screen action ## BINDINGS, if any. ## 4) Define PROCS, if any. ## 5) Additional GUI INITIALIZATION (typically with one or two ## of the procs), if needed. ## ## In more detail: ## ## 1a) Define ALL frames: From the top down on the GUI are several horizontal ## frames stretching across the GUI: ## - 'fRbuttons' and several entry-widget frames for plot title, ## axis titles, axis limits, and algebraic expression. ## ## - Below those frames, across the GUI, is a container frame: 'fRlow'. ## ## - There are 2 sub-frames on the left and right of the 'fRlow' frame: ## 'fRlow.fRmsg' and 'fRlow.fRplot' ## ## Help text is in the 'fRmsg' frame. ## The plot is in the 'fRplot' frame. ## ## 1b) Pack frames with appropriate '-side' '-anchor' '-fill' '-expand' ## parameters to get proper behavior of widgets within the frames, ## during window expansion. (Window expansion is allowed). ## ## 2) Define & pack all widgets in the frames -- basically going through ## frames & their interiors in top-to-bottom, left-to-right order: ## ## - 'fRbuttons' contains buttons -- ## Exit & Help & UpdatePlot & other buttons. ## ## - 'fRtitle_main' contains 1 label & 1 entry widget. ## - 'fRtitles_xy' contains 2 pairs of label & entry widgets. ## - 'fRlims_xy' contains 6 pairs of label & entry widgets. ## - 'fRexpr' contains 1 label & 1 entry widget. ## - 'fRexpr_opts' contains 1 pair of label & scale widgets. ## ## - 'fRlow.fRmsg' contains a message in a label (or text) widget. ## ## - 'fRlow.fRplot' contains a canvas widget (to be populated with ## 'items' when ever the 'UpdatePlot' button in 'fRbuttons' ## is poked). ## ## 3) Define BINDINGS: (See BINDINGS code section.) ## ## To Drag plot-title and axis-titles (and tic-mark labels). ## Basically: ## - .fRame.canvas bind TAGmoveable "itemSelect .fRame.canvas %x %y" ## - bind .fRame.canvas "itemMove .fRame.canvas %x %y" ## - .fRame.canvas bind TAGmoveable ".fRame.canvas dtag TAGselected" ## ## 4) Define PROCS: (See PROCS code section.) ## ## - 'update_plot' - Called by 'UpdatePlot' button --- and in the 'downsize_canvas' ## and 'upsize_canvas' procs --- and in the 'getSet_canvasColor' ## proc --- and at the bottom of this script, ## in the 'Additional GUI Initialization' section. ## ## (Re)Sets contents of the plot canvas!! ## ## - 'set_margins' - Called by proc 'update_plot'. ## Sets margins around the 'plot rectangle'. ## ## - 'itemSelect' - Called by a binding on the canvas. ## Selects a canvas item. ## ## - 'itemMove' - Called by a binding on the canvas. ## Moves a selected canvas item. ## ## - 'draw_points' - Called by 'update_plot' proc --- ## if 'Points' checkbutton is ON. ## ## - 'draw_border' - Called by 'update_plot' proc --- ## if 'Border' checkbutton is ON. ## ## - 'getSet_canvasColor' - Called by 'CanvasColor' button. ## ## - 'downsize_canvas' - Called by 'DwnCan' button. ## - 'upsize_canvas' - Called by 'UpCan' button. ## - 'resize_win' - Called by the 'downsize_canvas' and ## 'upsize_canvas' procs. ## ## - 'print_preview' - Called by 'PrtPreview' button. ## - 'print_plot' - Called by 'Print' button. ## ## - 'getPut_image' - Called by 'GetImg' button. ## ## - 'popup_msgVarWithScroll' - Called by 'Help' button --- and to pop up ## a msg whenever needed. ## ## 5) Additional GUI initialization: ## Set various directory and helper-app and plot parameter variables. ## Set some sample data for the entry fields. ## Issue 'update_plot' to present an intitial demo plot on the canvas. ## ##+####################################################################### ## DEVELOPED WITH: Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october, 'Karmic Koala') ## ## $ wish ## % puts "$tcl_version $tk_version" ## ## showed ## 8.5 8.5 ## but this script should work in most previous 8.x versions, and probably ## even in some 7.x versions (if font handling is made 'old-style'). ##+######################################################################## ## MAINTENANCE HISTORY: ## Started by: Blaise Montandon 2013jul18 Started development, on Ubuntu 9.10, ## based on my code ## 'plot_quik_xy_expr.tk' ## in the 'feHandyTools' subsystem of ## the 'Freedom Environment' subsystems ## at www.freedomenv.com --- adapted for ## donation of this code to the Tcl-Tk ## wiki at wiki.tcl.tk. Suspended. ## Updated by: Blaise Montandon 2017sep28 Restarted development for the FE ## 'tkGooies' system. ## Updated by: Blaise Montandon 2017????? Released this script at freedomenv.com. ##+######################################################################## ##+####################################################################### ## Set window title (long and short form). ##+####################################################################### wm title . "tkPlotQuik - XY Data from an Algebraic Expression" wm iconname . "PlotExpr" # catch { wm title . "$env(FE_WIN_TITLE)" } # catch { wm iconname . "$env(FE_ICON_TITLE)" } ##+################################### ## SET THE TOP WINDOW POSITION. ##+################################### wm geometry . +15+30 # catch {eval wm geometry . "$env(FE_WIN_LOC_GEOM)" } ##+####################################################################### ## SET COLOR SCHEME (palette) for the window and its widgets. ##+####################################################################### if {1} { ## Grayish palette set Rpal255 210 set Gpal255 210 set Bpal255 210 } if {0} { ## Bluish palette set Rpal255 180 set Gpal255 180 set Bpal255 255 } if {0} { ## Greenish palette set Rpal255 180 set Gpal255 255 set Bpal255 180 } if {0} { ## Reddish palette set Rpal255 255 set Gpal255 180 set Bpal255 180 } ## If env vars R255,G255,B255 were set, then we could use the following ## format statement to get a hex value for specifying tkGUI colors, ## after 'catch'-ing the three values into Rpal255,Gpal255,Bpal255 Tcl vars. # catch { set Rpal255 "$env(R255)" } # catch { set Gpal255 "$env(G255)" } # catch { set Bpal255 "$env(B255)" } set hexCOLORpal [format "#%02X%02X%02X" $Rpal255 $Gpal255 $Bpal255] ## Or could set palette from a hex-valued env var. # catch { set hexCOLORpal "$env(FE_PLOT_WINCOLOR)" } tk_setPalette "$hexCOLORpal" ##+####################################################### ## Set background colors for GUI widgets. ##+####################################################### set msgBKGD "#ffcccc" set entryBKGD "#f0f0f0" # set textBKGD "#f0f0f0" set textBKGD $msgBKGD set chkbuttBKGD "#c0c0c0" set scaleBKGD "#c0c0c0" ## Following widgets are not used, yet. # set listboxBKGD "#f0f0f0" # # set radbuttBKGD "#c0c0c0" # set radbuttBKGD $msgBKGD # set radbuttSELECTCOLOR "#cccccc" ##+####################################################################### ## SET FONT VARS to use in the 'font create' statements below. ## ## We use a VARIABLE-WIDTH FONT for label and button widgets. ## ## We use a FIXED-WIDTH FONT for entry fields and ## text widgets and listboxes, if any. ##+####################################################################### set FONTsize 14 set FONT_SMALLsize 12 set fontFamily "comic sans ms" set FONTparms_varwidth " -family {$fontFamily} \ -size -$FONTsize -weight bold -slant roman" set FONTparms_SMALL_varwidth " -family {$fontFamily} \ -size -$FONT_SMALLsize -weight normal -slant roman " ## Some other possible (similar) variable width fonts: ## Arial ## Bitstream Vera Sans ## DejaVu Sans ## Droid Sans ## FreeSans ## Liberation Sans ## Nimbus Sans L ## Trebuchet MS ## Verdana # set fontFamily "dejavu sans mono" # set fontFamily "freemono" set fontFamily "liberation mono" set FONTparms_fixedwidth " -family {$fontFamily} \ -size -$FONTsize -weight bold -slant roman " set FONTparms_SMALL_fixedwidth " -family {$fontFamily} \ -size -$FONT_SMALLsize -weight normal -slant roman " ## Some other possible fixed width fonts (esp. on Linux): ## Andale Mono ## Bitstream Vera Sans Mono ## Courier 10 Pitch ## Liberation Mono ## Droid Sans Mono ## FreeMono ## Nimbus Mono L ## TlwgMono ##+##################################################################### ## DEFINE (temporary) FONT VARS to be used in '-font' widget specs below ## --- and for some plot text on the canvas. ##+##################################################################### eval font create fontTEMP_varwidth $FONTparms_varwidth eval font create fontTEMP_fixedwidth $FONTparms_fixedwidth eval font create fontTEMP_button $FONTparms_varwidth eval font create fontTEMP_chkbutt $FONTparms_varwidth eval font create fontTEMP_label $FONTparms_varwidth eval font create fontTEMP_scale $FONTparms_varwidth eval font create fontTEMP_entry $FONTparms_fixedwidth eval font create fontTEMP_msg $FONTparms_fixedwidth eval font create fontTEMP_text $FONTparms_fixedwidth # eval font create fontTEMP_listbox $FONTparms_fixedwidth eval font create fontTEMP_SMALL_varwidth $FONTparms_SMALL_varwidth eval font create fontTEMP_SMALL_fixedwidth $FONTparms_SMALL_fixedwidth eval font create fontTEMP_SMALL_button $FONTparms_SMALL_varwidth eval font create fontTEMP_SMALL_chkbutt $FONTparms_SMALL_varwidth eval font create fontTEMP_SMALL_label $FONTparms_SMALL_varwidth eval font create fontTEMP_SMALL_scale $FONTparms_SMALL_varwidth eval font create fontTEMP_SMALL_entry $FONTparms_SMALL_fixedwidth eval font create fontTEMP_SMALL_msg $FONTparms_SMALL_fixedwidth eval font create fontTEMP_SMALL_text $FONTparms_SMALL_fixedwidth # eval font create fontTEMP_SMALL_listbox $FONTparms_SMALL_fixedwidth ## For the text in the plot (on the canvas): eval font create fontTEMP_plottext $FONTparms_varwidth eval font create fontTEMP_SMALL_plottext $FONTparms_SMALL_varwidth ##+####################################################################### ## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS. ## (e.g. padx, pady for Buttons) ## ## Possible values for '-relief' are: ## flat, groove, raised, ridge, solid, and sunken. ##+####################################################################### ## For BUTTON widgets: set PADYpx_button 0 set PADXpx_button 0 set BDwidthPx_button 2 set RELIEF_button raised ## For LABEL widgets: set PADXpx_label 0 set PADYpx_label 0 set BDwidthPx_label 2 set RELIEF_label flat ## For ENTRY widgets: set BDwidthPx_entry 2 set RELIEF_entry sunken ## For SCALE widgets: set BDwidthPx_scale 2 set RELIEF_scale sunken ## CHECKBUTTON geom parameters: set PADXpx_chkbutt 0 set PADYpx_chkbutt 0 set BDwidthPx_chkbutt 2 # set RELIEF_chkbutt raised set RELIEF_chkbutt ridge ## For TEXT widgets: set BDwidthPx_text 2 # set RELIEF_text raised set RELIEF_text ridge ## For CANVAS widgets: # set BDwidthPx_canvas 2 # set RELIEF_canvas raised set BDwidthPx_canvas 0 set RELIEF_canvas flat set initCanWidthPx 200 set initCanHeightPx 200 set minCanHeightPx 24 ## For LISTBOX widgets: (not used, yet) # set BDwidthPx_listbox 2 ##+############################################################## ## Set a TEXT-ARRAY to hold text for buttons & labels on the GUI. ## NOTE: This can aid INTERNATIONALIZATION. This array can ## be set according to a nation/region parameter. ##+############################################################## ## if { "$VARlocale" == "en"} ## For '.fRbuttons' frame: set aRtext(buttonEXIT) "Exit" set aRtext(buttonHELP) "Help" set aRtext(buttonUPDATE) "UpdatePlot" set aRtext(buttonCANCOLOR) "CanvasColor" set aRtext(chkbuttPOINTS) "Points" set aRtext(chkbuttBORDER) "Border" set aRtext(buttonIMG) "GetImg" set aRtext(buttonDWNCAN) "DwnCan" set aRtext(buttonUPCAN) "UpCan" set aRtext(buttonPRINT) "Print" set aRtext(buttonPRTPREVIEW) "PrtPreview" set aRtext(labelPRINTCMD) "PrintCommand:" ## For '.fRtitle_main' frame: set aRtext(labelPLOTTITLE) "PlotTitle:" ## For '.fRtitles_xy' frame: set aRtext(labelXAXISTITLE) "XaxisTitle:" set aRtext(labelYAXISTITLE) "YaxisTitle:" ## For '.fRlims_xy' frame: set aRtext(labelXAXISMIN) "XaxisMin:" set aRtext(labelXAXISMAX) "XaxisMax:" set aRtext(labelXTICDIST) "XticDist:" set aRtext(labelYAXISMIN) "YaxisMin:" set aRtext(labelYAXISMAX) "YaxisMax:" set aRtext(labelYTICDIST) "YticDist:" ## For '.fRexpr' frame: set aRtext(labelEXPR) "Expression:" ## For '.fRexpr_opts' frame: set aRtext(labelNVALS) "Number of Xvals to generate:" ## For '.fRlow.fRmsg' frame: set aRtext(labelHELPMSG) \ "To the right is a 'canvas' to contain a line plot of a math expression --- without or with data point markers. Recommended order of actions: 1. Increase the canvas AND plot size with the 'UpCan' button. Downsize with 'DwnCan'. Use the 'CanvasColor' button to change background color. 2. After making changes in any of the several entry fields, use the 'UpdatePlot' button. 3. You can drag any of the titles or tic-mark labels with mouse-button-1. When you use the 'UpdatePlot' button, titles and labels are returned to their initial locations. (Handy to restore labels if pulled off-canvas.) You can drag labels back where wanted. 4. You can use screen-grab, image- editor, and image-view-print utilities to make an image file or print the plot. (Use Help button for more.)" ## END OF if { "$VARlocale" == "en"} ##+################################################################### ## Set a MINSIZE of the window (roughly). ## ## For WIDTH, allow for the minwidth of the '.fRbuttons' frame: ## at least 9 widgets --- Exit, Help, etc. buttons. ## ## For HEIGHT, allow ## about 1 char high for the '.fRbuttons' frame and entry frames ## below that frame, ## about 24 pixels high for the '.fRplot' frame. ##+################################################################### set minWinWidthPx [font measure fontTEMP_varwidth \ "$aRtext(buttonEXIT) $aRtext(buttonHELP) \ $aRtext(chkbuttPOINTS) $aRtext(chkbuttBORDER) \ $aRtext(buttonCANCOLOR) $aRtext(buttonIMG) \ $aRtext(buttonUPDATE) \ $aRtext(buttonDWNCAN) $aRtext(buttonUPCAN) \ $aRtext(buttonPRINT) $aRtext(buttonPRTPREVIEW)"] ## Add some pixels to account for right-left-side window decoration ## (about 8 pixels), about 9 x 4 pixels/widget for borders/padding for ## about 9 button widgets. set minWinWidthPx [expr {44 + $minWinWidthPx}] ## MIN HEIGHT --- ## for the 7 stacked frames allow ## 1 char high for 'fRbuttons' ## 1 char high for 'fRtitle_main' ## 1 char high for 'fRtitles_xy' ## 1 char high for 'fRlims_xy' ## 1 char high for 'fRexpr' ## 1 char high for 'fRexpr_opts' ## 24 pixels high for 'fRplot'. set CharHeightPx [font metrics fontTEMP_varwidth -linespace] set minWinHeightPx [expr {6 * $CharHeightPx}] set minWinHeightPx [expr {$minWinHeightPx + 24}] ## Add about 28 pixels for top-bottom window decoration, ## about 7x4 pixels for each of the 7 stacked frames and their ## widgets (their borders/padding). set minWinHeightPx [expr {$minWinHeightPx + 56}] ## FOR TESTING: # puts "minWinWidthPx = $minWinWidthPx" # puts "minWinHeightPx = $minWinHeightPx" wm minsize . $minWinWidthPx $minWinHeightPx ## We allow the window to be resizable and we pack the canvas with ## '-fill both -expand 1' so that the canvas can be enlarged by enlarging ## the window. ## If you want to make the window un-resizable, ## you can use the following statement. # wm resizable . 0 0 ##+#################################################################### ##+#################################################################### ## DEFINE *ALL* THE FRAMES -- (top to bottom): ## ## - 'fRbuttons' contains buttons -- ## Exit, Help, UpdatePlot, etc. buttons. ## ## - 'fRtitle_main' contains 1 label & 1 entry widget. ## - 'fRtitles_xy' contains 2 pairs of label & entry widgets. ## - 'fRlims_xy' contains 6 pairs of label & entry widgets. ## - 'fRexpr' contains 1 label & 1 entry widget. ## - 'fRexpr_opts' contains 1 label & 1 scale widget. ## - 'fRlow' contains 2 side-by-side sub-frames. ## ## Then the sub-frames: ## - 'fRlow.fRmsg' contains a mini-guide in a label (or text) widget. ## - 'fRlow.fRplot' contains a canvas widget. ## ##+#################################################################### ## FOR TESTING change 0 to 1: ## (Example1: To see appearance of frames when borders are drawn.) ## (Example2: To see sizes of frames for various '-fill' options.) ## (Example3: To see how frames expand as window is resized.) if {0} { set RELIEF_frame raised set BDwidthPx_frame 2 } else { set RELIEF_frame flat set BDwidthPx_frame 0 } frame .fRbuttons -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRtitle_main -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRtitles_xy -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRlims_xy -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRexpr -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRexpr_opts -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRlow -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRlow.fRmsg -relief raised -bd 2 frame .fRlow.fRplot -relief raised -bd 2 ##+######################################################## ## PACK *ALL* the FRAMES. ##+######################################################## ## PACK THE FRAMES SEPARATELY, in order to facilitate ## experiment with different behaviors in window expansion. ##+######################################################## pack .fRbuttons \ -side top \ -anchor w \ -fill x \ -expand 0 pack .fRtitle_main \ -side top \ -anchor w \ -fill x \ -expand 0 pack .fRtitles_xy \ -side top \ -anchor w \ -fill x \ -expand 0 pack .fRlims_xy \ -side top \ -anchor w \ -fill x \ -expand 0 pack .fRexpr \ -side top \ -anchor w \ -fill x \ -expand 0 pack .fRexpr_opts \ -side top \ -anchor w \ -fill x \ -expand 0 pack .fRlow \ -side top \ -anchor center \ -fill both \ -expand 1 pack .fRlow.fRmsg \ -side left \ -anchor nw \ -fill y \ -expand 0 pack .fRlow.fRplot \ -side right \ -anchor ne \ -fill both \ -expand 1 ##+################################################################ ## Finished defining all the frames. ##+################################################################ ## START DEFINING & PACKING WIDGETS WITHIN THEIR FRAMES. ##+################################################################ ##+################################################################ ##+######################################################## ## IN THE 'fRbuttons' frame -- DEFINE ~8 BUTTON WIDGETs. ## THEN PACK EM. ##+######################################################## button .fRbuttons.buttExit \ -text "$aRtext(buttonEXIT)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {exit} button .fRbuttons.buttHelp \ -text "$aRtext(buttonHELP)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {popup_msgVarWithScroll .topHelp "$HELPtext" +10+10} button .fRbuttons.buttUpdate \ -text "$aRtext(buttonUPDATE)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {update_plot} button .fRbuttons.buttCanvasColor \ -text "$aRtext(buttonCANCOLOR)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {getSet_canvasColor} ## The checkbutton variable, Points0or1, will be initialized ## in the 'Additional GUI Initialization' section at the bottom of ## this Tk script. Example: ## set Points0or1 0 checkbutton .fRbuttons.chkbuttPoints \ -variable Points0or1 \ -selectcolor "$chkbuttBKGD" \ -text "$aRtext(chkbuttPOINTS)" \ -font fontTEMP_SMALL_chkbutt \ -padx $PADXpx_chkbutt \ -pady $PADYpx_chkbutt \ -bd $BDwidthPx_chkbutt \ -relief $RELIEF_chkbutt ## The checkbutton variable, Border0or1, will be initialized ## in the 'Additional GUI Initialization' section at the bottom of ## this Tk script. Example: ## set Border0or1 0 checkbutton .fRbuttons.chkbuttBorder \ -variable Border0or1 \ -selectcolor "$chkbuttBKGD" \ -text "$aRtext(chkbuttBORDER)" \ -font fontTEMP_SMALL_chkbutt \ -padx $PADXpx_chkbutt \ -pady $PADYpx_chkbutt \ -bd $BDwidthPx_chkbutt \ -relief $RELIEF_chkbutt button .fRbuttons.buttImg \ -text "$aRtext(buttonIMG)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {getPut_image} button .fRbuttons.buttDWNwin \ -text "$aRtext(buttonDWNCAN)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {downsize_canvas} button .fRbuttons.buttUPwin \ -text "$aRtext(buttonUPCAN)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {upsize_canvas} button .fRbuttons.buttPrtPreview \ -text "$aRtext(buttonPRTPREVIEW)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {print_preview} button .fRbuttons.buttPrint \ -text "$aRtext(buttonPRINT)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {print_plot} label .fRbuttons.labPRTCMD \ -text "$aRtext(labelPRINTCMD)" \ -font fontTEMP_label \ -justify left \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the 'Additional GUI Initialization' section. Example: # set ENTRYprintcmd "$PRINTcmd" entry .fRbuttons.entPRTCMD \ -textvariable ENTRYprintcmd \ -width 25 \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Pack the widgets in frame '.fRbuttons'. ## (We might want to change the order someday.) pack .fRbuttons.buttExit \ .fRbuttons.buttHelp \ .fRbuttons.chkbuttPoints \ .fRbuttons.chkbuttBorder \ .fRbuttons.buttImg \ .fRbuttons.buttUpdate \ .fRbuttons.buttCanvasColor \ .fRbuttons.buttDWNwin \ .fRbuttons.buttUPwin \ .fRbuttons.buttPrtPreview \ .fRbuttons.buttPrint \ .fRbuttons.labPRTCMD \ -side left \ -anchor center \ -fill none \ -expand 0 pack .fRbuttons.entPRTCMD \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRtitle_main' frame -- ## DEFINE 1 LABEL & 1 ENTRY WIDGET. THEN PACK THEM. ##+######################################################## label .fRtitle_main.labPlotTitle \ -text "$aRtext(labelPLOTTITLE)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the 'Additional GUI Inititalization' section. Example: # set ENTRYtitleMain " MAIN PLOT TITLE here." entry .fRtitle_main.entPlotTitle \ -textvariable ENTRYtitleMain \ -width 75 \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Pack the widgets in frame '.fRtitle_main'. pack .fRtitle_main.labPlotTitle \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRtitle_main.entPlotTitle \ -side left \ -anchor w \ -fill x \ -expand 1 ##+##################################################################### ## IN THE 'fRtitles_xy' frame -- ## DEFINE 2 pairs of LABEL & ENTRY widgets --- for x-axis, then y-axis. ## THEN PACK the 4 widgets. ##+##################################################################### label .fRtitles_xy.labXaxisTitle \ -text "$aRtext(labelXAXISTITLE)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the 'Additional GUI Initialization' section. Example: # set ENTRYtitleXaxis " X-AXIS TITLE here." entry .fRtitles_xy.entXaxisTitle \ -textvariable ENTRYtitleXaxis \ -width 40 \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ##+############################################################ ## Now, define the label and entry widgets for the y-axis title. ##+############################################################ label .fRtitles_xy.labYaxisTitle \ -text "$aRtext(labelYAXISTITLE)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the 'Additional GUI Initialization' section. Example: # set ENTRYtitleYaxis "Y-AXIS TITLE here. " entry .fRtitles_xy.entYaxisTitle \ -textvariable ENTRYtitleYaxis \ -width 40 \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Pack the widgets in frame '.fRtitles_xy'. pack .fRtitles_xy.labXaxisTitle \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRtitles_xy.entXaxisTitle \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRtitles_xy.labYaxisTitle \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRtitles_xy.entYaxisTitle \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRlims_xy' frame -- ## DEFINE 6 pairs of LABEL & ENTRY widgets --- for ## x-axis min & max &tic-dist and ## y-axis min & max & tic-dist. ## THEN PACK the 12 widgets. ##+######################################################## set entWIDTHchars 8 label .fRlims_xy.labXaxisMIN \ -text "$aRtext(labelXAXISMIN)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the 'Additional GUI Initialization' section. Example: # set ENTRYxaxismin "0" entry .fRlims_xy.entXaxisMIN \ -textvariable ENTRYxaxismin \ -width $entWIDTHchars \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry label .fRlims_xy.labXaxisMAX \ -text "$aRtext(labelXAXISMAX)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the 'Additional GUI Initialization' section. Example: # set ENTRYxaxismax "100" entry .fRlims_xy.entXaxisMAX \ -textvariable ENTRYxaxismax \ -width $entWIDTHchars \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry label .fRlims_xy.labXticDIST \ -text "$aRtext(labelXTICDIST)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Examples: # set ENTRYxticdist "10.0" entry .fRlims_xy.entXticDIST \ -textvariable ENTRYxticdist \ -width $entWIDTHchars \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Now define the Y-AXIS min-max-ticdist widgets: label .fRlims_xy.labYaxisMIN \ -text "$aRtext(labelYAXISMIN)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the 'Additional GUI Initialization' section. Example: # set ENTRYyaxismin "0" entry .fRlims_xy.entYaxisMIN \ -textvariable ENTRYyaxismin \ -width $entWIDTHchars \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry label .fRlims_xy.labYaxisMAX \ -text "$aRtext(labelYAXISMAX)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the 'Additional GUI Initialization' section. Example: # set ENTRYyaxismax "100" entry .fRlims_xy.entYaxisMAX \ -textvariable ENTRYyaxismax \ -width $entWIDTHchars \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry label .fRlims_xy.labYticDIST \ -text "$aRtext(labelYTICDIST)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Examples: # set ENTRYyticdist "10.0" entry .fRlims_xy.entYticDIST \ -textvariable ENTRYyticdist \ -width $entWIDTHchars \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Pack the XAXISmin, XAXISmax, XticDIST widgets ## and the YAXISmin, YAXISmax, YticDIST widgets in frame '.fRlims_xy': pack .fRlims_xy.labXaxisMIN \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRlims_xy.entXaxisMIN \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRlims_xy.labXaxisMAX \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRlims_xy.entXaxisMAX \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRlims_xy.labXticDIST \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRlims_xy.entXticDIST \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRlims_xy.labYaxisMIN \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRlims_xy.entYaxisMIN \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRlims_xy.labYaxisMAX \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRlims_xy.entYaxisMAX \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRlims_xy.labYticDIST \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRlims_xy.entYticDIST \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRexpr' frame -- ## DEFINE 1 LABEL & 1 ENTRY WIDGETs. THEN PACK THEM. ##+######################################################## label .fRexpr.labExpr \ -text "$aRtext(labelEXPR)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the 'Additional GUI Initialization' section. Example: # set ENTRYmathExpr { sin( ($pi/180)*$x ) + 0.5 * cos( 10*($pi/180)*$x ) } entry .fRexpr.entExpr \ -textvariable ENTRYmathExpr \ -width 80 \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Pack the widgets in frame '.fRexpr'. pack .fRexpr.labExpr \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRexpr.entExpr \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRexpr_opts' frame -- ## DEFINE 1 LABEL and 1 SCALE widget. THEN PACK THEM. ##+######################################################## label .fRexpr_opts.labNVALS \ -text "$aRtext(labelNVALS)" \ -font fontTEMP_label \ -justify right \ -anchor e \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We do not use the '-command' option of the scale widget. ## We call on proc 'get_numXvals' in proc 'update_plot' ## to get the requested number of values just once in ## proc 'update_plot' --- not repeatedly during motion ## of the slider bar. scale .fRexpr_opts.scaleNVALS \ -variable SCALEnxvals \ -orient horizontal \ -from 2 -to 1000 \ -resolution 1 \ -digits 0 \ -length 550 \ -font fontTEMP_SMALL_scale \ -repeatdelay 500 ## We initialize the position of the slider on the scale widget ## in the 'Additional GUI Initialization' section. Example: # set SCALEnxvals 10 ## Pack the label & scale widgets in frame '.fRexpr_opts'. pack .fRexpr_opts.labNVALS \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRexpr_opts.scaleNVALS \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRlow.fRmsg' frame -- DEFINE 1 LABEL WIDGET. ## THEN PACK IT. ##+######################################################## label .fRlow.fRmsg.labMSG \ -text "$aRtext(labelHELPMSG)" \ -font fontTEMP_SMALL_label \ -justify left \ -anchor nw \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## Pack the widget in frame '.fRlow.fRmsg'. pack .fRlow.fRmsg.labMSG \ -side top \ -anchor nw \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRlow.fRplot' frame -- DEFINE 1 CANVAS WIDGET. ## THEN PACK IT. ## ## We highlightthickness & borderwidth of the canvas to ## zero, as suggested on page 558, Chapter 37, 'The Canvas ## Widget', in the 4th edition of the book 'Practical ## Programming in Tcl and Tk', by Welch, Jones, Hobbs. ##+######################################################## ## Instead of hard-coding an initial canvas size, like this ## set canWidthPx 500 ## set canHeightPx 375 ## we set the canvas size in proportion to the screen size. set SCRNsizexPx [winfo screenwidth .] set SCRNsizeyPx [winfo screenheight .] set INITcanWidthPx [ expr {int(6 * $SCRNsizexPx / 10)} ] set INITcanHeightPx [ expr {int(6 * $SCRNsizeyPx / 10)} ] ## FOR TESTING: # puts "INITcanWidth: $INITcanWidthPx" # puts "INITcanHeight: $INITcanHeightPx" canvas .fRlow.fRplot.can \ -width $INITcanWidthPx \ -height $INITcanHeightPx \ -relief $RELIEF_canvas \ -highlightthickness 0 \ -borderwidth 0 ## Pack the widget in frame '.fRlow.fRplot'. ## Allow it to expand to fill window. Anchor at 'nw'. pack .fRlow.fRplot.can \ -side top \ -anchor nw \ -fill both \ -expand 1 ##+################################################################## ## Finished defining widgets in all the frames. ##+################################################################## ##+################################################################## ## END OF MAIN GUI BUILDING SECTION. ##+################################################################## ##+################################################################## ##+################################################################### ##+################################################################### ## DEFINE BINDINGS -- for mouse/pointer actions: ## - to Drag titles (and tic-mark labels and images) ## - to Change color of titles and tic-mark labels during their move ##+################################################################### ##+################################################################### ##+##################################### ## To Drag titles (and tic-mark labels): ##+##################################### ## The tag 'TAGmoveable' limits the select-and-move ## operations to items that we want to make moveable ## on the canvas. ## ## When the titles and tic-mark-labels are put on the ## canvas with 'create text', the 'TAGmoveable' tag ## is to be attached to them. ## And when images are put on the canvas with ## 'create image', the 'TAGmoveable' tag ## is to be attached to them. ##+################################################# .fRlow.fRplot.can bind TAGmoveable \ "itemSelect .fRlow.fRplot.can %x %y" bind .fRlow.fRplot.can \ "itemMove .fRlow.fRplot.can %x %y" ## Remove the 'TAGselected' tag (that was attached by ## the 'itemSelect' proc) when button is released. .fRlow.fRplot.can bind TAGmoveable \ ".fRlow.fRplot.can dtag TAGselected" ##+################################################################## ## To Change color of titles (and tic-mark-labels) during their move: ## (This assumes that 'TAGtext' was attached to titles and ## tic-mark-labels when they were created with 'create text'.) ##+################################################################## .fRlow.fRplot.can bind TAGtext \ {.fRlow.fRplot.can itemconfig current -fill "#$textCOLORselHEX"} .fRlow.fRplot.can bind TAGtext \ {.fRlow.fRplot.can itemconfig current -fill "#$textCOLORregHEX"} ##+################################################################### ##+################################################################### ## DEFINE PROCEDURES: ## ## Main procs: ## ## - 'update_plot' - Called by 'UpdatePlot' button --- and in the 'downsize_canvas' ## and 'upsize_canvas' procs --- and in the 'getSet_canvasColor' ## proc --- and at the bottom of this script, ## in the 'Additional GUI Initialization' section. ## ## (Re)Sets contents of the plot canvas. ## Performs the plot including plot-title, axes, axis ## titles, tic-marks, tic-mark-labels, data-lines --- ## and data-point-markers and border, if requested. ## ## - 'set_margins' - Called by proc 'update_plot'. ## Sets margins around the 'plot rectangle'. ## ## - 'get_numXvals' - Called by proc 'update_plot'. ## Sets the number of X values to generate ## (between ENTRYxaxismin and ENTRYxaxismax), from scale widget. ## ## - 'itemSelect' - Called by a binding on the canvas. ## Selects a canvas item. ## ## - 'itemMove' - Called by a binding on the canvas. ## Moves a selected canvas item. ## ## - 'draw_points' - Called by 'update_plot' proc --- ## if 'Points' checkbutton is ON. ## ## - 'draw_border' - Called by 'update_plot' proc --- ## if 'Border' checkbutton is ON. ## Draws a border around the plot, along the ## edge of the canvas. ## ## - 'getSet_canvasColor' - Called by 'CanvasColor' button. ## Gets and sets bkgd color for canvas, ## via a separate RGB color-selector GUI. ## ## - 'downsize_canvas' - Called by 'DwnCan' button. ## Reduces the GUI/canvas size by a percentage. ## ## - 'upsize_canvas' - Called by 'UpCan' button. ## Increases the GUI/canvas size by a percentage ## ## - 'resize_win' - Called by the 'downsize_canvas' and ## 'upsize_canvas' procs. ## ## - 'print_preview' - Called by 'PrtPreview' button. ## - 'print_plot' - Called by 'Print' button. ## ## - 'getPut_image' - Called by 'GetImg' button. ## ## - 'popup_msgVarWithScroll' - Called by 'Help' button --- and to pop up ## a msg whenever needed. ## ##+################################################################### ##+################################################################### ##+##################################################################### ## proc 'update_plot' (for expression-plotting, thru x,y-points) ##+##################################################################### ## PURPOSE: ## This procedure is invoked to (re)create the canvas items using the ## current GUI entries -- including an algebraic expression. ## Uses 'create line' to connect points in the plot. ## Uses 'create line' to create axes and tic-marks. ## Uses 'create text' for titles and tic-mark-labels. ## ## Arguments: none (uses global variables, many) ## ## CALLED BY: the 'UpdatePlot' button --- and in the 'downsize_canvas' ## and 'upsize_canvas' procs --- and in the 'getSet_canvasColor' ## proc --- and at the bottom of this script, ## in the 'Additional GUI Initialization' section. ##+##################################################################### proc update_plot {} { ## Titles from 'entry' widgets follow. global ENTRYtitleMain ENTRYtitleYaxis ENTRYtitleXaxis ## Plot limits and data values from 'entry' widgets follow. global ENTRYxaxismax ENTRYxaxismin ENTRYxticdist global ENTRYyaxismax ENTRYyaxismin ENTRYyticdist global ENTRYxvals ENTRYyvals ## Plot data info: math expression from 'entry' widget and ## requested number of points to plot from 'scale' widget follow. global ENTRYmathExpr SCALEnxvals ## Margins set by 'set_margins' proc follow. ## Determines the 'plot rectangle' within the canvas. global MARGNleftPx MARGNrightPx MARGNtopPx MARGNbotPx ## 'Regular' colors for text (titles and tic-mark labels), lines, ## and points follow. ## ## The text and line colors are set in proc 'set_plotColors' based ## on the choice of canvas color. ## ## We may temporarily change color while a text item is being moved. ## See BINDINGS section. global textCOLORregHEX lineCOLORhex pointCOLORregHEX ## Line width global variable --- for data-point connector lines, ## axes, and tic-marks. global lineWIDTHpx ## Checkbutton variables follow. global Points0or1 Border0or1 ## We may need to share the current canvas dimensions with other ## procs --- such as 'draw_lines' and 'draw_border'. global CURcanWidthPx CURcanHeightPx ## Some pixel parameters to be shared with proc 'draw_points'. global XaxisMINpx PX2UNITSx YaxisBOTpx PX2UNITSy ## Some data values to be shared with proc 'draw_points'. ## (These are 'world coordinates' not pixel coordinates. ## These are calculated from the math expression.) global Xvals Yvals ## Some values that may be used in math expressions. ## Set in the 'Additional GUI Initialization' section at the ## bottom of this Tk script. global pi e ########################################################## ## Make sure we are using the current canvas dimensions to ## place items on the plot canvas. ########################################################## set CURcanWidthPx [winfo width .fRlow.fRplot.can] set CURcanHeightPx [winfo height .fRlow.fRplot.can] ########################################################## ## Set some margin vars to be used to set endpoints of ## x and y axes, etc --- in pixel units. ## (NOTE: The contents of the 'set_margins' proc may ## need to take into account, i.e. use, various ## axis-location-related 'if' statements ## in this 'update_plot' code --- further below.) ########################################################## set_margins ########################################################### ## We now prepare the x and y values to plot. ########################################################### ## In case ENTRYxaxismax ENTRYxaxismin and ## ENTRYyaxismax ENTRYyaxismin are in integer form, ## convert them to floating. ## Not needed? ########################################################### # set ENTRYxaxismax [expr {double($ENTRYxaxismax)}] # set ENTRYxaxismin [expr {double($ENTRYxaxismin)}] # set ENTRYyaxismax [expr {double($ENTRYyaxismax)}] # set ENTRYyaxismin [expr {double($ENTRYyaxismin)}] ################################################################## ## Set the number of data-values requested in variable SCALEnxvals ## by doing a 'get' on the scale widget. Not needed? ################################################################## # get_numXvals ########################################################### ## (RE)LOAD DATA INTO Xvals & Yvals --- Tcl list vars. ## ## HERE IS WHERE WE CREATE THE X,Y DATA POINTS TO PLOT ## FROM THE MATH EXPRESSION. ## (We use SCALEnxvals points, equally spaced along the ## x-axis to calculate the y-values.) ## ## If the user makes a syntax error in entering the math ## expression, a Tk error dialog will popup at this point. ## (They should use '$x' for the x variable.) ## ## We do not clear the canvas before this point, so that the ## user is left with something (comforting) on the canvas. ########################################################### set Xvals {} set Yvals {} set deltaX [expr { double($ENTRYxaxismax - $ENTRYxaxismin) / $SCALEnxvals}] for {set i 0} {$i <= $SCALEnxvals} {incr i} { set x [expr {$ENTRYxaxismin + ($i * $deltaX)}] lappend Xvals $x lappend Yvals [eval expr {$ENTRYmathExpr}] ## Since we are not displaying the y-values (only plotting them), ## we do not need to format them nicely for display. # lappend Yvals [format "%f" [expr {$ENTRYmathExpr}]] # lappend Yvals [format "%2.2f" [expr {$ENTRYmathExpr}]] } ## FOR TESTING: # puts "Xval(0): [lindex $Xvals 0]" # puts "Yval(0): [lindex $Yvals 0]" # puts "Xval(3): [lindex $Xvals 3]" # puts "Yval(3): [lindex $Yvals 3]" ############################################################# ## CLEAR THE CANVAS WIDGET (and set border-toggle var to OFF). ############################################################# .fRlow.fRplot.can delete all ########################################################### ## PUT MAIN TITLE NEAR TOP OF THE PLOT-CANVAS. ## anchored to the left side of the plot area. ## NOTE: The user can use leading-spaces in the plot-title ## entry field to adjust the title to the right. ########################################################### # set xPX 10 set xPX $MARGNleftPx ## Note that we are placing the text with '-anchor nw' below. ## ## We set the northwest corner of the plot-title text ## just a few pixels below the top of the canvas ## and at the left side of the 'plot rectangle' set ## in the 'set_margins' proc. set yPX 5 .fRlow.fRplot.can create text \ $xPX $yPX \ -anchor nw \ -justify center \ -text "$ENTRYtitleMain" \ -font fontTEMP_plottext \ -fill "#$textCOLORregHEX" \ -tags {TAGmoveable TAGtext} ########################################################### ## SET XaxisMINpx,XaxisMAXpx,YaxisTOPpx,YaxisBOTpx ## (in canvas pixels) for global use for end-points of axes. ########################################################### ## YaxisTOPpx & YaxisBOTpx refer to locations at the top and ## bottom of the canvas area. ## XaxisMINpx & XaxisMAXpx refer to locations on the left and ## right of the canvas area. ########################################################### set XaxisMINpx $MARGNleftPx set XaxisMAXpx [expr { $CURcanWidthPx - $MARGNrightPx } ] set YaxisTOPpx $MARGNtopPx set YaxisBOTpx [expr { $CURcanHeightPx - $MARGNbotPx }] ########################################################### ## We put the Y-axis title near the top of the plot, ## horizontally oriented. ## NOTE: The user can use leading-spaces in the yaxis-title ## entry field to adjust the title to the right. ########################################################### # set xPX [expr { $MARGNleftPx + 4 } ] set xPX $MARGNleftPx ## Note that we are placing the text with '-anchor nw' below. ## ## We set the northwest corner of the yaxis-title text ## at the top of the left side of the 'plot rectangle' ## set in the 'set_margins' proc. # set yPX [expr { $MARGNtopPx - 3 }] set yPX $MARGNtopPx .fRlow.fRplot.can create text \ $xPX $yPX \ -anchor nw \ -justify left \ -text "$ENTRYtitleYaxis" \ -font fontTEMP_plottext \ -fill "#$textCOLORregHEX" \ -tags {TAGmoveable TAGtext} ########################################################### ## We put the X-axis title near the bottom of the canvas, ## anchored to the left side of the plot area. ## NOTE: The user can use leading-spaces in the xaxis-title ## entry field to adjust the title to the right. ########################################################### # set xPX [expr { $MARGNleftPx + 4 } ] set xPX $MARGNleftPx ## Note that we are placing the text with '-anchor sw' below. ## ## We set the southwest corner of the xaxis-title text ## just a few pixels above the bottom of the canvas ## and at the left side of the 'plot rectangle' set ## in the 'set_margins' proc. # set yPX $YaxisBOTpx set yPX [expr { $CURcanHeightPx - 5 }] .fRlow.fRplot.can create text \ $xPX $yPX \ -anchor sw \ -justify left \ -text "$ENTRYtitleXaxis" \ -font fontTEMP_plottext \ -fill "#$textCOLORregHEX" \ -tags {TAGmoveable TAGtext} ##################################################### ## SET FACTORS THAT WILL BE USED TO ## CONVERT DATA VALS TO PIXEL COORDS. ## Units: Pixels per 'world coordinate' units. ## Data type: floating point (not integer) ##################################################### set PX2UNITSx [expr { double( $XaxisMAXpx - $XaxisMINpx ) / ( $ENTRYxaxismax - $ENTRYxaxismin ) } ] set PX2UNITSy [expr { double( $YaxisBOTpx - $YaxisTOPpx ) / ( $ENTRYyaxismax - $ENTRYyaxismin ) } ] ## FOR TESTING: # puts "PX2UNITSx: $PX2UNITSx" # puts "PX2UNITSy: $PX2UNITSy" ########################################################### ## SET X-AXIS VERTICAL LOCATION (IN PIXELS) --- in XAXISyPX. ## If ENTRYxaxismax & ENTRYxaxismin straddle 0, ## set X-axis vert-loc according to location of y=0 IN PIXELS ## --- else use YaxisBOTpx. ## ## NOTE: These kinds of checks will probably need to be ## put in the 'set_margins' proc. ########################################################### set XAXISyPX $YaxisBOTpx if { $ENTRYyaxismax > 0 && $ENTRYyaxismin < 0 } { set XAXISyPX [ expr { $YaxisBOTpx + int($PX2UNITSy * $ENTRYyaxismin) } ] } ########################################################### ## SET Y-axis horizontal location (in pixels) --- in YAXISxPX. ## If ENTRYyaxismax & ENTRYyaxismin straddle 0, ## set Y-axis horiz-loc according to location of x=0 IN PIXELS ## --- else use XaxisMINpx. ## ## NOTE: These kinds of checks will probably need to be ## put in the 'set_margins' proc. ########################################################### set YAXISxPX $XaxisMINpx if { $ENTRYxaxismax > 0 && $ENTRYxaxismin < 0 } { set YAXISxPX [ expr { $XaxisMINpx - int($PX2UNITSx * $ENTRYxaxismin) } ] } ########################################################### ## DRAW X-AXIS. ########################################################### set x0PX $XaxisMINpx set y0PX $XAXISyPX set x1PX $XaxisMAXpx set y1PX $XAXISyPX .fRlow.fRplot.can create line \ $x0PX $y0PX \ $x1PX $y1PX \ -width $lineWIDTHpx -capstyle round -fill "#$lineCOLORhex" ########################################################### ## DRAW X-AXIS TIC-MARKS according to ENTRYxticdist ## and label them. ## ## These hard-coded x-axis tic-mark offsets may need to be ## set as a small percentage of the canvas height. ########################################################### # set ticOFFSETpx 15 set ticOFFSETpx 5 set xTicTopPx [expr { $y0PX - $ticOFFSETpx } ] set xTicBotPx [expr { $y0PX + $ticOFFSETpx } ] set Nxtics [expr { int ( ($ENTRYxaxismax - $ENTRYxaxismin) / $ENTRYxticdist) } ] set xTicIncrWrld $ENTRYxticdist set xTicIncrPx [expr { $PX2UNITSx * $xTicIncrWrld } ] set xDeciPlaces [get_deciPlaces "$xTicIncrWrld"] for {set i 0} {$i <= $Nxtics} {incr i} { set xPX [expr {$x0PX + ($i * $xTicIncrPx)}] .fRlow.fRplot.can create line \ $xPX $y0PX \ $xPX $xTicTopPx \ -width $lineWIDTHpx -capstyle round -fill "#$lineCOLORhex" set ticText [ format_deciPlaces [expr {$ENTRYxaxismin + ($xTicIncrWrld * $i)}] $xDeciPlaces ] .fRlow.fRplot.can create text \ $xPX $xTicBotPx \ -text $ticText \ -anchor n \ -font fontTEMP_SMALL_plottext \ -fill "#$textCOLORregHEX" \ -tags {TAGmoveable TAGtext} } ## END OF LOOP for {set i 0} {$i <= $Nxtics} {incr i} ########################################################### ## DRAW the Y-AXIS. ########################################################### set x0PX $YAXISxPX set y0PX $YaxisBOTpx set x1PX $YAXISxPX set y1PX $YaxisTOPpx .fRlow.fRplot.can create line $x0PX $y0PX \ $x1PX $y1PX \ -width $lineWIDTHpx -capstyle round -fill "#$lineCOLORhex" ########################################################### ## DRAW Y-AXIS TIC-MARKS according to ENTRYxyticdist ## and label them. ## ## These hard-coded y-axis tic-mark offsets may need to be ## set as a small percentage of the canvas width. ########################################################### # set ticOFFSETpx 15 set ticOFFSETpx 5 set yTicLeftPx [expr { $x0PX - $ticOFFSETpx } ] set yTicRightPx [expr { $x0PX + $ticOFFSETpx } ] set Nytics [expr { int ( ($ENTRYyaxismax - $ENTRYyaxismin) / $ENTRYyticdist) } ] set yTicIncrWrld $ENTRYyticdist set yTicIncrPx [expr { $PX2UNITSy * $yTicIncrWrld } ] set yDeciPlaces [get_deciPlaces "$yTicIncrWrld"] for {set i 0} {$i <= $Nytics} {incr i} { set yPX [expr {$y0PX - ($i*$yTicIncrPx)}] .fRlow.fRplot.can create line \ $x0PX $yPX \ $yTicRightPx $yPX \ -width $lineWIDTHpx -capstyle round -fill "#$lineCOLORhex" set ticText [ format_deciPlaces [expr {$ENTRYyaxismin + ($yTicIncrWrld * $i)}] $yDeciPlaces ] .fRlow.fRplot.can create text \ $yTicLeftPx $yPX \ -text $ticText \ -anchor e \ -justify right \ -font fontTEMP_SMALL_plottext \ -fill "#$textCOLORregHEX" \ -tags {TAGmoveable TAGtext} } ## END OF LOOP for {set i 0} {$i <= $Nytics} {incr i} ####################################################### ## PLOT LINES connecting the data points in Xvals,Yvals. ####################################################### ## LOOP THRU the x,y DATA LISTS, CREATING LINE SEGMENTS. ## But first set the xprev,yprev coords (in pixels). ##################################################### set xprev [expr {$XaxisMINpx + ( $PX2UNITSx * ( [lindex $Xvals 0] - $ENTRYxaxismin ) ) } ] set yprev [expr {$YaxisBOTpx - ( $PX2UNITSy * ( [lindex $Yvals 0] - $ENTRYyaxismin ) ) } ] for {set i 1} {$i <= $SCALEnxvals} {incr i} { ## FOR TESTING: # puts "ENTRYxaxismin: $ENTRYxaxismin" # puts "Xval(i): [lindex $Xvals $i]" # puts "i: $i" set xPX [expr {$XaxisMINpx + int( $PX2UNITSx * ( [lindex $Xvals $i] - $ENTRYxaxismin ) ) } ] set yPX [expr {$YaxisBOTpx - int( $PX2UNITSy * ( [lindex $Yvals $i] - $ENTRYyaxismin ) ) } ] .fRlow.fRplot.can create line \ $xprev $yprev \ $xPX $yPX \ -width $lineWIDTHpx -capstyle round -fill "#$lineCOLORhex" set xprev $xPX set yprev $yPX } ## END OF LOOP for {set i 1} {$i <= $SCALEnxvals} {incr i} ################################################################### ## If 'Points' checkbutton is ON, draw data-points. ## If 'Border' checkbutton is ON, draw border. ################################################################### if {$Points0or1 == 1} {draw_points} if {$Border0or1 == 1} {draw_border} } ## END of proc 'update_plot' ##+##################################################################### ## proc 'set_margins' ##+##################################################################### ## PURPOSE: ## Sets 4 'MARGN' variables that can be used to consistently set the ## limits of the 'plot rectangle' within the canvas widget. ## ## The 'plot rectangle' is the area on the canvas to which we want ## to confine the plotting of the data points. ## ## (Often the X-axis will be drawn at the bottom of the 'plot rectangle' ## and the Y-axis will be drawn at the left of the 'plot rectangle' ## --- BUT NOT ALWAYS.) ## ## The 4 'MARGN' values, in pixels, are meant to be: ## ## MARGNtopPx distance between TOP side of canvas and ## TOP side of 'plot rectangle' ## MARGNleftPx distance between LEFT side of canvas and ## LEFT side of 'plot rectangle' ## MARGNrightPx distance between RIGHT side of canvas and ## RIGHT side of 'plot rectangle' ## MARGNbotPx distance between BOTTOM side of canvas and ## BOTTOM side of 'plot rectangle' ## ## (Whenever the canvas is resized, these 'MARGN' values can be ## used to resize the 'central' plot rectangle.) ## #################################### ## SPECIFICS OF THE 'plot rectangle': (top,left,right,bottom) ## ## The 'plot rectangle' is always meant to allow some margin at ## the TOP of the canvas for a plot title --- without data points ## going into the plot title. ## ## The 'plot rectangle' is typically meant to allow some margin ## at the LEFT of the canvas, for some tic-mark labels on the ## left of a vertical Y-axis --- especially when that Y-axis is ## drawn at the left of the 'plot rectangle'. ## ## The 'plot rectangle' is typically meant to allow some margin ## at the RIGHT of the canvas, for some tic-mark labels on the ## right of a vertical Y-axis --- especially when the ## Y-axis is drawn at the right of the 'plot rectangle' ## (for example at x=0 when that is the right end of the x-axis). ## ## The 'plot rectangle' is typically meant to allow some margin ## at the BOTTOM of the canvas, for some tic-mark labels on the ## bottom side of a horizontal X-axis --- especially when the ## X is drawn at the bottom of the 'plot rectangle'. ## ######################################### ## MORE SPECIFICS OF THE 'plot rectangle': (dimensions) ## ## The 'plot rectangle', horizontally, starts at one end ## of the x-axis and goes to the other end of the x-axis ## --- in other words, the horizontal dimension of the ## 'plot rectangle' is supposed to be exactly equal to ## the length of the x-axis. ## ## The 'plot rectangle', vertically, starts at one end ## of the y-axis and goes to the other end of the y-axis ## --- in other words, the vertical dimension of the ## 'plot rectangle' is supposed to be exactly equal to ## the length of the y-axis. ## ## In short, the 'plot rectangle' is the smallest rectangle ## containing the drawing of the x and y axes. ## ############################################# ## USING FONT SIZES IN SETTING 'MARGN' VALUES: ## ## The plot-titles, axis-titles, and tic-mark labels generally ## lie outside the 'plot rectangle', so these 4 'MARGN' values ## should take those items into account (allow room for them). ## (Since the plot-titles, axis-titles, and tic-mark labels in ## this app can be moved, we have a little lee-way in setting ## the margins --- but not much.) ## ## Because of the text items in the margins, the choice of fonts ## (set at top of script) can/should be used to set these 4 ## 'MARGN' values (in pixels). ## ## Note that we set these margins in 'absolute' pixel units ## rather than as 'proportionality factors' to be applied ## to the canvas dimensions. ## ## These 4 'margin values' will be used to set variables that ## will be used to define the ending points (in pixel units) ## of the plot axes within the plot canvas, ## say XaxisMINpx,XaxisMAXpx,YaxisTOPpx,YaxisBOTpx (in pixels). ##+######################################################## ## Example use: ## set XaxisMINpx $MARGNleftPx ## set XaxisMAXpx [expr { $CURcanWidthPx - $MARGNrightPx } ] ## set YaxisTOPpx $MARGNtopPx ## set YaxisBOTpx [expr { $CURcanHeightPx - $MARGNbotPx }] ##+######################################################## ## CALLED BY: the 'update_plot' proc ##+######################################################## proc set_margins {} { ## The 'MARGN' settings below assume a Y axis at the left ## of the 'plot rectangle' and an X-axis at the bottom. ## ## Eventually we will want to put in logic, like some in ## the 'update_plot' proc, to take into account situations ## like X-axis above the bottom --- even at the top --- ## and Y axis in the middle or on the right. ## The variable 'CharHeightPx' was set where the GUI window ## minsize was set, near the top of this script. Specifically: ## set CharHeightPx [font metrics fontTEMP_varwidth -linespace] ## ## But we did not set a 'CharWidthPx' variable. ## We do that here. global CharHeightPx \ MARGNleftPx MARGNrightPx MARGNtopPx MARGNbotPx set CharWidthPx [font measure fontTEMP_varwidth "W"] ## NOTE: We are setting margins (in pixels) according ## to the font being used for text on the plot --- ## irrespective of the current dimensions of the canvas. ## I.e. we are not using percentages of canvas dimensions. set MARGNleftPx [expr {4 * $CharWidthPx}] set MARGNrightPx [expr {2 * $CharWidthPx}] set MARGNtopPx [expr {2 * $CharHeightPx}] set MARGNbotPx [expr {3 * $CharHeightPx}] } ## END of proc 'set_margins' ##+##################################################################### ## proc 'get_numXvals' ## (Not needed? '-variable' on scale widget suffices?) ##+##################################################################### ## PURPOSE: To get the number of X values to generate (between ## ENTRYxaxismin and ENTRYxaxismax), from which ## to compute Yvals from $ENTRYmathExpr. ## ## METHOD: Uses 'get' on the scale widget to get the current ## number of data-values requested by the user. ## ## CALLED BY: proc 'update_plot' ##+##################################################################### proc get_numXvals {} { global SCALEnxvals set SCALEnxvals [.fRexpr_opts.scaleNVALS get] } ## END of proc 'get_numXvals' ##+##################################################################### ## PROC 'get_deciPlaces' ##+##################################################################### ## PURPOSE: Get the number of decimal places in a number string. ## ## Argument: a number string like 10.0 or 10 or 0.25 ## ## CALLED BY: the 'update_plot' proc ##+##################################################################### proc get_deciPlaces {input} { set deciPlaces [string length [lindex [split "$input" "."] 1]] return "$deciPlaces" } ## END of proc 'get_deciPlaces' ##+##################################################################### ## PROC 'format_deciPlaces' ##+##################################################################### ## PURPOSE: Format a number string to have a given number of ## decimal places. ## ## Arguments: a number string AND an integer specifying the ## number of decimal places ## ## CALLED BY: the 'update_plot' proc ##+##################################################################### proc format_deciPlaces {input places} { set FORMAT4number "%0.${places}f" set output [format "$FORMAT4number" $input] return "$output" } ## END of proc 'format_deciPlaces' ##+##################################################################### ## proc 'itemSelect' ##+##################################################################### ## PURPOSE: ## This procedure is invoked when the mouse is pressed over a ## canvas item. It sets up a state to allow the item to be dragged. ## ## Arguments: ## w - The canvas window. ## x, y - The coordinates of the mouse press. ## ## CALLED BY: a binding on the canvas ##+##################################################################### set lastXsel 0 set lastYsel 0 proc itemSelect {w x y} { global lastXsel lastYsel ## Delete the tag 'TAGselected' from any 'TAGselected' items. $w dtag TAGselected ## Add the tag 'TAGselected' to the currently selected item. $w addtag TAGselected withtag current $w raise current set lastXsel $x set lastYsel $y } ## END of proc 'itemSelect' ##+##################################################################### ## proc 'itemMove' ##+##################################################################### ## ## PURPOSE: ## This procedure is invoked during mouse motion events. ## It drags the current item. ## ## Arguments: ## w - The canvas window. ## x, y - The coordinates of the mouse. ## ## CALLED BY: the binding ## .fRlow.fRplot.can ##+##################################################################### proc itemMove {w x y} { global lastXsel lastYsel $w move TAGselected [expr {$x - $lastXsel}] [expr {$y - $lastYsel}] set lastXsel $x set lastYsel $y } ## END of proc 'itemMove' ##+##################################################################### ## proc 'draw_points' ##+##################################################################### ## PURPOSE: Draw markers at the data points --- for example circles ## drawn with canvas 'create oval'. ## ## METHOD: ## Uses 'create oval' to draw markers at the data points. If needed, ## can raise the datapoint markers (that were done with 'create oval') ## so that parts of them are not hidden by the data-lines. ## ## Arguments: none (global variables) ## ## CALLED BY: checkbutton 'Points' ##+##################################################################### proc draw_points {} { global ENTRYxaxismax ENTRYxaxismin ENTRYyaxismax ENTRYyaxismin ## We get some pixel parameters that were set in proc 'update_plot'. global CURcanWidthPx CURcanHeightPx \ XaxisMINpx PX2UNITSx YaxisBOTpx PX2UNITSy ## We get some other parameters that were set via proc 'update_plot'. global SCALEnxvals Xvals Yvals lineWIDTHpx lineCOLORhex pointCOLORregHEX ######################################################## ## SET Pixel-RADIUS for DATA MARKERS. (Circles) ## ## (We could use squares if we give the user a choice via ## radiobuttons or listbox or spinbox or whatever.) ## ## As monitors get higher resolution, we may want to set ## this as a small percentage of the screen width/height. ######################################################## set markerRadiusPx 3 ##################################################### ## LOOP THRU DATA LISTS, CREATING LINE SEGMENTS. ## But first set the xprev,yprev coords (in pixels). ##################################################### set xprevPX [expr {$XaxisMINpx + ( $PX2UNITSx * ( [lindex $Xvals 0] - $ENTRYxaxismin ) ) } ] set yprevPX [expr {$YaxisBOTpx - ( $PX2UNITSy * ( [lindex $Yvals 0] - $ENTRYyaxismin ) ) } ] for {set i 1} {$i < $SCALEnxvals} {incr i} { ## FOR TESTING: # puts "ENTRYxaxismin: $ENTRYxaxismin" # puts "Xval(i): [lindex $Xvals $i]" # puts "i: $i" set xPX [expr {$XaxisMINpx + ( $PX2UNITSx * ( [lindex $Xvals $i] - $ENTRYxaxismin ) ) } ] set yPX [expr {$YaxisBOTpx - ( $PX2UNITSy * ( [lindex $Yvals $i] - $ENTRYyaxismin ) ) } ] .fRlow.fRplot.can create oval \ [expr {$xPX - $markerRadiusPx}] [expr {$yPX - $markerRadiusPx}] \ [expr {$xPX + $markerRadiusPx}] [expr {$yPX + $markerRadiusPx}] \ -outline "#$lineCOLORhex" -width 1 -fill "#$pointCOLORregHEX" \ -tags TAGdataPoints # -width $lineWIDTHpx } ## END OF LOOP for {set i 1} {$i < $NXvals} {incr i} ##################################################### ## RAISE DATA-POINT IMAGES ABOVE DATA-LINE IMAGES. ## (We could pause before doing the raise, to indicate ## it is being done --- i.e. it is really optional.) ##################################################### # after 1200 { .fRlow.fRplot.can raise TAGdataPoints } .fRlow.fRplot.can raise TAGdataPoints } ## END OF proc 'draw_points' ##+##################################################################### ## proc 'draw_border' ##+##################################################################### ## PURPOSE: To draw a border around the edge of the canvas. ## ## METHOD: ## Uses 'create line' to draw 4 straight lines and uses ## 'create arc' to draw 4 rounded corners. ## ## Arguments: none ## ## CALLED BY: button .fRbuttons.buttBorder ##+##################################################################### proc draw_border {} { ## Get current canvas dimensions, set in 'update_plot' proc. global CURcanWidthPx CURcanHeightPx lineCOLORhex lineWIDTHpx ################################################# ## Set border limits. ################################################# set BDxminPx [expr { int(0.01 * $CURcanWidthPx) } ] set BDxmaxPx [expr { int(0.99 * $CURcanWidthPx) } ] set BDytopPx [expr { int(0.01 * $CURcanHeightPx) }] set BDybotPx [expr { int(0.99 * $CURcanHeightPx) }] ################################################# ## Set corner arc radius. ################################################# set minDim $CURcanWidthPx if { $minDim > $CURcanHeightPx } { set minDim $CURcanHeightPx } set BDradPx [expr { 0.03 * $minDim } ] ################################################# ## Draw the four border lines (left,right,top,bot). ################################################# .fRlow.fRplot.can create line \ $BDxminPx [expr { $BDytopPx + $BDradPx } ] \ $BDxminPx [expr { $BDybotPx - $BDradPx } ] \ -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder .fRlow.fRplot.can create line \ $BDxmaxPx [expr { $BDytopPx + $BDradPx } ] \ $BDxmaxPx [expr { $BDybotPx - $BDradPx } ] \ -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder .fRlow.fRplot.can create line \ [expr { $BDxminPx + $BDradPx } ] $BDytopPx \ [expr { $BDxmaxPx - $BDradPx } ] $BDytopPx \ -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder .fRlow.fRplot.can create line \ [expr { $BDxminPx + $BDradPx } ] $BDybotPx \ [expr { $BDxmaxPx - $BDradPx } ] $BDybotPx \ -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder ################################################# ## Draw the four border arcs (UL,UR,LR,LL). ################################################# .fRlow.fRplot.can create arc \ $BDxminPx $BDytopPx \ [expr { $BDxminPx + 2*$BDradPx } ] [expr { $BDytopPx + 2*$BDradPx } ] \ -start 90 \ -extent 90 \ -style arc -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder .fRlow.fRplot.can create arc \ $BDxmaxPx $BDytopPx \ [expr { $BDxmaxPx - 2*$BDradPx } ] [expr { $BDytopPx + 2*$BDradPx } ] \ -start 0 \ -extent 90 \ -style arc -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder .fRlow.fRplot.can create arc \ $BDxmaxPx $BDybotPx \ [expr { $BDxmaxPx - 2*$BDradPx } ] [expr { $BDybotPx - 2*$BDradPx } ] \ -start 270 \ -extent 90 \ -style arc -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder .fRlow.fRplot.can create arc \ $BDxminPx $BDybotPx \ [expr { $BDxminPx + 2*$BDradPx } ] [expr { $BDybotPx - 2*$BDradPx } ] \ -start 180 \ -extent 90 \ -style arc -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder } ## END of proc 'draw_border' ##+##################################################################### ## proc 'getSet_canvasColor' ##+##################################################################### ## PURPOSE: Gets an RGB hex-color value (via a GUI with 3 RGB slider bars). ## The user uses the RGB color-selector GUI to select a color. ## ## Then sets the canvas 'bg' (background) to that color. ## ## NOTE: We always expect hex-color variables to hold the color in a ## form like 'ffffff' rather than '#ffffff'. We will supply the ## '#' wherever we use the hex-color variable. ## ## Arguments: none ## ## CALLED BY: the 'CanvasColor' button ##+##################################################################### proc getSet_canvasColor {} { global CANr255 CANg255 CANb255 RGBcolorSelectorScript ## FOR TESTING: # puts "CANr255: $CANr255" # puts "CANg255: $CANg255" # puts "CANb255: $CANb255" set TEMPrgb [ exec $RGBcolorSelectorScript $CANr255 $CANg255 $CANb255] ## FOR TESTING: # puts "TEMPrgb: $TEMPrgb" if { "$TEMPrgb" == "" } { return } ## Script 'sho_colorvals_via_sliders3rgb.tk' puts out 4 strings ## of the form 'r255 g255 b255 hexRGB' where the ## first 3 are integers (0-255) and the last is a 6-char hex RGB code. scan $TEMPrgb "%s %s %s %s" CANr255 CANg255 CANb255 hexRGB ## FOR TESTING: # puts "PROC 'getSet_canvasColor' :" # puts "TEMPrgb: $TEMPrgb" # puts "CANr255: $CANr255" # puts "CANg255: $CANg255" # puts "CANb255: $CANb255" ## Set the canvas background color and 'related' plot colors. set_plotColors "$hexRGB" ## Update the plot to apply the new colors. # update update_plot } ## END OF proc 'getSet_canvasColor' ##+##################################################################### ## proc 'set_plotColors' ##+##################################################################### ## PURPOSE: ## For a given hex RGB color, set the canvas background color ## and set 'related' (global) color variables: ## lineCOLORhex ## textCOLORregHEX ## textCOLORselHEX ## 'reg' = regular ; 'sel' = selected ## ## Argument: a hex RGB color string, like 'ff9933' ## ## CALLED BY: proc 'getSet_canvasColor' and at bottom of this script, in ## the 'Additional GUI Initialization' section, to ## initialize canvas color and related colors. ##+##################################################################### proc set_plotColors {hexRGBcolor} { global lineCOLORhex textCOLORregHEX textCOLORselHEX pointCOLORregHEX ############################################ ## Apply the color to the canvas background. ############################################ .fRlow.fRplot.can configure -bg "#$hexRGBcolor" ##+########################################### ## SET COLORS FOR CANVAS LINE and TEXT ITEMS. ## 'reg' = regular ; 'sel' = selected ## ## For line and text colors, we can use a choice ## of procs --- such as ## 'invert_hexRGBcolor' or ## 'blackORwhite_farthestFromHexRGBcolor' ## ## For the 'sel' text color, we want a color ## distinct from the 'reg' color. We use an ## 'augment_hexRGBcolor' proc. ##+########################################### # set lineCOLORhex [invert_hexRGBcolor "$hexRGBcolor"] set lineCOLORhex [blackORwhite_farthestFromHexRGBcolor "$hexRGBcolor"] # set textCOLORregHEX [invert_hexRGBcolor "$hexRGBcolor"] set textCOLORregHEX [blackORwhite_farthestFromHexRGBcolor "$hexRGBcolor"] set textCOLORselHEX [augment_hexRGBcolor "$textCOLORregHEX"] ######################################################### ## Set color for points (interior of ovals/circles). ## ## In the 'update_plot' proc, the outline of the circles ## is drawn with $lineCOLORhex. For some contrast, we ## used a differentiated color, such as $textCOLORselHEX ## --- the 'selected' text color --- or the canvas color, ## which should be quite different from the line color. ######################################################### ## A medium gray. # set pointCOLORregHEX "888888" # set pointCOLORregHEX "$textCOLORselHEX" set pointCOLORregHEX "$hexRGBcolor" ## FOR TESTING: if {0} { puts "PROC 'set_plotColors' :" puts "Canvas color: $hexRGBcolor" puts "Line color: $lineCOLORhex" puts "Text-regular color: $textCOLORregHEX" puts "Text-selected color: $textCOLORselHEX" puts "Point (circle) color: $pointCOLORregHEX" } } ## END OF proc 'set_plotColors' ##+##################################################################### ## proc 'invert_hexRGBcolor' ##+##################################################################### ## PURPOSE: For a given hex RGB color, invert it. ## Returns the inverted color as a hex RGB string. ## ## Argument:a hex RGB color string, like 'ff9933' ## ## CALLED BY: proc 'set_plotColors' ##+##################################################################### proc invert_hexRGBcolor {hexRGBin} { ## FOR TESTING: # puts "PROC 'invert_hexRGBcolor' :" # puts "hexRGBin: $hexRGBin" scan $hexRGBin "%2x%2x%2x" r255 g255 b255 set R255 [expr {255 - $r255}] set G255 [expr {255 - $g255}] set B255 [expr {255 - $b255}] set hexRGBout [format "%02x%02x%02x" $R255 $G255 $B255] return $hexRGBout } ## END OF proc 'invert_hexRGBcolor' ##+##################################################################### ## proc 'blackORwhite_farthestFromHexRGBcolor' ##+##################################################################### ## PURPOSE: For a given hex RGB color, returns either black or white ## --- as the hex RGB string '000000' or 'ffffff'. ## ## Argument:a hex RGB color string, like 'ff9933' ## ## CALLED BY: proc 'set_plotColors' ##+##################################################################### proc blackORwhite_farthestFromHexRGBcolor {hexRGBin} { scan $hexRGBin "%2x%2x%2x" r255 g255 b255 set tempRGBtot [expr {$r255 + $g255 + $b255}] set tempTOTlim 360 # set tempTOTlim 200 if {$tempRGBtot > $tempTOTlim} { set hexRGBout "000000" } else { set hexRGBout "ffffff" } return "$hexRGBout" } ## END OF proc 'blackORwhite_farthestFromHexRGBcolor' ##+##################################################################### ## proc 'augment_hexRGBcolor' ##+##################################################################### ## PURPOSE: For a given hex RGB color, make a color fairly distinct ## from it --- without exceeding the 0-255 limit for the ## RGB channels. ## Returns the 'augmented' color as a hex RGB string. ## ## Argument:a hex RGB color string, like 'ff9933' ## ## CALLED BY: proc 'set_plotColors' ##+##################################################################### proc augment_hexRGBcolor {hexRGBin} { scan $hexRGBin "%2x%2x%2x" r255 g255 b255 ## AUGamt should be less than half of 255, less than 127. # set AUGamt 40 set AUGamt 80 set R255 [expr {$r255 + $AUGamt}] if {$R255 > 255} { set R255 [expr {$r255 - $AUGamt}] } set G255 [expr {$g255 + $AUGamt}] if {$G255 > 255} { set G255 [expr {$g255 - $AUGamt}] } set B255 [expr {$b255 + $AUGamt}] if {$B255 > 255} { set B255 [expr {$b255 - $AUGamt}] } set hexRGBout [format "%02x%02x%02x" $R255 $G255 $B255] return $hexRGBout } ## END OF proc 'augment_hexRGBcolor' ##+##################################################################### ## proc 'downsize_canvas' ##+##################################################################### ## PURPOSE: To DOWN-size the canvas. ## ## METHOD: ## We apply a factor to the current width and height of the canvas. ## Then we call 'update_plot' to redo the plot. ## ## Actually we resize the entire GUI window and let the Tk 'pack' ## geometry manager take care of resizing the canvas appropriately ## according to the various '-fill' and '-expand' parameters for ## the widgets of the GUI. ## ## NOTE: ## The user can keep clicking the 'DwnCan' button to downsize ~5% per click. ## ## Arguments: none ## ## CALLED BY: the 'DwnCan' button ##+##################################################################### proc downsize_canvas {} { ############################################################## ## Downsize the GUI (top level) window somewhat. ############################################################## resize_win 0.95 ############################################################# ## Re-do the plot, according to the new canvas size --- which ## should be reduced because entire GUI window was reduced. ## ## The 'update' is necessary because 'update_plot' does not ## do 'update' before querying for the current canvas size. ############################################################# update update_plot } ## END OF proc 'downsize_canvas' ##+##################################################################### ## proc 'upsize_canvas' ##+##################################################################### ## PURPOSE: To UP-size the canvas. ## ## METHOD: ## We apply a factor to the current width and height of the canvas. ## Then we call 'update_plot' to redo the plot. ## ## Actually we resize the entire GUI window and let the Tk 'pack' ## geometry manager take care of resizing the canvas appropriately ## according to the various '-fill' and '-expand' parameters for ## the widgets of the GUI. ## ## NOTE: ## The user can keep clicking the 'UpCan' button to upsize ~5% per click. ## ## Arguments: none ## ## CALLED BY: the 'UpCan' button ##+##################################################################### proc upsize_canvas {} { ################################################################ ## Upsize the GUI (top level) window somewhat. ################################################################ resize_win 1.05 ########################################################### ## Re-do the plot, according to the new canvas size --- ## which should be enlarged because window was enlarged. ## ## The 'update' is necessary because 'update_plot' does not ## do 'update' before querying for the current canvas size. ########################################################### update update_plot } ## END OF proc 'upsize_canvas' ##+##################################################################### ## proc 'resize_win' ##+##################################################################### ## PURPOSE: To UP/DOWN-size the Tk window by a given factor. ## ## METHOD: Several methods could be used. ## For now, we query the top level (GUI) window width and height ## (and location) with 'wm' (rather than 'winfo') and apply the ## input argument ('factor') to the current window width and height. ## ## Then reset the window size (and location) with 'wm'. ## ## Arguments: one --- 'factor' ## ## CALLED BY: 'upsize_canvas' and 'downsize_canvas' procs ##+##################################################################### proc resize_win {factor} { ## This is not the exact window DIMENSIONS we want. ## These do not include the window decoration. # set winXlenPx [ winfo width . ] # set winYlenPx [ winfo height . ] ## FOR TESTING: # puts "FROM proc 'resize_win':" # puts "winfo-width-winXlenPx : $winXlenPx" # puts "winfo-width-winYlenPx : $winYlenPx" ## This is not the window LOCATION we want. ## It is the upper-left of the window without the window decoration. # set winXlocPx [ winfo rootx . ] # set winYlocPx [ winfo rooty . ] ## FOR TESTING: # puts "FROM proc 'resize_win':" # puts "winfo-rootx-winXlocPx : $winXlocPx" # puts "winfo-rooty-winYlocPx : $winYlocPx" ## NOTE: ## [wm geometry .] returns integers of the form ## ${winXlenPx}x${winYlenPx}+${winXlocPx}+${winYlocPx} set WMgeom [wm geometry .] set winXYlenPx [lindex [split $WMgeom '+'] 0] set winXlenPx [lindex [split $winXYlenPx 'x'] 0] set winYlenPx [lindex [split $winXYlenPx 'x'] 1] set winXlocPx [lindex [split $WMgeom '+'] 1] set winYlocPx [lindex [split $WMgeom '+'] 2] ## FOR TESTING: # puts "FROM proc 'resize_win':" # puts "wm-winXlenPx : $winXlenPx" # puts "wm-winYlenPx : $winYlenPx" # puts "wm-winXlocPx : $winXlocPx" # puts "wm-winYlocPx : $winYlocPx" ## Reduce the window size according to argument 'factor'. set winXlenPx [expr {int(floor ( $factor * $winXlenPx ))} ] set winYlenPx [expr {int(floor ( $factor * $winYlenPx ))} ] ## Adjust the 'locPx' vars for the window manager border. ## 'wm' does not account for the window decoration. ## We will have to adjust, to (try to) keep the upper-left corner ## of the window in place. set winXlocPx [ expr {$winXlocPx - 3} ] set winYlocPx [ expr {$winYlocPx - 23} ] wm geometry . ${winXlenPx}x${winYlenPx}+${winXlocPx}+${winYlocPx} } ## END OF proc 'resize_win' ##+##################################################################### ## proc 'getPut_image' ##+##################################################################### ## PURPOSE: To put one or more images (e.g. a logo) on the canvas. ## ## METHOD: ## Uses 'tk_getOpenFile' dialog to get an image filename (GIF or PNG). ## Uses Tk 'image create photo' command to create an in-memory image structure. ## Uses canvas 'create image' command to put the image on the canvas. ## ## NOTE: (on a Tk postscript limitation) ## A Tk image on a Tk canvas is not captured by the Tk canvas 'postscript' ## command. But a screen image could be captured --- in a PNG or GIF or JPEG ## file --- with a screen capture utility such as 'gnome-screenshot' --- ## for use in e-mails, web pages, or other docs. ## The screen image, in a PNG file say, could be printed with the Print ## option in a utility such as a web browser. ## ## Arguments: none ## ## CALLED BY: the 'GetImg' button ##+##################################################################### proc getPut_image {} { ## For de-activating this proc: # return ## DIRimages is set in the 'Additional GUI Initialization' section ## at the bottom of this script. global CURcanWidthPx CURcanHeightPx DIRimages set fName "" set fName [tk_getOpenFile -parent . \ -title "Select an image file (GIF or PNG)." \ -initialdir "$DIRimages" ] ## FOR TESTING: # puts "fName : $fName" if {"$fName" == ""} {return} if {[file exists "$fName"]} { ################################################ ## If the filename from the file selector exits, ## 1) create the in-memory image ## 2) put the in-memory image on the canvas ## --- near bottom-right of canvas. ############################################### set imgID [image create photo -file "$fName"] set xPx [expr { int(0.95 * $CURcanWidthPx) } ] set yPx [expr { int(0.95 * $CURcanHeightPx) }] .fRlow.fRplot.can create image \ $xPx $yPx -anchor se -image $imgID \ -tags {TAGmoveable TAGimage} ## Could pop a message here to user letting them know ## that the image is draggable --- and that Tk ## Postscript output from a Tk canvas will not show ## the image --- and they can 'delete' the image ## by dragging it off the canvas. Alternative: ## .fRlow.fRplot.can delete TAGimage } ## END OF if {[file exists "$fName"]} } ## END of proc 'getPut_image' ##+##################################################################### ## proc 'print_preview' ##+##################################################################### ## PURPOSE: To make and view a Postscript file of the canvas image. ## ## Arguments: none ## ## CALLED BY: the 'PrtPreview' button ##+##################################################################### proc print_preview {} { global env PSviewer DIRtemp #################################################### ## Make a name of the to-be-created postscript file. #################################################### set tmp_filename "${DIRtemp}/$env(USER)_tmp_tkplot.ps" ##################################################### ## Remove a file by the same name from a previous run. ##################################################### ## It looks like we can do it without this 'eval' method. # eval exec rm -f "$tmp_filename" exec rm -f "$tmp_filename" ############################### ## Make the postscript file. ############################### .fRlow.fRplot.can postscript -file "$tmp_filename" \ -colormode color \ -pageheight 10i \ -pagewidth 7i \ -pagex 1i \ -pagey 1i \ -pageanchor sw # -colormode color # -colormode gray # -colormode monochrome ################################################ ## Show the postscript file in a viewer program. ################################################ ## It looks like we can do it without this 'eval' method. # eval exec "$PSviewer \"$tmp_filename\" &" exec $PSviewer "$tmp_filename" & ###################################################### ## We could delete the file. But leave it for the user ## in case they want to do something else with it. ###################################################### # exec rm -f "$tmp_filename" } ## END of proc 'print_preview' ##+##################################################################### ## proc 'print_plot' ##+##################################################################### ## PURPOSE: To make and send a Postscript file of the canvas image ## to a printer. ## ## Arguments: none ## ## CALLED BY: the 'Print' button ##+##################################################################### proc print_plot {} { global env PRINTcmd DIRtemp #################################################### ## Make a name of the to-be-created postscript file. #################################################### set tmp_filename "${DIRtemp}/$env(USER)_tmp_tkplot.ps" ##################################################### ## Remove a file by the same name from a previous run. ##################################################### eval exec rm -f "$tmp_filename" ################################################### ## Make the postscript file. ################################################### .fRlow.fRplot.can postscript -file "$tmp_filename" \ -colormode color \ -pageheight 10i \ -pagewidth 7i \ -pagex 1i \ -pagey 1i \ -pageanchor sw # -colormode color # -colormode gray # -colormode monochrome ################################################ ## Print the postscript file using a command ## set in the 'ADDITIONAL GUI INITIALIZATION' ## section at the bottom of this script. ################################################ eval exec $PRINTcmd "$tmp_filename" ###################################################### ## We could delete the file. But leave it for the user ## in case they want to do something else with it. ###################################################### # eval exec rm "$tmp_filename" } ## END of proc 'print_plot' ##+######################################################################## ## PROC: 'popup_shortmsg' ##+######################################################################## ## PURPOSE: Popup a short message to user --- usually a one or two ## line error message. ## ## METHOD: We can use 'tk_dialog' or we can use the ## 'popup_msgVarWithScroll' proc below. ## ## CALLED BY: various procs --- 'update_plot' and maybe more. ##+####################################################################### proc popup_shortmsg { title message } { tk_dialog .xxx "$title" "$message" warning 0 Close # popup_msgVarWithScroll .xxx "$message" +40+40 } ## END of proc 'popup_shortmsg' ##+######################################################################## ## PROC: 'popup_msgVarWithScroll' ##+######################################################################## ## PURPOSE: Report help or error conditions to the user. ## ## We do not use focus,grab,tkwait in this proc, ## because we use it to show help when the GUI is idle, ## and we may want the user to be able to keep the Help ## window open while doing some other things with the GUI ## such as putting a filename in the filename entry field ## or clicking on a radiobutton. ## ## For a similar proc with focus-grab-tkwait added, ## see the proc 'popup_msgVarWithScroll_wait' in a ## 3DterrainGeneratorExaminer Tk script. ## ## REFERENCE: page 602 of 'Practical Programming in Tcl and Tk', ## 4th edition, by Welch, Jones, Hobbs. ## ## ARGUMENTS: A toplevel frame name (such as .fRhelp or .fRerrmsg) ## and a variable holding text (many lines, if needed). ## ## CALLED BY: 'help' button ##+######################################################################## ## To have more control over the formatting of the message (esp. ## words per line), we can use this 'toplevel-text' method, rather than ## the 'tk_dialog' method -- example on page 574 of the book ## by Hattie Schroeder & Mike Doyel,'Interactive Web Applications ## with Tcl/Tk', Appendix A "ED, the Tcl Code Editor". ##+######################################################################## proc popup_msgVarWithScroll { toplevName VARtext ULloc} { ## global fontTEMP_varwidth #; Not needed. 'wish' makes these global. ## global env # bell # bell ################################################# ## Set VARwidth & VARheight from $VARtext. ################################################# ## To get VARheight, ## split at '\n' (newlines) and count 'lines'. ################################################# set VARlist [ split $VARtext "\n" ] ## For testing: # puts "VARlist: $VARlist" set VARheight [ llength $VARlist ] ## For testing: # puts "VARheight: $VARheight" ################################################# ## To get VARwidth, ## loop through the 'lines' getting length ## of each; save max. ################################################# set VARwidth 0 ############################################# ## LOOK AT EACH LINE IN THE LIST. ############################################# foreach line $VARlist { ############################################# ## Get the length of the line. ############################################# set LINEwidth [ string length $line ] if { $LINEwidth > $VARwidth } { set VARwidth $LINEwidth } } ## END OF foreach line $VARlist ## For testing: # puts "VARwidth: $VARwidth" ############################################################### ## NOTE: VARwidth works for a fixed-width font used for the ## text widget ... BUT the programmer may need to be ## careful that the contents of VARtext are all ## countable characters by the 'string length' command. ############################################################### ##################################### ## SETUP 'TOP LEVEL' HELP WINDOW. ##################################### catch {destroy $toplevName} toplevel $toplevName # wm geometry $toplevName 600x400+100+50 # wm geometry $toplevName +100+50 wm geometry $toplevName $ULloc wm title $toplevName "Note" # wm title $toplevName "Note to $env(USER)" wm iconname $toplevName "Note" ##################################### ## In the frame '$toplevName' - ## DEFINE THE TEXT WIDGET and ## its two scrollbars --- and ## DEFINE an OK BUTTON widget. ##################################### if {$VARheight > 10} { text $toplevName.text \ -wrap none \ -font fontTEMP_SMALL_fixedwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 \ -yscrollcommand "$toplevName.scrolly set" \ -xscrollcommand "$toplevName.scrollx set" ## -font fontTEMP_SMALL_varwidth scrollbar $toplevName.scrolly \ -orient vertical \ -command "$toplevName.text yview" scrollbar $toplevName.scrollx \ -orient horizontal \ -command "$toplevName.text xview" } else { text $toplevName.text \ -wrap none \ -font fontTEMP_SMALL_fixedwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 ## -font fontTEMP_SMALL_varwidth } button $toplevName.butt \ -text "OK" \ -font fontTEMP_varwidth \ -command "destroy $toplevName" ############################################### ## PACK *ALL* the widgets in frame '$toplevName'. ############################################### ## Pack the bottom button BEFORE the ## bottom x-scrollbar widget, pack $toplevName.butt \ -side bottom \ -anchor center \ -fill none \ -expand 0 if {$VARheight > 10} { ## Pack the scrollbars BEFORE the text widget, ## so that the text does not monopolize the space. pack $toplevName.scrolly \ -side right \ -anchor center \ -fill y \ -expand 0 ## DO NOT USE '-expand 1' HERE on the Y-scrollbar. ## THAT ALLOWS Y-SCROLLBAR TO EXPAND AND PUTS ## BLANK SPACE BETWEEN Y-SCROLLBAR & THE TEXT AREA. pack $toplevName.scrollx \ -side bottom \ -anchor center \ -fill x \ -expand 0 ## DO NOT USE '-expand 1' HERE on the X-scrollbar. ## THAT KEEPS THE TEXT AREA FROM EXPANDING. pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } else { pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } ################################################ ## Set some 'event' bindings to allow for ## easy scrolling through huge listings. ## is a press of the Page-Down key. ## is a press of the Page-Up key. ## is a press of the Home key ## to go to the top of the listing. ## is a press of the End key ## to go to the bottom of the listing. ## is a press of the Up-arrow key. ## is a press of the Down-arrow key. ################################################ bind $toplevName "$toplevName.text yview scroll +1 page" bind $toplevName "$toplevName.text yview scroll -1 page" bind $toplevName "$toplevName.text see 1.0" bind $toplevName "$toplevName.text see end" bind $toplevName "$toplevName.text yview scroll -1 unit" bind $toplevName "$toplevName.text yview scroll +1 unit" ##################################### ## LOAD MSG INTO TEXT WIDGET. ##################################### ## $toplevName.text delete 1.0 end $toplevName.text insert end $VARtext $toplevName.text configure -state disabled } ## END OF PROC 'popup_msgVarWithScroll' ##+############################################### ## END OF PROCS SECTION. ##+############################################### ## SET HELP TEXT variable. ##+############################################### ##+###################################################################### ## Set the 'HELPtext' variable for the 'Help' button. ##+###################################################################### set HELPtext \ "******* tkPlotQuik - Lines (and Points) from a Math Expression ***** This Tk GUI script provides an intuitive, easy-to-use X-Y-AXIS LINES (and POINTS) PLOT UTILITY that can be used to make 'presentation quality' plots very QUICKLY. This Tk script presents a GUI with a 'canvas' widget showing a 2-D line plot --- with titles and labels that can be dragged with a pointer device (mouse, finger-tip, etc.). This script presents entry fields in the GUI to prompt for - a math expression --- f(x) --- a function of variable x - plot title - x,y axis titles - x,y axis min-max limits - x,y axis tic-mark distances. *************** OPERATING GUIDE: When the GUI first comes up, it is populated with some sample titles and a sample math expression (a function of x) --- AND that function is rendered as a lines-only plot in the canvas area --- or as lines-with-points, depending on the setting of the 'Points' checkbutton variable at the bottom of the script. (You can set that 'points0or1' variable as you prefer.) The title names indicate WHERE the 3 types of titles initially appear on the GUI. The user can 'drag' these 3 titles around to different places on the 'canvas' with a mouse. Just click on a title, hold down the button (button-1), and drag to a new position. Then release the button. In fact, you can 'whip' titles out-of-sight --- off an edge of the 'canvas'. If you want the titles back, you can simply click on the 'UpdatePlot' button. AND ... you can 'drag' the tic-mark labels. If you decide there are too many, you can 'whip' them off the canvas. You are not given the option to drag the data points, because you could end up with a plot that is not in 'sync' with the math expression shown in the 'entry' field of the GUI. BUT you can move data points by changing the math expression and then click on the 'UpdatePlot' button. The GUI could be initialized with different titles and math expression. At the bottom of the script --- in the 'Additional GUI Initialization' section --- there are some other sample math expressions that could be activated instead of this set of data. In fact, some sample math expressions are listed below and can be pasted into the math expression entry field of the GUI. Note that the math expression can include the following Tcl functions. *************************************************** Tcl Functions (available for use in the expression) Trig Functions: (in alphabetical order) acos(a) asin(a) atan(a) atan2(a,b) cos(a) hypot(a,b) sin(a) tan(a) Hyperbolic Functions: cosh(a) sinh(a) tanh(a) Exponent and Log Functions: exp(a) log(a) log10(a) pow(a,b) sqrt(a) Other Functions: abs(a) ceil(a) double(integer) floor(a) fmod(a,b) int(a) round(a) ************************* EXAMPLE MATH EXPRESSIONS (to paste into the Expression 'entry' field of the GUI) NOTE that you need to use '\$x' --- not 'x' --- for the 'independent' variable in the math expression. A straight-line plot example: 2.0 * \$x + 1.0 A superposition of two sine/cosine waves plot example: sin( (\$pi/180)*\$x ) + 0.5 * cos( 10*(\$pi/180)*\$x ) --- There are a good number of plot options. Here are some. *********************************************************** POINT SYMBOLS (in addition to lines connecting data points): You can click on the 'Points' checkbutton and then click on the 'UpdatePlot' button to cause point symbols to be drawn, at the data points. Turn the 'Points' checkbutton 'off' and click 'UpdatePlot' to revert to a lines-only plot. *********** PLOT BORDER: You can click on the 'Border' checkbutton and then click on the 'UpdatePlot' button to cause a border to be drawn around the plot. Turn the 'Border' checkbutton 'off' and click 'UpdatePlot' to revert to a plot without the border. *********************** CANVAS BACKGROUND COLOR: You can click on the 'CanvasColor' button and use an RGB color selector GUI that pops up to change the canvas background color. If you are going to capture the plot in an image file (such as PNG or GIF) and then print the image (say by reading the image file into a web browser and using the print capability of the web browser), you will probably want to change the plot background to WHITE --- to save on ink. Rather than make a crowded GUI more crowded by supplying buttons to set colors of text (titles and tic-mark labels) and colors of lines (data-lines, axes, tic-marks), the text and line colors are set 'automatically' based on the canvas color that is chosen. In particular, if a dark canvas color is chosen, the text and lines will be shown in a light color --- and if a light canvas color is chosen, the text and lines will be shown in a dark color. ******************************** THE 'DwnCan' and 'UpCan' BUTTONS: The 'canvas' area expands and contracts if you expand or contract the entire GUI window. One way to quickly downsize or upsize the window is to click on the 'DwnCan' or 'UpCan' button. This can be quicker than trying to get the attention of an extremely thin 'sensitive edge' of the GUI to drag the window to a different size. One thing to be aware of: The 'DwnCan' button will probably not work if the user has maximized the GUI window via the window manager 'Maximize' option or by repeated use of the 'UpCan' button. To make the 'DwnCan' button useable again, you can simply use the 'UnMaximize' ('Restore') option of the window manager. ********************************** POSTSCRIPT PREVIEW & PRINT OPTIONS: The 'PrtPreview' and the 'Print' buttons create a Postscript file in a '/tmp' directory. The 'PrtPreview' button uses a PDF/Postscript viewer utility --- such as 'evince' --- to show the Postscript file that is created. And the 'Print' button uses a print-command --- shown in an 'entry' field at the top-right of the GUI --- to send the Postscript code to a user's printer. The temporary-files-directory, the PDF/Postscript viewer-command, and the print-command can be changed by the user who downloads this script by changing 3 variables in 'set' statements at the bottom of the script in the 'Additional GUI Initialization' section: - DIRtemp - PSviewer - PRINTcmd For the print command, I found that the program '/usr/bin/cupsdoprint' of the CUPS printing system worked quite nicely --- on my Ubuntu 9.10 Linux system --- with the set of parameters seen in this code. NOTE: The Tk canvas 'postscript' option does not capture an image placed on the canvas. It captures points, curves, and text placed on the canvas. If you want to capture an image of the plot including any GIF or PNG images put on the canvas, you can use an image capture utility (such as 'gnome-screenshot') to capture the image in a PNG or GIF or JPEG file. You can crop the image with an interactive image editor (such as 'mtpaint') and then print the image file with an image-view/print utility (such as 'eog' = 'eye of gnome') or a web browser, as described above --- in the Canvas Background Color section. ******************* THE 'GetImg' BUTTON: The 'GetImg' button at the top of the GUI allows the user to get an image (like a logo) to put on the plot canvas. A file-selector GUI pops up and allows the user to select an image file (GIF or PNG) to put on the canvas. When a user selects a filename and clicks on the OK button of the file-selector, the file-selector dialog window disappears and the image appears at the lower-right of the 'canvas' area. Like for titles and tick-marks, the user can 'drag' the image from its initial placement on the canvas to anywhere else on the canvas --- and the image can be 'whipped' off of the canvas. More than one image can be fetched and placed on the canvas. ***************** THE 'Help' BUTTON: The 'Help' button on the GUI can provide more extensive help than the brief guide on the left side of the GUI. In fact, it presents this help. ********** CONCLUSION: This is a plotting-utility implementation using BASIC Tcl-Tk commands, i.e. not requiring an 'extension' of Tcl or Tk. Unfortunately, there do not seem to be any FAIRLY GENERAL, yet RELATIVELY SIMPLE, xy-point plotting scripts at Tcl-Tk archive sites --- even in 2017, more than 20 years after the development of the necessary Tk 'canvas' facilities to support plotting of lines and ovals and text and images. Nor are such GENERAL, INTERACTIVE, easy-to-use x,y point or line plotting Tk scripts available via web searches on keyword strings such as 'bin wish canvas' or 'bin wish oval' or 'bin wish line'. Even searches on 'canvas' and 'line' and 'oval' on the wiki.tcl.tk site, in early 2013, yielded only simplistic line plot 'demos' that are not suited to general and FAST point-or-line plots. There were none with entry fields for quick entry of user data and essential plot parameters. This script is meant to fill that long-time void. " ##+###################################################### ##+###################################################### ## ADDITIONAL GUI INITIALIZATION: ##+###################################################### ## - Set pi variable and the tcl_precision variable. ## ## - Set line-width value --- which is not currently settable via ## widgets on the GUI. (no room and too many choices already) ## ## - Set initial canvas background color and from that canvas ## color set line color (for data-lines, axes, tic-mark labels) ## and set text color (for titles and tic-mark labels). ## NOTE: ## Line and text colors are not currently settable via widgets ## on the GUI. (no room and too many choices already) ## So we set those colors 'automatically' from the canvas color. ## ## - Set some directories and helper-apps. ## ## - Set some initial 'entry' field values for a plot and ## make a plot from those entries. ##+###################################################### ##+###################################################### ## Set an initial value (position of the slider) for ## the 'scale' widget. ##+###################################################### set SCALEnxvals 20 # set SCALEnxvals 40 # .fRexpr_opts.scaleNVALS set $SCALEnxvals ##+###################################################### ## Set an accurate value to be used for pi ## and the 'natural' number, e. ##+###################################################### set pi [expr {atan2(1,1)*4}] set e [expr {exp(1)}] ##+###################################################### ## Set a value for the 'tcl_precision' variable. ## ## 6 IS THE DEFAULT VALUE OF $tcl_precision. ##+###################################################### # set tcl_precision 6 set tcl_precision 16 ##+####################################################################### ## Set line width (in pixels) --- for drawing lines connecting data points ## and axis lines and tic-mark lines. ## ## NOTE: ## Instead of hard-coding a value, we could set the width based on ## the screenwidth --- like 0.001 or 0.002 of screenwidth in pixels. ##+####################################################################### # set lineWIDTHpx 2 set SCRNsizexPx [winfo screenwidth .] # set lineWIDTHfactor 0.002 set lineWIDTHfactor 0.001 set lineWIDTHpx [expr {int($lineWIDTHfactor * $SCRNsizexPx) + 1}] ##+#################################################### ## Set an initial BACKGROUND COLOR FOR THE CANVAS --- ## and use that to set some 'related' (global) color variables: ## lineCOLORhex ## textCOLORregHEX ## textCOLORselHEX ## 'reg' = regular ; 'sel' = selected ## ## We set the canvas color a little lighter (brighter) ## than the GUI 'palette' color --- to make it stand out. ##+#################################################### set CANr255 230 set CANg255 230 set CANb255 230 set hexCOLORcan [format "%02X%02X%02X" $CANr255 $CANg255 $CANb255] set_plotColors "$hexCOLORcan" ##+#################################################### ## Set the full-name of the RGB color-selector Tk script ## that is used in one or more procs above. ##+#################################################### ## FOR TESTING: # puts "argv0: $argv0" set DIRthisScript "[file dirname $argv0]" ## For ease of testing in a Linux/Unix terminal and located at the ## directory containing this Tk script: Set the full directory name. if {"$DIRthisScript" == "."} { set DIRthisScript "[pwd]" } ## If the color selector script is in the directory with this Tk script: # set RGBcolorSelectorScript "$DIRthisScript/sho_colorvals_via_sliders3rgb.tk" ## Alternatively: If the RGB color-selector Tk script is in the ## SELECTORtools directory of the FE 'tkGooies' menu/toolchest system, ## use something like the following. set DIRupOne "[file dirname "$DIRthisScript"]" set DIRupTwo "[file dirname "$DIRupOne"]" set RGBcolorSelectorScript "$DIRupTwo/SELECTORtools/tkRGBselector/sho_colorvals_via_sliders3rgb.tk" ##+####################################################### ## Set a directory from which to get images. ## (We could put a few images in the directory with this ## Tk script --- or a lot of images in an 'images' ## subdirectory of the directory of this Tk script. ## Or use some subdirectory of the user's home directory.) ##+####################################################### # set DIRimages "$env(HOME)/Photos" # set DIRimages "${DIRthisScript}/images_GIF" # set DIRimages "${DIRthisScript}/images_PNG" set DIRimages "$DIRthisScript" ##+#################################################### ## Set a files directory for the Postscript print ## options --- 'PrtPreview' and 'Print' --- ## for a 'temporary' Postcript file. ##+#################################################### set DIRtemp "/tmp" ##+#################################################### ## Set a Postscript viewer program for use in the ## 'print_preview' proc. ##+#################################################### # set PSviewer "/usr/bin/xpdf" # set PSviewer "evince" set PSviewer "/usr/bin/evince" ##+#################################################### ## Set a print-command for use in the 'print_plot' proc. ## Show the print-command in an 'entry' widget at the ## top of the GUI. ##+#################################################### # set PRINTcmd "/usr/bin/kprinter" # set PRINTcmd "/usr/bin/hp-print" set PRINTcmd "/usr/bin/cupsdoprint -P EPSON-Epson-Stylus-NX430 -H localhost:631" set ENTRYprintcmd "$PRINTcmd" ##+#################################################### ## We can activate one of the following sets of initial ## plot settings by changing 'if {0}' to 'if {1}'. ##+#################################################### ## A simple plot example --- linear expression. if {1} { set ENTRYmathExpr { 2.0 * $x + 4.0 } set ENTRYtitleMain " Plot Title goes here. Linear Expression: $ENTRYmathExpr" set ENTRYtitleXaxis " X-axis title goes here." set ENTRYtitleYaxis " Y-axis title goes here. " set ENTRYxaxismin "0" set ENTRYxaxismax "20" set ENTRYxticdist "5" set ENTRYyaxismin "0" set ENTRYyaxismax "50" set ENTRYyticdist "10" } ## END OF if {0} ## A quadratic polynomial example. if {0} { set ENTRYmathExpr { (2.0 * pow($x,2)) + (3.5 * pow($x,1)) + 4.0 } set ENTRYtitleMain " Second-degree Polynomial: $ENTRYmathExpr" set ENTRYtitleXaxis " X-values" set ENTRYtitleYaxis " Y-values" set ENTRYxaxismin "0" set ENTRYxaxismax "5" set ENTRYxticdist "1" set ENTRYyaxismin "0" set ENTRYyaxismax "100" set ENTRYyticdist "10" } ## END OF if {0} ## A superposition of two sine waves plot example. if {0} { set SCALEnxvals 200 set ENTRYmathExpr { sin( ($pi/180.)*$x ) + 0.5 * cos( 10.*($pi/180.)*$x ) } set ENTRYtitleMain "Hi-freq. added to lower freq. : $ENTRYmathExpr" set ENTRYtitleXaxis " X-axis title goes here." set ENTRYtitleYaxis " Y-axis title goes here. " set ENTRYxaxismin "0" set ENTRYxaxismax "720" set ENTRYxticdist "40" set ENTRYyaxismin "-2" set ENTRYyaxismax "3" set ENTRYyticdist "0.5" } ## END OF if {0} ##+#################################################### ## Use the current entry field settings and canvas size ## to initialize the plot area with a line plot. ## ## (Since 'update_plot' does not do an 'update' before ## querying the current canvas size, we need to do it here ## --- to force the 'wish' interpreter to do all the ## widget packing with the 'pack' geometry manager, ## before 'update_plot' does its thing.) ##+#################################################### update update_plot