J. Serra
J. Serra

Reputation: 490

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))

Upvotes: 0

Views: 856

Answers (2)

swatchai
swatchai

Reputation: 18782

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)

parabola1

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])

Upvotes: -1

Davide_sd
Davide_sd

Reputation: 13150

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()

enter image description here

Upvotes: 2

Related Questions