Plot a Function with Variable Theta in Python - python

I'm new to Python, and especially new to plotting graphs using matplotlib. I'm working on an assignment where we have to plot spirographs on a cartesian coordinate system with equations for x and y:
x = (R + r) * math.cos(theta) - d * math.cos((R+r)*theta/r)
y = (R + r) * math.sin(theta) - d * math.sin((R+r)*theta/r)
where we are given the values of R, r, and d.
This produces an error because the variable theta isn't defined. I've seen ways of defining theta using numPy, but we aren't allowed to use that particular library for this assignment. What would be the best way of plotting the spirographs for 0 < theta < 2pi?
Thanks in advance!

If you cannot use numpy, you cannot use matplotlib; because numpy is a dependency of matplotlib. So I'd suggest to solve your problem in the following way:
Prepend a sentence to your solution saying "Because numpy is a dependency of matplotlib, it's technically impossible to solve this task without using numpy. Since I do not want this restriction to prevent me from solving the task, I simply assume that I can use numpy here."
Then go on with the canonical solution,
import matplotlib.pyplot as plt
import numpy as np
theta = np.linspace(0,2*np.pi,301)
R = 8
r = 1
d = 3
x = (R + r) * np.cos(theta) - d * np.cos((R+r)*theta/r)
y = (R + r) * np.sin(theta) - d * np.sin((R+r)*theta/r)
plt.plot(x,y)
plt.axis("equal")
plt.show()

If you can't use numpy, you can do it with functions and loops :
import math
import matplotlib.pyplot as plt
def X(theta,R,r,d) :
return (R + r) * math.cos(theta) - d * math.cos((R+r)*theta/r)
def Y(theta,R,r,d) :
return (R + r) * math.sin(theta) - d * math.sin((R+r)*theta/r)
nbSamples=100
theta=[]
for i in range (nbSamples) :
theta.append(i/(nbSamples-1)*2*math.pi)
x=[]
y=[]
R=8
r=1
d=3
for th in theta:
x.append(X(th,R,r,d))
y.append(Y(th,R,r,d))
plt.plot(x,y)
plt.axis("equal")
plt.show()

Related

PyCharm Matplotlib plot parametric equation with range

I want to plot a graph in PyCharm, using Matplotlib and a parametric equation. In this equation x and y are defined by some constant variables (a, b & c) and another variable (θ) which is in a range between 0 - 10. Python doesn't seem to handle the range because it's not a string.
This is an example code with an example equation:
import math
import matplotlib.pyplot as plt
a = 2
b = 3
c = 4
θ = range(0, 10)
x = (a + b * c) / θ
y = ((a / b) + c) * θ
plt.plot(x, y)
plt.show()
I would like to have something like this (2d) and eventually 3d:
I have tried to use the for loop and updating the graph, but that resulted in a very slow PyCharm and the graph to shut down.
Does any of you know how to do this?
Found the answer:
import math
import matplotlib.pyplot as plt
a = 2
b = 3
c = 4
θ = np.linspace(0, 10) #this sets an array between 0 and 10
x = (a + b * c) / θ
y = ((a / b) + c) * θ
plt.plot(x, y)
plt.show()
For the rest as an advice: np.linspace doesn't work with math.fabs, math.cos, math.pow. You have to use np.abs, np.cos or np.power instead ;)

Python: how to integrate functions with two unknown parameters numerically

Now I have two functions respectively are
rho(u) = np.exp( (-2.0 / 0.2) * (u**0.2-1.0) )
psi( w(x-u) ) = (1/(4.0 * math.sqrt(np.pi))) * np.exp(- ((w * (x-u))**2) / 4.0) * (2.0 - (w * (x-u))**2)
And then I want to integrate 'rho(u) * psi( w(x-u) )' with respect to 'u'. So that the integral result can be one function with respect to 'w' and 'x'.
Here's my Python code snippet as I try to solve this integral.
import numpy as np
import math
import matplotlib.pyplot as plt
from scipy import integrate
x = np.linspace(0,10,1000)
w = np.linspace(0,10,500)
u = np.linspace(0,10,1000)
rho = np.exp((-2.0/0.2)*(u**0.2-1.0))
value = np.zeros((500,1000),dtype="float32")
# Integrate the products of rho with
# (1/(4.0*math.sqrt(np.pi)))*np.exp(- ((w[i]*(x[j]-u))**2) / 4.0)*(2.0 - (w[i]*(x[j]-u))**2)
for i in range(len(w)):
for j in range(len(x)):
value[i,j] =value[i,j]+ integrate.simps(rho*(1/(4.0*math.sqrt(np.pi)))*np.exp(- ((w[i]*(x[j]-u))**2) / 4.0)*(2.0 - (w[i]*(x[j]-u))**2),u)
plt.imshow(value,origin='lower')
plt.colorbar()
As illustrated above, when I do the integration, I used nesting for loops. We all know that such a way is inefficient.
So I want to ask whether there are methods not using for loop.
Here is a possibility using scipy.integrate.quad_vec. It executes in 6 seconds on my machine, which I believe is acceptable. It is true, however, that I have used a step of 0.1 only for both x and w, but such a resolution seems to be a good compromise on a single core.
from functools import partial
import matplotlib.pyplot as plt
from numpy import empty, exp, linspace, pi, sqrt
from scipy.integrate import quad_vec
from time import perf_counter
def func(u, x):
rho = exp(-10 * (u ** 0.2 - 1))
var = w * (x - u)
psi = exp(-var ** 2 / 4) * (2 - var ** 2) / 4 / sqrt(pi)
return rho * psi
begin = perf_counter()
x = linspace(0, 10, 101)
w = linspace(0, 10, 101)
res = empty((x.size, w.size))
for i, xVal in enumerate(x):
res[i], err = quad_vec(partial(func, x=xVal), 0, 10)
print(f'{perf_counter() - begin} s')
plt.contourf(w, x, res)
plt.colorbar()
plt.xlabel('w')
plt.ylabel('x')
plt.show()
UPDATE
I had not realised, but one can also work with a multi-dimensional array in quad_vec. The updated approach below enables to increase the resolution by a factor of 2 for both x and w, and keep an execution time of around 7 seconds. Additionally, no more visible for loops.
import matplotlib.pyplot as plt
from numpy import exp, mgrid, pi, sqrt
from scipy.integrate import quad_vec
from time import perf_counter
def func(u):
rho = exp(-10 * (u ** 0.2 - 1))
var = w * (x - u)
psi = exp(-var ** 2 / 4) * (2 - var ** 2) / 4 / sqrt(pi)
return rho * psi
begin = perf_counter()
x, w = mgrid[0:10:201j, 0:10:201j]
res, err = quad_vec(func, 0, 10)
print(f'{perf_counter() - begin} s')
plt.contourf(w, x, res)
plt.colorbar()
plt.xlabel('w')
plt.ylabel('x')
plt.show()
Addressing the comment
Just add the following lines before plt.show() to have both axes scale logarithmically.
plt.gca().set_xlim(0.05, 10)
plt.gca().set_ylim(0.05, 10)
plt.gca().set_xscale('log')
plt.gca().set_yscale('log')

python quad: integrating over one variable while treating other variable as constant?

I am doing simple integration, only thing is that I want to keep 'n' as a variable. How can I do this while still integrating over t?
import numpy as np
import matplotlib as mpl
from matplotlib import pyplot as plt
import scipy.integrate as integrate
from scipy.integrate import quad
import math as m
y = lambda t: 3*t
T = 4 #period
n = 1
w = 2*np.pi*n/T
#for odd functions
def integrand(t):
#return y*(2/T)*np.sin(w*t)
return y(t)*np.sin(n*w*t)
Bn = (2/T)*quad(integrand,-T/2,T/2)[0]
print(Bn)
Using quad, you cannot. Perhaps you're looking for symbolic integration like you would do with pen and paper; sympy can help you here:
import sympy
x = sympy.Symbol("x")
t = sympy.Symbol("t")
T = sympy.Symbol("T")
n = sympy.Symbol("n", positive=True)
w = 2 * sympy.pi * n / T
y = 3 * t
out = 2 / T * sympy.integrate(y * sympy.sin(n * w * t), (t, -T/2, T/2))
print(out)
2*(-3*T**2*cos(pi*n**2)/(2*pi*n**2) + 3*T**2*sin(pi*n**2)/(2*pi**2*n**4))/T
If you want to evaluate the integral for many n, quadpy can help:
import numpy as np
from quadpy import quad
y = lambda t: 3 * t
T = 4
n = np.linspace(0.5, 4.5, 20)
w = 2 * np.pi * n / T
# for odd functions
def integrand(t):
return y(t) * np.sin(np.multiply.outer(n * w, t))
Bn = (2 / T) * quad(integrand, -T / 2, T / 2)[0]
print(Bn)
[ 2.95202424 4.88513496 4.77595051 1.32599514 -1.93954768 -0.23784853
1.11558278 -0.95397681 0.63709387 -0.4752673 0.45818227 -0.4740128
0.35943759 -0.01510463 -0.30348511 0.09861289 0.25428048 0.10030723
-0.06099483 -0.13128359]

sympy solve equation set: results in error: only zero-dimensional systems supported

i want to calculate the steady states of a set of differential equations, as you can see in the following code.
from sympy import *
from sympy import solve
from sympy import init_printing
init_printing()
X = Symbol("\X")
Y = Symbol("\Y")
Z = Symbol("\Z")
tau = Symbol(r"\tau")
Ryx = Symbol(r"\Ryx")
Rxy = Symbol(r"\Rxy")
Ry = Symbol(r"\Ry")
Rz = Symbol(r"\Rz")
Rzy = Symbol(r"\Rzy")
Rzz = Symbol(r"\Rzz")
Rxz = Symbol(r"\Rxz")
Ryz = Symbol(r"\Ryz")
#equation system
dX = X - X**2 - Ryx * Y * X
dY = Ry * ( Y - Y**2 + Rxy * X * Y + Rzy * Z * Y )
dZ = Rz * ( -Rzz * Z + Rxz * X * Z + Ryz * Y * Z )
equilibria = solve( (dX,dY,dZ),X,Y,Z )
If I copy my code in the sympy live shell the code works fine and gives me my set of solutions.
As I want to save my results in a latex file, I want to run this code on my system. Which is the following Ubuntu 12.04, python2.7.3, sympy 0.7.1.
Here my code results in the following error:
NotImplementedError: only zero-dimensional systems supported (finite number of solutions)
If I cancel out the last equation and the Z variable I get a set of solutions
equilibria = solve( (dX,dY),X,Y )
-> [(0, 0), (1, 0)]
In my opinion, the system needs to much computation time to solve the complete set.
Do you have any suggestions?
I found the module which might solve this problem
from sympy.solvers.solveset import nonlinsolve
But my version of sympy doesn't know this module.
Thank you in advance

Making random initial position by Python

I am now working to make rotational trajectories. In the beginning I need to define the initial position of an rotating object. How to make 1000 random initial position in three dimensions of this kind of object by Python or NumPy? I think a python function can solve the problem.
If I understand the question, you need to pick up point uniformly distributed on a sphere. See here for details.
import math
import numpy as np
cos_theta = 2.0 * np.random.random(100) - 1.0
phi = 2.0 * math.pi * np.random.random(100)
sin_theta = np.sqrt( (1.0 - cos_theta)*(1.0 + cos_theta) )
x = sin_theta * np.cos(phi)
y = sin_theta * np.sin(phi)
z = cos_theta
print(x, y, z)
print("---------------------")
print(np.square(x) + np.square(y) + np.square(z))

Categories