plotting issue with matplotlib - python

I have an issue with plotting a graph over some values in python and matplotlib. What i want is to plot the i's (iterations) on the x-axis and optimal q*'s on the y-axis in the code below.
#Question 1
#i)
#Defining the parameters using SimpleNameSpace. par = Parameters
par = SimpleNamespace()
par.y = 1 #assets
par.p = 0.2 #probability
par.theta = -2 #elasticity
#Defining utility function for agent
def utility(z,par):
return (z**(1+par.theta))/(1+par.theta)
#Defining premium
def premium(q,par):
return par.p*q
#Defining expected value
#Note that z_1, z_2 represents first and second part of the objective function - just in a compressed version
def exp_value (i,q,par):
z_1 = par.y-i+q-premium(q,par)
z_2 = par.y-premium(q,par)
return par.p*utility(z_1,par)+(1-par.p)*utility(z_2,par)
def opt_q(i,par):
obj = lambda q: -exp_value(i,q,par) #defining the objective function
solution = minimize_scalar(obj, bounds=(0,0.9), method='bounded') #bounded solution within [0, 0.9]
q = solution.x
return q
# ii), iii) Creating a for loop to make a grid of the optimum q
for i in np.linspace(0.01,0.9,num=100):
res = opt_q(i,par)
print(res)
#iv) plotting the is and q*s with matplotlib
plt.plot(res,i)
# function to show the plot
plt.show()
When i run the above code i get nothing out on the graph. Can somebody explain what is missing?

Related

Euler's method for Python

I want to approximate the solutions of dy/dx = -x +1, with eulers method on the interval from 0 to 2. I'm using this code
def f(x):
return -x+1 # insert any function here
x0 = 1 # Initial slope #
dt = 0.1 # time step
T = 2 # ...from...to T
t = np.linspace(0, T, int(T/dt) + 1) # divide the interval from 0 to 2 by dt
x = np.zeros(len(t))
x[0] = x0 # value at 1 is the initial slope
for i in range(1, len(t)): # apply euler method
x[i] = x[i-1] + f(x[i-1])*dt
plt.figure() # plot the result
plt.plot(t,x,color='blue')
plt.xlabel('t')
plt.ylabel('y(t)')
plt.show()
Can I use this code to approximate the solutions of any function on any interval? It's hard to see whether this actually works, because I don't know how to plot the actual solution ( -1/2x^2 + x ) along side the approximation.
It would probably help if you consistently used the same variable names for the same role. Per your output, the solution is y(t). Thus your differential equation should be dy(t)/dt = f(t,y(t)). This would then give an implementation for the slope function and its exact solution
def f(t,y): return 1-t
def exact_y(t,t0,y0): return y0+0.5*(1-t0)**2-0.5*(1-t)**2
Then implement the Euler loop also as a separate function, keeping out problem specific details as much as possible
def Eulerint(f,t0,y0,te,dt):
t = np.arange(t0,te+dt,dt)
y = np.zeros(len(t))
y[0] = y0
for i in range(1, len(t)): # apply euler method
y[i] = y[i-1] + f(t[i-1],y[i-1])*dt
return t,y
Then plot the solutions as
y0,T,dt = 1,2,0.1
t,y = Eulerint(f,0,y0,T,dt)
plt.plot(t,y,color='blue')
plt.plot(t,exact_y(t,0,y0),color='orange')
You can just plot the actual solution by using:
def F(x):
return -0.5*x+x
# some code lines
plt.plot(t,x,color='blue')
plt.plot(t,F(t),color='orange')
But please note that the actual solution (-1/2x+x = 1/2x) does not correspond to your slope f(x) and will show a different solution.
The *real slope f(x) of the actual solution (-1/2x+x = 1/2x) is just simply f(x)=1/2

Interpolating a complex-valued boundary function inside a circular disk with the Cauchy Intergral?

I have heard that the Cauchy integration formula can be used to interpolate complex-valued functions along a closed boundary of a disk to points inside the disk. For my current project, this sounds rather valuable, so I attempted to give this a shot. Unfortunately, my experiments were not very successful so far, and I am not certain what is going wrong. Some degree of interpolation is certainly going on, but the results do not seem to be correct along the boundaries. Here is what my code returns:
Here is my initial code example:
import scipy.stats
import numpy as np
import scipy.integrate
import scipy.interpolate
import matplotlib.pyplot as plt
plt.close('all')
# This is the interpolation function, which takes as input a position on the
# boundary in radians (x), a complex evaluation point (eval_point), and the
# function which returns the boundary condition
def f(x,eval_point,itp):
# What is the complex coordinate of this point on the boundary?
zi = np.cos(x) + 1j*np.sin(x)
# Get the boundary condition value
fz = itp(x)
return fz/(zi-eval_point)
# Complex quadrature for integration, adapted from
# https://stackoverflow.com/questions/57325919/using-scipy-quad-with-i%ce%b5-trick-bad-results
def cquad(func, a, b, **kwargs):
real_integral = scipy.integrate.quad(lambda x: np.real(func(x, **kwargs)), a, b, limit=200)
imag_integral = scipy.integrate.quad(lambda x: np.imag(func(x, **kwargs)), a, b, limit=200)
return (real_integral[0] + 1j*imag_integral[0], real_integral[1:], imag_integral[1:])
# Define the interpolation function for the boundary values
itp = scipy.interpolate.interp1d(
x = [0,np.pi/2,np.pi,1.5*np.pi,2*np.pi],
y = [0+0j,0+1j,1+1j,1+0j,0+0j])
# Get some evaluation points
X,Y = np.meshgrid(np.linspace(-1,1,51),
np.linspace(-1,1,51))
XY = X+1j*Y
x = np.ndarray.flatten(XY)
# Throw away all points outside the unit disk; avoid evaluting at radius 1 to
# dodge singularities
x = x[np.where(np.abs(x) <= 0.99)]
# Calculate the result for each evaluation point
res = []
for val in x:
res.append(cquad(
func = f,
a = 0,
b = 2*np.pi,
eval_point = val,
itp = itp)[0]/(2*np.pi*1j))
# Convert the results into an array
res = np.asarray(res)
# Plot the real part of the results
plt.tricontour(
np.real(x),
np.imag(x),
np.real(res),
cmap = 'jet')
plt.colorbar(label='real part')
# Plot the imaginary part of the results
plt.tricontour(
np.real(x),
np.imag(x),
np.imag(res),
cmap = 'Greys')
plt.colorbar(label='imaginary part')
Does anybody have an idea what is going wrong?
You can get an easy approximation of that function by employing the FFT. The inverse FFT can be interpreted as polynomial evaluation at the corresponding points on the unit circle, so that the polynomial in total is an approximation of the Cauchy-formula
c = np.fft.fft(itp(np.linspace(0,2*np.pi,401)[:-1]))
c=c[::-1]/len(c)
np.polyval(c,[1,1j,-1,-1j])
returns
[5.55111512e-17+5.55111512e-17j, 5.55111512e-17+1.00000000e+00j,
1.00000000e+00+1.00000000e+00j, 1.00000000e+00+5.55111512e-17j]
these are the values that were expected.
X,Y = np.meshgrid(np.linspace(-1,1,151),
np.linspace(-1,1,151))
Z = (X+1j*Y).flatten()
Z = Z[np.where(np.abs(Z) <= 0.99)]
W = np.polyval(c,Z)
# Plot the real part of the results
plt.tricontour( Z.real, Z.imag, W.real, cmap = 'jet')
plt.colorbar(label='real part')
# Plot the imaginary part of the results
plt.tricontour( Z.real, Z.imag, W.imag, cmap = 'Greys')
plt.colorbar(label='imaginary part')
plt.tight_layout(); plt.show()
This then gives the picture
The dominant terms of the polynomial are
(1+1j)*(0.500000 - 0.045040*z^3 - 0.008279*z^7
- 0.005012*z^391 - 0.016220*z^395 - 0.405293*z^399)
As far as I could see, the leading degree 3 after the constant term is constant under refinement of the sampling sequence.

Using lmfit minimize for the first time to fit z=f(x,y), it rune but coefficient always end at 0

I would like to fit z = f(x,y) using an objective function.
I plan to fit more parameters later on, and lmfit sounded a nice abstraction to try.
For the sake of testing I created a controlled data set. The data is an array of coordinate X, coordinate Y, Vector X, Vector Y
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib import gridspec
from scipy.optimize import leastsq
from lmfit import Parameters, fit_report, minimize
#Creat sample
xs = 10
ys = 10
s = 11
coo_x = np.linspace(-xs, xs,s)
coo_y = np.linspace(-ys, ys,s)
#Get all permutations of X,Ycoordinates
mesh = np.array(np.meshgrid(coo_x, coo_y))
coo = mesh.T.reshape(-1, 2)
header = ["W_DesignPosX","W_DesignPosY","W_Registration_X_A","W_Registration_Y_A"]
transX = 3
transY = 0
angle = 0
magX = 0
magY = 0
orthX = 0
trans = np.linspace((transX,transY),(transX,transY),s*s)
rot = np.flip(coo, axis=1)*np.array ([-angle,angle])
mag = np.array([magX,magY])
orth = np.flip(coo, axis=1)*orthX/2
np.random.seed(seed=30)
random = np.random.normal(0,0.1, (s*s,2))
#random = np.zeros((s*s,2))
#Compute data
test= np.concatenate((coo, trans+coo*mag+rot+orth+random), axis=1)
test_df = pd.DataFrame(data=test, columns=header)
In the test case above TransX = 3, all the other input are = 0
Running the minimize it should fit to the following A=3, B=0, C=0, but all end at 0 :(
def residual_x(param, x, y, data):
A=params['A']
B=params['B']
C=params['C']
model = A + B*x +C*y
return (model-data)
params = Parameters()
params.add('A', value=0.0)
params.add('B', value=0.0)
params.add('C', value=0.0)
x,y =test[:,:2].T
reg_x = test[:,2]
out = minimize(residual_x,params, args = (x,y,reg_x))
print(fit_report(out))
print()
print(out.params.pretty_print())
I did eyeball the array and the quiver chart. The data has a horizontal vector.
def vector_summary(df,Design_x,Design_y,Reg_x,Reg_y,s=1):
c = 'g'
fig = plt.figure(figsize=(8, 4))
grid = plt.GridSpec(2, 3,width_ratios=[1.5, 0.25,1])
#Vector map
###########
ax_q = fig.add_subplot(grid[:,0])
X = list(df[Design_x])
Y = list(df[Design_y])
U = list(df[Reg_x])
V = list(df[Reg_y])
ax_q.quiver(X,Y,U,V,scale=0.04/s,color=c)
ax_q.set_title("Vector map",fontsize=20)
ax_q.set_xlabel('W_DesignPosX')
ax_q.set_ylabel('W_DesignPosY')
#ax_q.set_ylim([-20000,20000])
#X_registration
###############
ax_x= fig.add_subplot(grid[0,2])
sns.histplot(df, x=Reg_x,ax=ax_x,color=c)
ax_x.set_title("Reg_X",fontsize=20)
#Y_registration
###############
ax_y= fig.add_subplot(grid[1,2])
sns.histplot(df, x=Reg_y,ax=ax_y,color=c)
ax_y.set_title("Reg_Y",fontsize=20)
plt.tight_layout()
plt.show()
vector_summary(test_df,'W_DesignPosX','W_DesignPosY','W_Registration_X_A','W_Registration_Y_A',0.0005)
I am not a computer scientist and only have some instinct that my issue lies in the objective function. but I cannot point my finger on the issue.
Any advises would be appreciated! I am eager to learn. It is about the journey right ;-)
You have a simple typo in your residuals function
def residual_x(param, x, y, data):
needs to be params and not param
def residual_x(params, x, y, data):
Hence instead of accessing the updated params from residuals (that exists in local namespace), it was just looking at your original params (that existed in global name space). There was no error raised because the minimizer doesn't check if the special keyword 'params' is passed or not, instead Python goes from local namespace to global namespace outside residuals and minimizer, and of course, that variable doesn't change.
Later when you were trying to access params you would get the original one you have created.

Solve_ivp output, into orbital plot?

I'm trying to plot an orbit of a moon around Jupiter using gravitational acceleration.
I cannot seem to determine how to use the solve_ivp function appropriately. Something is just not clicking... I have created ODEs for a moon, related to Jupiter at the origin.
year = np.arange(0,31536000,3600)
G = 6.67408e-11
jupiter_xpos = 0
jupiter_ypos = 0
jupiter_vel = (0,0)
jupiter_mass = 1.89819e27
Io_orbit = 421700000
Io_xpos = -421700000
Io_ypos = 0
Io_xvel = 0
Io_yvel = -1773400
Io_mass = 8.9319e22
Io = [Io_xpos,Io_xvel,Io_ypos,Io_yvel]
def ode(Moon,t_max):
#Moon[0,1,2,3]=[x,v_x,y,v_y]
output=[0,0,0,0]
R = ((Moon[0]**2 + Moon[2]**2)**(3/2))
output[0]=Moon[1]
output[1]= -G*jupiter_mass*Moon[0]/R
output[2]=Moon[3]
output[3]= -G*jupiter_mass*Moon[2]/R
return output
#This is where the problem is
sol= solve_ivp(ode,Io,year)
plt.plot(sol[:,0],sol[:,2],0,0,'ro')
plt.axis('equal')
plt.grid(True)
plt.show()
I'm hoping to achieve a 2D orbital plot like this...
and also track and plot each change in x and y position and velocity against time.
The documentation for solve_ivp shows that the parameters are
sol = solve_ivp(ode, [t0,tf], u0, tspan=year, atol = 100, rtol=1e-9)
where year=np.arange(t0,tf,hour). Then you find the solution values in sol.t for the repeated times and sol.y for the values.

Programming of 4th order Runge-Kutta in advection equation in python

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from math import pi
# wave speed
c = 1
# spatial domain
xmin = 0
xmax = 1
#time domain
m=500; # num of time steps
tmin=0
T = tmin + np.arange(m+1);
tmax=500
n = 50 # num of grid points
# x grid of n points
X, dx = np.linspace(xmin, xmax, n+1, retstep=True);
X = X[:-1] # remove last point, as u(x=1,t)=u(x=0,t)
# for CFL of 0.1
CFL = 0.3
dt = CFL*dx/c
# initial conditions
def initial_u(x):
return np.sin(2*pi*x)
# each value of the U array contains the solution for all x values at each timestep
U = np.zeros((m+1,n),dtype=float)
U[0] = u = initial_u(X);
def derivatives(t,u,c,dx):
uvals = [] # u values for this time step
for j in range(len(X)):
if j == 0: # left boundary
uvals.append((-c/(2*dx))*(u[j+1]-u[n-1]))
elif j == n-1: # right boundary
uvals.append((-c/(2*dx))*(u[0]-u[j-1]))
else:
uvals.append((-c/(2*dx))*(u[j+1]-u[j-1]))
return np.asarray(uvals)
# solve for 500 time steps
for k in range(m):
t = T[k];
k1 = derivatives(t,u,c,dx)*dt;
k2 = derivatives(t+0.5*dt,u+0.5*k1,c,dx)*dt;
k3 = derivatives(t+0.5*dt,u+0.5*k2,c,dx)*dt;
k4 = derivatives(t+dt,u+k3,c,dx)*dt;
U[k+1] = u = u + (k1+2*k2+2*k3+k4)/6;
# plot solution
plt.style.use('dark_background')
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
line, = ax1.plot(X,U[0],color='cyan')
ax1.grid(True)
ax1.set_ylim([-2,2])
ax1.set_xlim([0,1])
def animate(i):
line.set_ydata(U[i])
return line,
I want to program in Python an advection equation which is (∂u/∂t) +c (∂u/∂x) = 0. Time should be discretized with Runge-kutta 4th order. Spatial discretiziation is 2nd order finite difference. When I run my code, I get straight line which transforms into sine wave. But I gave as initial condition sine wave. Why does it start as straight line? And I want to have sine wave moving forward. Do you have any idea on how to get sine wave moving forward? I appreciate your help. Thanks in advance!
While superficially your computation steps are related to the RK4 method, they deviate from the RK4 method and the correct space discretization too much to mention it all.
The traditional way to apply ODE integration methods is to have a function derivatives(t, state, params) and then apply that to compute the Euler step or the RK4 step. In your case it would be
def derivatives(t,u,c,dx):
du = np.zeros(len(u));
p = c/(2*dx);
du[0] = p*(u[1]-u[-1]);
du[1:-1] = p*(u[2:]-u[:-2]);
du[-1] = p*(u[0]-u[-2]);
return du;
Then you can do
X, dx = np.linspace(xmin, xmax, n+1, retstep=True);
X = X[:-1] # remove last point, as u(x=1,t)=u(x=0,t)
m=500; # number of time steps
T = tmin + np.arange(m+1);
U = np.zeros((m+1,n),dtype=float)
U[0] = u = initial_u(X);
for k in range(m):
t = T[k];
k1 = derivatives(t,u,c,dx)*dt;
k2 = derivatives(t+0.5*dt,u+0.5*k1,c,dx)*dt;
k3 = derivatives(t+0.5*dt,u+0.5*k2,c,dx)*dt;
k4 = derivatives(t+dt,u+k3,c,dx)*dt;
U[k+1] = u = u + (k1+2*k2+2*k3+k4)/6;
This uses dt as computed as the primary variable in the time stepping, then constructs the arithmetic sequence from tmin with step dt. Other ways are possible, but one has to make tmax and the number of time steps compatible.
The computation up to this point should now be successful and can be used in the animation. In my understanding, you do not produce a new plot in each frame, you only draw the graph once and after that just change the line data
# animate the time data
line, = ax1.plot(X,U[0],color='cyan')
ax1.grid(True)
ax1.set_ylim([-2,2])
ax1.set_xlim([0,1])
def animate(i):
line.set_ydata(U[i])
return line,
etc.

Categories