12

I'm trying to create aesthetically pleasing 3D plots in Python with specular shading, and thus far have tried using both Matplotlib with 3D axes and surface plots from Mayavi, e.g., from the Mayavi surf examples web page:

enter image description here

The results look good, and in Mayavi there does seem to be reasonable control of the lighting, although I can't seem to achieve a "shiny" appearance.

In Matlab, this can be achieved by using 'Phong' lighting:

enter image description here

see http://www.mathworks.com/matlabcentral/fileexchange/35240-matlab-plot-gallery-change-lighting-to-phong/content/html/Lighting_Phong.html

Therefore, my question is: how can I achieve this Phong-style shiny shading in a Python-based 3D plot?

Vaishak Suresh
  • 5,735
  • 10
  • 41
  • 66
NewPythonUsers1
  • 141
  • 1
  • 3
  • Two things spring to mind. In matlab, I noticed that if you switch renderers (from the matlab software renderer to the OpenGL renderer) it goes from shiny looking to much more flat looking. So it might be that matplotlib is using the OpenGL renderer. Secondly, is there a way to change the colour and brightness of the source light in matplotlib. This might allow you to change the "shininess" of your plot. – shaw2thefloor Jan 30 '15 at 11:04
  • Thanks. Good suggestion - I wonder how I can change the Mayavi / Matplotlib renderer then to help achieve this please? – NewPythonUsers1 Jan 30 '15 at 17:17
  • Maybe this will help - changing backends in matplotlib: http://stackoverflow.com/questions/3285193/how-to-switch-backends-in-matplotlib-python Phong-style lighting would be really nice in python, but I couldn't find anything on it. The only mention was in the context of using Blender python API: http://blenderartists.org/forum/showthread.php?190352-Simple-Phong-shader-via-PyNodes – mmagnuski Feb 01 '15 at 13:10
  • For a numpy implementation of blinn-phong, see answer: https://stackoverflow.com/questions/54965330/blinn-phong-shading-with-numpy – Kaan E. Mar 05 '19 at 16:24

2 Answers2

17

As @ben mentioned, you can use Mayavi and then interactively change the lighting. A good idea is to click in the record script button, then you can use those lines of code in your scripts (That's how I did for the Mayavi part here).

Another option is to use Matplotlib. Based on the shading example, I managed to generate a surface with lighting.

See the code below.

import numpy as np
from mayavi import mlab
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.colors import LightSource

## Test data: Matlab `peaks()`
x, y = np.mgrid[-3:3:150j,-3:3:150j]
z =  3*(1 - x)**2 * np.exp(-x**2 - (y + 1)**2) \
   - 10*(x/5 - x**3 - y**5)*np.exp(-x**2 - y**2) \
   - 1./3*np.exp(-(x + 1)**2 - y**2) 

## Mayavi
surf = mlab.surf(x, y, z, colormap='RdYlBu', warp_scale='auto')
# Change the visualization parameters.
surf.actor.property.interpolation = 'phong'
surf.actor.property.specular = 0.1
surf.actor.property.specular_power = 5



## Matplotlib
fig = plt.figure()
ax = fig.gca(projection='3d')

# Create light source object.
ls = LightSource(azdeg=0, altdeg=65)
# Shade data, creating an rgb array.
rgb = ls.shade(z, plt.cm.RdYlBu)
surf = ax.plot_surface(x, y, z, rstride=1, cstride=1, linewidth=0,
                       antialiased=False, facecolors=rgb)
plt.show()
mlab.show()

This gives as results:

  • Mayavi: enter image description here
  • Matplotlib: enter image description here
nicoguaro
  • 3,629
  • 1
  • 32
  • 57
  • 2
    In Mayavi, with `specular = 1.0` and `specular_power = 100` I get shinier highlights. The trouble with Matplotlib is that [it can't draw intersecting objects properly](http://stackoverflow.com/q/20407936/1143274), because it draws one thing at a time. This means that e.g. it's impossible to draw nice contours on surfaces (unless none of them are occluded by other parts of the surface). Also, those banding artifacts visible in the bottom figure become more pronounced for rougher surfaces and [there is no workaround](https://github.com/matplotlib/matplotlib/issues/6027#issuecomment-187807292). – Evgeni Sergeev Mar 10 '17 at 14:20
2

Yes, you can do this in Mayavi. In the Mayavi window, click on the little Mayavi icon in the upper left-hand corner to show the advanced menu. Click on the surface in the scene that corresponds to your surface, then click on the "Actor" tab in the menu on the right, scroll down to the box labeled "Property", and click on "More options". You can set the shading to phong shading in the "Interpolation" box.

ben
  • 467
  • 3
  • 11