import tkinter as tk
from tkinter import ttk
from math import *

# written by Eddie Vanda - no responsibility taken 
# but please report any problems to eddie.vanda@rmit.edu.au

class PlotExpr:
  def __init__(self):
    self.window = tk.Tk()
    self.window.title("Plot Expression")
    self.window.geometry('900x900')
    try:
      self.window.iconbitmap('pythontutorial.ico')
    except:
      pass

    self.canvas = tk.Canvas(self.window, height=600, width = 600, 
                            bd = 2,
                            bg = 'alice blue',
                            highlightthickness=1)

    self.head1 = ttk.Label(self.window, 
                           text="Enter expression: ", 
                           font=("Arial", 20)) # 
    self.exprText = tk.StringVar()
    self.exprEntry = ttk.Entry(self.window, 
                               textvariable=self.exprText, 
                               font=("Arial", 20) )

  def valuate (self, expr, x):
    dict = {'sin':sin,
            'cos':cos,
            'tan':tan,
            'sqrt':sqrt,
            'x':x}
    y = eval(expr,{'__builtins__': None}, dict)
    return y

  def getYminmax(self, expr, xMin=0, xMax=400, width=400):
    #height = canvas.winfo_reqheight() 
    x = xMin
    xStep = width / (xMax - xMin)
    yMax = -10e20
    yMin = 10e20
  
    while x < xMax:
      y = self.valuate(expr, x)
      if y > yMax:
        yMax = y
      if y < yMin:
        yMin = y
      x += xStep
    minmaxY = [yMin, yMax]
    return minmaxY

 
  # plot (expr, canvas, minmax, 0, 400)
  def plot(self, expr, canvas, minmaxY, xMin=0, xMax=400):
    self.canvas.delete('all')
    height = self.canvas.winfo_reqheight() 
    width = self.canvas.winfo_reqwidth()
    y0 = 0
    yPos = 0
    xPos = 0
    x = xMin
    xStep = width / (xMax - xMin)
    yScale = height / (minmaxY[1] - minmaxY[0])
    while xPos < width:
      y = height - self.valuate(expr, x) * yScale
      self.canvas.create_line(xPos, y0, xPos + 1, y, fill = "red")
      x += xStep
      xPos += 1
      y0 = y

  # callback() is called by pressing the button
  def callback(self):
    #print("diagnostic: callback")
 
    expr = self.exprEntry.get()
    print (expr) # diagnostic
 
    x = 0
    #def getYminmax(expr, xMin=0, xMax=400, width=400):
    minmax= self.getYminmax(expr, 0, 400, 400)
    print ("min y = " + str(minmax[0]) + ", max y = " + str(minmax[1]))
    self.plot (expr, self.canvas, minmax, 0, 400)

  def callback1(self, event):
    self.callback()
 
  def main(self):
    #self.button = tk.Button(self.window, 
    #                        text='PLOT', 
    #                        command=self.callback,
    #                        font=("Arial", 20))
    self.exprEntry.bind('<Return>', self.callback1)
    #self.head1.pack()
    self.exprEntry.pack(ipadx=10, ipady=10)
    self.exprEntry.focus_set()
    #self.button.pack(ipadx=10, ipady=10)
    self.canvas.pack()

    self.window.mainloop()
pe = PlotExpr()
pe.main()