I am simulating a set of ODEs in Python, but I am getting this error:
x = odeint(model,x0,t,args=(rim,))
File "C:\Python\anaconda3\lib\site-packages\scipy\integrate\odepack.py", line 244, in odeint
int(bool(tfirst)))
ValueError: setting an array element with a sequence.
Here is my code:
import sklearn
import pandas as pd
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
#from gekko import GEKKO
Kg=0.1
Kd=1.1
kg=0.05
kd=0.05
ka=0.0455
Kr=4.5
Kd=1
alpha=0.026
beta=0.00075
n=4
l=4
m0= 2.5
f0= 2.5
p0= 2.5
g0= 2.5
x0 = [m0,f0,p0,g0]
ds = pd.read_csv('dataset.csv')
ds.columns
rim = ds[1:]
def model(x,t,rim):
m,f,p,g = x
m = x[0]
f = x[1]
p = x[2]
g = x[3]
dmdt = ((kg*(f*g))/(Kg+f))-((m*p)/(1+m))+ rim
dfdt = -kg*(f*g)/(Kg+f)+(m*p)/(1+m)-(f*p)/(1+f)
dpdt = (alpha*(f**n)/(Kr**n+f**n)-ka*p**2)
dgdt = beta*(f**l)/(Kd**l+f**l)-kd*(g*p)/(Kd+g)
dxdt = [dmdt, dfdt, dpdt, dgdt]
return dxdt
t = np.linspace(0,90000000,20000000)
x = odeint(model,x0,t,args=(rim,))
m = x[:,0]
f = x[:,1]
p = x[:,2]
g = x[:,3]
plt.figure(figsize=(10,10))
plt.subplot(3,1,1)
plt.plot(t,f, color='blue', lw=3, label='M')
plt.plot(t,m, color='red', lw=3, label='F')
plt.xlabel('Time (s)')
plt.ylabel('F and M')
plt.legend()
plt.xlim(0, 1000)
plt.ylim(0, 20)
plt.subplot(3,1,2)
plt.plot(t,p, color='green', lw=3, label='P')
plt.plot(t,g, color='yellow', lw=3, label='G')
plt.xlabel('Time (s)')
plt.ylabel('P and G')
plt.legend()
plt.xlim(0, 1000)
plt.ylim(0, 2.5)
plt.subplot(3 ,1,3)
plt.plot(f,m, color='blue', lw=3, label='P')
plt.xlabel('F')
plt.ylabel('M')
plt.show()
Can you kindly please help me with solving this error? Thanks in advance!
Related
I have the following code that should draw a cycloid with animation and save it to a gif
but after running the program, a white square appears that covers everything, I can't find the reason cycloid_animation
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.animation import FuncAnimation, PillowWriter
plt.rcParams['animation.html'] = 'html5'
R = 1
def circle(a, b, r):
# (a,b): the center of the circle
# r: the radius of the circle
# T: The number of the segments
T = 100
x, y = [0]*T, [0]*T
for i,theta in enumerate(np.linspace(0,2*np.pi,T)):
x[i] = a + r*np.cos(theta)
y[i] = b + r*np.sin(theta)
return x, y
# Calculate the cycloid line
thetas = np.linspace(0,4*np.pi,100)
cycloid_x = R*(thetas-np.sin(thetas))
cycloid_y = R*(1-np.cos(thetas))
cycloid_c = R*thetas
fig = plt.figure()
lns = []
trans = plt.axes().transAxes
for i in range(len(thetas)):
x,y = circle(cycloid_c[i], R, R)
ln1, = plt.plot(x, y, 'g-', lw=2)
ln2, = plt.plot(cycloid_x[:i+1] ,cycloid_y[:i+1], 'r-', lw=2)
ln3, = plt.plot(cycloid_x[i], cycloid_y[i], 'bo', markersize=4)
ln4, = plt.plot([cycloid_c[i], cycloid_x[i]], [R,cycloid_y[i]], 'y-', lw=2)
tx1 = plt.text(0.05, 0.8, r'$\theta$ = %.2f $\pi$' % (thetas[i]/np.pi), transform=trans)
lns.append([ln1,ln2,ln3,ln4,tx1])
plt.xlim(0,15)
plt.ylim(0,3)
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.axes().set_aspect('equal')
ani = animation.ArtistAnimation(fig, lns, interval=50)
#ani.save('cycloid_ArtistAnimation.mp4',writer='ffmpeg')
ani.save('cycloid_ArtistAnimation.gif',writer='pillow')
ani
Each time you call plt.axis() you are creating a new axis on top of the figure. Since what you want is to get the current axis and then apply the transformations, after creating the figure you should call plt.gca() to get the current axis and use that instead.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.animation import FuncAnimation, PillowWriter
plt.rcParams['animation.html'] = 'html5'
R = 1
def circle(a, b, r):
# (a,b): the center of the circle
# r: the radius of the circle
# T: The number of the segments
T = 100
x, y = [0]*T, [0]*T
for i,theta in enumerate(np.linspace(0,2*np.pi,T)):
x[i] = a + r*np.cos(theta)
y[i] = b + r*np.sin(theta)
return x, y
# Calculate the cycloid line
thetas = np.linspace(0,4*np.pi,100)
cycloid_x = R*(thetas-np.sin(thetas))
cycloid_y = R*(1-np.cos(thetas))
cycloid_c = R*thetas
fig = plt.figure()
lns = []
trans = plt.gca().transAxes #<=== HERE
for i in range(len(thetas)):
x,y = circle(cycloid_c[i], R, R)
ln1, = plt.plot(x, y, 'g-', lw=2)
ln2, = plt.plot(cycloid_x[:i+1] ,cycloid_y[:i+1], 'r-', lw=2)
ln3, = plt.plot(cycloid_x[i], cycloid_y[i], 'bo', markersize=4)
ln4, = plt.plot([cycloid_c[i], cycloid_x[i]], [R,cycloid_y[i]], 'y-', lw=2)
tx1 = plt.text(0.05, 0.8, r'$\theta$ = %.2f $\pi$' % (thetas[i]/np.pi), transform=trans)
lns.append([ln1,ln2,ln3,ln4,tx1])
plt.xlim(0,15)
plt.ylim(0,3)
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.gca().set_aspect('equal') #<=== And HERE
ani = animation.ArtistAnimation(fig, lns, interval=50)
#ani.save('cycloid_ArtistAnimation.mp4',writer='ffmpeg')
ani.save('cycloid_ArtistAnimation.gif',writer='pillow')
I am trying to calculate one of the basic decay simulation and plot the results as animation. Without animation results fine but when i try to create animation both line appears fully developed at the first time step. The change over time is not as it should be. What am I doing wrong? I'm open to suggestions.
Original plot:
plot
Here the code:
# I135 Xe135 decay.
"""
EQUATIONS:
dIdt = (-Lambda_I * N_I)
dXedt = ((-Lambda_Xe * N_Xe) + (Lambda_I * N_I))
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from scipy.integrate import odeint
def model(z,t):
"""
INITIAL CONDITIONS:
I(0) = 1e8 atoms
Xe(0) = 0 atom
PARAMETERS:
Lambda_I
Lambda_Xe
"""
Lambda_I = (np.log(2) / 6.57)
Lambda_Xe = (np.log(2) / 9.2)
N_I = z[0]
N_Xe = z[1]
dIdt = (-Lambda_I * N_I)
dXedt = ((-Lambda_Xe * N_Xe) + (Lambda_I * N_I))
return [dIdt,dXedt]
z0 = [1e8, 0.0] # initial conditions for N_Xe and N_I
n = 10000
max_time = 100
t = np.linspace(0,max_time,n)
N_I = np.zeros(n)
N_Xe = np.zeros(n)
# Solution
for i in range(n):
z = odeint(model,z0,t)
z0 = z[1]
N_I[i] = z0[0]
N_Xe[i] = z0[1]
# Graph and animation
fig, ax = plt.subplots(figsize=(8,8))
ax.set_ylim(0, 1e8)
ax.set_xlim(0, max_time)
line1, = ax.plot(N_I, 'b-', linewidth=2)
line2, = ax.plot(N_Xe,'g-.', linewidth=2)
plt.rcParams['font.size'] = '14'
plt.minorticks_on()
plt.tick_params(axis="both", which="major", length=12, labelsize=12, width=1, color="black")
plt.tick_params(axis="both", which="minor", length=6, labelsize=10, width=0.8, color="black")
plt.title('I-135 Xe-135 Decay Sim.', fontsize=18)
plt.xlabel('Time (h)', fontsize=16)
plt.ylabel('N', fontsize=16)
plt.legend(['I-135','Xe-135'],prop={'size': 12})
plt.grid(color = 'black', linestyle = '--', linewidth = 0.6)
def animate(j):
line1.set_xdata(np.linspace(0,j,n))
line2.set_xdata(np.linspace(0,j,n))
return [line1,line2,]
ani = animation.FuncAnimation(fig, animate, frames=max_time, blit=True, interval=10, save_count=10)
plt.show()
f = r"C://Users/USER_NAME/Desktop/animation.gif"
writergif = animation.PillowWriter(fps=30)
ani.save(f, writer=writergif)
I was able to make a program that shows both a 3d graph of a 2 variable function then a vector field of the gradient of the function, but then I wanted to have it calculate the gradient itself, but I keep getting isinfinite errors from plt.quiver(). I feel like part of the reason is because I'm going back and forth from numpy and sympy notation for x and y, but i have no idea what to do in that case.
def z_func(x,y):
return (x**2+y**2)
def show_graph():
x,y = np.meshgrid(np.linspace(-15,15,20),np.linspace(-15,15,20))
z = z_func(x,y)
fig = plt.figure(2)
ax = fig.gca( projection='3d')
surf = ax.plot_surface(x,y,z,rstride=1,cstride=1)
ax.set_xlabel('X', fontweight = 'bold', fontsize = 14)
ax.set_ylabel('Y', fontweight = 'bold', fontsize = 14)
ax.set_zlabel('Z', fontweight = 'bold', fontsize = 14)
plt.title('Ahem', fontweight = 'bold', fontsize = 16)
def get_grad():
x = sy.Symbol('x')
y= sy.Symbol('y')
f = z_func(x,y)
gradi = sy.diff(f,x)
gradj = sy.diff(f,y)
show_vector(gradi,gradj)
def show_vector(gradi,gradj):
a = sy.Symbol('x')
b = sy.Symbol('y')
u = gradi
v = gradj
print('[{0},{1}]'.format(u,v))
a,b = np.meshgrid(np.linspace(-10,10,10),np.linspace(-10,10,10))
print('[{0},{1}]'.format(u,v))
figv = plt.figure(1)
plt.xlabel('X')
plt.ylabel('Y')
plt.quiver(a,b,u,v)
def lazy():
get_grad()
show_graph()
plt.show()
lazy()
When you want to use sympy expressions outside sympy, you need lambdify.
Is the following code doing what you expected?
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import sympy as sy
def z_func(x, y):
return (x ** 2 + y ** 2)
x = sy.Symbol('x')
y = sy.Symbol('y')
f = z_func(x, y)
gradi = sy.diff(f, x)
gradj = sy.diff(f, y)
np_gradi = sy.lambdify(x, gradi, 'numpy')
np_gradj = sy.lambdify(y, gradj, 'numpy')
a, b = np.meshgrid(np.linspace(-10, 10, 10), np.linspace(-10, 10, 10))
u = np_gradi(a)
v = np_gradj(b)
x, y = np.meshgrid(np.linspace(-15, 15, 20), np.linspace(-15, 15, 20))
z = z_func(x, y)
fig = plt.figure(2)
ax = fig.gca(projection='3d')
surf = ax.plot_surface(x, y, z, rstride=1, cstride=1)
ax.set_xlabel('X', fontweight='bold', fontsize=14)
ax.set_ylabel('Y', fontweight='bold', fontsize=14)
ax.set_zlabel('Z', fontweight='bold', fontsize=14)
figv = plt.figure(1)
plt.xlabel('X')
plt.ylabel('Y')
plt.quiver(a, b, u, v)
plt.show()
I have certain function, for example sin(b*x), with sympy I get derivative and antiderivative expressions, but I need to plot these 3 functions in matplotlib. My problem is I can't convert correctly functions to numpy in order to plot in matplotlib. I have followed the documentation in sympy page with lambify function but it doesn't work. http://docs.sympy.org/latest/modules/utilities/lambdify.html
I have this code:
from sympy import Symbol, diff, integrate, sin, cos, Function
from sympy.utilities.lambdify import lambdify, implemented_function
from sympy.abc import x
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons
def signal(b,x):
return sin(b*x)
def derivative(b,x):
yprime = diff(signal(b,x), x)
return yprime
def antiderivative(b,x):
anti = integrate(signal(b,x), x)
return anti
b = 5
evalfunc = lambdify((b,x), signal(b,x), modules=['numpy'])
evalderiv = lambdify((b,x), derivative(b,x), modules=['numpy'])
evalantideriv = lambdify((b,x), antiderivative(b,x), modules=['numpy'])
axis_color = 'lightgoldenrodyellow'
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
fig.subplots_adjust(left=0.25, bottom=0.25)
t = np.arange(-10, 10, 0.001)
[line] = ax.plot(t, evalfunc(b,t), linewidth=2, color='red')
[line2] = ax.plot(t, evalderiv(b,t), linewidth=2, color='blue')
[line3] = ax.plot(t, evalantideriv(b,t), linewidth=2, color='blue')
ax.set_xlim([-10, 10])
ax.set_ylim([-5, 5])
ax.grid()
plt.show()
It fails in ax.plot ValueError: sequence too large; cannot be greater than 32
Your code is not quite a minimal working example, but it requires only minimal changes to work.
You need to declare your b as real symbol before the derivation.
You set it as b=5 before the numerical evaluation.
See:
from sympy import Symbol, diff, integrate, sin, cos, Function
from sympy.utilities.lambdify import lambdify, implemented_function
from sympy.abc import x
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons
def signal(b,x):
return sin(b*x)
def derivative(b,x):
yprime = diff(signal(b,x), x)
return yprime
def antiderivative(b,x):
anti = integrate(signal(b,x), x)
return anti
b = Symbol('b', real=True)
evalfunc = lambdify((b,x), signal(b,x), modules=['numpy'])
evalderiv = lambdify((b,x), derivative(b,x), modules=['numpy'])
evalantideriv = lambdify((b,x), antiderivative(b,x), modules=['numpy'])
axis_color = 'lightgoldenrodyellow'
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
fig.subplots_adjust(left=0.25, bottom=0.25)
t = np.arange(-10, 10, 0.001)
b = 5
[line] = ax.plot(t, evalfunc(b,t), linewidth=2, color='red')
[line2] = ax.plot(t, evalderiv(b,t), linewidth=2, color='blue')
[line3] = ax.plot(t, evalantideriv(b,t), linewidth=2, color='blue')
ax.set_xlim([-10, 10])
ax.set_ylim([-5, 5])
ax.grid()
plt.show()
I want to randomly generate n points on this plot.
I have used the .scatter method, but the points don't seem to be random. is there a way I could simply pass a number and it to generate that number of points?
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
def f(t):
s1 = np.cos(2*np.pi*t)
e1 = np.exp(-t)
return np.multiply(s1,e1)
t1 = np.arange(0.0, 5.0, 0.1)
t2 = np.arange(0.0, 5.0, 0.02)
t3 = np.arange(0.0, 2.0, 0.01)
fig = plt.figure(figsize=plt.figaspect(2.))
ax = fig.add_subplot(2, 1, 2, projection='3d')
X = np.arange(-20, 20, 0.25)
xlen = len(X)
Y = np.arange(-20, 20, 0.25)
ylen = len(Y)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color='yellow',
linewidth=0, antialiased=False)
scatteredpoints = ax.scatter(X[1::20, 1::20],Y[1::20, 1::20],Z[1::20, 1::20],linewidth=0, antialiased=False)
ax.set_zlim3d(-1, 1)
plt.show()
You need to feed random data to plt.scatter.
def scatterRandomPoints(n):
plt.scatter(*np.random.randint(100, size = (2, n)))