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()
Related
I'd like to plot a certain 3D-function where a parameter changes over time using the sympy.plotting module.
I don't want several plots in one figure, I want one plot that updates, e.g. a parabola getting wider or narrower. How can I do that? I didn't find anything in the docs, but maybe I just missed it...
You can use the link provided by #Lior Cohen. You just need to convert your symbolic expression to a numerical function. Here is how I would do it:
import matplotlib.pyplot as plt
import numpy as np
import sympy as sp
# symbolic expression
x, y, t = sp.symbols("x, y, t")
expr = sp.cos((x**2 + y**2) * t)
# convert to numerical function
func = sp.lambdify([x, y, t], expr)
# numerical discretization
x, y = np.mgrid[-2:2:20j, -2:2:20j]
# evaluate the function at time t=0
z = func(x, y, 0)
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
surface = ax.plot_surface(x, y, z, color="b")
ax.set_zlim(-1, 1)
for t in np.linspace(0, 1):
# sadly, its not possible to update a surface.
# hence, we remove the previous and add a new one
surface.remove()
# add a new 3d surface
surface = ax.plot_surface(x, y, func(x, y, t), color="b")
fig.canvas.draw()
fig.canvas.flush_events()
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.
I am trying to plot a 2 variable function with additional parameters which can be changed. Below is the function-
f(x,y) = (x - a*y)/(b+y)
I want to plot it in 3d and would like to see the change in the plot by changing the values of a and b, i.e. when a=1 and b=0, etc.
I can plot it for specific a and b cases, below is the code that works for a=1 and b=0. Is there any way where I don't need to map separately for different cases of a and b?
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import numpy as np
x = np.linspace(30,7000,10000)
y = np.linspace(1,11000, 10000)
def delCAD(x,y):
return (x-y)/(y) # the function when a=1 and b=0
fig = plt.figure(figsize=(12,8))
ax = Axes3D(fig)
ax = fig.gca(projection = "3d")
surf = ax.plot_trisurf(x, y, delCAD(x,y), cmap = cm.coolwarm)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
I generally use IPython or Jupyter for that sort of thing — maybe that's an option for you? For example, using ipywidgets.interact():
import matplotlib.pyplot as plt
import numpy as np
from ipywidgets import interact
x = np.linspace(1, 20, 50)
y = np.linspace(1, 20, 50)
y, x = np.meshgrid(y, x)
def delCAD(x, y, a=1, b=0):
return (x - a * y) / (b + y)
#interact(a=(1, 10), b=(0, 10))
def plot(a, b):
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, figsize=(12, 6))
surf = ax.plot_trisurf(x.flat, y.flat, delCAD(x, y, a, b).flat, cmap='coolwarm')
fig.colorbar(surf, ax=ax, shrink=0.5, aspect=5)
ax.view_init(elev=30, azim=160)
plt.show()
return
Produces this:
As well as the interact wrapper, I introduced the meshgrid line to compute all the locations in the grid, and I changed some of your parameters a bit so you can see more going on in the function. I hope you can unpick the various pieces to fit your needs.
I have a function with two variables and I need to find a global minimum. Also, build the 3D graph and show a global minimum (one point) on the graph. But I'm getting a whole second figure instead of a point. I use Jupyter Notebook. My code is:
import numpy as np
from matplotlib import pyplot as plt
from scipy import optimize
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(10,10))
axes = fig.gca(projection='3d')
def f(x, y):
return (np.exp(np.sqrt(x**2 + y**2)))
y = x = np.linspace(-3, 3, 50)
x, y = np.meshgrid(x, y)
z = f(x,y)
# optimization
optimize.minimize(f, -3, args=(3)) # maybe something is wrong right here
optimization = optimize.minimize(f, -3, args=(3))
surf = axes.plot_surface(x, y, z, cmap='coolwarm',linewidth=0, antialiased=False)
surf1 = axes.plot_surface(x, y, f(optimization.x,y), cmap='coolwarm',linewidth=0, antialiased=False)
axes.set_xlabel('Ось X')
axes.set_ylabel('Ось Y')
axes.set_zlabel('Ось Z')
plt.show()
The problem is that you optimize your surface among one axis only resulting to another surface plot in your script.
You can find a solution by optimizing iteratively each axis. In the solution I provided below, it works for your example, but finding a global optimum for more complex function (i.e not convex) will required more iterations to converge. (and probably more subtle gradient descent method)
Note that I used contour3D instead of plot_surface to better visualize the plotted point.
import numpy as np
from matplotlib import pyplot as plt
from scipy import optimize
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(10,10))
axes = fig.gca(projection='3d')
def f(x, y):
return (np.exp(np.sqrt(x**2 + y**2)))
y = x = np.linspace(-3, 3, 50)
x, y = np.meshgrid(x, y)
z = f(x,y)
# optimization x
optimization = optimize.minimize(f, [-3], args=(-3,))
best_x = optimization.x
# optimization y
optimization = optimize.minimize(lambda x,y: f(y,x), [-3], args=(-3,))
best_y = optimization.x
#surf = axes.plot_surface(x, y, z, cmap='coolwarm',linewidth=0, antialiased=True)
surf = axes.contour3D(x, y, z, 50, cmap='coolwarm',)
axes.scatter3D([best_x], [best_y], [f(best_x, best_y)], s=[100], c="g");
axes.set_xlabel('Ось X')
axes.set_ylabel('Ось Y')
axes.set_zlabel('Ось Z')
plt.show()
]
Let's say I have a 3D plane equation:
ax+by+cz=d
How can I plot this in python matplotlib?
I saw some examples using plot_surface, but it accepts x,y,z values as 2D array. I don't understand how can I convert my equation into the parameter inputs to plot_surface or any other functions in matplotlib that can be used for this.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
a,b,c,d = 1,2,3,4
x = np.linspace(-1,1,10)
y = np.linspace(-1,1,10)
X,Y = np.meshgrid(x,y)
Z = (d - a*X - b*Y) / c
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z)