3

I have a 3D scene created with Matplotlib and I would like to apply a chessboard like pattern on the bottom plane in the image below. Do you have any idea how to achieve this?

enter image description here

Here is the code to create this image:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# Create figure
plt.style.use('dark_background') # Dark theme
fig = plt.figure(frameon=False)
ax = fig.add_subplot(111, projection='3d')

# Make panes transparent
ax.xaxis.pane.fill = False # Left pane
ax.yaxis.pane.fill = False # Right pane
# ax.zaxis.pane.fill = False # Bottom pane

# Remove grid lines
ax.grid(False)

# Remove tick labels
ax.set_xticklabels([])
ax.set_yticklabels([])
ax.set_zticklabels([])

# Random data to illustrate
zdata = 15 * np.random.random(100)
xdata = np.sin(zdata) + 0.1 * np.random.randn(100)
ydata = np.cos(zdata) + 0.1 * np.random.randn(100)
ax.scatter3D(xdata, ydata, zdata, c=zdata, cmap='Greens')

# Print chart
file_path = 'charts/3d.png'
fig.savefig(file_path, bbox_inches='tight', pad_inches=0.05, transparent=True)
Alexis.Rolland
  • 5,724
  • 6
  • 50
  • 77

1 Answers1

2

You can generate a grid of rectangles and use pathpatch_2d_to_3d function from mpl_toolkits.mplot3d.art3d to insert then into the 3d scene:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

from matplotlib.patches import Rectangle
import mpl_toolkits.mplot3d.art3d as art3d

# Create figure
plt.style.use('dark_background') # Dark theme
fig = plt.figure(frameon=False)
ax = fig.add_subplot(111, projection='3d')

# Make planes transparent
ax.xaxis.pane.fill = False # Left plane
ax.yaxis.pane.fill = False # Right plane
# ax.zaxis.pane.fill = False # Horizontal plane

# Remove grid lines
ax.grid(False)

# Remove tick labels
ax.set_xticklabels([])
ax.set_yticklabels([])
ax.set_zticklabels([])

# Draw chessboard on hortizontal plane
for x_index, x in enumerate(np.arange(-1, 1.1, 0.2)):
    for y_index, y in enumerate(np.arange(-1, 1.1, 0.2)):
        if (x_index+y_index)%2:
            p = Rectangle([x,y], 0.2, 0.2)
            ax.add_patch(p)
            art3d.pathpatch_2d_to_3d(p, z=0, zdir="z")

ax.set(xlim=(-1,1.1), ylim=(-1,1.2), zlim=(0,15))

# Random data to illustrate
zdata = 15 * np.random.random(100)
xdata = np.sin(zdata) + 0.1 * np.random.randn(100)
ydata = np.cos(zdata) + 0.1 * np.random.randn(100)
ax.scatter3D(xdata, ydata, zdata, c=zdata, cmap='Greens')

# Print chart
file_path = 'charts/3d.png'
fig.savefig(file_path, bbox_inches='tight', pad_inches=0.05, transparent=True)

enter image description here


EDIT: cleaner version

RECT_SIZE_X = 0.2
RECT_SIZE_Y = 0.2
xlims = (-1, 1)
ylims = (-1, 1)

for x_index, x_pos in enumerate(np.arange(xlims[0], xlims[1], RECT_SIZE_X)):
    for y_index, y_pos in enumerate(np.arange(ylims[0], ylims[1], RECT_SIZE_Y)):
        if (x_index+y_index)%2:
            p = Rectangle([x_pos, y_pos], RECT_SIZE_X, RECT_SIZE_Y, color='orange')
        else:
            p = Rectangle([x_pos, y_pos], RECT_SIZE_X, RECT_SIZE_Y, color='gray')
        ax.add_patch(p)
        art3d.pathpatch_2d_to_3d(p, z=0, zdir="z")

ax.set(xlim=xlims, ylim=ylims, zlim=(0,15))
# Transparent spines
ax.w_xaxis.line.set_color((1.0, 1.0, 1.0, 0.0))
ax.w_yaxis.line.set_color((1.0, 1.0, 1.0, 0.0))
ax.w_zaxis.line.set_color((1.0, 1.0, 1.0, 0.0))

# Transparent panes
ax.w_xaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
ax.w_yaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
ax.w_zaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))

# No ticks
ax.set_xticks([]) 
ax.set_yticks([]) 
ax.set_zticks([])

enter image description here

Andrea
  • 2,932
  • 11
  • 23
  • 1
    Beautiful! Thank you so much, I will try that! – Alexis.Rolland Jan 22 '20 at 11:43
  • it seems the last line triggers an error in your code snippet `ax.set(xlim=(-1,1.1), ylim=(-1,1.2), zlim=(0,15))` returns `SyntaxError: invalid syntax` – Alexis.Rolland Jan 22 '20 at 12:29
  • 1
    I found the issue, adding one extra line after the for loop fixes it on my side – Alexis.Rolland Jan 22 '20 at 12:41
  • since you seem gifted with matplotlib, would you have any idea how to do this one? https://stackoverflow.com/questions/59857203/remove-border-from-matplotlib-3d-pane/59857277 – Alexis.Rolland Jan 22 '20 at 12:45
  • Sure, here you have it :) – Andrea Jan 22 '20 at 13:17
  • One more question if it's not too much asking... would you mind explaining the nested for loops? I understand they are used to compute the rectangles and their coordinates but I am not clear on the choice of the hard coded values you have used. – Alexis.Rolland Jan 22 '20 at 14:07
  • 1
    I admit I did not think about it much, I just made a checkboard and then adjusted the x and y lims to make it work. I added a cleaner version of the code, it should be more self-explanatory, but ask if you have doubts. ps. If you leave there the plane, there is a small mismatch in the axis limits that I don't fully understand and handmade ad-hoc adjustments might be needed – Andrea Jan 22 '20 at 14:39
  • [Here](https://stackoverflow.com/questions/16488182/removing-axes-margins-in-3d-plot) a possible workaround for the mismatch, but I would not use it. It seems like a matplotlib problem and they might want to patch this behavior in the future. – Andrea Jan 22 '20 at 15:00
  • It’s precisely because of the small mismatch / offset in the previous version which I was asking to clarify. Your workaround looks good enough to me. Thanks!! – Alexis.Rolland Jan 23 '20 at 00:15