My goal is to plot the function $f(x,y) = 3^{\min\{x,2\}}t_0 y$
where $t_0$
is the smallest solution of $2t^x-3t-1=0$ (it's just a MWE; I didn't check the existence of the root(s). )
I did it. But in somehow an ugly way.
My approach is to apply the function element-wise. Here is my code:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fsolve
def equ(t,*data): # 2t^x - 3t -1
x = data
return 2*(t ** x) - 3*t - 1
def t0(t): # call fslove to solve the equation
return fsolve(equ, 1.5, args=(t))[0] # 1.5 is randomly choosed
xx = np.linspace(1,3,50) # range of x
yy = np.linspace(1,3,50) # range of y
ff = [] # the value of f at each (x, y)
# compute the value of f element-wise
for x in xx:
for y in yy:
f = (3 ** np.minimum(x, 2)) * t0(x) * y
ff.append(f)
fv = np.split(np.array(ff), np.size(xx)) # split ff to make it conform with meshgrid
xv, yv = np.meshgrid(xx, yy)
plt.pcolormesh(xv, yv, fv)
plt.colorbar()
plt.show()
But I think the elegancy of numpy is to avoid writing loops manually and to manipulate lists as a whole. So, is there a more elegant way to do that?
I have some code designed to plot an isocline or nullcline of a 2nd order ODE but I keep getting an ValueError: math domain error. I will provide the code that I have a picture of what it is supposed to look like. the 2nd order ODE is split into 2 different first order ODE's dx/dt = f(x,y) = 3x - y^2 and dy/dt = g(x,y) = sin(y) - x. this code is designed for any 2nd order ODE but im using the equations in our notes so I make sure that it works before I use it on any other one.
the code is in python 3.8.
Code:
import matplotlib.pyplot as plt
import math
def f(x,y):
return 3*x-y*y
def g(x,y):
return math.sin(y) - x
x = []
y = []
def IsoNull(x0, y0, dt, time):
x.append(x0)
y.append(y0)
for i in range(time):
x.append(x[i] + (f(x[i],y[i])) * dt)
y.append(y[i] + (g(x[i],y[i])) * dt)
return x, y
IsoNull(0.5, 1, 0.01, 1000)
plt.plot(x, 'r-', label='x')
plt.plot(y, 'b-', label='y')
plt.xlabel("time")
plt.legend(loc='best')
the error occurs for line 6 of the code "return sin(y) - x
Trying to obtain a plot like this using the above code.
So I am having a problem plotting an if statement function. Could someone tell me where i am going wrong? The code follows:
import numpy as np
import matplotlib.pyplot as plt
#x-axis
x_1 = np.arange(-20,20,0.001)
#defining the function
def h(x):
"""
input: x \in R
oupit: h(x) defined above in R.
"""
if x == 0:
return 1
else:
return np.sin(x)/x
def g(x):
"""
input: x \in R
oupit: g(x) defined above in R.
"""
return np.cos(x)
#drawing the function
plt.plot(x_1,h(x_1),label = r"$\frac{\sin(x)}{x}$",color="red")
plt.legend()
plt.plot(x_1,g(x_1),label = r"$\cos(x)$",color="blue")
plt.legend()
plt.grid(linestyle="dotted")
plt.ylabel("$f(x)$")
#plt.savefig('img231.pdf')
plt.show()
The main problem is probably in the line with plt.plot(x_1,h(x_1)). Any answers are appreciated:)~ Thanks, Y
To write an if-test in numpy, you need np.where: np.where(x == 0, 1, np.sin(x)/x).
This still will write a warning for division by zero, which can be suppressed using with np.errstate(divide='ignore').
Also note that np.arange(-20, 20, 0.001) generates 40000 values, which is quite high compared to the number of pixels on a screen (an even compared to the dots on a printer). Using np.linspace() you have easier control over the number of points used. Using too many points can unnecessarily slow down calculations and plotting.
Calling plt.legend() twice can be a bit confusing. The second call will remove the first legend.
import numpy as np
import matplotlib.pyplot as plt
x_1 = np.linspace(-20, 20, 1000)
def h(x):
with np.errstate(divide='ignore'):
return np.where(x == 0, 1, np.sin(x) / x)
def g(x):
return np.cos(x)
plt.plot(x_1, h(x_1), label=r"$\frac{\sin(x)}{x}$", color="crimson")
plt.plot(x_1, g(x_1), label=r"$\cos(x)$", color="cornflowerblue")
plt.grid(linestyle="dotted")
plt.ylabel("$f(x)$")
plt.legend()
plt.show()
I want to study symbolic functions in python. I want to create y(x) = x^2 + 2x + 3 and plot it in the range [1, 255]. I want to use the subs() function to calculate the values by using the for loop. However, when I run that I get this error:
IndexError('list index out of range')
Can you help me please?
import numpy as np
import matplotlib.pyplot as plot
from sympy import *
a = [1,2,3]
x = Symbol('x')
fx = a[0]*x**2 + a[1]*x + a[2]
t = list(range(1,256))
y = np.zeros(256)
for i in t:
y[i] = fx.subs({x:t[i]})
plot.plot(t,y)
plot.show()
Just replace with the following lines:
y = np.zeros(len(t))
for i in range(len(t)):
y[i] = fx.subs({x:t[i]})
The problem was that the length of t was only 255 but the len of y was 256 in your code because you define y = np.zeros(256), hence the Index Error because there is no t[256]. I am using y = np.zeros(len(t)) because you have as many y points as t (or x) points. By the way, you are most likely to get an error in your plot command the way it is right now because you have called import matplotlib.pyplot as plot. I would simply call it plt instead of plot
Output
How do I numerically solve an ODE in Python?
Consider
\ddot{u}(\phi) = -u + \sqrt{u}
with the following conditions
u(0) = 1.49907
and
\dot{u}(0) = 0
with the constraint
0 <= \phi <= 7\pi.
Then finally, I want to produce a parametric plot where the x and y coordinates are generated as a function of u.
The problem is, I need to run odeint twice since this is a second order differential equation.
I tried having it run again after the first time but it comes back with a Jacobian error. There must be a way to run it twice all at once.
Here is the error:
odepack.error: The function and its Jacobian must be callable functions
which the code below generates. The line in question is the sol = odeint.
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from numpy import linspace
def f(u, t):
return -u + np.sqrt(u)
times = linspace(0.0001, 7 * np.pi, 1000)
y0 = 1.49907
yprime0 = 0
yvals = odeint(f, yprime0, times)
sol = odeint(yvals, y0, times)
x = 1 / sol * np.cos(times)
y = 1 / sol * np.sin(times)
plot(x,y)
plt.show()
Edit
I am trying to construct the plot on page 9
Classical Mechanics Taylor
Here is the plot with Mathematica
In[27]:= sol =
NDSolve[{y''[t] == -y[t] + Sqrt[y[t]], y[0] == 1/.66707928,
y'[0] == 0}, y, {t, 0, 10*\[Pi]}];
In[28]:= ysol = y[t] /. sol[[1]];
In[30]:= ParametricPlot[{1/ysol*Cos[t], 1/ysol*Sin[t]}, {t, 0,
7 \[Pi]}, PlotRange -> {{-2, 2}, {-2.5, 2.5}}]
import scipy.integrate as integrate
import matplotlib.pyplot as plt
import numpy as np
pi = np.pi
sqrt = np.sqrt
cos = np.cos
sin = np.sin
def deriv_z(z, phi):
u, udot = z
return [udot, -u + sqrt(u)]
phi = np.linspace(0, 7.0*pi, 2000)
zinit = [1.49907, 0]
z = integrate.odeint(deriv_z, zinit, phi)
u, udot = z.T
# plt.plot(phi, u)
fig, ax = plt.subplots()
ax.plot(1/u*cos(phi), 1/u*sin(phi))
ax.set_aspect('equal')
plt.grid(True)
plt.show()
The code from your other question is really close to what you want. Two changes are needed:
You were solving a different ODE (because you changed two signs inside function deriv)
The y component of your desired plot comes from the solution values, not from the values of the first derivative of the solution, so you need to replace u[:,0] (function values) for u[:, 1] (derivatives).
This is the end result:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
def deriv(u, t):
return np.array([u[1], -u[0] + np.sqrt(u[0])])
time = np.arange(0.01, 7 * np.pi, 0.0001)
uinit = np.array([1.49907, 0])
u = odeint(deriv, uinit, time)
x = 1 / u[:, 0] * np.cos(time)
y = 1 / u[:, 0] * np.sin(time)
plt.plot(x, y)
plt.show()
However, I suggest that you use the code from unutbu's answer because it's self documenting (u, udot = z) and uses np.linspace instead of np.arange. Then, run this to get your desired figure:
x = 1 / u * np.cos(phi)
y = 1 / u * np.sin(phi)
plt.plot(x, y)
plt.show()
You can use scipy.integrate.ode. To solve dy/dt = f(t,y), with initial condition y(t0)=y0, at time=t1 with 4th order Runge-Kutta you could do something like this:
from scipy.integrate import ode
solver = ode(f).set_integrator('dopri5')
solver.set_initial_value(y0, t0)
dt = 0.1
while t < t1:
y = solver.integrate(t+dt)
t += dt
Edit: You have to get your derivative to first order to use numerical integration. This you can achieve by setting e.g. z1=u and z2=du/dt, after which you have dz1/dt = z2 and dz2/dt = d^2u/dt^2. Substitute these into your original equation, and simply iterate over the vector dZ/dt, which is first order.
Edit 2: Here's an example code for the whole thing:
import numpy as np
import matplotlib.pyplot as plt
from numpy import sqrt, pi, sin, cos
from scipy.integrate import ode
# use z = [z1, z2] = [u, u']
# and then f = z' = [u', u''] = [z2, -z1+sqrt(z1)]
def f(phi, z):
return [z[1], -z[0]+sqrt(z[0])]
# initialize the 4th order Runge-Kutta solver
solver = ode(f).set_integrator('dopri5')
# initial value
z0 = [1.49907, 0.]
solver.set_initial_value(z0)
values = 1000
phi = np.linspace(0.0001, 7.*pi, values)
u = np.zeros(values)
for ii in range(values):
u[ii] = solver.integrate(phi[ii])[0] #z[0]=u
x = 1. / u * cos(phi)
y = 1. / u * sin(phi)
plt.figure()
plt.plot(x,y)
plt.grid()
plt.show()
scipy.integrate() does ODE integration. Is that what you are looking for?