In [1]:
import numpy as np
import matplotlib.pyplot as plt
import tkinter as Tk
import pandas as pd

Final Review 2

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)
2
4
10
20
34
52
74
100
130
164

2
4
10
20
34
52
74
100
130
164

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]:
Phone First Last
Member #
A1003 695-919-3789 Carol Vazquez
A1006 139-907-8100 Martena Jenkins
A1009 820-847-5666 Tana Vazquez
A1024 607-929-1091 Roth Nunez
A1047 619-948-4860 Scarlett Browning
A1060 242-782-8361 Tatum Le
A1077 672-355-0177 Vaughan Browning
A1079 241-622-2164 Todd Le
A1091 963-621-8389 Thane Jenkins
A1099 162-830-7380 Joseph Nunez