Draw a specific function in Python - python

I need to draw a graph in python using this function:
b²x²+a²z²+2dxz²+d²z²-a²b²=0
where b, a and d will be different each time.
The problem here for me is that I cannot separate X and Z. I've tried something like that.
import numpy as np
import matplotlib.pyplot as plt
z = -np.linspace(9,15,100)
x = np.linspace(-26,26,1000)
x,z = np.meshgrid(x,z)
a = 4
b = 2
d = 1
Z = a**2*z**2+2*d*z**2-a**2*b**2
X = b**2*x**2
plt.contour(x,z,(X+Z),[0])
plt.xlim([-1.5,1.5])
plt.ylim([-11.5,-8.5])

I don't know if matplotlib can create an implicit plot; a quick search of their documentation didn't turn up anything. But it appears you can use Sympy for that. From this SO question:
from sympy import var, Plot
var('x y')
Plot(x*y**3 - y*x**3)

Working code here:
from functools import partial
import numpy
import scipy.optimize
import matplotlib.pyplot as pp
a = 4
b = 3
d = 0.6
def z(x, y):
return b**2*x**2+a**2*y**2+2*d*x*y**2+d**2*y**2-a**2*b**2
x_window = 0, 5
y_window = 0, 5
xs = []
ys = []
for x in numpy.linspace(*x_window, num=200):
try:
# A more efficient technique would use the last-found-y-value as a
# starting point
y = scipy.optimize.brentq(partial(z, x), *y_window)
except ValueError:
# Should we not be able to find a solution in this window.
pass
else:
xs.append(x)
ys.append(y)
pp.plot(xs, ys)
pp.xlim(*x_window)
pp.ylim(*y_window)
pp.show()

Related

Second order coupled ODE using ODEINT

I am new to solving coupled ODEs with python, I am wondering if my approach is correct, currently this code outputs a graph that looks nothing like the expected output. These are the equations I am trying to solve:
And here is the code I am using (for the functions f_gr, f_sc_phi and f_gTheta you can just put any constant value)
import Radial as rd
import ScatteringAzimuthal as sa
import PolarComponent as pc
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
#gamma for now set to 1
g_mm = 1
def f(u,t):
#y1 = thetadot :: y2 = phidot :: y3 = cdot
rho, theta, y1, phi, y2, c, y3 = u
p = [y1, (pc.f_gTheta(theta,524.1+rho)/(c*np.cos(phi))-(g_mm*y1)+(2*y1*y2*np.tan(phi))-(2*y3*y1/c)),
y2, ((sa.f_sc_phi(theta,524.1+rho/c))-(g_mm*y2)-(2*y3*y2/c)-(np.sin(phi)*np.cos(phi)*y2**2)),
y3, (rd.f_gr(theta,524.1+rho)-(g_mm*y3)+(c*y2**2)+(c*(y1**2)*(np.cos(phi)**2))), phi]
return p
time = np.linspace(0,10,100)
z2 = odeint(f,[0.1,np.pi/2,0.1,np.pi/2,0.1,0.1,0.1], time)
rhoPl = z2[:,0]
thetaPl = z2[:,1]
phiPl = z2[:,3]
'''
plt.plot(rhoPl,time)
plt.plot(thetaPl,time)
plt.plot(phiPl,time)
plt.show()
'''
x = rhoPl*np.sin(thetaPl)*np.cos(phiPl)
y = rhoPl*np.sin(thetaPl)*np.sin(phiPl)
z = rhoPl*np.cos(thetaPl)
plt.plot(x,time)
plt.plot(y,time)
plt.plot(z,time)
plt.show()
when I change the time from 0.1 to 5 I get an error:
ODEintWarning: Excess work done on this call (perhaps wrong Dfun type). Run with full_output = 1 to get quantitative information.
Any ideas on how to improve this code or if my approach is completely incorrect?
Code for Radial.py
import numpy as np
from scipy.special import spherical_jn
from scipy.special import spherical_yn
import sympy as sp
import matplotlib.pyplot as plt
R_r = 5.6*10**(-5)
l = 720
n_w = 1.326
#k = 524.5/R_r
X_r = 524.5
# R is constant r is changing
def f_gr(theta,x):
f = ((sp.sin(theta))**(2*l-2))*(1+(sp.cos(theta))**2)
b = (spherical_jn(l,n_w*x)*spherical_jn(l,n_w*x,True))+(spherical_yn(l,n_w*x)*spherical_yn(l,n_w*x,True))
c = (spherical_jn(l,n_w*X_r)*spherical_jn(l,n_w*X_r,True))+(spherical_yn(l,n_w*X_r)*spherical_yn(l,n_w*X_r,True))
n = b/c
f = f*n
return f
Code for ScatteringAzimuthal.py
from scipy.special import spherical_jn, spherical_yn
import numpy as np
import matplotlib.pyplot as plt
l = 720
n_w = 1.326
n_p = 1.572
X_r = 524.5
R_r = 5.6*10**(-5)
R_p = 7.5*10**(-7)
k = X_r/R_r
def f_sc_phi(theta,x):
f = (2/3)*(n_w**2)*((X_r**3)/x)*((R_p**3)/(R_r**3))*(((n_p**2)-(n_w**2))/((n_p**2)+(2*(n_w**2))))
g = np.sin(theta)**(2*l-3)
numerator = (l*(1+np.sin(theta))- np.cos(2*theta))\
*((spherical_jn(l,n_w*x)*spherical_jn(l,n_w*x))+(spherical_yn(l,n_w*x)*spherical_yn(l,n_w*x)))
denominator = ((spherical_jn(l,n_w*X_r)*spherical_jn(l,n_w*X_r,True))\
+(spherical_yn(l,n_w*X_r)*spherical_yn(l,n_w*X_r,True)))
m = numerator/denominator
final = f*g*m
return final
And Code for PolarComponent.py
import numpy as np
from scipy.special import spherical_yn, spherical_jn
import matplotlib.pyplot as plt
l = 720
n_w = 1.326
X_r = 524.5 #this value is implemented in the ode file
#define dimensionless polar component
#X_r is radius, x is variable
def f_gTheta(theta,x):
bessel1 = (spherical_jn(l,n_w*x)*spherical_jn(l,n_w*x)) + \
(spherical_yn(l,n_w*x)*spherical_yn(l,n_w*x))
bessel2 = ((spherical_yn(l,n_w*X_r)*spherical_yn(l,n_w*X_r,True)) + \
(spherical_yn(l,n_w*X_r)*spherical_yn(l,n_w*X_r,True)))*n_w*x
bessels = bessel1/bessel2
rest = (np.sin(theta)**(2*l-3))*((l-1)*(1+(np.cos(theta)**2)) \
-((np.sin(theta)**2)*np.cos(theta)))
final = rest*bessels
return final
Here is a link that I really like for simulating second order odes. It has an optamization twist on it because it is fitting the model to match a simulation. It has a couple of examples for odeint and also gekko.

Python3 [Jupyter] code is not showing data on graph [duplicate]

This question already has an answer here:
try plotting an iteration but plt.plot is empty
(1 answer)
Closed 4 years ago.
I'm sure this question has been asked numerous times before but alas I cannot find the correct answer. I'm trying to plot really simple code however when it executes the final result is just an empty graph. Code below:
import math
import matplotlib.pyplot as mpl
import numpy as np
Q = 13.6
m_e = 9.11e-31
k = 8.6e-5
c = 3e8
eta = 4e-10
for T in np.arange(3000,4500):
S = 3.84*eta*((k*T)/(m_e*c**2))**(3/2)*(Q/(k*T))
X = (-1 + np.sqrt(1+(4*S)))/(2*S)
%matplotlib inline
mpl.plot(S, T)
mpl.show()
I realise that is the way with code it's probably a very trivial answer but I can't find the problem. Thanks in advance for any help!
You are not doing anything with the values you create in the for loop. Therefore, when you come to plot, you just have 1 value of S and X and T, therefore, your graph will be empty.
One way to fix this would be to append the values into a list which you can then pass to a call to plot:
Q = 13.6
m_e = 9.11e-31
k = 8.6e-5
c = 3e8
eta = 4e-10
S_list = []
X_list = []
for T in np.arange(3000,4500):
S = 3.84*eta*((k*T)/(m_e*c**2))**(3/2)*(Q/(k*T))
X = (-1 + np.sqrt(1+(4*S)))/(2*S)
S_list.append(S)
X_list.append(X)
I'm not sure if you actually want to plot the values of S against T, but if you do, then you would do something like:
mpl.plot(S_list, np.arange(3000,4500))
mpl.show()
Which gives something like:
Edit:
You don't actually need to do any loops here, numpy can handle the complete calculation:
T = np.arange(3000,4500)
S = 3.84*eta*((k*T)/(m_e*c**2))**(3/2)*(Q/(k*T))
X = (-1 + np.sqrt(1+(4*S)))/(2*S)
mpl.plot(S, T)
mpl.show()
Would give you the same figure
S, X and T are all scalar. I am assuming you want to plot a vector against vector.
I think you are trying to do this:
import math
import matplotlib.pyplot as mpl
import numpy as np
Q = 13.6
m_e = 9.11e-31
k = 8.6e-5
c = 3e8
eta = 4e-10
S=[]
X=[]
for T in np.arange(3000,4500):
tmp=3.84*eta*((k*T)/(m_e*c**2))**(3/2)*(Q/(k*T))
S.append(tmp)
X.append((-1 + np.sqrt(1+(4*tmp)))/(2*tmp))
%matplotlib inline
mpl.plot(S, X)
mpl.show()
import math
import matplotlib.pyplot as mpl
import numpy as np
Q = 13.6
m_e = 9.11e-31
k = 8.6e-5
c = 3e8
eta = 4e-10
x=[]
t=[]
for T in np.arange(3000,4500):
S = 3.84*eta*((k*T)/(m_e*c**2))**(3/2)*(Q/(k*T))
X = (-1 + np.sqrt(1+(4*S)))/(2*S)
x.append(X)
t.append(T)
mpl.plot(x,t)
mpl.show()

I am getting two plots for one data set in python

I am working through example 8.1 titled Euler's Method from Mark Newman's book Computational Physics. I rewrote the example as a method with Numpy arrays but when I plot it I get two plots on the same figure not sure how to correct it. Also is there better way to convert my 2 1D arrays into 1 2D array to use for plotting in Matplotlib, thanks.
Newman's example :
from math import sin
from numpy import arange
from pylab import plot,xlabel,ylabel,show
def f(x,t):
return -x**3 + sin(t)
a = 0.0 # Start of the interval
b = 10.0 # End of the interval
N = 1000 # Number of steps
h = (b-a)/N # Size of a single step
x = 0.0 # Initial condition
tpoints = arange(a,b,h)
xpoints = []
for t in tpoints:
xpoints.append(x)
x += h*f(x,t)
plot(tpoints,xpoints)
xlabel("t")
ylabel("x(t)")
show()
My modifications:
from pylab import plot,show,xlabel,ylabel
from numpy import linspace,exp,sin,zeros,vstack,column_stack
def f(x,t):
return (-x**(3) + sin(t))
def Euler(f,x0,a,b):
N=1000
h = (b-a)/N
t = linspace(a,b,N)
x = zeros(N,float)
y = x0
for i in range(N):
x[i] = y
y += h*f(x[i],t[i])
return column_stack((t,x)) #vstack((t,x)).T
plot(Euler(f,0.0,0.0,10.0))
xlabel("t")
ylabel("x(t)")
show()
The reason you get two lines is that t as well as x are plotted against their index, instead of x plotted against t
I don't see why you'd want to stack the two arrays. Just keep then separate, which will also solve the problem of the two plots.
The following works fine.
import numpy as np
import matplotlib.pyplot as plt
f = lambda x,t: -x**3 + np.sin(t)
def Euler(f,x0,a,b):
N=1000
h = (b-a)/N
t = np.linspace(a,b,N)
x = np.zeros(N,float)
y = x0
for i in range(N):
x[i] = y
y += h*f(x[i],t[i])
return t,x
t,x = Euler(f,0.0,0.0,10.0)
plt.plot(t,x)
plt.xlabel("t")
plt.ylabel("x(t)")
plt.show()

I don't understand what is wrong with my code - Pyplot gives me errors

import random
import matplotlib.pyplot as plt
from math import log, e, ceil, floor,sqrt,pi,exp
import numpy as np
from numpy import arange,array, empty
import pdb
from random import randint
import copy
from operator import add
import scipy
from scipy.optimize import curve_fit
import numpy as np
import matplotlib.pyplot as plt
import math
import scipy
def walk(n):
time = 0
i = 0
while i < n:
if i == 0:
r = random.random()
t = -log(1-r,e)
time = time+t
i=i+1
elif i !=0 and i!=n-1 :
r_2 = random.random()
t_2 = -log(1-r_2,e)
time = time+t_2
R = random.random()
if 0 <= R < 0.5:
i = i -1
elif 0.5 <= R <=1:
i=i+1
else:
i = n
return time
def many_walks(n,m):
v_t = []
for i in range(m):
w = walk(n)
v_t.append(w)
return v_t
n = 20
m = 2000
bins = [10*i for i in range(200)]
numpy_hist = plt.figure()
plt.hist(many_walks(n,m), bins)
def func(x,s):
x = np.array(x)
return (4/(x*np.sqrt(np.pi*n*s)))*np.exp(-(np.log(x)**2)/(2*n*s))
xx = np.linspace(0.1,2000,10000)
popt, pcov = curve_fit(func, bins, many_walks(n,m))
Without you reading too much, basically the function "many_walks(n,m)" gives me a vector containing m numbers. I've used matplotlib to plot a histogram and it works.
Now I want to consider the function which I defined as func(x,s). Notice it also has a parameter, which is n (yes, the same n of walks and many_walks). I would like to fit this function to my histogram, so I tried similar to here but it doesn't work. I mean I'm very suck I don't understand what I am doing wrong, seems I'm doing the same as in the question posted. My aim is to be able to find the coefficient s such that the function is fitted on the histogram and plot it on the same plot.
here's the error that it is giving me
return (4/(x*np.sqrt(np.pi*n*s)))*np.exp(-(np.log(x,e)**2)/(2*n*s))
TypeError: return arrays must be of ArrayType

Find an Inverse for the Exponential Integral function

I have a program where I have to find x.
But I have to use the special function Ei - the exponential integral, and x is inside the argument of Ei.
So Python isn't recognizing it.
ei(mx) = te^r + ei(c)
Here the RHS is a constant alongwith m.
I want to find the value of x, and then append it to a list. But Python isn't able to do this.
from scipy import special
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
Y = []
X = np.arange(0,10,.1)
for i in X:
y = scipy.special.expi(i)
Y.append(y)
N_0 = 2
t_f = 100
r = 2
K = 100
N_t = [N_0,]
t = np.arange(0,100,1)
for i in t:
l = i*e**r + scipy.special.expi(r*N_t[i]/K)
N_t.append(l)
plt.plot(X,Y)
plt.plot(t,N_t)
plt.show
I've corrected some mistakes in your code to give the following. You should compare this with your code line by line.
from scipy.special import expi
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
Y = []
X = np.arange(0,10,.1)
for i in X:
y = expi(i)
Y.append(y)
N_0 = 2
t_f = 100
r = 2
K = 100
N_t = [N_0,]
t = np.arange(0,100,1)
for i in t:
l = i*np.exp(r) + expi(r*N_t[i]/K)
N_t.append(l)
plt.plot(X,Y)
plt.plot(t,N_t)
plt.show()
However, there is still one possible flaw that I notice and can't resolve. You plot X and t together in the same graph at the end yet X ranges over 0 to 10 and t ranges over 0 to 100. Is this what you intended?
Also matplotlib complains that the lengths of the vectors supplied to it in the second call to plot are not the same.

Categories

Resources