Plotting a function with more than one variable in Matplotlib - python

import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
from ipywidgets.widgets import interact
sym.init_printing(use_latex="mathjax")
x, y, z, t = sym.symbols('x y z t')
We were given a function in class to write as code
\begin{equation}
p_w(z,t)=\frac{1}{\sqrt{\pi \left(1-\exp\left[-2 t\right]\right)}}
\exp\left[-\frac{\left(z-\exp\left[-t\right]\right)^{2}}{1-
\exp\left[-2t\right]}\right]
\end{equation}
which I have written as this
p_w = (1/(sym.sqrt((sym.pi)*(1-(sym.exp(-2*t))))))*(sym.exp((-(z-sym.exp(-t))**2)/(1-sym.exp(-2*t))))
Then find the partial differential equation
∂𝑡𝑝𝑤(𝑧,𝑡)=∂𝑧[𝑧𝑝𝑤(𝑧,𝑡)]+1/2 ∂2𝑧𝑝𝑤(𝑧,𝑡)
which I have written as this:
LHS=sym.diff(p_w,t,1)
#differentiate once with respect to t
RHS=sym.diff(z*p_w,z,1)+((1/2)*(sym.diff(p_w,z,2)))
#now differentiate with respect to z
Now we need to plot it and can only use matplotlib/numpy/sympy libraries.
Plot 𝑝𝑤(𝑧,𝑡) for the three values t=0.1,1,10 in a 𝑝𝑤(𝑧,𝑡) versus z diagram.
Here's what I've got so far:
t_points=[0.1,1,10]
#pw = sym.lambdify(t,p_w)
mytspace=np.linspace(0,10,200)
#myzspace=pw(mytspace)
plt.xlabel("t axis")
plt.ylabel("z axis")
plt.plot(t_array,np.zeros(3),'bs')
I haven't studied multivariable calculus before so I'm a bit lost!

Since one of your variables is given (you know t must be t=0.1, t=1 or t=10) your only variable for plotting is z. I know you are using sympy for the calculations, but for plotting maybe it's simpler to just return p_w as a numpy array. You can define a function to return p_w as so:
import numpy as np
import matplotlib.pyplot as plt
def p_w(z, t):
p_w = (1/(np.sqrt((np.pi)*(1-(np.exp(-2*t))))))*(np.exp((-(z-np.exp(-t))**2)/(1-np.exp(-2*t))))
return p_w
This will give you a numpy array with the results of p_w(z, t) where z is an array and t is just one number. Then you can just iterate over the values of t that you need:
t_points=[0.1, 1, 10]
z = np.linspace(0,10,200)
for t in t_points:
plt.plot(z, p_w(z, t), label='t = {0}'.format(t))
plt.legend()
plt.show()
Result:

Related

I am not able to display graph in matplotlib

I'm trying to print a logistic differential equation and I'm pretty sure the equation is written correctly but my graph doesn't display anything.
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
def eq(con,x):
return con*x*(1-x)
xList = np.linspace(0,4, num=1000)
con = 2.6
x= .4
for num in range(len(xList)-1):
plt.plot(xList[num], eq(con,x))
x=eq(con,x)
plt.xlabel('Time')
plt.ylabel('Population')
plt.title("Logistic Differential Equation")
plt.show()
You get nothing in your plot because you are plotting points.
In plt you need to have x array and y array (that have the same length) in order to make a plot.
If you want to do exactly what you are doing I suggest to do like this:
import matplotlyb.pyplot as plt # just plt is sufficent
import numpy as np
def eq(con,x):
return con*x*(1-x)
xList = np.linspace(0,4, num=1000)
con = 2.6
x= .4
y = np.zeros(len(xList)) # initialize an array with the same lenght as xList
for num in range(len(xList)-1):
y[num] = eq(con,x)
x=eq(con,x)
plt.figure() # A good habit is always to use figures in plt
plt.plot(xList, y) # 2 arrays of the same lenght
plt.xlabel('Time')
plt.ylabel('Population')
plt.title("Logistic Differential Equation")
plt.show() # now you should get somthing here
I hope that this helps you ^^

How do I use scipy and matplotlib to fit a reverse sigmoid function

I have some data points which I was successfully able to graph, but now I would like to fit a curve to the data. I looked into other stackoverflow answers and found a few questions, but I can't seem to implement them. I know the function is a reverse sigmoid.
I would like to use this hill equation: https://imgur.com/rYqEASm
So far I tried to use the curve_fit() function from the scipy package to find the parameters but my code always breaks.
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
x = np.array([1, 1.90, 7.70, 30.10, 120.40, 481.60, 1925.00, 7700.00])
y = np.array([4118.47, 4305.79, 4337.47, 4838.11, 2660.76, 1365.05, 79.21, -16.40])
def fit_hill(t,b,s,i,h):
return b + ((t-b)/(1 + (((x * s)/i)**-h)))
plt.plot(x,y, 'o')
plt.xscale('log')
plt.show()
params = curve_fit(fit_hill, x, y)
[t,b,s,i,h] = params[0]
fit_hill should have 6 parameters.
(see https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html)
fit_hill(x,t,b,s,i,h).
You should try to give an initial guess for parameters.
For example in your model, when x=0, the value is t. So you can set the value at x=0 as an estimate for t.
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
x = np.array([1, 1.90, 7.70, 30.10, 120.40, 481.60, 1925.00])
y = np.array([4118.47, 4305.79, 4337.47, 4838.11, 2660.76, 1365.05, 79.21])
def fit_hill(x,t,b,s,i,h):
return b + ((t-b)/(1 + (((x * s)/i)**-h)))
plt.plot(x,y, 'o')
popt,pcov = curve_fit(fit_hill, x, y,(4118,200,1,1900,-2))
plt.plot(x,fit_hill(x,*popt),'+')
plt.xscale('log')
plt.show()
Have you drawn your model to visualize if it is suitable for you data ?
s and i, used only in s/i could be replaced with one variable in your model.

Plotting a 3D quiver plot and ode

I am trying to do a 3D quiver plot and combining it with odeint to solve a linearized equation. Basically, I want something similar to this but in 3D. The particular issue I am having is that near the end of the code, when I am doing the ax.quiver() plot, I keep getting the error that "val must be a float or nonzero sequence of floats", and I am unsure how to resolve it.
from scipy.integrate import odeint
from numpy import *
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax =fig.add_subplot(1, 1, 1, projection='3d')
ax.set_xlabel('x')
ax.set_ylabel('u')
ax.set_zlabel('u1')
def testplot(X, t=0,c=0.2):
x = X[0]
u = X[1]
u1=X[2]
dxdt =x**2*(-1+x+u)*(1-x+(-1+c)*u**2)
du1dt =c**2*u*(2+x*(-4+2.25*x)+(-4 + 4*x)*u**2 + 2*u**4 + x**2*u*u1)
dudt=u1*dxdt
return [dxdt, dudt,du1dt]
X0 = [0.01,0.995,-0.01]#initial values
t = linspace(0, 50, 250)
c=[0.2,0.5,1,2]#changing parameter
for m in c:
sol = odeint(testplot,X0,t,mxstep=5000000,args=(m,))#solve ode
ax.plot(sol[:,0],sol[:,1],sol[:,2],lw=1.5,label=r'$c=%.1f$'%m)
x = linspace(-3,3,15)
y = linspace(-4,4,15)
z= linspace(-2,2,15)
x,y,z = meshgrid(x,y,z) #create grid
X,Y,Z = testplot([x,y,z])
M = sqrt(X**2+Y**2+Z**2)#magnitude
M[M==0]=1.
X,Y,Z = X/M, Y/M, Z/M
ax.quiver(x,y,z,X,Y,Z,M,cmap=plt.cm.jet)
ax.minorticks_on()
ax.legend(handletextpad=0,loc='upper left')
setp(ax.get_legend().get_texts(),fontsize=12)
fig.savefig("testplot.svg",bbox_inches="tight",\
pad_inches=.15)
Looks like you have an extra argument in ax.quiver(). From what I can tell, it looks like "M" is the extra argument. Taking that out, your quiver call looks like:
ax.quiver(x,y,z,X,Y,Z,cmap=plt.cm.jet)
The resulting image looks like:

Algorithm equalivence from Matlab to Python

I've plotted a 3-d mesh in Matlab by below little m-file:
[x,n] = meshgrid(0:0.1:20, 1:1:100);
mu = 0;
sigma = sqrt(2)./n;
f = normcdf(x,mu,sigma);
mesh(x,n,f);
I am going to acquire the same result by utilization of Python and its corresponding modules, by below code snippet:
import numpy as np
from scipy.integrate import quad
import matplotlib.pyplot as plt
sigma = 1
def integrand(x, n):
return (n/(2*sigma*np.sqrt(np.pi)))*np.exp(-(n**2*x**2)/(4*sigma**2))
tt = np.linspace(0, 20, 2000)
nn = np.linspace(1, 100, 100)
T = np.zeros([len(tt), len(nn)])
for i,t in enumerate(tt):
for j,n in enumerate(nn):
T[i, j], _ = quad(integrand, -np.inf, t, args=(n,))
x, y = np.mgrid[0:20:0.01, 1:101:1]
plt.pcolormesh(x, y, T)
plt.show()
But the output of the Python is is considerably different with the Matlab one, and as a matter of fact is unacceptable.
I am afraid of wrong utilization of the functions just like linespace, enumerate or mgrid...
Does somebody have any idea about?!...
PS. Unfortunately, I couldn't insert the output plots within this thread...!
Best
..............................
Edit: I changed the linespace and mgrid intervals and replaced plot_surface method... The output is 3d now with the suitable accuracy and smoothness...
From what I see the equivalent solution would be:
import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
x, n = np.mgrid[0:20:0.01, 1:100:1]
mu = 0
sigma = np.sqrt(2)/n
f = norm.cdf(x, mu, sigma)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(x, n, f, rstride=x.shape[0]//20, cstride=x.shape[1]//20, alpha=0.3)
plt.show()
Unfortunately 3D plotting with matplotlib is not as straight forward as with matlab.
Here is the plot from this code:
Your Matlab code generate 201 points through x:
[x,n] = meshgrid(0:0.1:20, 1:1:100);
While your Python code generate only 20 points:
tt = np.linspace(0, 19, 20)
Maybe it's causing accuracy problems?
Try this code:
tt = np.linspace(0, 20, 201)
The seminal points to resolve the problem was:
1- Necessity of the equivalence regarding the provided dimensions of the linespace and mgrid functions...
2- Utilization of a mesh with more density to make a bee line into a high degree of smoothness...
3- Application of a 3d plotter function, like plot_surf...
The current code is totally valid...

resampled time using scipy.signal.resample

I have a signal that is not sampled equidistant; for further processing it needs to be. I thought that scipy.signal.resample would do it, but I do not understand its behavior.
The signal is in y, corresponding time in x.
The resampled is expected in yy, with all corresponding time in xx. Does anyone know what I do wrong or how to achieve what I need?
This code does not work: xx is not time:
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
x = np.array([0,1,2,3,4,5,6,6.5,7,7.5,8,8.5,9])
y = np.cos(-x**2/4.0)
num=50
z=signal.resample(y, num, x, axis=0, window=None)
yy=z[0]
xx=z[1]
plt.plot(x,y)
plt.plot(xx,yy)
plt.show()
Even when you give the x coordinates (which corresponds to the t argument), resample assumes that the sampling is uniform.
Consider using one of the univariate interpolators in scipy.interpolate.
For example, this script:
import numpy as np
from scipy import interpolate
import matplotlib.pyplot as plt
x = np.array([0,1,2,3,4,5,6,6.5,7,7.5,8,8.5,9])
y = np.cos(-x**2/4.0)
f = interpolate.interp1d(x, y)
num = 50
xx = np.linspace(x[0], x[-1], num)
yy = f(xx)
plt.plot(x,y, 'bo-')
plt.plot(xx,yy, 'g.-')
plt.show()
generates this plot:
Check the docstring of interp1d for options to control the interpolation, and also check out the other interpolation classes.

Categories