Matplotlib plotting with float values for x - python

I have tried to find the answer to this question, maybe its very easy and thats why i cant.
If I have made a Gaussian function and I want to plot it with Matplotlib.pyplot.plot, how can i do that with float values. I.e. values from -20<=x<=20 in increments of 0.1
import matplotlib.pyplot as plt
import math
from math import exp
import numpy
#Parameters for the Gaussian
A=1
c=10
t=0
a=1
x=[]
p=-20.
while p<=20:
x.append(p)
p+=0.1
def Gaussian(A,c,t,a,x):
return A*exp(-((c*t-x)^2 /(4*a*c^2)))
plt.plot(x,Gaussian(A,c,t,a,x))
plt.show()
The Error i get is:
Traceback (most recent call last):
File "C:--------/Gaussian Function.py", line 21, in <module>
plt.plot(x,Gaussian(A,c,t,a,x))
File "C:--------/Gaussian Function.py", line 19, in Gaussian
return A*exp(-((c*t-x)^2 /(4*a*c^2)))
TypeError: unsupported operand type(s) for -: 'int' and 'list'

The problem has nothing to do with matplotlib. You will get the same error if you just call Gaussian(A, c, t, a, x) without using matplotlib at all. Your function accepts an argument x that is a list, and then tries to do stuff like c*t-x. You can't subtract a list from a number. As the error message suggests, you should probably make x a numpy array, which will allow you to do these kinds of vectorized operations on it.

There are some mistakes in your code. The corrected one is below:
import matplotlib.pyplot as plt
import numpy as np
#Parameters for the Gaussian
A, c, t, a = 1, 10, 0, 1
x = np.arange(-20,20,0.1) #use this instead
def Gaussian(A,c,t,a,x):
return A*np.exp(-((c*t-x)**2/(4*a*c**2))) #power in Python is ** not ^
plt.plot(x,Gaussian(A,c,t,a,x))
plt.show()
and result is:

Related

How to create a Numpy array with integer values? (current version doesn't work with getpixel)

I'm using PIL to get the red values from every pixel of a picture. However, I need all the values to be in numpy arrays, because as far as I know, that is the only way to plot a 3D graph with a colourmap.
The problem is when I try to find the required red values using getpixel(), I get the following error:
Traceback (most recent call last):
File "C:\Users\Elitebook\Desktop\PIL\Smoke\get_data_smoke.py", line 14, in <module>
Z=im_rgb.getpixel((X,Y))[0]
File "C:\Users\Elitebook\AppData\Roaming\Python\Python37\site-packages\PIL\Image.py", line 1436, in getpixel
return self.im.getpixel(xy)
TypeError: an integer is required
So far, I have tried using x=x.astype(int) and dtype to get integer values, but none of them worked.
Here is my code:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
im=Image.open("smoke.jpg")
im_rgb=im.convert("RGB")
w,h=im.size
x=np.arange(1,w+1,1)
y=np.arange(1,h+1,1)
X,Y=np.meshgrid(x,y)
Z=im_rgb.getpixel((X,Y))[0]
fig=plt.figure()
ax=fig.add_subplot(projection='3d')
ax.plot(X,Y,Z)
plt.show()
If you want the image as a Numpy array, just use:
na = np.array(im_rgb)
By the way, the converse operation, turning a Numpy array back into a PIL Image is:
pilImage = Image.fromarray(na)
Your problem is that getpixel needs a sequence of integers. Your inputs X and Y were arrays. Therefore, you need some form of loop to extract the individual indexes:
x = np.arange(1,w+1,1)
y = np.arange(1,h+1,1)
X,Y = np.meshgrid(x,y)
Z = []
for i,j in zip(X,Y):
for ii, jj in zip(i,j):
Z.append(im_rgb.getpixel((int(ii),int(jj))))

TypeError: only size-1 arrays can be converted to Python scalars + Solution

According to Python Documentation a TypeError is defined as
Raised when an operation or function is applied to an object of inappropriate type. The associated value is a string giving details about the type mismatch.
exception TypeError
The reason I got this Error was because my code looked like this:
import math as m
import pylab as pyl
import numpy as np
#normal distribution function
def normal(x,mu,sigma):
P=(1/(m.sqrt(2*m.pi*sigma**2)))*(m.exp((-(x-mu)**2)/2*sigma**2))
return P
#solution
x = np.linspace(-5,5,1000)
P = normal(x,0,1)
#plotting the function
pyl.plot(x,P)
pyl.show()
P=(1/(m.sqrt(2***m**.pisigma2)))(**m.exp((-(x-mu)2)/2*sigma2))
Notice the m. - This is incorrect, because math. can only handle scalars. And the Error said that a TypeError had occurred.
np. (Numpy) can handle scalers as well as arrays and the problem is solved.
The right code looks like this:
import math as m
import pylab as pyl
import numpy as np
# normal distribution function
def normal(x,mu,sigma):
P = (1/(np.sqrt(2*np.pi*sigma**2))) * (np.exp((-(x-mu)**2)/2*sigma**2))
return P
# solution
x = np.linspace(-5,5,1000)
P = normal(x,0,1)
# plotting the function
pyl.plot(x,P)
pyl.show()
In the end we get a great normal distribution function that looks like this:
This Error occurred in Spyder IDE.

Using power results in ValueError: a <= 0

I have written the following code but it fails with a ValueError.
from numpy import *
from pylab import *
t = arange(-10, 10, 20/(1001-1))
x = 1./sqrt(2*pi)*exp(power(-(t*t), 2))
Specifically, the error message I'm receiving is:
ValueError: a <= 0
x = 1./sqrt(2*pi)*exp(power(-(t*t), 2))
File "mtrand.pyx", line 3214, in mtrand.RandomState.power (numpy\random\mtrand\mtrand.c:24592)
Traceback (most recent call last):
File "D:\WinPython-64bit-3.4.4.3Qt5\notebooks\untitled1.py", line 6, in <module>
Any idea what the issue might be here?
Both numpy and pylab define a function called power, but they are completely different. Because you imported pylab after numpy using import *, the pylab version is the one you end up with. What is pylab.power? From the docstring:
power(a, size=None)
Draws samples in [0, 1] from a power distribution with positive exponent a - 1.
The moral of the story: don't use import *. In this case, it is common to use import numpy as np:
import numpy as np
t = np.arange(-10, 10, 20/(1001-1))
x = 1./np.sqrt(2*np.pi)*np.exp(np.power(-(t*t), 2))
Further reading:
Why is "import *" bad?
Idioms and Anti-Idioms in Python (That's in the Python 2 documentation, but it also applies to Python 3.)

Function that computes rk method/no plotting

import math
import matplotlib
import numpy as np
from numpy import linspace
tmax=10.0
n=2000
G=4
D=-1
m=2
t=np.linspace (0,400,n+1)
phi=10
dphi=delta=phi_dot=np.linspace(0,400,n+1)
def f(delta_dot,t):
return ((G)*(D*delta+m))
def iterate (func,phi,delta,tmax,n):
dt=tmax/(n-1)
t=0.0
for i in range(n):
phi,delta = func (phi,delta,t,dt)
t += dt
return phi
def rk_iter(phi,delta,t,dt):
k1=f(t,phi)
k2=f(t+dt*0.5,phi+k1*0.5*dt)
k3=f(t+dt*0.5,phi*k2*0.5*dt)
k4=f(t*dt,phi*k3*dt)
delta +=dt*(k1+2*k2+2*k3+k4)/6
k1=k2=k3=k4=delta=phi_dot
phi += dt*(k1+2*k2+2*k3+k4)/6
return phi,delta
runge_kutta = lambda delta, phi,tmax,n:iterate(rk_iter,delta,phi,tmax,n)
def plot_result (delta,phi,tmax,n):
dt=tmax/(n-1)
error_rk=[]
r_rk=[]
t=0.0
phi=phi_rk=phi
delta=delta_rk=delta
for i in range(n):
phi_rk,delta_rk=rk_iter(phi_rk,delta_rk,t,dt=tmax/(n-1))
t+=dt
_plot("error.png","Error","time t", "error e",error_rk)
def _plot(title,xlabel,ylabel,rk):
import matplotlib.pyplot as plt
plt.title(title)
plt.ylabel(ylabel)
plt.xlabel(xlabel)
plt.plot(rk,"r--",label="Runge-Kutta")
plt.legend(loc=4)
plt.grid(True)
plt.plot(runge_kutta,t)
print "runge_kutta=", runge_kutta(phi,delta,tmax,n)
print "tmax=",t
I have no idea how to get the function plt.show() to work. What do I have to do to open a plot window?
You haven't defined f; instead, f is being imported from matplotlib by the statement from matplotlib import *:
In [10]: import matplotlib
In [11]: matplotlib.f
Out[11]: Forward: "a"
In [12]: matplotlib.f(1,1)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-12-5843007d7dbe> in <module>()
----> 1 matplotlib.f(1,1)
TypeError: __call__() takes at most 2 arguments (3 given)
You will save yourself many headaches like this in the future if you never use the * form of the import statement in your scripts. For example, instead of from math import *, use one of these two forms:
import math
# Now refer to math.sin, math.pi, etc.
or, explicilty import only the names that you will use:
from math import sin, pi
At no point do you call the plot_result procedure. And even if you called it, you do not fill the rk and error_rk lists. You could simply use the result from the runge_kutta call,...
As commented in the other, duplicate post, you define the system equation as f(y,t) but use it as f(t,y).
There is some confusion in the usage of delta, sometimes it is the integration variable, sometimes the rk4-step update.
In the rk4-step, there are some misplaced multiplications where there should be additions. And the line
k1=k2=k3=k4=delta=phi_dot
is complete nonsense and invalidates the previous computations and makes the rk4-update in the next step meaningless.
Remove the imports of math and linspace, neither is used in the code. Move the aliasing of plt to the top and merge it with the unnecessary import of matplotlib.

Error: [only length-1 arrays can be converted to Python scalars] when changing variable order

Dear Stackoverflow Community,
I am very new to Python and to programming in general, so please don't get mad when I don't get your answers and ask again.
I am trying to fit a curve to experimental data with scipy.optimization.curve_fit. This is my code:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as nm
from __future__ import division
import cantera as ct
from matplotlib.backends.backend_pdf import PdfPages
import math as ma
import scipy.optimize as so
R = 8.314
T = nm.array([700, 900, 1100, 1300, 1400, 1500, 1600, 1700])
k = nm.array([289, 25695, 763059, 6358040, 14623536, 30098925, 56605969, 98832907])
def func(A, E, T):
return A*ma.exp(-E/(R*T))
popt, pcov = so.curve_fit(func, T, k)
Now this code works for me, but if I change the function to:
def func(T, A, E)
and keep the rest I get:
TypeError: only length-1 arrays can be converted to Python scalars
Also I am not really convinced by the Parameter solution of the first one.
Can anyone tell me what happens when you change the variable order?
I got the same problem and found the cause and its solution:
The problem lies on the implementation of Scipy. After the optimal parameter has been found, Scipy calls your function with the input array xdata as first argument. That is, it calls func(xdata, *args), and the function complains with a type error because xdata is not an scalar. For example:
from math import erf
erf([1, 2]) # TypeError
erf(np.array([1, 2])) # TypeError
To avoid the error, you can add custom code for supporting arrays, or better, as suggested in the answer of Joris, use numpy functions because they have support for scalars and arrays.
If the math function is not in numpy , like erf or any custom function you coded, then I recommend you instead of doing from math import erf, to do as follows:
from math import erf as math_erf # only supports scalars
import numpy as np
erf = np.vectorize(math_erf) # adds array support
def fit_func(t,s):
return 0.5*(1.0-erf(t/(np.sqrt(2)*s)))
X = np.linspace(-5,5,1000)
Y = np.array([fit_func(x,1) for x in X])
curve_fit(fit_func, X, Y)
The curve_fit function from scipy does not handle very well embedded functions from the math module. When you change the exponential function to the numpy exponential function you don't get the error:
def func(A, E, T):
return A*np.exp(-E/(R*T))
I wonder whether you data shows an exponential decay of rate. The mathematical model may not be the most suitable one.
See the doc string of curve_fit
f : callable
The model function, f(x, ...). It must take the independent variable as the first argument and the parameters to fit as separate remaining arguments.
since your formula is essentially: k=A*ma.exp(-E/(R*T)), the right order of parameters in func should be (T, A, E) or (T, E, A).
Regarding the order of A and E, they don't really matter. If you flip them, the result will get flipped as well:
>>> def func(T, A, E):
return A*ma.exp(-E/(R*T))
>>> so.curve_fit(func, T, k)
(array([ 8.21449078e+00, -5.86499656e+04]), array([[ 6.07720215e+09, 4.31864058e+12],
[ 4.31864058e+12, 3.07102992e+15]]))
>>> def func(T, E, A):
return A*ma.exp(-E/(R*T))
>>> so.curve_fit(func, T, k)
(array([ -5.86499656e+04, 8.21449078e+00]), array([[ 3.07102992e+15, 4.31864058e+12],
[ 4.31864058e+12, 6.07720215e+09]]))
I didn't get your typeerror at all.

Categories