I would like my y-axis to be superimposed/shifted as it is in this image:
Here is the graph that I have created using python with the code shown below:
There is only one origin on the graph I produced. I would like there to be at least three so that the functions with the smaller amplitudes are more visible/ easier to read.
What functions can I use to achieve this?
Thank you!
import numpy as np
import matplotlib.pyplot as plt
import math
def initial():
#obtain inital parameters
dt = .04
g = 9.8
l = 9.8
q = 0.5
f_d = 1.2 #driving force
frequency = 0.667 #frequency of driving force
theta_start = 0.2
omega_start = 0
time_stop = 60
return dt, g, l, q, frequency, theta_start, omega_start, time_stop
def rk_2(dt, g, l, q, frequency, theta_start, omega_start, time_stop):
#create arrays for theta and omega, calculate omega and theta using rk2 method
forces = [0, 0.5, 1.2]
j = 0
while j < 3:
f_d = forces[j]
theta = []
omega = []
time = [np.array([0])]
theta = np.append(theta, theta_start)
omega = np.append(omega, omega_start)
i = 0
while time[i] < time_stop:
#if theta[i] not in range(-3.14,3.14)
theta_prime = theta[i] + 0.5*omega[i]*dt
omega_prime = omega[i] + 0.5*((-g/l)*math.sin(theta[i]) - q*omega[i] + f_d*math.sin(frequency*time[i]))*dt
time_prime = time[i] + 0.5*dt
theta_new = theta[i] + omega_prime*dt
omega_new = omega[i] + ((-g/l)*math.sin(theta_prime) - q*omega[i] + f_d*math.sin(frequency*time_prime))*dt
time_new = time[i] + dt
theta = np.append(theta, theta_new)
omega = np.append(omega, omega_new)
time = np.append(time, time_new)
i = i + 1
plt.plot(time, theta)
j = j+1
plt.plot(time, theta)
plt.xlabel('Time [s]')
plt.ylabel('Angle [rad]')
plt.show()
return theta, omega, time
def main():
dt, g, l, q, frequency, theta_start, omega_start, time_stop = initial()
theta, omega, time = rk_2(dt, g, l, q, frequency, theta_start, omega_start, time_stop)
#plot(theta, omega, time)
main()
The answer referenced in #tom10's comment can be modified to ensure the tick spacing is consistent across all subplots, even when the height of the subplots is different, by explicitly setting the tick locations (and labels) as well as the limits for each subplot:
import numpy as np
import matplotlib.pyplot as plt
import math
ratios = [5, 5, 7]
lim = [[-0.3, 0.3], [-1, 1], [-12,4]]
labels = [['' if (e != (ratios[j] - 1) / 2) else 0
for e in range(ratios[j]-1)]+[lim[j][1]] for j in range(len(ratios))]
fig, axs = plt.subplots(3, 1, sharex=True, gridspec_kw={'height_ratios': ratios})
def initial():
#obtain inital parameters
dt = .04
g = 9.8
l = 9.8
q = 0.5
f_d = 1.2 #driving force
frequency = 0.667 #frequency of driving force
theta_start = 0.2
omega_start = 0
time_stop = 60
return dt, g, l, q, frequency, theta_start, omega_start, time_stop
def rk_2(dt, g, l, q, frequency, theta_start, omega_start, time_stop):
forces = [0, 0.5, 1.2]
for j in range(3):
f_d = forces[j]
theta = []
omega = []
time = [np.array([0])]
theta = np.append(theta, theta_start)
omega = np.append(omega, omega_start)
i = 0
while time[i] < time_stop:
theta_prime = theta[i] + 0.5*omega[i]*dt
omega_prime = omega[i] + 0.5*((-g/l)*math.sin(theta[i]) - q*omega[i] +
f_d*math.sin(frequency*time[i]))*dt
time_prime = time[i] + 0.5*dt
theta_new = theta[i] + omega_prime*dt
omega_new = omega[i] + ((-g/l)*math.sin(theta_prime) - q*omega[i] +
f_d*math.sin(frequency*time_prime))*dt
time_new = time[i] + dt
theta = np.append(theta, theta_new)
omega = np.append(omega, omega_new)
time = np.append(time, time_new)
i = i + 1
axs[j].plot(time, theta)
if j != 0: axs[j].spines['top'].set_visible(False)
if j != 2:
axs[j].spines['bottom'].set_visible(False)
axs[j].tick_params(bottom=False)
axs[j].tick_params(axis='y', direction='in')
axs[j].set_ylim(lim[j])
axs[j].set_yticks(np.linspace(lim[j][0], lim[j][1], ratios[j]))
axs[j].set_yticklabels(labels[j])
plt.subplots_adjust(hspace=0)
plt.figtext(0.08, 0.5, 'Angle [rad]', rotation = 90, ha='center', va='center')
plt.xlabel('Time [s]')
plt.show()
return theta, omega, time
def main():
dt, g, l, q, frequency, theta_start, omega_start, time_stop = initial()
theta, omega, time = rk_2(dt, g, l, q, frequency, theta_start, omega_start, time_stop)
main()
Related
I wrote code for Runge-Kutta 4 for solving system of 3 ODEs
I think that it does not work fine for because I solved the system with Euler's method and I had have the following results
But with the RK4's code attached I get a very different result:
import matplotlib.pyplot as plt
umax = 0.53
Km = 0.12
Yxs = 0.4
S1f = 4
Yxp = 0.4
D=0.5 #
X1f=0.2
P1f=0.1
# Equations:
#du/dt=V(u,t)
def V(u,t):
X1, S1, P1, vx, vs, vp = u
return np.array([ vx,vs,vp,
D*(X1f - X1)+(umax*(1-np.exp(-S1/Km)))*X1,
D*(S1f - S1)-(umax*(1-np.exp(-S1/Km))*X1)/Yxs,
D*(P1f - P1)+(umax*(1-np.exp(-S1/Km)))*X1*Yxp ])
def rk4(f, u0, t0, tf , n):
t = np.linspace(t0, tf, n+1)
u = np.array((n+1)*[u0])
h = (t[1]-t[0])/n
for i in range(n):
k1 = h * f(u[i], t[i])
k2 = h * f(u[i] + 0.5 * k1, t[i] + 0.5*h)
k3 = h * f(u[i] + 0.5 * k2, t[i] + 0.5*h)
k4 = h * f(u[i] + k3, t[i] + h)
u[i+1] = u[i] + (k1 + 2*(k2 + k3 ) + k4) / 6
return u, t
u, t = rk4(V, np.array([0., 0., 0. , 0., 1. , 0.]) , 0. , 40. , 4000)
x,y,z, vx,vs,vp = u.T
# plt.plot(t, x, t,y)
plt.plot(t, x, t,y,t,z)
plt.grid('on')
plt.show()
I have reviewed the code several times but I can't find the reason why the result is very different from the previous one
You should notice that the function V there will only be the variables X1, S1, P1 = u and the return vector as
np.array([D*(X1f - X1)+(umax*(1-np.exp(-S1/Km)))*X1, D*(S1f - S1)-(umax*(1-np.exp(-S1/Km))*X1)/Yxs, D*(P1f - P1)+(umax*(1-np.exp(-S1/Km)))*X1*Yxp ])
So your code would look like the following
import numpy as np
import matplotlib.pyplot as plt
umax = 0.53
Km = 0.12
Yxs = 0.4
S1f = 4
Yxp = 0.4
D=0.5 # Para teissier 0<D<0.514
X1f=0.2
P1f=0.1
# Equations:
#du/dt=V(u,t)
def V(u,t):
X1, S1, P1 = u
return np.array([D*(X1f - X1)+(umax*(1-np.exp(-S1/Km)))*X1,D*(S1f - S1)-(umax*(1-np.exp(-S1/Km))*X1)/Yxs,D*(P1f - P1)+(umax*(1-np.exp(-S1/Km)))*X1*Yxp] )
def rk4(f, u0, t0, tf , n):
t = np.linspace(t0, tf, n+1)
u = np.array((n+1)*[u0])
h = (t[1]-t[0])
for i in range(n):
k1 = h * f(u[i], t[i])
k2 = h * f(u[i] + 0.5 * k1, t[i] + 0.5*h)
k3 = h * f(u[i] + 0.5 * k2, t[i] + 0.5*h)
k4 = h * f(u[i] + k3, t[i] + h)
u[i+1] = u[i] + (k1 + 2*(k2 + k3 ) + k4) / 6
return u, t
u, t = rk4(V, np.array([0., 0., 1. ]) , 0. , 40. , 4000)
x,y,z= u.T
fig = plt.figure() # create figure
plt.plot(t, x, linewidth = 2, label = 'Biomasa') # plot Y to t
plt.plot(t, y, linewidth = 2, label = 'Sustrato') # plot P to tplt.title('Title', fontsize = 12) # add some title to your plot
plt.plot(t, z, linewidth = 2, label = 'Producto') # plot P to tplt.title('Title', fontsize = 12) # add some title to your plot
plt.xlabel('t (en segundos)', fontsize = 12)
plt.ylabel('Biomasa, Sustrato, Producto', fontsize = 12)
plt.xticks(fontsize = 12)
plt.yticks(fontsize = 12)
plt.grid(True) # show grid
plt.legend()
plt.show()
Thus obtaining the graphics you want
You did too much in
h = (t[1]-t[0])/n
The difference t[1]-t[0] is already the step size, what you did makes it the step size for n^2 steps in the same interval.
Are the initial values really the same? In the first graph it does not look like all variables start at zero.
im trying to run an SIR model in python. I want to plot changing beta values against the maximum of I for each beta value. I have the beta's figured out but i dont know how i would plot the I against it?.
here's my code so far:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import math
def SIR(y, t):
S, I, R = y
mu = 0.1
N = S + I + R
Sdot = -beta * S * I
Idot = beta * S * I - mu * I
Rdot = mu * I
return Sdot, Idot, Rdot
tf = 100
Nsteps = 1000
t = np.linspace(0, tf, Nsteps+1)
S0 = 10**4 - 3
I0 = 3
R0 = 0
y0 = np.array([S0, I0, R0])
y_sol = odeint(SIR, y0, t)
S = y_sol[:,0]
I = y_sol[:,1]
R = y_sol[:,2]
Imax = max(I)
tmax = t[I.argmax()]
Smax = S[I.argmax()]
beta_vals = np.linspace(0.2, 0.6, 5)
max_I =[]
for beta in beta_vals:
max_I.append(max(I))
plt.plot(beta_vals, max_I)
plt.xlabel('beta')
plt.ylabel('Maximum value of I')
plt.title('Effect of beta on the maximum value of I')
plt.show()
I thought that using append would give me the corresponding values but i end up with a straight line
You are almost there.
Try this updated code :
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import math
def SIR(y, t, beta):
S, I, R = y
mu = 0.1
N = S + I + R
Sdot = -beta * S * I
Idot = beta * S * I - mu * I
Rdot = mu * I
return Sdot, Idot, Rdot
tf = 100
Nsteps = 1000
t = np.linspace(0, tf, Nsteps+1)
S0 = 10**4 - 3
I0 = 3
R0 = 0
y0 = np.array([S0, I0, R0])
beta_vals = np.linspace(0.2, 0.6, 5)
max_I = []
for beta in beta_vals:
y_sol = odeint(SIR, y0, t, args=(beta,))
S = y_sol[:,0]
I = y_sol[:,1]
max_I.append(max(I))
plt.plot(beta_vals, max_I)
plt.xlabel('beta')
plt.ylabel('Maximum value of I')
plt.title('Effect of beta on the maximum value of I')
plt.show()
I need help to solve a ODE system using odeint or any workaround that works. I`m trying to model a ODE system descriving the beheaviour of a cilinder on a mechanichal arm, using Lagrangian mechanics I got the following 2nd order ODE system:
$$\ddot{x} = x*\dot{\phi}^2 - g*(sin(\phi) +cos(\phi))$$
$$\ddot{\phi} = \frac{1}{2*\dot{x}*m_c}*(\frac{k*i}{x}-\frac{m_b*L*\dot{\phi}}{2}-g*cos(\phi)*(m_c*x-m_b*L/2))$$
Then I transformed it to a 4x4 1st order ODE system y linearized 2 equations aroun initial condition, to make it more "solveable".
In python I`wrote the folllowing:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
# source: https://apmonitor.com/pdc/index.php/Main/SolveDifferentialEquations
g, mc, mb, k, L = (9.8, 0.5, 1.3, 2, 1.2)
def model(z, t, i, z0):
global g, mc, mb, k, L
#ODE variables
x1 = z[0]
y1 = z[1]
x2 = z[2]
y2 = z[3]
#ODE initial conditions
zx1 = z0[0]
zy1 = z0[1]
zx2 = z0[2]
zy2 = z0[3]
#Diferential for linealization around I.C.
dx1 = z[0]-z0[0]
dy1 = z[1]-z0[1]
dx2 = z[2]-z0[2]
dy2 = z[3]-z0[3]
def w1(zx1, zy1, zx2, zy2):
global g, mc, mb, k, L
return zx2*zy1**2-g*(np.sin(zy2)+np.cos(zy2))
def w2(zx1, zy1, zx2, zy2):
global g, mc, mb, k, L
return 1/(2*zx1*mc)*((k*i)/(zx2)-mb*zy2*L/2-g*np.cos(zy2*(mc*zx2-mb*L/2)))
dx2dt = x1
#dx1dt = x2*y1**2-g*(np.sin(y2)+np.cos(y2))
dx1dt = w1(zx1, zy1, zx2, zy2) + zy1**2*dx2+2*zx2 * \
zy1*dy1-g*(np.cos(zy2)-np.sin(zy2))*dy2
dy2dt = y1
#dy1dt = 1/(2*x1*mc)*((k*i)/(x2)-mb*y2*L/2-g*np.cos(y2*(mc*x2-mb*L/2)))
dy1dt = w2(zx1, zy1, zx2, zy2) - 1/(4*zx1**2*mc) * \
((k*i)/(zx2)-mb*zy2*L/2-g*np.cos(zy2*(mc*zx2-mb*L/2)))*dx1
+(k*i*np.log(abs(zx2))/(2*zx1*mc)-g*np.cos(zy2)*mc)*dx2-(mb*L) / \
(4*zx1*mc)*dy1+g*np.sin(zy2)*(mc*zx2-mb*L/2)*(2*zx1*mc)*dy2
dzdt = [dx1dt, dy1dt, dx2dt, dy2dt]
return dzdt
# initial condition
z0 = [0.01, 0.01, 0.8, np.pi/8]
# number of time points
n = 30
# time points
t = np.linspace(0, 1, n)
# step input
u = np.zeros(n)
# change to 2.0 at time = 5.0
u[:] = 1
# store solution
x1 = np.zeros(n)
y1 = np.zeros(n)
x2 = np.zeros(n)
y2 = np.zeros(n)
# record initial conditions
x1[0] = z0[0]
y1[0] = z0[1]
x2[0] = z0[2]
y2[0] = z0[3]
# 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], z0)) )
# store solution for plotting
if -np.pi/4 <= z[1][3] <= np.pi/4: # Angulo +/- Pi/4
u[i] = u[i-1] + 1
else:
u[i] = u[i-1]
if 0 <= z[1][2] <= L: # Se mantiene en el brazo
print("Se saliΓ³")
x1[i] = z[1][0]
y1[i] = z[1][1]
x1[i] = z[1][2]
y1[i] = z[1][3]
# Siguientes CI
z0 = z[1]
# plot results
plt.plot(t, u, 'g:', label='u(t)')
plt.plot(t, x2, 'b-', label='x(t)')
plt.plot(t, y2, 'r--', label='phi(t)')
plt.ylabel('Cilindro(x,phi)')
plt.xlabel('Tiempo(s)')
plt.legend(loc='best')
plt.show()
Then I`ve got the following error, telling me than too much accuracy is needed to solve my system:
lsoda-- at start of problem, too much accuracy
requested for precision of machine.. see tolsf (=r1)
in above message, r1 = NaN
lsoda-- repeated occurrences of illegal input
lsoda-- at start of problem, too much accuracy
requested for precision of machine.. see tolsf (=r1)
in above message, r1 = NaN
dy1dt = w2(zx1, zy1, zx2, zy2) - 1/(4*zx1**2*mc) * \
lsoda-- warning..internal t (=r1) and h (=r2) are
such that in the machine, t + h = t on the next step
(h = step size). solver will continue anyway
in above, r1 = 0.3448275862069D+00 r2 = 0.1555030227910D-28
I am trying to develop an algorithm (use scipy.integrate.odeint()) that predicts the changing concentration of cells, substrate and product (i.e., π, π, π) over time until the system reaches steady- state (~100 or 200 hours). The initial concentration of cells in the bioreactor is 0.1 π/πΏ and there is no glucose or product in the reactor initially. I want to test the algorithm for a range of different flow rates, π, between 0.01 πΏ/β and 0.25 πΏ/β and analyze the impact of the flow rate on product production (i.e., π β
π in π/β). Eventually, I would like to generate a plot that shows product production rate (y-axis) versus flow rate, π, on the x-axis. My goal is to estimate the flow rate that results in the maximum (or critical) production rate. This is my code so far:
from scipy.integrate import odeint
import numpy as np
# Constants
u_max = 0.65
K_s = 0.14
K_1 = 0.48
V = 2
X_in = 0
S_in = 4
Y_s = 0.38
Y_p = 0.2
# Variables
# Q - Flow Rate (L/h), value between 0.01 and 0.25 that produces best Q * P
# X - Cell Concentration (g/L)
# S - The glucose concentration (g/L)
# P - Product Concentration (g/L)
# Equations
def func_dX_dt(X, t, S):
u = (u_max) / (1 + (K_s / S))
dX_dt = (((Q * S_in) - (Q * S)) / V) + (u * X)
return dX_dt
def func_dS_dt(S, t, X):
u = (u_max) / (1 + (K_s / S))
dS_dt = (((Q * S_in) - (Q * S)) / V) - (u * (X / Y_s))
return dS_dt
def func_dP_dt(P, t, X, S):
u = (u_max) / (1 + (K_s / S))
dP_dt = ((-Q * P) / V) - (u * (X / Y_p))
return dP_dt
t = np.linspace(0, 200, 200)
# Q placeholder
Q = 0.01
# Attempt to solve the Ordinary differential equations
sol_dX_dt = odeint(func_dX_dt, 0.1, t, args=(S,))
sol_dS_dt = odeint(func_dS_dt, 0.1, t, args=(X,))
sol_dP_dt = odeint(func_dP_dt, 0.1, t, args=(X,S))
In the programs current state there does not seem to be be a way to generate the steady state value for P. I attempted to make this modification to get the value of X.
sol_dX_dt = odeint(func_dX_dt, 0.1, t, args=(odeint(func_dS_dt, 0.1, t, args=(X,)),))
It produces the error:
NameError: name 'X' is not defined
At this point I am not sure how to move forward.
(Edit 1: Added Original Equations)
First Equation
Second Equation and Third Equation
You do not have to apply the functions to each part but return a tuple of the derivatives as I show below:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
Q = 0.01
V = 2
Ys = 0.38
Sin = 4
Yp = 0.2
Xin = 0
umax = 0.65
Ks = 0.14
K1 = 0.48
def mu(S, umax, Ks, K1):
return umax/((1+Ks/S)*(1+S/K1))
def dxdt(x, t, *args):
X, S, P = x
Q, V, Xin, Ys, Sin, Yp, umax, Ks, K1 = args
m = mu(S, umax, Ks, K1)
dXdt = (Q*Xin - Q*X)/V + m*X
dSdt = (Q*Sin - Q*S)/V - m*X/Ys
dPdt = -Q*P/V - m*X/Yp
return dXdt, dSdt, dPdt
t = np.linspace(0, 200, 200)
X0 = 0.1
S0 = 0.1
P0 = 0.1
x0 = X0, S0, P0
sol = odeint(dxdt, x0, t, args=(Q, V, Xin, Ys, Sin, Yp, umax, Ks, K1))
plt.plot(t, sol[:, 0], 'r', label='X(t)')
plt.plot(t, sol[:, 1], 'g', label='S(t)')
plt.plot(t, sol[:, 2], 'b', label='P(t)')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid()
plt.show()
Output:
Hi i'm trying to get a plot of the trajectory of a mass under projectile motion. One with a force acting on the horizontal axis and one without (basically 2 sets of x values plotted against a 1 set of y-values). Here's what i have so far.. I'm new to programming and i can't seem to figure out where this went wrong. Hope you guys can help me. Thank you!
import numpy as np
import matplotlib.pyplot as pl
def position(y0, v0, theta, g, t):
y= y0 + v0*np.sin(theta)*t + (g*t**2)/2
return y
def position2(x0, v0, theta, c, e, alpha, t):
x1 = x0 + v0*(np.cos(theta))*t + c*(t*(e-1)+(2-2*e)/alpha)
return x1
def position3(x0, v0, theta, t):
x2 = x0 + v0*(np.cos(theta))*t
return x2
t = np.linspace(0,10,1000)
#part1
m = 1
theta = 45
y0 = 2
x0 = 0
v0 = 3
k = 1
alpha = 0.5
g = -9.8
c = (-k/m)*(1/alpha**2)
e = -(np.e**(-alpha*t))
x1 = []
x2 = []
y = []
for a in t:
x1_data = position2(x0, v0, theta, c, e, alpha, t)
x1.append(x1_data)
x2_data = position3(x0, v0, theta, t)
x2.append(x2_data)
y_data = position(y0, v0, theta, g, t)
y.append(y_data)
print x1_data
print x2_data
print y_data
pl.title('Constant and Time-Dependent Forces')
pl.xlabel(b'x-position')
pl.ylabel(b'y-position')
x1label = 'projectile 1'
x2label = "'normal' projectile"
plot1 = pl.plot(x1_data, y, 'r')
plot2 = pl.plot(x2_data, y, 'b')
pl.legend()
pl.show()
I went through your code since i am new to matplotlib and wanted to play a bit with it. The only mistake i found is in the for loop where you do for a in t: but end up passing t to the functions instead of a.
import numpy as np
import matplotlib.pyplot as pl
sin = np.sin
cos = np.cos
pi = np.pi
def y_position(y0, v0, phi, g, t):
y_t = y0 + v0 * sin(phi) * t + (g * t**2) / 2
return y_t
def x_position_force(x0, v0, phi, k, m, alpha, t):
term1 = (-k / m) * (1 / alpha ** 2)
term2 = -np.e ** (-alpha * t)
x_t = x0 + v0 * cos(phi) * t + term1 * (t * (term2 - 1) + (2 - 2 * term2) / alpha)
return x_t
def x_position_no_force(x0, v0, phi, t):
x_t = x0 + v0 * cos(phi) * t
return x_t
time = np.linspace(0, 10, 100)
#------------- I N P U T -------------#
x_init = 0
y_init = 2
v_init = 3
theta = 45
gravity = -9.8
m = 1
k = 1
alpha = 0.5
#------------- I N P U T -------------#
x_with_force = []
x_with_no_force = []
y = []
for time_i in time:
x_with_force.append(x_position_force(x_init, v_init, theta, k, m, alpha, time_i))
x_with_no_force.append(x_position_no_force(x_init, v_init, theta, time_i))
y.append(y_position(y_init, v_init, theta, gravity, time_i))
# print(x1_data)
# print(x2_data)
# print(y_data)
pl.subplot(211)
pl.title('Constant and Time-Dependent Forces')
pl.xlabel('time')
plot1 = pl.plot(time, x_with_force, 'r', label='x_coord_dynamicF')
plot2 = pl.plot(time, x_with_no_force, 'g', label='x_coord_staticF')
plot3 = pl.plot(time, y, 'b', label='y_coord')
pl.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, ncol=2, mode="expand", borderaxespad=0.)
pl.subplot(212)
pl.title('Trajectory (x,y)')
pl.xlabel('X')
pl.ylabel('Y')
plot4 = pl.plot(x_with_force, y, 'r^')
plot5 = pl.plot(x_with_no_force, y, 'b*')
pl.show()
I changed a number of things though to make the code inline with PEP8. In my opinion it is the use of bad variable names that lead you to the mistake you did. So i would recommend taking the time to type those few extra characters that ultimately help you and the people reading your code.