Yet another question about matplotlib 3d surfaces… I have code which adds a scatter point to a matplotlib surface graph.
The problem that I have is that the point always appears behind the surface, regardless of which angle you view it from.
If I cobble an (admittedly ugly) version using 3 short lines to mark the same point, it is visible.
I have turned off the depthshade
function, so it isn’t this. Can anybody explain what is going on and how I can correct it? Here is a simplified version of the code:
import pandas as pd import matplotlib import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import numpy as np df = pd.DataFrame({10: {10: 1,15: 1,20: 1,25: 1,30: 1,35: 1,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 15: {10: 4,15: 1,20: 1,25: 1,30: 1,35: 1,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 20: {10: 6,15: 3,20: 1,25: 1,30: 1,35: 1,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 25: {10: 7,15: 5,20: 3,25: 1,30: 1,35: 1,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 30: {10: 9,15: 6,20: 4,25: 3,30: 1,35: 1,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 35: {10: 10,15: 7,20: 5,25: 4,30: 2,35: 1,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 40: {10: 11,15: 8,20: 6,25: 4,30: 3,35: 2,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 45: {10: 12,15: 9,20: 7,25: 5,30: 4,35: 3,40: 2,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 50: {10: 13,15: 9,20: 7,25: 6,30: 5,35: 4,40: 3,45: 2,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 55: {10: 14,15: 10,20: 8,25: 7,30: 5,35: 4,40: 3,45: 3,50: 2,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 60: {10: 15,15: 11,20: 9,25: 7,30: 6,35: 5,40: 4,45: 3,50: 3,55: 2,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 65: {10: 16,15: 12,20: 9,25: 8,30: 6,35: 5,40: 5,45: 4,50: 3,55: 2,60: 2,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 70: {10: 17,15: 12,20: 10,25: 8,30: 7,35: 6,40: 5,45: 4,50: 4,55: 3,60: 2,65: 2,70: 1,75: 1,80: 1,85: 1,90: 1}, 75: {10: 18,15: 13,20: 10,25: 9,30: 7,35: 6,40: 5,45: 5,50: 4,55: 3,60: 3,65: 2,70: 2,75: 1,80: 1,85: 1,90: 1}, 80: {10: 19,15: 14,20: 11,25: 9,30: 8,35: 7,40: 6,45: 5,50: 4,55: 4,60: 3,65: 3,70: 2,75: 2,80: 1,85: 1,90: 1}, 85: {10: 21,15: 14,20: 11,25: 10,30: 8,35: 7,40: 6,45: 6,50: 5,55: 4,60: 4,65: 3,70: 3,75: 2,80: 2,85: 1,90: 1}, 90: {10: 23,15: 15,20: 12,25: 10,30: 9,35: 8,40: 7,45: 6,50: 5,55: 5,60: 4,65: 3,70: 3,75: 3,80: 2,85: 2,90: 1}}) xv, yv = np.meshgrid(df.index, df.columns) ma = np.nanmax(df.values) norm = matplotlib.colors.Normalize(vmin = 0, vmax = ma, clip = True) fig = plt.figure(1) ax = Axes3D(fig) surf = ax.plot_surface(yv,xv,df, cmap='viridis_r', linewidth=0.3, alpha = 0.8, edgecolor = 'k', norm=norm) ax.scatter(25,35,4, c='k', depthshade=False, alpha = 1, s=100) fig = plt.figure(2) ax = Axes3D(fig) surf = ax.plot_surface(yv,xv,df, cmap='viridis_r', linewidth=0.3, alpha = 0.8, edgecolor = 'k', norm=norm) line1_x = [25,25] line1_y = [35,35] line1_z = [3,5] line2_x = [25,25] line2_y = [33,37] line2_z = [4,4] line3_x = [23,27] line3_y = [35,35] line3_z = [4,4] ax.plot(line1_x, line1_y, line1_z, alpha = 1, linewidth = 1, color='k') ax.plot(line2_x, line2_y, line2_z, alpha = 1, linewidth = 1, color='k') ax.plot(line3_x, line3_y, line3_z, alpha = 1, linewidth = 1, color='k') plt.show()
Advertisement
Answer
OK, so as per the comment by Mr T above, there doesn’t seem to be a direct method of dealing with this. There is however, a workaround for what I’m trying to do (highlight specific points on the surface). Using the matplotlib.patches
and mpl_toolkits.mplot3d.art3d
modules, it is possible to plot a circle on the graph at the appropriate point, and this appears to be unaffected by the same issue.
The modified code is:
import pandas as pd import matplotlib import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D, art3d from matplotlib.patches import Circle import numpy as np df = pd.DataFrame({10: {10: 1,15: 1,20: 1,25: 1,30: 1,35: 1,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 15: {10: 4,15: 1,20: 1,25: 1,30: 1,35: 1,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 20: {10: 6,15: 3,20: 1,25: 1,30: 1,35: 1,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 25: {10: 7,15: 5,20: 3,25: 1,30: 1,35: 1,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 30: {10: 9,15: 6,20: 4,25: 3,30: 1,35: 1,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 35: {10: 10,15: 7,20: 5,25: 4,30: 2,35: 1,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 40: {10: 11,15: 8,20: 6,25: 4,30: 3,35: 2,40: 1,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 45: {10: 12,15: 9,20: 7,25: 5,30: 4,35: 3,40: 2,45: 1,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 50: {10: 13,15: 9,20: 7,25: 6,30: 5,35: 4,40: 3,45: 2,50: 1,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 55: {10: 14,15: 10,20: 8,25: 7,30: 5,35: 4,40: 3,45: 3,50: 2,55: 1,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 60: {10: 15,15: 11,20: 9,25: 7,30: 6,35: 5,40: 4,45: 3,50: 3,55: 2,60: 1,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 65: {10: 16,15: 12,20: 9,25: 8,30: 6,35: 5,40: 5,45: 4,50: 3,55: 2,60: 2,65: 1,70: 1,75: 1,80: 1,85: 1,90: 1}, 70: {10: 17,15: 12,20: 10,25: 8,30: 7,35: 6,40: 5,45: 4,50: 4,55: 3,60: 2,65: 2,70: 1,75: 1,80: 1,85: 1,90: 1}, 75: {10: 18,15: 13,20: 10,25: 9,30: 7,35: 6,40: 5,45: 5,50: 4,55: 3,60: 3,65: 2,70: 2,75: 1,80: 1,85: 1,90: 1}, 80: {10: 19,15: 14,20: 11,25: 9,30: 8,35: 7,40: 6,45: 5,50: 4,55: 4,60: 3,65: 3,70: 2,75: 2,80: 1,85: 1,90: 1}, 85: {10: 21,15: 14,20: 11,25: 10,30: 8,35: 7,40: 6,45: 6,50: 5,55: 4,60: 4,65: 3,70: 3,75: 2,80: 2,85: 1,90: 1}, 90: {10: 23,15: 15,20: 12,25: 10,30: 9,35: 8,40: 7,45: 6,50: 5,55: 5,60: 4,65: 3,70: 3,75: 3,80: 2,85: 2,90: 1}}) xv, yv = np.meshgrid(df.index, df.columns) ma = np.nanmax(df.values) norm = matplotlib.colors.Normalize(vmin = 0, vmax = ma, clip = True) fig = plt.figure(1) ax = Axes3D(fig) surf = ax.plot_surface(yv,xv,df, cmap='viridis_r', linewidth=0.3, alpha = 0.8, edgecolor = 'k', norm=norm) p = Circle((25, 35), 3, ec='k', fc="none") ax.add_patch(p) art3d.pathpatch_2d_to_3d(p, z=4, zdir="z") plt.show()