Skip to content Skip to sidebar Skip to footer

Matplotlib Surface Plot Hides Scatter Points Which Should Be In Front

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

Solution 1:

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.

an example of "there I fixed it"

The modified code is:

importpandasaspdimportmatplotlibimportmatplotlib.pyplotaspltfrommpl_toolkits.mplot3dimportAxes3D,art3dfrommatplotlib.patchesimportCircleimportnumpyasnpdf=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()

Solution 2:

Run into this problem in 2020 and do not want to switch to another package. This solution is a modification of Will's answer above. Basically draw the circle in three axis to make it more like a dot. Also use ellipse to adjust for axis ratios. Works better if you set the radius smaller and choose a face color:

enter image description here

   def add_point(ax, x, y, z, fc = None, ec = None, radius = 0.005):
       xy_len, z_len = ax.get_figure().get_size_inches()
       axis_length = [x[1] - x[0] for x in [ax.get_xbound(), ax.get_ybound(), ax.get_zbound()]]
       axis_rotation =  {'z': ((x, y, z), axis_length[1]/axis_length[0]),
                         'y': ((x, z, y), axis_length[2]/axis_length[0]*xy_len/z_len),
                         'x': ((y, z, x), axis_length[2]/axis_length[1]*xy_len/z_len)}
       for a, ((x0, y0, z0), ratio) in axis_rotation.items():
           p = Ellipse((x0, y0), width = radius, height = radius*ratio, fc=fc, ec=ec)
           ax.add_patch(p)
           art3d.pathpatch_2d_to_3d(p, z=z0, zdir=a)

where radius is the radius of the "circle", fc is the face color, ec is the edge color.

The modified code:

importpandasaspdimportmatplotlibimportmatplotlib.pyplotaspltfrommpl_toolkits.mplot3dimportAxes3D,art3dfrommatplotlib.patchesimportCircle,Ellipseimportnumpyasnpdf=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)add_point(ax,25,35,0,radius=1)add_point(ax,25,35,2,radius=2)add_point(ax,25,35,4,radius=3)plt.show()

Post a Comment for "Matplotlib Surface Plot Hides Scatter Points Which Should Be In Front"