Python - Find all intersection points of 2 graphs - python

I'm trying to find all the intersection points of two graphs and display them on the final plot. I've looked around and tried multiple things, but I haven't been able to obtain what l'm looking for.
Currently, I attempting to generate a list wherein the intersection points would be listed, though I keep getting the following error:
The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all().
import numpy as np
from scipy.optimize import fsolve
import matplotlib.pyplot as plt
x = np.arange(-7.0, 7.0, 0.05)
def y(x):
return np.sin(x)*(0.003*x**4 - 0.1*x**3 + x**2 + 4*x + 3)
def g(x):
return -10 * np.arctan(x)
def intersection(x):
if (y(x) - g(x)) == 0:
print y.all(x)
plt.plot(x, y(x), '-')
plt.plot(x, g(x), '-')
plt.show()

It's similar to:
Intersection of two graphs in Python, find the x value:
import numpy as np
from scipy.optimize import fsolve
import matplotlib.pyplot as plt
x = np.arange(-7.0, 7.0, 0.05)
y = np.sin(x)*(0.003*x**4 - 0.1*x**3 + x**2 + 4*x + 3)
g = -10 * np.arctan(x)
def intersection():
idx = np.argwhere(np.isclose(y, g, atol=10)).reshape(-1)
print idx
plt.plot(x, y, '-')
plt.plot(x, g, '-')
plt.show()
intersection()
edit: you don't use a function, but a list of values

For single solutions, this is answered in http://glowingpython.blogspot.de/2011/05/hot-to-find-intersection-of-two.html:
from scipy.optimize import fsolve
def findIntersection(fun1,fun2,x0):
return fsolve(lambda x : fun1(x) - fun2(x),x0)
result = findIntersection(y,g,0.0)
Now, you just need to iterate through your range to get all the roots. This gives some duplicates, which you might be able to remove by using mpmath, setting the precision low enough, and using a set.
from scipy.optimize import fsolve
import numpy as np
rng = np.arange(-7.0, 7.0, 0.05)
def y(x):
return np.sin(x)*(0.003*x**4 - 0.1*x**3 + x**2 + 4*x + 3)
def g(x):
return -10 * np.arctan(x)
def findIntersection(fun1,fun2,x0):
return fsolve(lambda x : fun1(x) - fun2(x),x0)
result = []
for x in rng:
result.append(float(findIntersection(y,g,x)))

Related

Is there a more elegant way to apply complicated functions to meshgrid?

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?

how to plot isocline or nullcline of a second order ODE

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.

Not able to plot a function

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()

How to Insert an Array of Values to a Symbolic Function in Python

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

Numerical ODE solving in Python

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?

Categories

Resources