 # Plotting and Viewing 3D Bars on a 3D Surface

Hi all. I would like to plot 3D visualisations (bars, contours, etc) on top of a 3D surface.

In my case, the surface is a football pitch, but I have heavily simplified the code to just show a green surface (where all z-values are 0) and some 3D bars which all shoot upwards from z=0.

The problem: the bars are invisible from most angles, as Matplotlib is prioritising the surface/collection over the bars (apologies if I’m mixing up technical terms!). I have tried playing around with zorder values, but to no avail.

After a lot of googling, I eventually found an FAQ page which appears to confirm my fear that what I want to achieve is not yet possible in Matplotlib, but as I have invested so much time and effort into this project and was otherwise extremely happy with how the finished product was looking: is there any way this can be done? Thanks so much for any responses • Simplified code is below, along with an image showing only a portion of the bars that are near the edge, when there should be more. I tried attaching another image but as a new user it won’t let me.

• What the real thing would normally look like is here, for those that are interested! https://twitter.com/DymondFormation/status/1361367676451487745

import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.art3d as art3d
%matplotlib notebook

fig = plt.figure()
ax = fig.gca(projection=‘3d’)
ax.set_facecolor(‘black’)

# plotting a surface

grass_x = [-40, -40, 40, 40]
grass_y = [-60, 60, 60, -60]
grass_z = [0, 0, 0, 0]
grass_verts = [list(zip(grass_x, grass_y, grass_z))]
grass = art3d.Poly3DCollection(grass_verts, color=‘green’, lw=1, alpha=1, zorder=1)

# plotting 50 bars in random places

num = 50
x = np.random.uniform(low=-40, high=40, size=(num,))
y = np.random.uniform(low=-60, high=60, size=(num,))
z = *num
dx = *num
dy = *num
dz = np.random.uniform(low=0.3, high=5, size=(num,))
ax.bar3d(x, y, z, dx, dy, dz, shade=True, zorder=200, color=‘white’)

ax.set_xlim(-45, 45)
ax.set_ylim(-45, 45)
ax.set_zlim(-10, 10)
ax.set_axis_off() “After a lot of googling, I eventually found an FAQ page…”

Apologies - meant to link to the FAQ page here: mplot3d FAQ — Matplotlib 2.2.2 documentation

It looks like your grass is at `z=0`; I wonder if using the Axis panes would work? So instead of `ax.set_axis_off`, change the z pane to green with `ax.zaxis.set-pane_color` (and make the others transparent):

``````ax.xaxis.set_pane_color((0, 0, 0, 0))
ax.yaxis.set_pane_color((0, 0, 0, 0))
ax.zaxis.set_pane_color(mcolors.to_rgba('green'))
ax.grid(False)
ax.set_zlim(0, -10)
``````

For some reason, `.set_pane_color` only accepts an RGBA tuple, so you can’t pass `'green'` directly.