From 2c65f8c59dbdbebfcceed3343fe5928780d39560 Mon Sep 17 00:00:00 2001 From: Rnhmjoj Date: Tue, 14 Jan 2014 20:12:07 +0100 Subject: [PATCH] English translation and some fixes --- graph.py | 87 ++++++++++++++++++++ plotter.py | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 320 insertions(+) create mode 100644 graph.py create mode 100644 plotter.py diff --git a/graph.py b/graph.py new file mode 100644 index 0000000..13ebded --- /dev/null +++ b/graph.py @@ -0,0 +1,87 @@ +import turtle + + +def points(tup): + """ + Given a tuple ((x_1, y_1), (x_2, y_2), (x_n, y_n),...) + return a function f(x_n): y=y_n. + """ + return lambda x: dict(tup)[float(x)] + + +class Tools(): + """Miscellanous functions for turtle""" + def go(self, x, y): + """Move cursor to point (x, y) without drawing a line""" + self.pu() + self.goto(x, y) + self.pd() + + +class Arrow(turtle.Pen, Tools): + """Custom turtle cursor""" + def __init__(self): + super(Arrow, self).__init__() + self.speed(0) + self.shape("triangle") + self.shapesize(0.5) + + +class Graph(turtle.Pen, Tools): + + def __init__(self, canvas, X=10, Y=10): + """ + Initialization of the graph. + Providing the size of the axes if necessary. + """ + super(Graph, self).__init__() + turtle.title("Plot") + self.X = X + self.Y = Y + self.canvas = canvas + self.frame = turtle._Screen._root + self.axes() + self.arrows() + + def axes(self): + """Draw the axes of the coordinate plane""" + turtle.setworldcoordinates( + -(self.X + 2), -(self.Y + 2), + self.X + 2, self.Y + 2) + self.hideturtle() + self.speed(0) + self.go(-self.X, 0) + self.fd(self.X * 2) + self.go(0, -self.Y) + self.lt(90) + self.fd(self.Y * 2) + + def arrows(self): + """Draw arrows and labels""" + a = Arrow() + a.go(self.X, 0) + a.write(" x", font=("helvetiva", 16)) + b = Arrow() + b.lt(90) + b.go(0, self.Y) + b.write(" y", font=("helvetiva", 16)) + + def plot(self, function, start, stop, color="blue"): + """Plot a function""" + medium = 2 / self.X + self.color(color) + try: + self.go(start, function(start)) + except ZeroDivisionError: + self.go(start, function(start + 1 * medium)) + for x in range(int(start / medium), int(stop / medium) + 1): + x *= medium + try: + self.goto(x, function(x)) + except ZeroDivisionError: + self.go(x, function(x + 1 * medium)) + + def clean(self): + """Clean the canvas redraw axes""" + self.reset() + self.axes() diff --git a/plotter.py b/plotter.py new file mode 100644 index 0000000..bba286a --- /dev/null +++ b/plotter.py @@ -0,0 +1,233 @@ +import tkinter +import tkinter.filedialog +import re +#import canvas2svg +from math import * +import graph + + +class Application(tkinter.Frame): + """Application class""" + def __init__(self): + tkinter.Frame.__init__(self, window) + + #Window settings + + window.title("Settings") + window.resizable(0, 0) + window.geometry("{}x{}+{}+{}".format( + 550, 110, + int((window.winfo_screenwidth() / 2) - 320), + window.winfo_screenheight())) + self.type = tkinter.StringVar() + self.text = tkinter.StringVar() + self.type.set("normal") + self.graph = graph.Graph(20, 20) + self.frame = self.graph.frame + self.widgets() + self.label() + + def widgets(self): + """Draws widgets""" + + #Labels + + self.label1 = tkinter.Label(window, textvariable=self.text) + self.label2 = tkinter.Label(window, text="Interval:") + self.label3 = tkinter.Label(window, text="Color:") + + #Textboxes + + self.textbox1 = tkinter.Entry(window) + self.textbox2 = tkinter.Entry(window) + self.textbox3 = tkinter.Entry(window) + + #Options + + self.choose1 = tkinter.Radiobutton( + window, + value="normal", + text="Normal", + variable=self.type, + command=self.label) + self.choose2 = tkinter.Radiobutton( + window, + value="punti", + text="Points", + variable=self.type, + command=self.label) + self.choose3 = tkinter.Radiobutton( + window, + value="piecewise", + text="Piecewise", + variable=self.type, + command=self.label) + + #Pulsanti + + self.button1 = tkinter.Button( + window, + text="Plot", + command=self.plot) + self.button2 = tkinter.Button( + window, + text="Clear", + command=self.clear) + self.button3 = tkinter.Button( + window, + text="Clean Canvas", + command=self.graph.clean) + self.button4 = tkinter.Button( + window, + text="Save", + command=self.save) + self.button5 = tkinter.Button( + window, + text="Exit", + command=self.exit) + + #Widgets layout + + self.label1.grid( + column=0, row=0, + sticky="nw", + pady=5, padx=5) + self.label2.grid( + column=0, row=1, + sticky="nw", + pady=2.5, padx=5) + self.label3.grid( + column=0, row=2, + sticky="nw", + pady=2.5, padx=5) + self.textbox1.grid( + column=1, row=0, + sticky="nw", + pady=5, padx=5) + self.textbox2.grid( + column=1, row=1, + sticky="nw", + pady=2.5, padx=5) + self.textbox3.grid( + column=1, row=2, + padx=5, pady=2.5) + self.choose1.grid( + column=2, row=1, + sticky="nw", + pady=2.5, padx=5) + self.choose2.grid( + column=3, row=1, + sticky="nw", + pady=2.5, padx=5) + self.choose3.grid( + column=4, row=1, + sticky="nw", + pady=2.5, padx=5) + self.button1.grid( + column=2, row=0, + sticky="nwes", + pady=2.5, padx=5) + self.button2.grid( + column=3, row=0, + sticky="nwes", + pady=2.5, padx=5) + self.button3.grid( + column=4, row=0, + sticky="nwes", + pady=2.5, padx=5) + self.button4.grid( + column=2, row=2, + sticky="nwes", + pady=2.5, padx=5, + columnspan=2) + self.button5.grid( + column=4, row=2, + sticky="nwes", + pady=2.5, padx=5) + + def label(self): + """Change label basing on graph type""" + if self.type.get() == "normal": + self.text.set("f(x): y =") + elif self.type.get() == "piecewise": + self.text.set("[f1(x),(interval)],[f2(x),(interval)],...") + else: + self.text.set("(x1,y1),(x2,y2),...") + + def plot(self): + """Plot the data""" + + #Converte la function in modo che possa essere interpretata da eval(). + function = re.sub( + "([\+-\-]?\d+)(x)", + "\\1*x", + self.textbox1.get().replace("^", "**")) + function = re.sub( + "(\|)(.+)(\|)", + "abs(\\2)", + function) + function = re.sub( + "(.+)(\!)", + "factorial(\\1)", + function) + + #Legge l'interval inserito. + try: + interval = eval(self.textbox2.get()) + except SyntaxError: + start = -self.graph.X + stop = self.graph.X + else: + start = float(interval[0]) + stop = float(interval[1]) + + #Legge il color inserito. + color = self.textbox3.get() + if color == "": + color = "orange" + + #Disegna il graph in base al type inserito. + if self.type.get() == "normal": + function = eval("lambda x:" + function) + self.graph.plot(function, start, stop, color) + elif self.type.get() == "piecewise": + functions = re.sub("(\[\()(.+?\))", "\\1lambda x:\\2", function) + functions = re.sub("(\[)", "(", functions.replace("]", ")")) + for function in eval(functions): + self.graph.plot( + function[0], + function[1][0], + function[1][1], + color) + else: + function = graph.punti(eval(self.textbox1.get())) + self.graph.plot( + function, + punti[0][0], + punti[len(punti) - 1][1], + color) + + def clear(self): + """Clear entered data""" + self.textbox1.delete(0, "end") + self.textbox2.delete(0, "end") + self.textbox3.delete(0, "end") + + def save(self): + """Save plot in svg""" + settings = { + "parent": self.frame, + "defaultextension": ".svg", + "initialfile": "graph.svg", + "title": "Salva il graph" + } + file = tkinter.filedialog.asksaveasfilename(**settings) + canvas2svg.saveall(file, self.canvas) + + def exit(self): + window.destroy() + self.frame.destroy() + +window = tkinter.Tk() +app = Application() +app.mainloop()