### ### This demonstration script creates a canvas widget showing a 2-D ### plot with data points that can be dragged with the mouse. ### ### It is a ripoff of the plot.tcl demo from the tk 8.0 distribution ### All I did was to add the code to plot the fitted regression line. # Copyright (C) 2000-2008 The R Core Team require(tcltk) || stop("tcl/tk library not available") require(graphics); require(stats) local({ have_ttk <- as.character(tcl("info", "tclversion")) >= "8.5" if(have_ttk) { tkbutton <- ttkbutton tkframe <- ttkframe tklabel <- ttklabel } tclServiceMode(FALSE) # don't display until complete top <- tktoplevel() tktitle(top) <- "Plot Demonstration" msg <- tklabel(top, font="helvetica", wraplength="4i", justify="left", text="This window displays a canvas widget containing a simple 2-dimensional plot. You can doctor the data by dragging any of the points with mouse button 1.") tkpack(msg, side="top") buttons <- tkframe(top) tkpack(buttons, side="bottom", fill="x", pady="2m") dismiss <- tkbutton(buttons, text="Dismiss", command=function()tkdestroy(top)) tkpack(dismiss, side="left", expand=TRUE) canvas <- tkcanvas(top, relief="raised", width=450, height=300) tkpack(canvas, side="top", fill="x") plotFont <- "Helvetica 18" tkcreate(canvas, "line", 100, 250, 400, 250, width=2) tkcreate(canvas, "line", 100, 250, 100, 50, width=2) tkcreate(canvas, "text", 225, 20, text="A Simple Plot", font=plotFont, fill="brown") # X tickmarks & labels for (i in 0:10) { x <- 100 + i * 30 tkcreate(canvas, "line", x, 250, x, 245, width=2) tkcreate(canvas, "text", x, 254, text=10*i, anchor="n", font=plotFont) } # Y tickmarks & labels for (i in 0:5) { y <- 250 - i * 40 tkcreate(canvas, "line", 100, y, 105, y, width=2) tkcreate(canvas, "text", 96, y, text=formatC(50*i,format="f",digits=1), anchor="e", font=plotFont) } # The (original) data points <- matrix(c(12, 56, 20, 94, 33, 98, 32, 120, 61, 180, 75, 160, 98, 223), ncol=2, byrow=TRUE) ## `self-drawing' point object point.items <- apply(points, 1, function(row) { x <- 100 + 3 * row[1] y <- 250 - 4/5 * row[2] item <- tkcreate(canvas, "oval", x - 6, y - 6, x + 6, y + 6, width=1, outline="black", fill="SkyBlue2") tkaddtag(canvas, "point", "withtag", item) item }) plotDown <- function(x, y) { ## This procedure is invoked when the mouse is pressed over one ## of the data points. It sets up state to allow the point ## to be dragged. ## ## Arguments: ## x, y - The coordinates of the mouse press. x <- as.numeric(x) y <- as.numeric(y) tkdtag(canvas, "selected") tkaddtag(canvas, "selected", "withtag", "current") tkitemraise(canvas,"current") lastX <<- x lastY <<- y } plotMove <- function(x, y) { ## This procedure is invoked during mouse motion events. ## It drags the current item. ## ## Arguments: ## x, y - The coordinates of the mouse. x <- as.numeric(x) y <- as.numeric(y) tkmove(canvas, "selected", x - lastX, y - lastY) lastX <<- x lastY <<- y } ### FIXME : Don't allow points to be moved outside the canvas !! plotLine <- function(){ coords <- lapply(point.items, function(item) as.double(tkcoords(canvas,item))) x <- sapply(coords, function(z) (z[1]+z[3])/2) y <- sapply(coords, function(z) (z[2]+z[4])/2) lm.out <- lm(y~x) x0 <- range(x) y0 <- predict(lm.out, data.frame(x=x0)) tkcreate(canvas, "line", x0[1], y0[1], x0[2], y0[2], width=3) } line <- plotLine() lastX <- 0 lastY <- 0 tkitembind(canvas, "point", "", function() tkitemconfigure(canvas, "current", fill="red")) tkitembind(canvas, "point", "", function() tkitemconfigure(canvas, "current", fill="SkyBlue2")) tkitembind(canvas, "point", "<1>", plotDown) tkitembind(canvas, "point", "", function(x){ tkdtag(canvas, "selected") tkdelete(canvas, "withtag", line) line <<- plotLine() }) tkbind(canvas, "", plotMove) tclServiceMode(TRUE) cat("******************************************************\n", "The source for this demo can be found in the file:\n", file.path(system.file(package = "tcltk"), "demo", "tkcanvas.R"), "\n******************************************************\n") })