from tkinter import * from R2Graph import * import math import numpy as np from sklearn.tree import DecisionTreeRegressor def main(): points = [] mouseButtons = [] objectIDs = [] funcDrawn = False scaleX = 40.; scaleY = 40. root = Tk() root.title("Plot Function") root.geometry("800x600") panel = Frame(root) drawButton = Button(panel, text="Draw") clearButton = Button(panel, text="Clear") drawArea = Canvas(root, bg="white") panel.pack(side=TOP, fill=X) drawButton.pack(side=LEFT, padx=4, pady=4) clearButton.pack(side=LEFT, padx=4, pady=4) drawArea.pack(side=TOP, fill=BOTH, expand=True, padx=4, pady=4) degree = 1 treeModel = None depth = 3 w = np.zeros(depth + 1) degreeLabel = Label(panel, text="Degree:") degreeScale = Scale(panel, from_=1, to=10, orient=HORIZONTAL) degreeScale.set(degree) depthLabel = Label(panel, text="Depth:") depthScale = Scale(panel, from_=2, to=20, orient=HORIZONTAL) depthScale.set(depth) degreeLabel.pack(side=LEFT, padx=4, pady=4) degreeScale.pack(side=LEFT, padx=4, pady=4) depthLabel.pack(side=LEFT, padx=4, pady=4) depthScale.pack(side=LEFT, padx=4, pady=4) root.update() def map(t): w = drawArea.winfo_width() h = drawArea.winfo_height() centerX = w/2. centerY = h/2. x = centerX + t.x*scaleX y = centerY - t.y*scaleY return (x, y) def invmap(p): w = drawArea.winfo_width() h = drawArea.winfo_height() centerX = w/2. centerY = h/2. x = (p[0] - centerX)/scaleX y = (centerY - p[1])/scaleY return R2Point(x, y) def xMin(): w = drawArea.winfo_width() return (-(w/scaleX)/2.) def xMax(): return (-xMin()) def yMin(): w = drawArea.winfo_height() return (-(w/scaleY)/2.) def yMax(): return (-yMin()) def drawGrid(): ix0 = int(xMin()) ix1 = int(xMax()) x = ix0 while x <= ix1: if x != 0: p0 = map(R2Point(x, yMin())) p1 = map(R2Point(x, yMax())) drawArea.create_line(p0, p1, fill="lightGray", width=1) x += 1 iy0 = int(yMin()) iy1 = int(yMax()) y = iy0 while y <= iy1: if y != 0: p0 = map(R2Point(xMin(), y)) p1 = map(R2Point(xMax(), y)) drawArea.create_line(p0, p1, fill="lightGray", width=1) y += 1 # Draw x-axis drawArea.create_line( map(R2Point(xMin(), 0.)), map(R2Point(xMax(), 0.)), fill="black", width=2 ) # Draw y-axis drawArea.create_line( map(R2Point(0., yMin())), map(R2Point(0., yMax())), fill="black", width=2 ) def func(x): if treeModel == None: return 0. X = np.array([[x]]) y = treeModel.predict(X)[0] return y def mse(x): nonlocal w if treeModel == None: return 0. return np.polyval(w, x) def plotFunction(f, color="blue", width = 1): t = R2Point(xMin(), f(xMin())) dx = 0.05 path = [] while t.x <= xMax(): path.append(map(t)) t.x += dx t.y = f(t.x) lineID = drawArea.create_line(path, fill=color, width=width) objectIDs.append(lineID) def onMouseRelease(e): # print("Mouse release event:", e) p = (e.x, e.y) t = invmap(p) points.append(t) mouseButtons.append(e.num) drawPoint(t, e.num) def drawPoint(t, mouseButton = 1): vx = R2Vector(0.1, 0.) vy = R2Vector(0., 0.1) color = "red" if mouseButton == 2: color = "green" elif mouseButton == 3: color = "magenta" ''' lineID = drawArea.create_line( map(t - vx), map(t + vx), fill=color, width=3 ) objectIDs.append(lineID) lineID = drawArea.create_line( map(t - vy), map(t + vy), fill=color, width=3 ) objectIDs.append(lineID) ''' pointID = drawArea.create_oval( map(t - vx + vy), map(t + vx - vy), fill=color, outline=color ) def drawPoints(): for i in range(len(points)): drawPoint(points[i], mouseButtons[i]) def onDraw(): nonlocal treeModel, depth, w, degree, funcDrawn degree = degreeScale.get() x = np.array( [[p.x] for p in points] ) y = np.array( [p.y for p in points] ) depth = depthScale.get() treeModel = DecisionTreeRegressor(max_depth = depth) treeModel.fit(x, y) # MSE function X = np.array( [ [p.x**d for d in range(degree, -1, -1)] for p in points ] ) w = np.linalg.pinv(X) @ y clearPicture() drawPoints() plotFunction(func, color = "green", width = 3) plotFunction(mse, color = "blue", width = 1) funcDrawn = True def clearPicture(): for i in objectIDs: drawArea.delete(i) objectIDs.clear() def onClear(): nonlocal funcDrawn clearPicture() points.clear() mouseButtons.clear() funcDrawn = False treeModel = None def onConfigure(e): drawArea.delete("all") drawGrid() drawPoints() if funcDrawn: plotFunction(func, color = "green", width = 3) plotFunction(mse, color = "blue", width = 1) drawButton.configure(command = onDraw) clearButton.configure(command = onClear) drawArea.bind("", onMouseRelease) drawArea.bind("", onMouseRelease) drawArea.bind("", onMouseRelease) drawArea.bind("", onConfigure) drawGrid() # plotFunction(func) root.mainloop() if __name__ == "__main__": main()