Using Sympy Equations for Plotting - python

What is the best way to create a Sympy equation, do something like take the derivative, and then plot the results of that equation?
I have my symbolic equation, but can't figure out how to make an array of values for plotting. Here's my code:
from sympy import symbols
import matplotlib.pyplot as mpl
t = symbols('t')
x = 0.05*t + 0.2/((t - 5)**2 + 2)
nums = []
for i in range(1000):
nums.append(t)
t += 0.02
plotted = [x for t in nums]
mpl.plot(plotted)
mpl.ylabel("Speed")
mpl.show()
In my case I just calculated the derivative of that equation, and now I want to plot the speed x, so this is fairly simplified.

You can use numpy.linspace() to create the values of the x axis (x_vals in the code below) and lambdify().
from sympy import symbols
from numpy import linspace
from sympy import lambdify
import matplotlib.pyplot as mpl
t = symbols('t')
x = 0.05*t + 0.2/((t - 5)**2 + 2)
lam_x = lambdify(t, x, modules=['numpy'])
x_vals = linspace(0, 10, 100)
y_vals = lam_x(x_vals)
mpl.plot(x_vals, y_vals)
mpl.ylabel("Speed")
mpl.show()
(improvements suggested by asmeurer and MaxNoe)
Alternatively, you can use sympy's plot():
from sympy import symbols
from sympy import plot
t = symbols('t')
x = 0.05*t + 0.2/((t - 5)**2 + 2)
plot(x, (t, 0, 10), ylabel='Speed')

Using SymPy
You can use directly the plotting functions of SymPy:
from sympy import symbols
from sympy.plotting import plot as symplot
t = symbols('t')
x = 0.05*t + 0.2/((t - 5)**2 + 2)
symplot(x)
Most of the time it uses matplotlib as a backend.

Related

Using Matplotlib to Plot Sympy Implicit Function

I have an implicit function, say x**2 - y = 0 (to simplify), of which I want to obtain a plot for a certain range of x values.
sympy.plot_implicit usually gives some spreading of the lines that I am not happy with.
I would like to have access to the plotted values, and so pyplot.plot is preferable to me. Usually I use the following piece of code to get my explicit Sympy functions plotted, but I am unsure how to use something similar for exp = sym.Eq(x**2 - y, 0). Does anyone have a solutions for this?
import sympy as sym
import numpy as np
from matplotlib import pyplot as plt
x, y = sym.symbols('x y', nonnegative=True)
exp = x**2
# Plot using a numpy-ready function
x_arr = np.linspace(-2, 2, 100)
exp_func = sym.lambdify(x, exp, 'numpy')
exp_arr = exp_func(x_arr)
plt.plot(x_arr, exp_arr)
PS: my real expression is b_sim (see below) and I want the plot for the equation b_sim = -1. With sym.plot_implicit(b_sim + 1, (n,0.225,1.5), (h, -1.1, 1.1)) one can see the lines spreading I dislike. Following Oscar Benjami's tips here, I attempted the following piece of code that is giving an error for roots.
from sympy import *
h, nu = symbols('h nu', nonnegative=True)
b_sim = 1.0*cos(pi*sqrt(1 - h)/(2*nu))*cos(pi*sqrt(h + 1)/(2*nu)) - 1.0*sin(pi*sqrt(1 - h)/(2*nu))*sin(pi*sqrt(h + 1)/(2*nu))/sqrt(1 - h**2)
eq = Eq(b_sim + 1, 0)
sols = roots(eq, h)
sym.plot(*sols, (nu, 0.225, 1.5), ylim=(-1.1, 1.1))
The line spread of plot_implicit is caused by the adaptive algorithm. If you set the option adaptive=False the plotting module would use a meshgrid approach. However, due to the implementation, the figure is likely not going to be good (too much "segmentation").
This is how you can do it with Numpy and Matplotlib:
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import numpy as np
expr = eq.rewrite(Add)
f = lambdify([nu, h], expr)
n = 2000j
nnu, hh = np.mgrid[0.225:1.5:n, -1.1:1.1:n]
res = f(nnu, hh)
plt.figure()
cmap = ListedColormap(["tab:blue", "tab:blue"])
plt.contour(nnu, hh, res, levels=[0], cmap=cmap)
plt.show()
To have access to the plotted values of a sympy function plot, in this case the coordinates of lines2d plot, is simple.
Here is the code that plots the function.
import matplotlib.pyplot as plt
from sympy import symbols
import numpy as np
import sympy
x, y = symbols('x y', nonnegative=True)
exp = x**2
# Plot using a numpy-ready function
x_arr = np.linspace(-2, 2, 10) #small number for demo
exp_func = sympy.lambdify(x, exp, 'numpy')
exp_arr = exp_func(x_arr)
plt.figure(figsize=(4, 3))
lines2d = plt.plot(x_arr, exp_arr)
In the code above, lines2d is a list of line2d objects. To get the coordinates from the 1st (only one in this case), do this:
xys = lines2d[0].get_xydata()
And you can use it to plot with this code:-
fig = plt.figure(figsize=(4, 3))
ax = fig.add_subplot()
ax.plot(xys[:,0], xys[:,1])

Equation with Matplotlib

How can i do this equation with library Matplotlib?
f(x) = exp(sqrt(x))/2 - sqrt(x**3)/5 + 2
import matplotlib as plt
import numpy as np
import math
fig, (ax1) = plt.subplots(nrows=2)
x = np.linspace(-3, 3, 100)
ax1.plot(x, 0.5.np.exp)
plt.show()
This represents your equation, but please double check it.
import math
e1 = lambda x: 0.5 * math.exp(-1 * math.sqrt(x)) - (0.2 * math.sqrt(x^3)) + 2
e1(1) # 1.901097008111102

Is there a way in which a polynomial equation can be graphed via input()?

I started learning Python a few months back (in 11th grade), and decided to test my knowledge by creating a miniature Graphing Calculator in Python. Using matplotlib.pyplot i was able to graph the sin(), cos(), and the tan(). Now, I wanted the user to enter a polynomial equation in terms of y, and then display the graph of the equation, but I am getting a Type Error.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-10, 10, 0.1)
y = input("Enter polynomial equation in terms of y\ny = ")
plt.plot(x, y)
plt.show()
Sympy, Python's symbolic math library, can be used to create a plot from a function inputted by the user:
import matplotlib.pyplot as plt
import sympy as sy
from sympy.abc import x
y = input("Enter equation in terms of x\ny = ")
sy.plot(sy.sympify(y), (x, -10, 10) )
plt.show()
When inputted "sin(x)/x":
a = input("x^2 coefficient: ")
b = input("x^1 coefficient: ")
c = input("x^0 coefficient: ")
y = (a * (x * x)) + (b * x) + c
plt.plot(x, y)
Input is not evaluated automatically. There are good reasons for that. If you want to evaluate input you need to explicitely do it with eval
y = eval(input(...))
Hence,
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-10, 10, 0.1)
y = eval(input("Enter polynomial equation in terms of y\ny = "))
plt.plot(x, y)
plt.show()

How do I create a 3D line plot in matplotlib from the data in arrays?

I have numerically solved the Lorenz equations using SciPy with the script:
# Lorenz Equations SciPy solver
import numpy as np
from scipy import integrate
from math import cos
from matplotlib import pyplot as plt
a, b = 0, 100
sigma, rho, beta = 10, 28, 8/3
N = 1000000
h = (b-a) / float(N)
def solvr(Y, t):
return [sigma*(Y[1]-Y[0]), Y[0]*(rho-Y[2])-Y[1], Y[0]*Y[1]-beta*Y[2]]
t = np.arange(a, b, h)
asol = integrate.odeint(solvr, [0, 1, 1], t)
x = asol[:,0]
y = asol[:,1]
z = asol[:,2]
Now what I would like to do is plot x, y and z (which are all Numpy ndarrays, if you are unsure) against each other in a 3D line (or wireframe) plot. I think this would have to be done using matplotlib, but I am not picky, so long as you give me a solution that will plot the data in 3D I do not care what modules I need to import.
Here is the Lorenz attractor both in 3D and animated. The script is in the following link (along with many goodies) in Jake VanderPlas' Pythonic Perambulations. You can learn a lot by going line-by-line through the script - it's an elegant use of matplotlib objects.
https://jakevdp.github.io/blog/2013/02/16/animating-the-lorentz-system-in-3d/
I added these two lines just before return in the animate function, and then used ImageJ to import the "image stack" and save the "animated GIF":
fname = "Astro_Jake_" + str(i+10000)[1:]
fig.savefig(fname)
Note: For OSX it seems to be necessary to set blit = False in animation.FuncAnimation.
Here is a minimal, simplified example of plotting lines in 3D based on the above:
def lorentz_deriv((x, y, z), t0, sigma=10., beta=8./3, rho=28.0):
"""Compute the time-derivative of a Lorentz system."""
return [sigma * (y - x), x * (rho - z) - y, x * y - beta * z]
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.integrate import odeint as ODEint
x = np.linspace(0, 20, 1000)
y, z = 10.*np.cos(x), 10.*np.sin(x) # something simple
fig = plt.figure()
ax = fig.add_subplot(1,2,1,projection='3d')
ax.plot(x, y, z)
# now Lorentz
times = np.linspace(0, 4, 1000)
start_pts = 30. - 15.*np.random.random((20,3)) # 20 random xyz starting values
trajectories = []
for start_pt in start_pts:
trajectory = ODEint(lorentz_deriv, start_pt, times)
trajectories.append(trajectory)
ax = fig.add_subplot(1,2,2,projection='3d')
for trajectory in trajectories:
x, y, z = trajectory.T # transpose and unpack
# x, y, z = zip(*trajectory) # this also works!
ax.plot(x, y, z)
plt.show()
There is a brief example / tutorial on how to do wireframe plots (as well as 3d scatter) at the matplotlib site http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#wireframe-plots

polar plot in python

I am trying to make a polar plot of 1/t. What I have so far is below (which may be wrong). How can I finish this or make it work?
from pylab import *
import matplotlib.pyplot as plt
theta = arange(0, 6 * pi, 0.01)
def f(theta):
return 1 / theta
I think the problem is that your first value of f(theta) is 1/0 = inf
theta = np.arange(0, 6*np.pi, .01)[1:]
def f(x):
return 1/x
plt.polar(theta, f(theta))
and it looks even nicer if you zoom in:
from mpl_toolkits.axes_grid.axislines import SubplotZero
from matplotlib.ticker import MultipleLocator, FuncFormatter
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
fig = plt.figure(1)
ax = SubplotZero(fig, 111)
fig.add_subplot(ax)
for dir in ax.axis:
ax.axis[dir].set_visible(dir.endswith("zero"))
ax.set_xlim(-.35,.4)
ax.set_ylim(-.25,.45)
ax.set_aspect('equal')
tick_format = lambda x, i: '' if x == 0.0 else '%.1f' % x
for a in [ax.xaxis, ax.yaxis]:
a.set_minor_locator(MultipleLocator(0.02))
a.set_major_formatter(FuncFormatter(tick_format))
theta = np.arange(2*np.pi/3,6*np.pi,0.01)
r = 1 / theta
ax.plot(r*np.cos(theta), r*np.sin(theta), lw=2)
plt.show()
raw_input()
If you want a square plot like Mathematica gave you, the standard plot function just takes an array of x values and an array of y values. Here, f(theta) is the radius, and cos and sin give the x and y directions, so
plt.plot(f(theta)*cos(theta), f(theta)*sin(theta))
should do the job. This will show all of the data, rather than a cleverly chosen subset like in Mathematica, so you might want to limit it. For example:
plt.xlim((-0.35,0.43))
plt.ylim((-0.23,0.45))
gives me the ranges in your version.

Categories

Resources