Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to annotate/highlight a 3d plot in MatPlotLib

I would like to do something like this: http://matplotlib.sourceforge.net/_images/86cbd17f31.png in a 3d space. Basically I want to highlight a portion of a surface plot. Any suggestions?

like image 841
ofosho Avatar asked Jul 23 '26 01:07

ofosho


1 Answers

edit3 (this replaces a very mis-guided previous answer)

updated again. See comment

You can modify the face colors of a surface plot if you drill down to the polygon collection that is generated by the plot. It does some magic shading and re-orders the list of colors depending on zorder so I had some trouble figuring out how to keep the assigned shading in the un-highlighted region yet still be able to index the region of interests. Here is a method that works. I hope you wanted shaded faces and not some kind of 3D semi-transparent columns. This could also be done, but I think it would be very difficult to tell what is highlighted and would be really tricky to define the zorder.

enter image description here

enter image description here

import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import mpl_toolkits.mplot3d.art3d as art3d
from matplotlib.patches import Rectangle, PathPatch

fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)

xlo = X.min()
xhi = X.max()
ylo = Y.min()
yhi = Y.max()
zlo = -2
zhi = 2

surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, linewidth=1, zorder=100)
cset = ax.contour(X, Y, Z, zdir='z', offset=zlo, alpha=0.0)

def highlight((xmin, xmax),(ymin, ymax)):
    # draw highlight on xz plane
    p1 = Rectangle((ymin,zlo),(ymax-ymin),(zhi-zlo), color='y', alpha=0.5, zorder=0)
    ax.add_patch(p1)
    art3d.pathpatch_2d_to_3d(p1, z=xlo, zdir='x')

    # draw highlight on yz plane
    p2 = Rectangle((xmin,zlo),(xmax-xmin),(zhi-zlo), color='y', alpha=0.5, zorder=0)
    ax.add_patch(p2)
    art3d.pathpatch_2d_to_3d(p2, z=yhi, zdir='y')

    # define a region to highlight
    highlight = (X>xmin)&(X<xmax)&(Y>ymin)&(Y<ymax)
    coll = ax.collections[0]
    # get the original color shading (if you want to keep that effect)
    colors = coll._facecolors_original
    #colors = coll.get_facecolors()
    # they are stored as a list for some reason so get the flat indicies
    for idx in np.where(highlight[:-1,:-1].flat)[0]:
        # and modifly one-by-one
        color = colors[idx][:]
        colors[idx][0] = color[2]  # swap red with blue
        colors[idx][3] = color[0]
        colors[idx][4] = .2  #change alpha
    # re-set the face colors
    coll.set_facecolors(colors)

highlight((-3,0),(-3,1))

ax.set_xlim3d(xlo, xhi)
ax.set_ylim3d(ylo, yhi)
ax.set_zlim3d(zlo, zhi)

plt.show()
like image 184
Paul Avatar answered Jul 25 '26 15:07

Paul



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!