In [1]:

```
import numpy as np
import matplotlib.pyplot as plt
import tkinter as Tk
import pandas as pd
```

Day two of final exam review. As a reminder, the exam is cummulative and will cover the entirety of the course, except for NLTK and Scikit-Learn. Here is a list of topics that might help you study:

- Python syntax
- Strings, Lists, Dictionaries, Tuples, Sets
- Lambda expressions
- Classes, Inheritance
- Iterators, Generators
- Regular Expressions
- Pyplot, NumPy, Image Editing
- Tkinter
- Pandas

No algorithms (e.g., blurring, edge detection) will be tested on the exam.

The responses from my poll at the last discussion were to cover the following topics: NumPy/Pyplot, Iterators, Tkinter, Classes, and Pandas. We probably will not get through all these exercises, but you may find some of them helpful for practice on your own.

** Exercise 1:** Use NumPy and Pyplot to plot the functions

`y = sin(x)`

, `y = x`

, `y = x - x^3/6`

and `y = x - x^3/6 + x^5/120`

from `-pi`

to `pi`

. Give the plots labels, a title, and a legend.In [2]:

```
X = np.linspace(-np.pi, np.pi, 100)
plt.plot(X,np.sin(X))
plt.plot(X,X)
plt.plot(X,X - X**3/6)
plt.plot(X,X - X**3/6 + X**5/120)
plt.title('Sin and some polynomials')
plt.xlabel('x')
plt.ylabel('y')
plt.legend(['y = sin x', 'y = x', 'y = x - x^3/6', 'y = x - x^3/6 + x^5/120'])
plt.show()
```

** Exercise 2:** Use NumPy and Pyplot to create a rainbow gradient as image. It should smoothly go from red at the top left through the rainbow to magenta/purple on the bottom right. The colors should be

red -> yellow -> green -> cyan -> blue -> magenta

in terms of RGB, this is

[255, 0, 0] -> [255, 255, 0] -> [0, 255, 0] -> [0, 255, 255] -> [0, 0, 255] -> [255, 0, 255]

In [3]:

```
image = np.zeros([100, 100, 3])
x,y = np.ogrid[0:100, 0:100]
grid = x + y
# We divide the image into 5 parts based on what colors they are between.
red_to_ylw = grid < 40
ylw_to_grn = np.logical_and(grid >= 40, grid < 80)
grn_to_cyn = np.logical_and(grid >= 80, grid < 120)
cyn_to_blu = np.logical_and(grid >= 120, grid < 160)
blu_to_mag = grid >= 160
# At each part we want a smooth transition that starts at the color
# and ends right before the next color. We will use floats instead
# of integers, since they will be easier.
# Let's think about how we want to red to yellow, for example.
# When x+y = 0 we want the color to be [1.0, 0, 0].
# When x+y = 40 we want the color to be [1.0, 1.0, 0].
# So we want the color to be something like [1, (x+y)/40, 0].
# the other colors work similarly, but we might have to flip or subtract
image[red_to_ylw, 0] = 1
image[red_to_ylw, 1] = grid[red_to_ylw]/40
image[red_to_ylw, 2] = 0
image[ylw_to_grn, 0] = 2 - grid[ylw_to_grn]/40
image[ylw_to_grn, 1] = 1
image[ylw_to_grn, 2] = 0
image[grn_to_cyn, 0] = 0
image[grn_to_cyn, 1] = 1
image[grn_to_cyn, 2] = grid[grn_to_cyn]/40 - 2
image[cyn_to_blu, 0] = 0
image[cyn_to_blu, 1] = 4 - grid[cyn_to_blu]/40
image[cyn_to_blu, 2] = 1
image[blu_to_mag, 0] = grid[blu_to_mag]/40 - 4
image[blu_to_mag, 1] = 0
image[blu_to_mag, 2] = 1
plt.imshow(image)
plt.show()
```

** Exercise 3:** Write an iterator or generator that takes in a list and returns (in order) only the elements that have a square number for an index (so 0, 1, 4, 9, ...)

In [4]:

```
from math import sqrt
# generator
def only_squares(l):
for i, x in enumerate(l):
if int(sqrt(i)) == sqrt(i): # if the square root is an integer
yield x
# iterator
class Square_Iter:
def __init__(self, l):
self.l = l
self.curr = -1
def __iter__(self):
self.curr = -1
return self
def __next__(self):
while True:
self.curr += 1
if self.curr >= len(self.l):
raise StopIteration()
if int(sqrt(self.curr)) == sqrt(self.curr):
return self.l[self.curr]
for x in only_squares(list(range(2,200,2))):
# since each element here is twice its index, this will return
# all the numbers that are twice a square
print(x)
print('')
for x in Square_Iter(list(range(2,200,2))):
print(x)
```

** Exercise 4:** Write a Tkinter window that allows you to click to place squares. Make the colors of the square cycle between red, blue, and green every time you click. Also, make each new square larger than the previous.

In [5]:

```
root = Tk.Tk()
c = Tk.Canvas(root, width=500, height = 500)
color = 'red'
size = 10
def create_square(event):
global color # again, we can put this in a class and use an instance variable, if we want
global size
c.create_rectangle(event.x-size,event.y-size,event.x+size,event.y+size, fill=color)
if color == 'red':
color = 'blue'
elif color == 'blue':
color = 'green'
else:
color = 'red'
size += 5
c.bind('<Button-1>', create_square)
c.pack()
root.mainloop()
```

** Exercise 5:** Below is a Tkinter program and a class

`MovingRectangle`

.In [6]:

```
import random
root = Tk.Tk()
c = Tk.Canvas(root, width=500, height=500)
class MovingRectangle:
def __init__(self):
self.x = random.randint(0, 449)
self.y = random.randint(0, 449)
self.shape = c.create_rectangle(self.x, self.y, self.x+50, self.y+50, fill='blue')
self.speed = 10
root.after(40, self.update)
def update(self):
c.move(self.shape, self.speed, 0)
self.x += self.speed
if self.x >= 450 or self.x <= 0:
self.speed *= -1
root.after(40, self.update)
MovingRectangle()
MovingRectangle()
MovingRectangle()
c.pack()
root.mainloop()
```

Make a `ClickableRectangle`

class that extends `MovingRectangle`

that is a different color and changes direction when you click it. (You can only bind one function to a given press, so it's okay if you have this only work for one instance of `ClickableRectangle`

.)

In [7]:

```
class ClickableRectangle(MovingRectangle):
def __init__(self):
super().__init__()
c.itemconfig(self.shape, fill='red')
c.bind('<Button-1>', self.mouse_click)
def mouse_click(self, event):
# \ continues a line to the one below it
if event.x >= self.x and event.x <= self.x + 50 \
and event.y >= self.y and event.y <= self.y + 50:
self.speed *= -1
root = Tk.Tk()
c = Tk.Canvas(root, width=500, height=500)
MovingRectangle()
MovingRectangle()
MovingRectangle()
ClickableRectangle()
ClickableRectangle()
c.pack()
root.mainloop()
```

** Exercise 6:** Load the

`data.xlsx`

table from the Pandas lecture. Get all the member who share a last name with another member.In [8]:

```
df = pd.read_excel('data.xlsx', 'Worksheet', index_col=0)
# we can loop through the list to get the duplicates, or we can use some Pandas commands.
# this command gets the mask which has True for duplicates
duplicates = df['Last'].duplicated()
names = df['Last'][duplicates]
names = list(names)
members = df[df.Last.isin(names)]
members
```

Out[8]: