Plotting defined function - python

I've defined a function which I would now like to plot:
import numpy as np
from math import pi, sqrt
import matplotlib.pyplot as plt
def f(x: float) -> float:
return pi * x * sqrt(x**2 + 400) + pi * x**2 - 1200
plt.plot(f(x))
plt.show()
When running this code, I get "NameError: name 'x' is not defined".

It is often usefull to use numpy in conjunction with matplotlib. When you then define a function, you may write it such that it takes single floats as well as numpy arrays as input.
import numpy as np
import matplotlib.pyplot as plt
def f(x):
return np.pi * x * np.sqrt(x**2 + 400) + np.pi * x**2 - 1200
x = np.array([1,2,3,4])
plt.plot(x, f(x))
plt.show()
Of course you could now also evaluate the function for a single float
print( f(9.2) )
or use it for each element of a list or array
y = [f(i) for i in x]
plt.plot(x,y)
But once you know about the fact that mathematical operations can be applied to numpy arrays easily, you probably don't want to opt for the latter anymore.

Related

Creating a plot of a SymPy expression with a a equation with multiple variables [duplicate]

This question already has answers here:
Using Sympy Equations for Plotting
(2 answers)
Closed 4 months ago.
I have figured out how to make a equation with SymPy, however, I am not sure how to plot the relationship between two values. I keep getting an TypeError: Cannot convert expression to float whenever I write plt.plot(Rho , T). I have a code like this so far:
import matplotlib as plt
from sympy import init_session
init_session()
rho, X, Y, Z, T_9, T, T_8, m, n, Gamma = symbols('rho X Y Z T_9 T T_8 m n Gamma')
q_pp = (2.4 * 10**(4) * rho * X**2 / T_9**(2/3)) * exp((-3.380/T_9**(1/3)))
q_CNO = (4.4 * 10**(25) * rho * X* Z/ T_9**(2/3)) * exp((-15.228/T_9**(1/3)))
q_min = q_pp + q_CNO
simplify(q_min)
T_9 = T / (10**9)
Rho = (10**3)*(T_9**(1/3) / (24000 * X * exp(15.228/T_9**(1/3)) + (4.4*10**25) * Z * exp(3.38/T_9**(1/3)))) * exp(-18.608/ T_9**(1/3))
simplify(Rho)
plot_implicit(T, Rho)
Updated: I used SymPy plot to get new error, I updated the code to reflect what I currently have, TypeError: object of type 'Mul' has no len()
You need to provide values for the independent variable(s). For example, to plot an expression like y = x**2 - 1, I would do this:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 20) # Provide the range of the independent variable.
y = x**2 - 1 # Compute the dependent variable.
plt.plot(x, y)
In your case, you'll need to provide values for T I suppose, and it looks like there are several other unknowns too. Take a look at this question, answers to which show a SymPy plotting example.

How can I numerically (and efficiently) integrate and plot my function?

I want to do a plot of this equation below:
Problem 1: You see... since my function is a function of ν I have to calculate my integral to each ν in my domain. My question is: what is the best way to do that?
I thought about using scipy to do the integral and a for loop to calculate it several times to each ν, but it seems a very inelegant way to solve my problem. Does someone know a better alternative? Does someone have a different idea?
Problem 2: When I write my code I get some errors, mainly because I think that the exponential has a very small expoent. Do you have any ideas of how should I change it so I can do this plot using Python?
Oh, if you try with a different method, it is supposed to look like this
Here is the code I was working on. I'm coming back to Python now, so maybe there is some errors. The plot I'm getting is very different from the one that this is supposed to look.
from scipy.integrate import quad
from scipy.constants import c, Planck, k, pi
import numpy as np
import matplotlib.pyplot as plt
def luminosity_integral(r, x):
T_est = 4000
R_est = 2.5 * (696.34*1e6)
Temp = ((2/(3*pi))**(1/4)) * T_est * ((R_est/r)**(3/4))
termo1 = ((4 * (pi**2) * Planck * (x**4) ) / (c**2))
termo2 = ((Planck * x) / (k*Temp))
return ((termo1 * r ) / (np.exp(termo2) - 1))
freqs = np.linspace(1e10, 1e16)
y = np.array([])
for i in freqs:
I = quad(luminosity_integral, (6 * 2.5 * (696.34*1e6)), (7e4 * 2.5 * (696.34*1e6)), args = (i))
temp = np.array([I[0]])
y = np.concatenate((y, temp))
plt.loglog(freqs, y)
plt.show()
Reuse the term R_est instead instead of writing its expression 3 times (better if you want to change that parameter).
you used a pi**2 in the constant multiplying the integral (don't affect the shape)
The shape resembles what you put as reference, but not in the suggested range.
You are using the value of T as T_*, are you sure about that?
Try this version of the code
from scipy.integrate import quad
from scipy.constants import c, Planck, k, pi
import numpy as np
import matplotlib.pyplot as plt
R_est = 2.5 * (696.34e6)
def luminosity_integral(r, x):
T_est = 4000
termo1 = ((4 * pi * Planck * (x**4) ) / (c**2))
termo2 = ((Planck * x) / (k*T_est)) * (3*pi/2 * (r/R_est)**3)**0.25
termo3 = np.exp(-termo2)
return ((termo1 * r ) * termo3 / (1 - termo3))
freqs = np.logspace(6, 16)
y = np.zeros_like(freqs)
for i, nu in enumerate(freqs):
y[i] = quad(luminosity_integral, (6* R_est), (7e4 * R_est), args = (nu))[0]
plt.loglog(freqs, y)
plt.ylim([1e6, 1e25])
plt.show()

How to do a (trapeze) integration in Python with x^2?

My task is to do first an integration and second a trapezoid integration with Python of f(x)=x^2
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-10,10)
y = x**2
l=plt.plot(x,y)
plt.show(l)
Now I want to integrate this function to get this: F(x)=(1/3)x^3 with the picture:
This should be the output in the end:
Could someone explain me how to get the antiderivative F(x) of f(x)=x^2 with python?
I want to do this with a normal integration and a trapeze integration. For trapezoidal integration from (-10 to 10) and a step size of 0.01 (width of the trapezoids). In the end I want to get the function F(x)=(1/3)x^3 in both cases. How can I reach this?
Thanks for helping me.
There are two key observations:
the trapezoidal rule refers to numeric integration, whose output is not an integral function but a number
integration is up to an arbitrary constant which is not included in your definition of F(x)
With this in mind, you can use scipy.integrate.trapz() to define an integral function:
import numpy as np
from scipy.integrate import trapz
def numeric_integral(x, f, c=0):
return np.array([sp.integrate.trapz(f(x[:i]), x[:i]) for i in range(len(x))]) + c
or, more efficiently, using scipy.integrate.cumtrapz() (which does the computation from above):
import numpy as np
from scipy.integrate import cumtrapz
def numeric_integral(x, f, c=0):
return cumtrapz(f(x), x, initial=c)
This plots as below:
import matplotlib.pyplot as plt
def func(x):
return x ** 2
x = np.arange(-10, 10, 0.01)
y = func(x)
Y = numeric_integral(x, func)
plt.plot(x, y, label='f(x) = x²')
plt.plot(x, Y, label='F(x) = x³/3 + c')
plt.plot(x, x ** 3 / 3, label='F(x) = x³/3')
plt.legend()
which provides you the desidered result except for the arbitrary constant, which you should specify yourself.
For good measure, while not relevant in this case, note that np.arange() does not provide stable results if used with a fractional step. Typically, one would use np.linspace() instead.
The cumtrapz function from scipy will provide an antiderivative using trapezoid integration:
from scipy.integrate import cumtrapz
yy = cumtrapz(y, x, initial=0)
# make yy==0 around x==0 (optional)
i_x0 = np.where(x >= 0)[0][0]
yy -= yy[i_x0]
Trapezoid integration
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-10, 10, 0.1)
f = x**2
F = [-333.35]
for i in range(1, len(x) - 1):
F.append((f[i] + f[i - 1])*(x[i] - x[i - 1])/2 + F[i - 1])
F = np.array(F)
fig, ax = plt.subplots()
ax.plot(x, f)
ax.plot(x[1:], F)
plt.show()
Here I have applied the theoretical formula (f[i] + f[i - 1])*(x[i] - x[i - 1])/2 + F[i - 1], while the integration is done in the block:
F = [-333.35]
for i in range(1, len(x) - 1):
F.append((f[i] + f[i - 1])*(x[i] - x[i - 1])/2 + F[i - 1])
F = np.array(F)
Note that, in order to plot x and F, they must have the same number of element; so I ignore the first element of x, so they both have 199 element. This is a result of the trapezoid method: if you integrate an array f of n elements, you obtain an array F of n-1 elements. Moreover, I set the initial value of F to -333.35 at x = -10, this is the arbitrary constant from the integration process, I decided that value in order to pass the function near the origin.
Analytical integration
import sympy as sy
import numpy as np
import matplotlib.pyplot as plt
x = sy.symbols('x')
f = x**2
F = sy.integrate(f, x)
xv = np.arange(-10, 10, 0.1)
fv = sy.lambdify(x, f)(xv)
Fv = sy.lambdify(x, F)(xv)
fig, ax = plt.subplots()
ax.plot(xv, fv)
ax.plot(xv, Fv)
plt.show()
Here I use the symbolic math through sympy module. The integration is done in the block:
F = sy.integrate(f, x)
Note that, in this case, F and x have already the same number of elements. Moreover, the code is simpler.

How do I convert the x and y values in polar form from these coupled ODEs to to cartesian form and graph them?

I have written this code to model the motion of a spring pendulum
import numpy as np
from scipy.integrate import odeint
from numpy import sin, cos, pi, array
import matplotlib.pyplot as plt
def deriv(z, t):
x, y, dxdt, dydt = z
dx2dt2=(0.415+x)*(dydt)**2-50/1.006*x+9.81*cos(y)
dy2dt2=(-9.81*1.006*sin(y)-2*(dxdt)*(dydt))/(0.415+x)
return np.array([x,y, dx2dt2, dy2dt2])
init = array([0,pi/18,0,0])
time = np.linspace(0.0,10.0,1000)
sol = odeint(deriv,init,time)
def plot(h,t):
n,u,x,y=h
n=(0.4+x)*sin(y)
u=(0.4+x)*cos(y)
return np.array([n,u,x,y])
init2 = array([0.069459271,0.393923101,0,pi/18])
time2 = np.linspace(0.0,10.0,1000)
sol2 = odeint(plot,init2,time2)
plt.xlabel("x")
plt.ylabel("y")
plt.plot(sol2[:,0], sol2[:, 1], label = 'hi')
plt.legend()
plt.show()
where x and y are two variables, and I'm trying to convert x and y to the polar coordinates n (x-axis) and u (y-axis) and then graph n and u on a graph where n is on the x-axis and u is on the y-axis. However, when I graph the code above it gives me:
Instead, I should be getting an image somewhat similar to this:
The first part of the code - from "def deriv(z,t): to sol:odeint(deriv..." is where the values of x and y are generated, and using that I can then turn them into rectangular coordinates and graph them. How do I change my code to do this? I'm new to Python, so I might not understand some of the terminology. Thank you!
The first solution should give you the expected result, but there is a mistake in the implementation of the ode.
The function you pass to odeint should return an array containing the solutions of a 1st-order differential equations system.
In your case what you are solving is
While instead you should be solving
In order to do so change your code to this
import numpy as np
from scipy.integrate import odeint
from numpy import sin, cos, pi, array
import matplotlib.pyplot as plt
def deriv(z, t):
x, y, dxdt, dydt = z
dx2dt2 = (0.415 + x) * (dydt)**2 - 50 / 1.006 * x + 9.81 * cos(y)
dy2dt2 = (-9.81 * 1.006 * sin(y) - 2 * (dxdt) * (dydt)) / (0.415 + x)
return np.array([dxdt, dydt, dx2dt2, dy2dt2])
init = array([0, pi / 18, 0, 0])
time = np.linspace(0.0, 10.0, 1000)
sol = odeint(deriv, init, time)
plt.plot(sol[:, 0], sol[:, 1], label='hi')
plt.show()
The second part of the code looks like you are trying to do a change of coordinate.
I'm not sure why you try to solve the ode again instead of just doing this.
x = sol[:,0]
y = sol[:,1]
def plot(h):
x, y = h
n = (0.4 + x) * sin(y)
u = (0.4 + x) * cos(y)
return np.array([n, u])
n,u = plot( (x,y))
As of now, what you are doing there is solving this system:
Which leads to x=e^t and y=e^t and n' = (0.4 + e^t) * sin(e^t) u' = (0.4 + e^t) * cos(e^t).
Without going too much into the details, with some intuition you could see that this will lead to an attractor as the derivative of n and u will start to switch sign faster and with greater magnitude at an exponential rate, leading to n and u collapsing onto an attractor as shown by your plot.
If you are actually trying to solve another differential equation I would need to see it in order to help you further
This is what happen if you do the transformation and set the time to 1000:

Evaluate 1/tanh(x) - 1/x for very small x

I need to compute the quantity
1/tanh(x) - 1/x
for x > 0, where x can be both very small and very large.
Asymptotically for small x, we have
1/tanh(x) - 1/x -> x / 3
and for large x
1/tanh(x) - 1/x -> 1
Anyhow, when computing the expression, already from 10^-7 and smaller round-off errors lead to the expression being evaluated as exactly 0:
import numpy
import matplotlib.pyplot as plt
x = numpy.array([2**k for k in range(-30, 30)])
y = 1.0 / numpy.tanh(x) - 1.0 / x
plt.loglog(x, y)
plt.show()
For very small x, one could use the Taylor expansion of 1/tanh(x) - 1/x around 0,
y = x/3.0 - x**3 / 45.0 + 2.0/945.0 * x**5
The error is of the order O(x**7), so if 10^-5 is chosen as the breaking point, relative and absolute error will be well below machine precision.
import numpy
import matplotlib.pyplot as plt
x = numpy.array([2**k for k in range(-50, 30)])
y0 = 1.0 / numpy.tanh(x) - 1.0 / x
y1 = x/3.0 - x**3 / 45.0 + 2.0/945.0 * x**5
y = numpy.where(x > 1.0e-5, y0, y1)
plt.loglog(x, y)
plt.show()
Use the python package mpmath for arbitrary decimal precision. For example:
import mpmath
from mpmath import mpf
mpmath.mp.dps = 100 # set decimal precision
x = mpf('1e-20')
print (mpf('1') / mpmath.tanh(x)) - (mpf('1') / x)
>>> 0.000000000000000000003333333333333333333333333333333333333333311111111111111111111946629156220629025294373160489201095913
It gets extremely precise.
Look into mpmath plotting. mpmath plays well with matplotlib, which you are using, so this should solve your problem.
Here is an example of how to integrate mpmath into the code you wrote above:
import numpy
import matplotlib.pyplot as plt
import mpmath
from mpmath import mpf
mpmath.mp.dps = 100 # set decimal precision
x = numpy.array([mpf('2')**k for k in range(-30, 30)])
y = mpf('1.0') / numpy.array([mpmath.tanh(e) for e in x]) - mpf('1.0') / x
plt.loglog(x, y)
plt.show()
A probably simpler solution to overcome this is changing the data type under which numpy is operating:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-30, 30, dtype=np.longdouble)
x = 2**x
y = 1.0 / np.tanh(x) - 1.0 / x
plt.loglog(x, y)
plt.show()
Using longdouble as data type does give the proper solution without rounding errors.
I did sightly modify your example, in your case the only thing you need to modify is:
x = numpy.array([2**k for k in range(-30, 30)])
to:
x = numpy.array([2**k for k in range(-30, 30)], dtype=numpy.longdouble)

Categories