1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#imports
from Tkinter import *
from PIL import Image, ImageTk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
from scipy import *
from scipy.special import jn, jn_zeros
import numpy as np
import os

class MathDrum:
    def __init__(self, master):
        #create frame to hold all the widgets
        frame = Frame(master)
        #define seperate window for use in plots etc
        self.window = Toplevel(master=frame)
        
        #calls for main program areas
        self.makeInterface(frame)
        self.openPlotWindow(frame)
        self.plotWindowInputs(frame)
    #make main program areas
    def makeInterface(self, frame):
        #make a background using an image
        background = ImageTk.PhotoImage(Image.open('background.png'))
        
        #getting the height and width dimensions of the image, the upperleft hand corner of the frame, then map root window to the size of the image
        w = background.width()
        h = background.height()
        x, y = 0, 0
        
        #takes the w,h,x,y and formats as decimals in a text string
        root.geometry("%dx%d+%d+%d" % (w, h, x, y))
        
        #root has no image argument, so use a label as a panel
        self.panel = Label(root, image=background)
        self.panel.pack(side='top', fill='both', expand='yes')
        self.panel.image = background
        
        #creates multiple frames be used as seperators, and frames used to hold stuff.
        seperator1 = Frame(self.panel)
        seperator1.grid(column=0,row=0,padx=50,pady=65)
        
        seperator2 = Frame(self.panel)
        seperator2.grid(column=0,row=1,padx=225,pady=0)
        
        LabelFrame1 = Frame(self.panel)
        LabelFrame1.grid(column=0,row=1)
        
        ButtonFrame1 = Frame(self.panel)
        ButtonFrame1.grid(column=0,row=2)
        
        ButtonFrame2 = Frame(self.panel)
        ButtonFrame2.grid(column=0,row=3)
        
        ButtonFrame3 = Frame(self.panel)
        ButtonFrame3.grid(column=0,row=4)
        
        ButtonFrame4 = Frame(self.panel)
        ButtonFrame4.grid(column=0,row=5)
        
        ButtonFrame5 = Frame(self.panel)
        ButtonFrame5.grid(column=0,row=6)
        
        LabelFrame2 = Frame(self.panel)
        LabelFrame2.grid(column=0,row=7)
        
        ButtonFrame6 = Frame(self.panel)
        ButtonFrame6.grid(column=0,row=8)
        
        #buttons + labels
        Heading1 = Label(LabelFrame1, text='Understanding the Mathematics', justify='left' ,bg='white', fg='black', font=("Purisa",14))
        Heading1.grid(column=0,row=0)
        
        Chapter1 = Button(ButtonFrame1, text='Chapter 1: The Wave Equation', justify='left' ,bg='white', fg='black', font=("Purisa",11), command=self.openFile('Chapter1.pdf'))
        Chapter1.grid(column=0, row=0)
        
        Chapter3 = Button(ButtonFrame2, text='Chapter 2: Solving with Seperation of Variables', justify='left', font=("Purisa",11), bg='white', fg='black', command=self.openFile('Chapter1.pdf'))
        Chapter3.grid(column=0, row=0)
        
        Chapter4 = Button(ButtonFrame3, text='Chapter 3: Sturm-Liouville form of the radial equation', bg='white', font=("Purisa",11), fg='black', justify='left', command=self.openFile('Chapter1.pdf'))
        Chapter4.grid(column=0, row=0)
        
        Chapter5 = Button(ButtonFrame4, text='Chapter 4: The Bessel Equation', justify='left', bg='white', fg='black', font=("Purisa",11), command=self.openFile('Chapter1.pdf'))
        Chapter5.grid(column=0, row=0)
        
        Chapter6 = Button(ButtonFrame5, text='Chapter 5: The Circular Drum', justify='left', bg='white', fg='black', font=("Purisa",11), command=self.openFile('Chapter1.pdf'))
        Chapter6.grid(column=0, row=0)
        
        Heading2 = Label(LabelFrame2, text='Interactive Applications', justify='left' ,bg='white', fg='black', font=("Purisa",14))
        Heading2.grid(column=0,row=0)
        
        new_window_button = Button(ButtonFrame6, text="Animated Circular Drum", justify='left', bg='white', fg='black', font=("Purisa",11), command=self.openPlotWindow(self.window))
        new_window_button.grid(column=0, row=8)

    def openPlotWindow(self, frame):
        self.fig = Figure(figsize=(5,4), dpi=100)
        
        #create a canvas to hold the figure
        self.canvas = FigureCanvasTkAgg(self.fig,self.window)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(row = 0, column = 1)
        
        #adds a standard plot toolbar
        self.toolbar = NavigationToolbar2TkAgg(self.canvas, frame)
        self.toolbar.update()
        self.toolbar.grid(row = 7, column = 1)
        
    def plotWindowInputs(self, frame):
        #make frame for the labels, buttons, entry boxes and set co-ords
        InputFrame = Frame(self.window)
        InputFrame.grid(column = 0, row = 0)
        
        #the labels
        self.n_label = Label(InputFrame, text = "n=0,1,2...", justify=LEFT)
        self.n_label.grid(column= 0,row= 0)
        self.k_label = Label(InputFrame, text = "k=1,2,3...", justify=LEFT)
        self.k_label.grid(column= 0,row= 2)
        self.time_label = Label(InputFrame, text = "time", justify=LEFT)
        self.time_label.grid(column= 0,row= 4)
        
        #corresponding entry boxes
        self.n_entry = Entry(InputFrame)
        self.n_entry.grid(column = 1, row = 0)
        self.k_entry = Entry(InputFrame)
        self.k_entry.grid(column = 1, row = 2)
        self.time_entry = Entry(InputFrame)
        self.time_entry.grid(column = 1, row = 4)
        
        #plot button
        self.plot_button = Button(InputFrame, text ='PLOT', command = self.DrumPattern)
        self.plot_button.grid(column = 0, row = 6)#
        
    def DrumPattern(self):
        #get values from the previous entry boxes
        n = int(self.n_entry.get())
        k = int(self.k_entry.get())
        time = float(self.time_entry.get())
        
        #calculate values for use in plot
        radius = linspace(0,pi/2.,100)
        theta = linspace(0,2.*pi,100)
        x = np.array([r*np.cos(theta) for r in radius])
        y = np.array([r*np.sin(theta) for r in radius])
        z = np.array([self.drumhead_height(n, k, r, theta, time) for r in radius])
        
        #creating the plot
        ax=Axes3D(self.fig)
        ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap=cm.spectral)
        ax.set_title("vibrational modes on a circular drum")
        ax.set_xlabel("x")
        ax.set_ylabel("y")
        ax.set_zlabel("z")
        self.canvas.show()
        
    def drumhead_height(self, n, k, distance, angle, time):
        nth_zero = jn_zeros(n, k)[-1]
        a =(jn(n, distance*nth_zero))
        b =np.cos(time)*np.cos(angle*n)
        z =a*b
        return z

    def openFile(self, filename):
        os.startfile(filename)
        
#make tk object  
root = Tk()
drum = MathDrum(root)
#run the main loop
root.mainloop()