Plotting a function of two variables based on data from a file - python

Suppose the values of a function are written line by line in the file in the form x y f(x, y) and I read this file into the list of lists [ [x1, y1, f(x1, y1)], ..., [xN, yN, f(xN, yN)] ]:
with open('data.txt', 'r') as file:
data = [[float(x) for x in line.split()] for line in file]
The question is how to plot this function.
I managed to write a program (see below) that implements the task (the values for data are taken as an example), but it looks too complicated and, it seems to me, there is a more elegant solution.
import numpy as np
import matplotlib.pyplot as plt
data = [[0, 0, 1], [0, 1, 1], [1, 0, 2], [1, 1, 3]]
x, y, _ = np.array(data).T.tolist()
x = list(set(x))
y = list(set(y))
def f(x, y):
for val in data:
if x == val[0] and y == val[1]:
return val[2]
X, Y = np.meshgrid(x, y)
Z = [[f(x_, y_) for x_ in x] for y_ in y]
cp = plt.contourf(Y, X, Z)
plt.colorbar(cp)
plt.show()
Therefore, I think it is more correct to ask how to solve the problem gracefully, elegantly.

I found a way to significantly speed up the filling of Z. The solution, of course, is not elegant.
import numpy as np
import matplotlib.pyplot as plt
data = [[0, 0, 1], [0, 1, 1], [1, 0, 2], [1, 1, 3]]
x, y, _ = np.array(data).T.tolist()
x = list(set(x))
y = list(set(y))
X, Y = np.meshgrid(x, y)
#####
Z = np.zeros((len(x), len(y)))
x_ind = {xx[1] : xx[0] for xx in enumerate(x)}
y_ind = {yy[1] : yy[0] for yy in enumerate(y)}
for d in data:
xx, yy, zz = d
Z[x_ind[xx], y_ind[yy]] = zz
#####
cp = plt.contourf(Y, X, Z)
plt.colorbar(cp)
plt.show()
I compare these two approaches with a simple code:
import numpy as np
import sys
import time
def f1(data, x, y):
for val in data:
if x == val[0] and y == val[1]:
return val[2]
def init1(data, x, y):
Z = [[f1(data, x_, y_) for x_ in x] for y_ in y]
return Z
def init2(data, x, y):
Z = np.zeros((len(x), len(y)))
x_ind = {xx[1] : xx[0] for xx in enumerate(x)}
y_ind = {yy[1] : yy[0] for yy in enumerate(y)}
for d in data:
xx, yy, zz = d
Z[x_ind[xx], y_ind[yy]] = zz
return Z
def test(n):
data = []
x = y = [nn / n for nn in range(n+1)]
for xx in x:
for yy in y:
data.append([xx, yy, 0.])
t1 = time.time()
init1(data, x, y)
dt1 = time.time() - t1
t2 = time.time()
init2(data, x, y)
dt2 = time.time() - t2
print(f'n = {n:5d} ; t1 = {dt1:10.3f} s ; t2 = {dt2:10.3f} s')
def main():
n = 10
if len(sys.argv) > 1:
try:
n = int(sys.argv[1])
except:
print(f'Can not convert "{sys.argv[1]}" to integer')
exit(0)
if n <= 0:
print(f'n is negative or equal zero')
exit(0)
test(n)
if __name__ == '__main__':
main()
Without specifying the characteristics of the machine on which the program was run, I will only give the result of its work for n = 100 and n = 200:
$ python test.py 100 ; python test.py 200
n = 100 ; t1 = 1.092 s ; t2 = 0.001 s
n = 200 ; t1 = 19.312 s ; t2 = 0.005 s
Of course, this is still an inefficient way. So, for example, it will take 2 seconds for a 4000 by 4000 grid.
I want to note that the new method works acceptably on small and medium amounts of data, and the operating time of matplotlib is significantly longer. On large amounts of data, the problems are primarily related to matplotlib.
I think that, although the solution is not elegant, it solves the problem at an acceptable speed. To be honest, I'm not even sure that the result can be significantly accelerated.

Related

newton interpolation in pyton

I have to do a second degree interpolation using an already existing code and changing the values for mine, but for some reason when i go ahead and gragth the interpolation, the fuction suddently stops (it is not continuous). Can someone help me figuring out whats wrong? I believe it has something to do with line 43 (evaluation on new data points), but I am not sure.
Source code:
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-poster')
%matplotlib inline
def divided_diff(x, y):
'''
function to calculate the divided
differences table
'''
n = len(y)
coef = np.zeros([n, n])
# the first column is y
coef[:,0] = y
for j in range(1,n):
for i in range(n-j):
coef[i][j] = \
(coef[i+1][j-1] - coef[i][j-1]) / (x[i+j]-x[i])
return coef
def newton_poly(coef, x_data, x):
'''
evaluate the newton polynomial
at x
'''
n = len(x_data) - 1
p = coef[n]
for k in range(1,n+1):
p = coef[n-k] + (x -x_data[n-k])*p
return p
x = np.array([-5, -1, 0, 2])
y = np.array([-2, 6, 1, 3])
# get the divided difference coef
a_s = divided_diff(x, y)[0, :]
# evaluate on new data points
x_new = np.arange(-5, 2.1, .1)
y_new = newton_poly(a_s, x, x_new)
plt.figure(figsize = (12, 8))
plt.plot(x, y, 'bo')
plt.plot(x_new, y_new)
My code (adjusted for data points (0,0);(6.4,1.9);(10.6,4.3)):
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-poster')
%matplotlib inline
def divided_diff(x, y):
'''
function to calculate the divided
differences table
'''
n = len(y)
coef = np.zeros([n, n])
# the first column is y
coef[:,0] = y
for j in range(1,n):
for i in range(n-j):
coef[i][j] = \
(coef[i+1][j-1] - coef[i][j-1]) / (x[i+j]-x[i])
return coef
def newton_poly(coef, x_data, x):
'''
evaluate the newton polynomial
at x
'''
n = len(x_data) - 1
p = coef[n]
for k in range(1,n+1):
p = coef[n-k] + (x -x_data[n-k])*p
return p
x = np.array([0, 6.4, 10.6])
y = np.array([0, 1.9, 4.3])
# get the divided difference coef
a_s = divided_diff(x, y)[0, :]
# evaluate on new data points
x_new = np.arange(-5, 2.1, .1)
y_new = newton_poly(a_s, x, x_new)
plt.figure(figsize = (12, 8))
plt.plot(x, y, 'bo')
plt.plot(x_new, y_new)

Can't generate data to graph a piecewise function in Python

I'm trying to graph this function. x domain is (1,3) a_1 domain is (0,1) and b domain is (0,0.8)
function
My code is this so far:
import numpy as np
def t2(x,a,b):
if (x <= 1.5 - (a/2)).any():
imagent2=0
elif np.logical_and((1.5) - (a/2) < x, x <=(1.5) + (a/2)).all():
imagent2=(x-(1.5)+(a/2))/a
elif np.logical_and((1.5)+(a/2) < x ,x <= (2.6)-(b/2)).all():
imagent2=1
elif np.logical_and((2.6)-(b/2) < x, x <= 2.6+(b/2)).all():
imagent2=((2.6)+(b/2)-x)/b
elif (((2.6)+(b/2)) < x).any():
imagent2=0
return imagent2
n=5
q = np.linspace(1.01, 2.99,n)
w = np.linspace(0.01,0.99,n)
e = np.linspace(0.01,0.79,n)
X, A, B= np.meshgrid(q, w, e, indexing='ij')
assert np.all(X[:,0,0] == q)
assert np.all(A[0,:,0] == w)
assert np.all(B[0,0,:] == e)
print(t2(X,A,B))
I put the .all() and .any() cause i was getting errors without them. I will like to have an array with the values of the function on the specific domain. With that i would graph using f(x) as z, x as x, a as y and b should be represented as a colour. Don't really know how to do that last part also.
In the end i did something like this. Not quite what i wanted but i guess is enough.
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
def t2(x,a,b):
return np.piecewise(x, [np.logical_and(x>1,x<=1.5-(a/2)),np.logical_and((1.5)-(a/2)<x,x<=(1.5)+(a/2)),np.logical_and((1.5)+(a/2)<x,x<=(2.6)-(b/2)),np.logical_and((2.6)-(b/2)<x,x<=2.6+(b/2)),np.logical_and(x<3,((2.6)+(b/2))<x)], [lambda x: 0, lambda x: (x-(1.5)+(a/2))/a,lambda x: 1, lambda x: ((2.6)+(b/2)-x)/b, lambda x: 0])
n=100
x = np.linspace(1.01, 2.99,n)
y = np.linspace(0.01,0.99,n)
X,Y = np.meshgrid(x,y)
b_vals = [ 0.01,0.4, 0.79 ]
num_subplots = len(b_vals)
fig = plt.figure(figsize=(10, 4))
for i,b in enumerate(b_vals):
ax = fig.add_subplot(1 , num_subplots , i+1, projection='3d')
ax.plot_surface(X, Y, np.vectorize(t2)(X,Y,b), cmap=cm.gnuplot)
ax.set_title('b = %.2f'%b, fontsize=10)
plt.xlabel("x")
plt.ylabel("a")
ax.set_zlabel('T1(x,a,a_2)')
fig.savefig('contours.png', facecolor='grey', edgecolor='none')

Using solve_ivp instead of odeint to solve initial problem value

Currently, I solve the following ODE system of equations using odeint
dx/dt = (-x + u)/2.0
dy/dt = (-y + x)/5.0
initial conditions: x = 0, y = 0
However, I would like to use solve_ivp which seems to be the recommended option for this type of problems, but honestly I don't know how to adapt the code...
Here is the code I'm using with odeint:
import numpy as np
from scipy.integrate import odeint, solve_ivp
import matplotlib.pyplot as plt
def model(z, t, u):
x = z[0]
y = z[1]
dxdt = (-x + u)/2.0
dydt = (-y + x)/5.0
dzdt = [dxdt, dydt]
return dzdt
def main():
# initial condition
z0 = [0, 0]
# number of time points
n = 401
# time points
t = np.linspace(0, 40, n)
# step input
u = np.zeros(n)
# change to 2.0 at time = 5.0
u[51:] = 2.0
# store solution
x = np.empty_like(t)
y = np.empty_like(t)
# record initial conditions
x[0] = z0[0]
y[0] = z0[1]
# solve ODE
for i in range(1, n):
# span for next time step
tspan = [t[i-1], t[i]]
# solve for next step
z = odeint(model, z0, tspan, args=(u[i],))
# store solution for plotting
x[i] = z[1][0]
y[i] = z[1][1]
# next initial condition
z0 = z[1]
# plot results
plt.plot(t,u,'g:',label='u(t)')
plt.plot(t,x,'b-',label='x(t)')
plt.plot(t,y,'r--',label='y(t)')
plt.ylabel('values')
plt.xlabel('time')
plt.legend(loc='best')
plt.show()
main()
It's important that solve_ivp expects f(t, z) as right-hand side of the ODE. If you don't want to change your ode function and also want to pass your parameter u, I recommend to define a wrapper function:
def model(z, t, u):
x = z[0]
y = z[1]
dxdt = (-x + u)/2.0
dydt = (-y + x)/5.0
dzdt = [dxdt, dydt]
return dzdt
def odefun(t, z):
if t < 5:
return model(z, t, 0)
else:
return model(z, t, 2)
Now it's easy to call solve_ivp:
def main():
# initial condition
z0 = [0, 0]
# number of time points
n = 401
# time points
t = np.linspace(0, 40, n)
# step input
u = np.zeros(n)
# change to 2.0 at time = 5.0
u[51:] = 2.0
res = solve_ivp(fun=odefun, t_span=[0, 40], y0=z0, t_eval=t)
x = res.y[0, :]
y = res.y[1, :]
# plot results
plt.plot(t,u,'g:',label='u(t)')
plt.plot(t,x,'b-',label='x(t)')
plt.plot(t,y,'r--',label='y(t)')
plt.ylabel('values')
plt.xlabel('time')
plt.legend(loc='best')
plt.show()
main()
Note that without passing t_eval=t, the solver will automatically choose the time points inside tspan at which the solution will be stored.

How to calculate error in Polynomial Linear Regression?

I am trying to calculate the error rate of the training data I'm using.
I believe I'm calculating the error incorrectly. The formula is as shown:
y is calculated as shown:
I am calculating this in the function fitPoly(M) at line 49. I believe I am incorrectly calculating y(x(n)), but I don't know what else to do.
Below is the Minimal, Complete, and Verifiable example.
import numpy as np
import matplotlib.pyplot as plt
dataTrain = [[2.362761180904257019e-01, -4.108125266714775847e+00],
[4.324296163702689988e-01, -9.869308732049049127e+00],
[6.023323504115264404e-01, -6.684279243433971729e+00],
[3.305079685397107614e-01, -7.897042003779912278e+00],
[9.952423271981121200e-01, 3.710086310489402628e+00],
[8.308127402955634011e-02, 1.828266768673480147e+00],
[1.855495407116576345e-01, 1.039713135916495501e+00],
[7.088332047815845138e-01, -9.783208407540947560e-01],
[9.475723071629885697e-01, 1.137746192425550085e+01],
[2.343475721257285427e-01, 3.098019704040922750e+00],
[9.338350584099475160e-02, 2.316408265530458976e+00],
[2.107903139601833287e-01, -1.550451474833406396e+00],
[9.509966727520677843e-01, 9.295029459100994984e+00],
[7.164931165416982273e-01, 1.041025972594300075e+00],
[2.965557300301902011e-03, -1.060607693351102121e+01]]
def strip(L, xt):
ret = []
for i in L:
ret.append(i[xt])
return ret
x1 = strip(dataTrain, 0)
y1 = strip(dataTrain, 1)
# HELP HERE
def getY(m, w, D):
y = w[0]
y += np.sum(w[1:] * D[:m])
return y
# HELP ABOVE
def dataMatrix(X, M):
Z = []
for x in range(len(X)):
row = []
for m in range(M + 1):
row.append(X[x][0] ** m)
Z.append(row)
return Z
def fitPoly(M):
t = []
for i in dataTrain:
t.append(i[1])
w, _, _, _ = np.linalg.lstsq(dataMatrix(dataTrain, M), t)
w = w[::-1]
errTrain = np.sum(np.subtract(t, getY(M, w, x1)) ** 2)/len(x1)
print('errTrain: %s' % (errTrain))
return([w, errTrain])
#fitPoly(8)
def plotPoly(w):
plt.ylim(-15, 15)
x, y = zip(*dataTrain)
plt.plot(x, y, 'bo')
xw = np.arange(0, 1, .001)
yw = np.polyval(w, xw)
plt.plot(xw, yw, 'r')
#plotPoly(fitPoly(3)[0])
def bestPoly():
m = 0
plt.figure(1)
plt.xlim(0, 16)
plt.ylim(0, 250)
plt.xlabel('M')
plt.ylabel('Error')
plt.suptitle('Question 3: training and Test error')
while m < 16:
plt.figure(0)
plt.subplot(4, 4, m + 1)
plotPoly(fitPoly(m)[0])
plt.figure(1)
plt.plot(fitPoly(m)[1])
#plt.plot(fitPoly(m)[2])
m+= 1
plt.figure(3)
plt.xlabel('t')
plt.ylabel('x')
plt.suptitle('Question 3: best-fitting polynomial (degree = 8)')
plotPoly(fitPoly(8)[0])
print('Best M: %d\nBest w: %s\nTraining error: %s' % (8, fitPoly(8)[0], fitPoly(8)[1], ))
bestPoly()
Updated: This solution uses numpy's np.interp which will connect the points as a kind of "best fit". We then use your error function to find the difference between this interpolated line and the predicted y values for the degree of each polynomial.
import numpy as np
import matplotlib.pyplot as plt
import itertools
dataTrain = [
[2.362761180904257019e-01, -4.108125266714775847e+00],
[4.324296163702689988e-01, -9.869308732049049127e+00],
[6.023323504115264404e-01, -6.684279243433971729e+00],
[3.305079685397107614e-01, -7.897042003779912278e+00],
[9.952423271981121200e-01, 3.710086310489402628e+00],
[8.308127402955634011e-02, 1.828266768673480147e+00],
[1.855495407116576345e-01, 1.039713135916495501e+00],
[7.088332047815845138e-01, -9.783208407540947560e-01],
[9.475723071629885697e-01, 1.137746192425550085e+01],
[2.343475721257285427e-01, 3.098019704040922750e+00],
[9.338350584099475160e-02, 2.316408265530458976e+00],
[2.107903139601833287e-01, -1.550451474833406396e+00],
[9.509966727520677843e-01, 9.295029459100994984e+00],
[7.164931165416982273e-01, 1.041025972594300075e+00],
[2.965557300301902011e-03, -1.060607693351102121e+01]
]
data = np.array(dataTrain)
data = data[data[:, 0].argsort()]
X,y = data[:, 0], data[:, 1]
fig,ax = plt.subplots(4, 4)
indices = list(itertools.product([0,1,2,3], repeat=2))
for i,loc in enumerate(indices, start=1):
xx = np.linspace(X.min(), X.max(), 1000)
yy = np.interp(xx, X, y)
w = np.polyfit(X, y, i)
y_pred = np.polyval(w, xx)
ax[loc].scatter(X, y)
ax[loc].plot(xx, y_pred)
ax[loc].plot(xx, yy, 'r--')
error = np.square(yy - y_pred).sum() / X.shape[0]
print(error)
plt.show()
This prints out:
2092.19807848
1043.9400277
1166.94550318
252.238810889
225.798905379
155.785478366
125.662973726
143.787869281
6553.66570273
10805.6609259
15577.8686283
13536.1755299
108074.871771
213513916823.0
472673224393.0
1.01198058355e+12
Visually, it plots out this:
From here, it's just a matter of saving those errors to a list and finding the minimum.
I may contribute :
def pol_y(x, w):
y = 0; power = 0;
for i in w:
y += i*(x**power);
power += 1;
return y
The M is included implicitly because it is the final index of w. So if w = [0, 0, 1], then pol_y(x, w) is as same as f(x) = x^2.
If you want to map the 1st column of the dataTrain :
get_Y = [pol_y(i, w) for i in x1 ]
The error may be calculated by
vec_error = [(y1[i] - getY[i])**2 for i in range(0, len(y1)];
train_error = np.sum(vec_error)/len(y1);
Hope this helps.

Fitting a polynomial function for a vector field in python

At first, thank you everybody for the amazing work on stackoverflow... you guys are amazing and have helped me out quite some times already. Regarding my problem: I have a series of vectors in the format (VectorX, VectorY, StartingpointX, StartingpointY)
data = [(-0.15304757819399128, -0.034405679205349315, -5.42877197265625, 53.412933349609375), (-0.30532995491023485, -0.21523935094046465, -63.36669921875, 91.832427978515625), (-0.15872430479453215, -0.077999419482978283, -67.805389404296875, 81.001983642578125), (-0.36415549211687903, -0.33757147194808113, -59.015228271484375, 82.976226806640625), (0.0, 0.0, 0.0, 0.0), (-0.052973530805275004, 0.098212384392411423, 19.02667236328125, -13.72125244140625), (-0.34318724086483599, 0.17123742336019632, 80.0394287109375, 108.58499145507812), (0.19410169197834648, -0.17635303976555861, -55.603790283203125, -76.298828125), (-0.38774018337716143, -0.0824692384322816, -44.59942626953125, 68.402496337890625), (0.062202543524108478, -0.37219011831012949, -79.828826904296875, -10.764404296875), (-0.56582988168383963, 0.14872365390732512, 39.67657470703125, 97.303192138671875), (0.12496832467900276, -0.12216653754859408, 24.65948486328125, -30.92584228515625)]
When I plot the vectorfield it looks like this:
import numpy as np
import matplotlib.pyplot as plt
def main():
# Format Data...
numdata = len(data)
x = np.zeros(numdata)
y = np.zeros(numdata)
u = np.zeros(numdata)
v = np.zeros(numdata)
for i,el in enumerate(data):
x[i] = el[2]
y[i] = el[3]
# length of vector
z[i] = math.sqrt(el[0]**2+el[1]**2)
u[i] = el[0]
v[i] = el[1]
# Plot
plt.quiver(x,y,u,v )
# showing the length with color
plt.scatter(x, y, c=z)
plt.show()
main()
I want to create a polynomial function to fit a continous vector field for the whole area. After some research I found the following functions for fitting polynoms in two dimensions. The problem is, that it only accepts one value for the value that is fitted.
def polyfit2d(x, y, z, order=3):
ncols = (order + 1)**2
G = np.zeros((x.size, ncols))
ij = itertools.product(range(order+1), range(order+1))
for k, (i,j) in enumerate(ij):
G[:,k] = x**i * y**j
m, _, _, _ = np.linalg.lstsq(G, z)
return m
def polyval2d(x, y, m):
order = int(np.sqrt(len(m))) - 1
ij = itertools.product(range(order+1), range(order+1))
z = np.zeros_like(x)
for a, (i,j) in zip(m, ij):
z += a * x**i * y**j
return z
Also when I tried to fit the one dimensional length of the vectors, the values returned from the polyval2d were completely off. Does anybody know a method to get a fitted function that will return a vector (x,y) for any point in the grid?
Thank you!
A polynomial to fit a 2-d vector field will be two bivariate polynomials - one for the x-component and one for the y-component. In other words, your final polynomial fitting will look something like:
P(x,y) = ( x + x*y, 1 + x + y )
So you will have to call polyfit2d twice. Here is an example:
import numpy as np
import itertools
def polyfit2d(x, y, z, order=3):
ncols = (order + 1)**2
G = np.zeros((x.size, ncols))
ij = itertools.product(range(order+1), range(order+1))
for k, (i,j) in enumerate(ij):
G[:,k] = x**i * y**j
m, _, _, _ = np.linalg.lstsq(G, z)
return m
def fmt1(x,i):
if i == 0:
return ""
elif i == 1:
return x
else:
return x + '^' + str(i)
def fmt2(i,j):
if i == 0:
return fmt1('y',j)
elif j == 0:
return fmt1('x',i)
else:
return fmt1('x',i) + fmt1('y',j)
def fmtpoly2(m, order):
for (i,j), c in zip(itertools.product(range(order+1), range(order+1)), m):
yield ("%f %s" % (c, fmt2(i,j)))
xs = np.array([ 0, 1, 2, 3] )
ys = np.array([ 0, 1, 2, 3] )
zx = np.array([ 0, 2, 6, 12])
zy = np.array([ 1, 3, 5, 7])
mx = polyfit2d(xs, ys, zx, 2)
print "x-component(x,y) = ", ' + '.join(fmtpoly2(mx,2))
my = polyfit2d(xs, ys, zy, 2)
print "y-component(x,y) = ", ' + '.join(fmtpoly2(my,2))
In this example our vector field is:
at (0,0): (0,1)
at (1,1): (2,3)
at (2,2): (6,5)
at (3,3): (12,7)
Also, I think I found a bug in polyval2d - this version gives more accurate results:
def polyval2d(x, y, m):
order = int(np.sqrt(len(m))) - 1
ij = itertools.product(range(order+1), range(order+1))
z = np.zeros_like(x)
for a, (i,j) in zip(m, ij):
z = z + a * x**i * y**j
return z

Categories

Resources