1

I am reading the following articles 3D animation using matplotlib. It shows the animation in 3D.

I am considering the following scenario:

  1. I have a x-y meshgrid, [1,2,...,20] X [1,2,...,20]
  2. For each point, a z-value is assigned.
  3. Based on 1. and 2., I plot the 3-D gradient graph as the following

enter image description here

Suppose I have 5 20X20 data for z values (.xlsx). Therefore, I get 5 different graphs as above.

Now, I want to plot all 5 graphs in one graph but with a slider such that when I move the slider from 1 to 5, I can get an animation (variation) of the graph but in the same meshgrid.

The code for only one graph (one data) is provided here

fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
rm = pd.read_excel("test_3d.xlsx", header = None)
rec = np.shape(rm)
X = np.arange(1,rec[1]+1,1)
Y = np.arange(1,rec[0]+1,1)
x , y = np.meshgrid(X,Y)
# Plot the surface.

surf = ax.plot_surface(x, y, rm, cmap=cm.coolwarm,
                       linewidth=0, antialiased=False)

# Customize the z axis.
ax.set_zlim(-110, -80)
ax.zaxis.set_major_locator(LinearLocator(10))
# A StrMethodFormatter is used automatically
ax.zaxis.set_major_formatter('{x:.02f}')

# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()

How to modified the code to get what I want? A hint please. Thanks!

Zephyr
  • 11,891
  • 53
  • 45
  • 80
sleeve chen
  • 221
  • 1
  • 11

1 Answers1

1

If you create an animation, the plot won't be interactive: the animation will repeat and in each frame a different surface will be shown, but you won't be able to interact with it. Since you mentioned a slider, I suppose you want an interactive plot, that will be updated after a user will change a value of a slider. This is substantially different from an animation.
Here I describe how you can set up an interactive slider.
You should create one axis for the 3D plot and another one for the slider:

ax1 = fig.add_axes([0, 0, 1, 0.8], projection = '3d')  # <-- 3D plot axis
ax2 = fig.add_axes([0.1, 0.85, 0.8, 0.1])              # <-- slider axis

Then you can crate and place the slider in the appropriate axis:

s = Slider(ax = ax2, label = 'value', valmin = 0, valmax = 5, valinit = 2)

At this moment it is necessary to define a function which will be called when a user will change the value of the slider. Inside the function the slider actual value is read, then the previous plot is erased and finally the new plot is drawn. It is convenient to fix x, y and z axes limits inside the updating function, so the frame of the plot will remain fixed and only the surface would change.
In the case below, I assume that the value defined in the slider moves up or down the surface, so inside the plot_surface I add z + value; you have to tailor this based on you needs (*).

def update(val):
    value = s.val
    ax1.cla()
    ax1.plot_surface(x, y, z + value, cmap = cm.coolwarm, linewidth = 0, antialiased = False)
    ax1.set_zlim(-2, 7)

Finally you need to link the slider to the updating function:

s.on_changed(update)

This passage is not mandatory, but I suggest to call the update function just before plt.show(); in this way the initial plot that matplotlib will show will be already coherent with the initial value expressed in the slider.

Complete Code

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.widgets import Slider

N = 100

X = np.linspace(0, 20, N)
Y = np.linspace(0, 20, N)
x, y = np.meshgrid(X, Y)
z = np.sin(x) + np.sin(y)


fig = plt.figure()

ax1 = fig.add_axes([0, 0, 1, 0.8], projection = '3d')
ax2 = fig.add_axes([0.1, 0.85, 0.8, 0.1])

s = Slider(ax = ax2, label = 'value', valmin = 0, valmax = 5, valinit = 2)

def update(val):
    value = s.val
    ax1.cla()
    ax1.plot_surface(x, y, z + value, cmap = cm.coolwarm, linewidth = 0, antialiased = False)
    ax1.set_zlim(-2, 7)

s.on_changed(update)
update(0)

plt.show()

enter image description here

(*) You mentioned:

Suppose I have 5 20X20 data for z values (.xlsx). Therefore, I get 5 different graphs as above.

So you have 5 different .xlsx files, one for each surface? In this case you have to read those files and plot them inside the update function.

Zephyr
  • 11,891
  • 53
  • 45
  • 80