A question on double integration using SciPy's nquad - python

I am trying to get the following result using (numerical) double integration of the two partial derivatives:
def deriv_y(x,y):
return -2*x*y*np.exp(-x**2-y**2)
and
def deriv_x(x,y):
return (1-2*x**2)*np.exp(-x**2-y**2)
The function is an introductory example suitable for novices. The derivatives and some properties are provided here by Wolfram Alpha.
This function is also used by this tutorial "3D Surface Plots".
Successfully I could integrate the function along the x-Axis by implementing:
from scipy import integrate
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
arr_x = np.arange(-5,5,0.5)
arr_y = np.arange(-5,5,0.5)
X,Y = np.meshgrid(arr_x, arr_y)
Z = np.zeros([arr_x.size, arr_y.size])
def deriv_y(x,y):
return 2*x*y*np.exp(-x**2-y**2)
def deriv_x(x,y):
return (1-2*x**2)*np.exp(-x**2-y**2)
def bounds_x(y):
return [y, np.inf]
def bounds_y():
return [0, np.inf]
for idx_x, x in enumerate(arr_x):
for idx_y, y in enumerate(arr_y):
m = integrate.nquad(deriv_x, [bounds_x(y), bounds_y])
Z[idx_x][idx_y] = m[0]
fig = plt.figure(figsize=(14,10))
ax1 = fig.add_subplot(111, projection='3d')
mycmap = plt.get_cmap('gist_earth')
surf1 = ax1.plot_surface(X, Y, Z, cmap=mycmap)
fig.colorbar(surf1, ax=ax1, shrink=0.5, aspect=5)
plt.show()
The output seems to be correct:
I have read the official documentation "Integration (scipy.integrate)". Then I tried to chain both functions deriv_x and deriv_y in many combinations. In any case a got some wrong plots. I would be greateful if anyone could help me, doing it right.

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

Does streamplot in Python matplotlib care about the order of coordinates?

I need to use the streamplot function in matplotlib with coordinates x, p in the order as in the code below.
import numpy as np
import matplotlib.pyplot as plt
size = 2
x, p = np.mgrid[-size:size:100j, -size:size:100j]
x_force = p
p_force = x**3
fig = plt.figure()
ax = fig.gca()
ax.streamplot(x, p, x_force, p_force, density=[0.5, 1])
plt.show()
This produces an error: ValueError: The rows of 'x' must be equal.
Quite surprisingly, changing the order of x and p in the streamplot solves the problem.
ax.streamplot(p, x, p_force, x_force, density=[0.5, 1])
Why does this happen please? How can I make the plot with coordinates in my chosen order?
Changing the order of x and p in the meshgrid command solves the problem:
p, x = np.mgrid[-size:size:100j, -size:size:100j]

Animating 3D Equation/Plot Via "t" Variable on Python 3.0

My goal is to animate the hyper-specific (canonical) diffusion equation by being able to "tell" Python to increment the "t" variable existing in said equation. I have easily done this in Mathematica but need to use Python for my assigned research project.
The equation is structured/defined as c(x,y,t), and obviously my question applies for any type of function that c(x,y,t) is set to equal. Every answer related to my question ether:
1) Does not include a function that is not a PDE
2) Consists of not incrementing a time variable (t)
Furthermore, I cannot find any method to graph a 3D equation on Python that is for 2 variables.
EDIT: I have figured out a way to do this.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import random
def fun(x, t):
return x+t #Any equation
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.arange(-20.0, 20.0, 0.05)
t = np.arange(0.0,50.0,1)
X, Y = np.meshgrid(x, t)
zs = np.array([fun(x,t) for x,t in zip(np.ravel(X), np.ravel(Y))])
Z = zs.reshape(X.shape)
ax.plot_surface(X, Y, Z)
ax.set_xlabel('X Position')
ax.set_ylabel('Time')
ax.set_zlabel('Concentration')
plt.show()
Credit: Wim I want to use matplotlib to make a 3d plot given a z function
Any help or simple code of an animation procedure would mean a lot, as my research project deals with 7D mathematics and this is essentially the most basic example of a non-trivial representation of what I am trying to do. So expect more questions to come (regardless of an answer).
Ok so let's take the example from this answer. We can easily modify it to use a function c(x,y,t) instead of f(x,y,sig) (those are just variable names).
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
def update_plot(frame_number, zarray, plot):
plot[0].remove()
plot[0] = ax.plot_surface(x, y, zarray[:,:,frame_number], cmap="magma")
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
N = 14
nmax=20
x = np.linspace(-4,4,N+1)
x, y = np.meshgrid(x, x)
zarray = np.zeros((N+1, N+1, nmax))
sig = lambda t: 1.5+np.sin(t*2*np.pi/nmax)
c = lambda x,y,t : 1/np.sqrt(sig(t))*np.exp(-(x**2+y**2)/sig(t)**2)
for t in range(nmax):
zarray[:,:,t] = c(x,y,t)
plot = [ax.plot_surface(x, y, zarray[:,:,0], color='0.75', rstride=1, cstride=1)]
ax.set_zlim(0,1.5)
animate = animation.FuncAnimation(fig, update_plot, nmax, fargs=(zarray, plot))
plt.show()

Plotting 3D image form a data in NumPy-array

I have a data file in NumPy array, I would like to view the 3D-image. I am sharing an example, where I can view 2D image of size (100, 100), this is a slice in xy-plane at z = 0.
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
X, Y, Z = np.mgrid[-10:10:100j, -10:10:100j, -10:10:100j]
T = np.sin(X*Y*Z)/(X*Y*Z)
T=T[:,:,0]
im = plt.imshow(T, cmap='hot')
plt.colorbar(im, orientation='vertical')
plt.show()
How can I view a 3D image of the data T of shape (100, 100, 100)?
I think the main problem is, that you do have 4 informations for each point, so you are actually interessted in a 4-dimensional object. Plotting this is always difficult (maybe even impossible). I suggest one of the following solutions:
You change the question to: I'm not interessted in all combinations of x,y,z, but only the ones, where z = f(x,y)
You change the accuracy of you plot a bit, saying that you don't need 100 levels of z, but only maybe 5, then you simply make 5 of the plots you already have.
In case you want to use the first method, then there are several submethods:
A. Plot the 2-dim surface f(x,y)=z and color it with T
B. Use any technic that is used to plot complex functions, for more info see here.
The plot given by method 1.A (which I think is the best solution) with z=x^2+y^2 yields:
I used this programm:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib as mpl
X, Y = np.mgrid[-10:10:100j, -10:10:100j]
Z = (X**2+Y**2)/10 #definition of f
T = np.sin(X*Y*Z)
norm = mpl.colors.Normalize(vmin=np.amin(T), vmax=np.amax(T))
T = mpl.cm.hot(T) #change T to colors
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, facecolors=T, linewidth=0,
cstride = 1, rstride = 1)
plt.show()
The second method gives something like:
With the code:
norm = mpl.colors.Normalize(vmin=-1, vmax=1)
X, Y= np.mgrid[-10:10:101j, -10:10:101j]
fig = plt.figure()
ax = fig.gca(projection='3d')
for i in np.linspace(-1,1,5):
Z = np.zeros(X.shape)+i
T = np.sin(X*Y*Z)
T = mpl.cm.hot(T)
ax.plot_surface(X, Y, Z, facecolors=T, linewidth=0, alpha = 0.5, cstride
= 10, rstride = 10)
plt.show()
Note: I changed the function to T = sin(X*Y*Z) because dividing by X*Y*Zmakes the functions behavior bad, as you divide two number very close to 0.
I have got a solution to my question. If we have the NumPy data, then we can convert them into TVTK ImageData and then visualization is possible with the help of mlab form Mayavi. The code and its 3D visualization are the following
from tvtk.api import tvtk
import numpy as np
from mayavi import mlab
X, Y, Z = np.mgrid[-10:10:100j, -10:10:100j, -10:10:100j]
data = np.sin(X*Y*Z)/(X*Y*Z)
i = tvtk.ImageData(spacing=(1, 1, 1), origin=(0, 0, 0))
i.point_data.scalars = data.ravel()
i.point_data.scalars.name = 'scalars'
i.dimensions = data.shape
mlab.pipeline.surface(i)
mlab.colorbar(orientation='vertical')
mlab.show()
For another randomly generated data
from numpy import random
data = random.random((20, 20, 20))
The visualization will be

Square root scale using matplotlib/python

I want to make a plot with square root scale using Python:
However, I have no idea how to make it. Matplotlib allows to make log scale but in this case I need something like power function scale.
You can make your own ScaleBase class to do this. I have modified the example from here (which made a square-scale, not a square-root-scale) for your purposes. Also, see the documentation here.
Note that to do this properly, you should probably also create your own custom tick locator; I haven't done that here though; I just manually set the major and minor ticks using ax.set_yticks().
import matplotlib.scale as mscale
import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
import matplotlib.ticker as ticker
import numpy as np
class SquareRootScale(mscale.ScaleBase):
"""
ScaleBase class for generating square root scale.
"""
name = 'squareroot'
def __init__(self, axis, **kwargs):
# note in older versions of matplotlib (<3.1), this worked fine.
# mscale.ScaleBase.__init__(self)
# In newer versions (>=3.1), you also need to pass in `axis` as an arg
mscale.ScaleBase.__init__(self, axis)
def set_default_locators_and_formatters(self, axis):
axis.set_major_locator(ticker.AutoLocator())
axis.set_major_formatter(ticker.ScalarFormatter())
axis.set_minor_locator(ticker.NullLocator())
axis.set_minor_formatter(ticker.NullFormatter())
def limit_range_for_scale(self, vmin, vmax, minpos):
return max(0., vmin), vmax
class SquareRootTransform(mtransforms.Transform):
input_dims = 1
output_dims = 1
is_separable = True
def transform_non_affine(self, a):
return np.array(a)**0.5
def inverted(self):
return SquareRootScale.InvertedSquareRootTransform()
class InvertedSquareRootTransform(mtransforms.Transform):
input_dims = 1
output_dims = 1
is_separable = True
def transform(self, a):
return np.array(a)**2
def inverted(self):
return SquareRootScale.SquareRootTransform()
def get_transform(self):
return self.SquareRootTransform()
mscale.register_scale(SquareRootScale)
fig, ax = plt.subplots(1)
ax.plot(np.arange(0, 9)**2, label='$y=x^2$')
ax.legend()
ax.set_yscale('squareroot')
ax.set_yticks(np.arange(0,9,2)**2)
ax.set_yticks(np.arange(0,8.5,0.5)**2, minor=True)
plt.show()
This is old, but I made a quick-fix because i didn't want to bother with creating a custom tick-locator. If you are making a lot of plots with custom scales that is probably the way to go. Just plotting the function with the scale you want, then setting the ticks and changing the labels is quicker if you just need a plot or two.
Nx = 100
x = np.linspace(0,50,Nx)
y = np.sqrt(x)
fig, ax = plt.subplots(1, 1)
plt.plot(np.sqrt(x), y)
ax.set_xticks([np.sqrt(x[i]) for i in range(0, Nx, Nx // 10)])
ax.set_xticklabels([str(round(x[i],0))[:-2] for i in range(0, Nx, Nx // 10)])
plt.xlabel('x')
plt.ylabel(r'y = $\sqrt{x}$')
plt.grid()
plt.show()
produces the plot
I like lolopop's comment and tom's answer, a more quick and dirty solution would be using set_yticks and set_yticklabels as in the following:
x = np.arange(2, 15, 2)
y = x * x
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
ax1.plot(x,y)
ax2.plot(x, np.sqrt(y))
ax2.set_yticks([2,4,6,8,10,12,14])
ax2.set_yticklabels(['4','16','36','64','100','144','196'])
Matplotlib now offers a powlaw norm. Thus setting power to 0.5 should do the trick!
C.f. Matplotlib Powerlaw norm
And their example:
"""
Demonstration of using norm to map colormaps onto data in non-linear ways.
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
from matplotlib.mlab import bivariate_normal
N = 100
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
'''
PowerNorm: Here a power-law trend in X partially obscures a rectified
sine wave in Y. We can remove gamma to 0.5 should do the trick using PowerNorm.
'''
X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)]
Z1 = (1 + np.sin(Y * 10.)) * X**(2.)
fig, ax = plt.subplots(2, 1)
pcm = ax[0].pcolormesh(X, Y, Z1, norm=colors.PowerNorm(gamma=1./2.),
cmap='PuBu_r')
fig.colorbar(pcm, ax=ax[0], extend='max')
pcm = ax[1].pcolormesh(X, Y, Z1, cmap='PuBu_r')
fig.colorbar(pcm, ax=ax[1], extend='max')
fig.show()
This a simple way to graph
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams["figure.dpi"] = 140
fig, ax = plt.subplots()
ax.spines["left"].set_position("zero")
ax.spines["bottom"].set_position("zero")
ax.spines["right"].set_color("none")
ax.spines["top"].set_color("none")
ax.xaxis.set_ticks_position("bottom")
ax.yaxis.set_ticks_position("left")
origin = [0, 0]
# 45
plt.plot(
np.linspace(0, 1, 1000),
np.sqrt(np.linspace(0, 1, 1000)),
color="k",
)
ax.set_aspect("equal")
plt.xlim(-0.25, 1)
plt.ylim(0, 1)
plt.yticks(ticks=np.linspace(0, 1, 6))
plt.show()

Categories

Resources