# 1. Print out data in columns
height = [134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178]
fev = [1.7, 1.9, 2., 2.1, 2.2, 2.5, 2.7, 3.,3.1, 3.4, 3.8, 3.9]
n_height = len(height)
n = 0
for x in range (0,n_height) :
print (f"{height [n]} {fev [n]}")
n = n + 1

# 2. Import libraries - NumPy and matplotlib
import numpy as np
import matplotlib.pyplot as plt

# 3. Plot the data; add labels to axes and plot title
x= height
y= fev
plt.plot (x,y, "b+")
plt.xlabel ("Height")
plt.ylabel ("FEV")
plt.title ("Scatter plot of data")

# 4. Input functions to find interpolating polynomial
def compute_int_coeff (n, x, y) :
coeff = [n] # initialize list
for i in range (0,n+1): # loop to calculate n+1 coefficients
numerator = y[i]
denominator = 1. # because denominator is a product we must initialize to 1
for j in range (0,n+1):
if ( i != j) : # denominator is product of all terms except
# when x_i=x_j which would give 0
denominator = denominator * (x[i] - x[j])
coeff.append (numerator / denominator) # add term to list
return (coeff)
#
#
def eval_int_polynomial (n, x, x_eval, coeff) :
my_sum = 0. # formula is sum of n+1 terms so initialize
for i in range (0,n+1) : # loop to form sum of terms
product = 1. # initialize product in numerator of L_i
for j in range (0, n+1) : # loop to form product of terms in numerator
if ( i != j ) : # include all terms except when i = j
product = product * (x_eval - x[j])
# when this j loop is complete we have the numerator of L_i for one term
yi_times_Li = product * coeff[i] # multiplies numerator times C_i (y_i/ product)
my_sum = my_sum + yi_times_Li # keeps running tally of sum of terms
return (my_sum)

# 5. Plot the interpolating polynomial from a height of 134 cm to 178 cm
height = [134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178]
fev = [1.7, 1.9, 2., 2.1, 2.2, 2.5, 2.7, 3.,3.1, 3.4, 3.8, 3.9]
x = height
y = fev
n = 11
x_plt = np.linspace(134, 178, 10000)
coeff = compute_int_coeff (n,x,y)
y_plt= []
for i in range (0, len(x_plt)):
poly = eval_int_polynomial (n, x, x_plt [i], coeff)
y_plt.append (poly)
print (x_plt)
print (y_plt)
plt.plot (x_plt,y_plt, "r")
plt.plot (x,y, "g+")
plt.xlabel ("Height")
plt.ylabel ("Polynomial")
plt.title ("Scatter plot of data")

# 6. Use the polynomial to predict the FEV for a height of 165 cm and of 175 cm.
# Which do you think is a better prediction?
height = [134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178]
fev = [1.7, 1.9, 2., 2.1, 2.2, 2.5, 2.7, 3.,3.1, 3.4, 3.8, 3.9]
x = height
y = fev
n = 11
x_plt = np.linspace(165, 178, 10000)
coeff = compute_int_coeff (n,x,y)
y_plt= []
for i in range (0, len(x_plt)):
poly = eval_int_polynomial (n, x, x_plt [i], coeff)
y_plt.append (poly)
print (x_plt)
print (y_plt)
plt.plot (x_plt,y_plt, "r")
plt.plot (x,y, "g+")
plt.xlabel ("Height")
plt.ylabel ("Polynomial")
plt.title ("Scatter plot of data")
#The first graph is a better prediction because more of the points fall on the red line

# Import libraries
import matplotlib.pyplot as plt
import numpy as np

# Plot piecewise linear interpolating polynomial and data; use
height = [134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178]
fev = [1.7, 1.9, 2., 2.1, 2.2, 2.5, 2.7, 3.,3.1, 3.4, 3.8, 3.9]
x = height
y = fev
n = 11
x_plt = np.linspace(134, 178)
x_int = np.linspace(134, 178, 11)
pw_lin = np.interp (x_plt,x_int,y_int)
coeff = compute_int_coeff (n,x,y)
y_int = height
y_plt= []
for i in range (0, len(x_plt)):
poly = eval_int_polynomial (n, x, x_plt [i], coeff)
y_plt.append (poly)
#print (x_plt)
#print (y_plt)
plt.plot (x_plt,pw_lin, "r")
plt.plot (x,y, "g+")
plt.xlabel ("Height")
plt.ylabel ("Polynomial")
plt.title ("Scatter plot of data")
x_plt = np.linspace (134, 178, 50)

# Use the piecewise polynomial to predict the FEV for a height of 165 cm and of 176 cm.
# How does this compare with 11th degree polynomial which predicted 3.104 for 165 cm and
# 2.697 for 176 cm