Reputation: 8449
I have the following Python code:
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams['figure.figsize'] = [12, 7]
n = 100
m = 100
X = np.arange(-n/2,n/2,1)
Y = np.arange(-m/2,m/2,1)
X, Y = np.meshgrid(X, Y)
landscape = np.exp(-0.01 * (X*X + Y*Y) )
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(X, Y, landscape,
linewidth=0,
antialiased=False
)
Running this in a notebook produces this image
If you look very closely you will see that the left-hand side of the Gaussian peak is very slightly lighter than the right-hand side. This lighting effect is barely visible, though, and I would like to increase it, so that the 3D shape becomes easily visible.
I'm aware of matplotlib.colors.LightSource, but no matter what I do I can't get that to produce the effect I want. Ideally, I'd just like to increase the intensity of the 'default' lighting, rather than fiddling around with this. But if someone can explain how to use LightSource for this image that would help too.
Note that I don't want to apply a height map to the image, and I also don't want to draw grid lines on it - I just want to increase the lighting effect while keeping the surface a uniform colour.
It's also worth mentioning that I'm somewhat stuck with MatPlotLib, because I'm using Jupyterlite to share the notebook with students who don't have Python installed, so I need a solution that works with that.
Upvotes: 4
Views: 3362
Reputation: 50949
Using LightSource
you can do something like
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.colors import LightSource
plt.rcParams['figure.figsize'] = [12, 7]
n = 100
m = 100
X = np.arange(-n / 2, n / 2, 1)
Y = np.arange(-m / 2, m / 2, 1)
X, Y = np.meshgrid(X, Y)
landscape = np.exp(-0.01 * (X * X + Y * Y))
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
# this is used to set the graph color to blue
blue = np.array([0., 0., 1.])
rgb = np.tile(blue, (landscape.shape[0], landscape.shape[1], 1))
ls = LightSource()
illuminated_surface = ls.shade_rgb(rgb, landscape)
ax.plot_surface(X, Y, landscape,
linewidth=0,
antialiased=False,
facecolors=illuminated_surface)
If you want the light from the right change the azdeg
parameter at the LightSource
creation
ls = LightSource(azdeg=80)
Parameters
----------
azdeg : float, default: 315 degrees (from the northwest)
The azimuth (0-360, degrees clockwise from North) of the light
source.
altdeg : float, default: 45 degrees
The altitude (0-90, degrees up from horizontal) of the light
source.
Upvotes: 7
Reputation: 13185
Keeping in mind that Matplotlib's 3D capabilities are rather limited, I would suggest to use a different library. Better libraries for 3D plots are:
Keep in mind that each one of those libraries come with their advantages and disadvantages.
I'm going to replicate your example with Mayavi, since I have it installed in the current environment:
import numpy as np
from mayavi import mlab
n = 100
m = 100
x, y = np.mgrid[-n/2:n/2:n*1j,-m/2:m/2:m*1j]
z = np.exp(-0.01 * (x**2 + y**2) )
surf = mlab.surf(x, y, z, warp_scale='auto', color=(0, 0.5, 1))
mlab.show()
Upvotes: 3