#This file contains functions to visualise the approximations of the methods.
import numpy as np
import scipy as sp
import R1
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import time
from scipy.optimize import root
from skimage import measure

#The function below draws the max error plot for each method for orders in a range.
#Parameters: input points, f, the domain, weighing function theta and the range of orders of the polynomial space.
def max_error(points, f, domain, theta, ms):

	max_error_ls = [0] * len(ms)
	max_error_wls = [0] * len(ms)
	max_error_mls = [0] * len(ms)
	i = 0	
	for m in ms:
		approx_ls = R1.least_squares_R(points, f(points), m)
		approx_wls = R1.weighted_least_squares_R(points, f(points), m, theta)
		approx_mls = R1.moving_least_squares_R(points, f(points), m, theta)

		for x in domain:
			err_ls = np.abs(f(x) - approx_ls(x))
			err_wls = np.abs(f(x) - approx_wls(x))
			err_mls = np.abs(f(x) - approx_mls(x))
			if err_ls > max_error_ls[i]:
				max_error_ls[i] = err_ls
			if err_wls > max_error_wls[i]:
				max_error_wls[i] = err_wls
			if err_mls > max_error_mls[i]:
				max_error_mls[i] = err_mls
		i+=1
		
	width = 0.2
	plt.bar(ms, max_error_ls, width, color='b')
	plt.bar(ms+width, max_error_wls, width, color='g')
	plt.bar(ms+width*2, max_error_mls, width, color='r')
	plt.xlabel('Order of the polynomial space')
	plt.ylabel('The maximal error of the approximation on the domain')
	plt.show()

#Function below draws a x, f(x) plot of the three approximations of a certain order: 
#Parameters: input points, f, the domain, weighing function theta and the order of the polynomial space.
def plot(points, f, domain, theta, order):
	order = 2
	approx_ls = R1.least_squares_R(points, f(points), order)
	approx_wls = R1.weighted_least_squares_R(points, f(points), order, theta)
	approx_mls = R1.moving_least_squares_R(points, f(points), order, theta)

	plt.plot(domain, f(domain), '#000000')
	plt.plot(domain, approx_ls(domain), 'b')
	plt.plot(domain, approx_wls(domain), 'g')
	plt.plot(domain, approx_mls(domain), 'r')
	plt.scatter(points, f(points))
	plt.xlabel('x')
	plt.ylabel('f(x)')
	plt.show()

# h = 10
# theta = lambda d : ((1-d/(h))**4)*(4*d/(h) + 1)
# test = np.linspace(-5,5,10) #The input points
# xs = np.linspace(-5,5,1000); #The sampling space for the graph
# f = np.vectorize(lambda x : np.abs(x) ) #The function can be specified here.
# ms = np.arange(1, 9) #The range of orders can be adjusted here
# max_error(test, f, xs, theta, ms)
# plot(test, f, xs, theta, 2)

#This file contains functions to visualise the approximations of the methods.
import numpy as np
import scipy as sp
import R1
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import time
from scipy.optimize import root
from skimage import measure

#The function below draws the max error plot for each method for orders in a range.
#Parameters: input points, f, the domain, weighing function theta and the range of orders of the polynomial space.
def max_error(points, f, domain, theta, ms):

	max_error_ls = [0] * len(ms)
	max_error_wls = [0] * len(ms)
	max_error_mls = [0] * len(ms)
	i = 0	
	for m in ms:
		approx_ls = R1.least_squares_R(points, f(points), m)
		approx_wls = R1.weighted_least_squares_R(points, f(points), m, theta)
		approx_mls = R1.moving_least_squares_R(points, f(points), m, theta)

		for x in domain:
			err_ls = np.abs(f(x) - approx_ls(x))
			err_wls = np.abs(f(x) - approx_wls(x))
			err_mls = np.abs(f(x) - approx_mls(x))
			if err_ls > max_error_ls[i]:
				max_error_ls[i] = err_ls
			if err_wls > max_error_wls[i]:
				max_error_wls[i] = err_wls
			if err_mls > max_error_mls[i]:
				max_error_mls[i] = err_mls
		i+=1
		
	width = 0.2
	plt.bar(ms, max_error_ls, width, color='b')
	plt.bar(ms+width, max_error_wls, width, color='g')
	plt.bar(ms+width*2, max_error_mls, width, color='r')
	plt.xlabel('Order of the polynomial space')
	plt.ylabel('The maximal error of the approximation on the domain')
	plt.show()

#Function below draws a x, f(x) plot of the three approximations of a certain order: 
#Parameters: input points, f, the domain, weighing function theta and the order of the polynomial space.
def plot(points, f, domain, theta, order):
	order = 2
	approx_ls = R1.least_squares_R(points, f(points), order)
	approx_wls = R1.weighted_least_squares_R(points, f(points), order, theta)
	approx_mls = R1.moving_least_squares_R(points, f(points), order, theta)

	plt.plot(domain, f(domain), '#000000')
	plt.plot(domain, approx_ls(domain), 'b')
	plt.plot(domain, approx_wls(domain), 'g')
	plt.plot(domain, approx_mls(domain), 'r')
	plt.scatter(points, f(points))
	plt.xlabel('x')
	plt.ylabel('f(x)')
	plt.show()

# h = 10
# theta = lambda d : ((1-d/(h))**4)*(4*d/(h) + 1)
# test = np.linspace(-5,5,10) #The input points
# xs = np.linspace(-5,5,1000); #The sampling space for the graph
# f = np.vectorize(lambda x : np.abs(x) ) #The function can be specified here.
# ms = np.arange(1, 9) #The range of orders can be adjusted here
# max_error(test, f, xs, theta, ms)
# plot(test, f, xs, theta, 2)

#This file contains functions to visualise the approximations of the methods. #The function below draws the max error plot for each method for orders in a range. #Parameters: input points, f, the domain, weighing function theta and the range of orders of the polynomial space. #Function below draws a x, f(x) plot of the three approximations of a certain order: #Parameters: input points, f, the domain, weighing function theta and the order of the polynomial space. # h = 10 # theta = lambda d : ((1-d/(h))**4)*(4*d/(h) + 1) # test = np.linspace(-5,5,10) #The input points # xs = np.linspace(-5,5,1000); #The sampling space for the graph # f = np.vectorize(lambda x : np.abs(x) ) #The function can be specified here. # ms = np.arange(1, 9) #The range of orders can be adjusted here # max_error(test, f, xs, theta, ms) # plot(test, f, xs, theta, 2)