creating a log Axes3D object is an issue (see here)
a workaround is
import matplotlib.ticker as mticker
ax.plot_surface(x, y, np.log10(z))
def log_tick_formatter(val, pos=None):
return "{:.2e}".format(10**val)
ax.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))
this produces zticks of the form 1.0e-5.
How should I modify it to have ticks of the (LaTeX)
form 10^{-5} (as in standard logplots)?
Here is a minimal example to play with. Many thanks in advance!
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.ticker as mticker
fig = plt.figure()
ax = fig.gca(projection="3d")
x = np.arange(5+1)
y = np.arange(6+1)
X, Y = np.meshgrid(x, y)
Z = np.zeros(X.shape)
for ii in x:
for jj in y:
Z[jj, ii] = -min(ii, jj)
ax.plot_wireframe(X, Y, Z)
ax.view_init(elev=10, azim=-45)
def log_tick_formatter(val, pos=None):
return "{:.0e}".format(10**val)
ax.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))
plt.gca().invert_yaxis()
plt.show()
plt.close()
You can use the following format:
def log_tick_formatter(val, pos=None):
return r"$10^{{{:.0f}}}$".format(val)
but be aware that this - just like your solution - only works, if ticks are accidentally placed at whole numbers.
Related
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.
This is the code I have so far, I'm trying to set the y limit to be [0,4] and the x limit to be [-2,3]. I can take care of the plot titles myself but I can't figure out how to get these two functions on the same graph.
import math as m
from matplotlib import pylab as plt
import numpy as np
def fermi_dirac(x):
fermi_result = (1/(np.exp(x)+1))
return fermi_result
def bose_einstein(x):
bose_result = (1/(np.exp(x)-1))
return bose_result
Here is a template to get you going
import math as m
import matplotlib.pyplot as plt
import numpy as np
def fermi_dirac(x):
fermi_result = (1./(np.exp(x)+1))
return fermi_result
def bose_einstein(x):
bose_result = (1/(np.exp(x)-1))
return bose_result
x = np.linspace( -2,3, 100)
fd = fermi_dirac(x)
be = bose_einstein(x)
plt.figure()
plt.plot(x, fd, label='fermi dirac')
plt.plot(x, be, label ='bose einstein')
plt.legend(loc='best')
plt.show()
Here's what I did and it works fine with the exception of a divide by zero error for certain values (I'm assuming graphical asymptotes):
import matplotlib.pyplot as plt
import numpy as np
def fermi_dirac(x):
fermi_result = (1/(np.exp(x)+1))
return fermi_result
def bose_einstein(x):
bose_result = (1/(np.exp(x)-1))
return bose_result
f = plt.figure()
x_vals = range(-2,3)
plt.plot(x_vals, fermi_dirac(x_vals))
plt.plot(x_vals, bose_einstein(x_vals))
plt.show()
Here's the documentation for pyplot when you need more references: https://matplotlib.org/api/_as_gen/matplotlib.pyplot.html
To get those functions on the same plot, just use plt.plot(...) two times.
Reference: How to plot multiple functions on the same figure, in Matplotlib?
import math as m
from matplotlib import pylab as plt
import numpy as np
def fermi_dirac(x):
fermi_result = (1/(np.exp(x)+1))
return fermi_result
def bose_einstein(x):
bose_result = (1/(np.exp(x)-1))
return bose_result
x = np.linspace(-2, 3, 100)
y1 = fermi_dirac(x)
y2 = bose_einstein(x)
plt.plot(x, y1, 'r')
plt.plot(x, y2, 'b')
plt.ylim(0, 4)
plt.show()
Output:
Very simple, you just have to define an array of input values (that you can call x). Here's an example with 1000 such values, input as a line plot using both formulas and the axis ranges you provided:
x = np.linspace(-2, 3, 1000)
plt.xlim([-2, 3])
plt.ylim([0,4])
plt.plot(x, fermi_dirac(x), '-', x, bose_einstein(x), '--')
plt.show()
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()
I wanted to plot y=(x+2)(x−1)(x−2) for x going from −3 to 3 using a dashed red line. When I wrote the following code, nothing shows up.
import numpy as np
import matplotlib.pyplot as plt
def graph(formula, x_range):
x = np.array(x_range)
y = eval(formula)
plt.plot(x, y)
plt.show()
graph('((x-3) * (x-2))', range(-3,3))
Make sure graph(..) call is outside the graph function definition (IOW, indent correctly):
import numpy as np
import matplotlib.pyplot as plt
def graph(formula, x_range):
x = np.array(x_range)
y = eval(formula)
plt.plot(x, y, 'r--') # `r--` for dashed red line
plt.show()
graph('((x-3) * (x-2))', range(-3,3)) # <----
UPDATE
It's not a good idea to use eval. Instead you can pass a function in this case.
def graph(formula, x_range):
x = np.array(x_range)
y = formula(x) # <-----
plt.plot(x, y, 'r--')
plt.show()
graph(lambda x: (x-3) * (x-2), range(-3,3)) # <---
When I plot something with contourf, I see at the bottom of the plot window the current x and y values under the mouse cursor.
Is there a way to see also the z value?
Here an example contourf:
import matplotlib.pyplot as plt
import numpy as hp
plt.contourf(np.arange(16).reshape(-1,4))
The text that shows the position of the cursor is generated by ax.format_coord. You can override the method to also display a z-value. For instance,
import matplotlib.pyplot as plt
import numpy as np
import scipy.interpolate as si
data = np.arange(16).reshape(-1, 4)
X, Y = np.mgrid[:data.shape[0], :data.shape[1]]
cs = plt.contourf(X, Y, data)
func = si.interp2d(X, Y, data)
def fmt(x, y):
z = np.take(func(x, y), 0)
return 'x={x:.5f} y={y:.5f} z={z:.5f}'.format(x=x, y=y, z=z)
plt.gca().format_coord = fmt
plt.show()
The documentation example shows how you can insert z-value labels into your plot
Script: http://matplotlib.sourceforge.net/mpl_examples/pylab_examples/contour_demo.py
Basically, it's
plt.figure()
CS = plt.contour(X, Y, Z)
plt.clabel(CS, inline=1, fontsize=10)
plt.title('Simplest default with labels')
Just a variant of wilywampa's answer. If you already have a pre-computed grid of interpolated contour values because your data is sparse or if you have a huge data matrix, this might be suitable for you.
import matplotlib.pyplot as plt
import numpy as np
resolution = 100
Z = np.arange(resolution**2).reshape(-1, resolution)
X, Y = np.mgrid[:Z.shape[0], :Z.shape[1]]
cs = plt.contourf(X, Y, Z)
Xflat, Yflat, Zflat = X.flatten(), Y.flatten(), Z.flatten()
def fmt(x, y):
# get closest point with known data
dist = np.linalg.norm(np.vstack([Xflat - x, Yflat - y]), axis=0)
idx = np.argmin(dist)
z = Zflat[idx]
return 'x={x:.5f} y={y:.5f} z={z:.5f}'.format(x=x, y=y, z=z)
plt.colorbar()
plt.gca().format_coord = fmt
plt.show()
Ex: