Reputation: 55
I have written a script, using coordinate values from a text file to move a sphere around in space.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
from matplotlib import cm
from matplotlib import animation
import pandas as pd
df = pd.read_csv('/path/to/text/file', sep=" ", header=None)
fig = plt.figure(facecolor='black')
ax = plt.axes(projection = "3d")
u = np.linspace(0, 2*np.pi, 100)
v = np.linspace(0, np.pi, 100)
r = 4
ax.set_xlim(0, 60)
ax.set_ylim(0, 60)
ax.set_zlim(0, 60)
x0 = r * np.outer(np.cos(u), np.sin(v)) + df[1][0]
y0 = r * np.outer(np.sin(u), np.sin(v)) + df[2][0]
z0 = r * np.outer(np.ones(np.size(u)), np.cos(v)) + df[3][0]
surface_color = "tab:blue"
def init():
ax.plot_surface(x0, y0, z0, color=surface_color)
return fig,
def animate(i):
# remove previous collections
ax.collections.clear()
x = df[1][i]
y = df[2][i]
z = df[3][i]
# add the new sphere
ax.plot_surface(x, y, z, color=surface_color)
return fig,
ani = animation. FuncAnimation(fig, animate, init_func = init, frames = 500, interval = 2)
plt.show()
The code produces the error "Value error: Argument Z must be 2-dimensional" and I'm not entirely sure why or how to solve this.
Full error message:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
File "C:\Users\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 839, in callit
func(*args)
File "C:\Users\Downloads\pythonProject1\venv\lib\site-packages\matplotlib\backends\_backend_tk.py", line 141, in _on_timer
super()._on_timer()
File "C:\Users\Downloads\pythonProject1\venv\lib\site-packages\matplotlib\backend_bases.py", line 1198, in _on_timer
ret = func(*args, **kwargs)
File "C:\Users\Downloads\pythonProject1\venv\lib\site-packages\matplotlib\animation.py", line 1406, in _step
still_going = super()._step(*args)
File "C:\Users\Downloads\pythonProject1\venv\lib\site-packages\matplotlib\animation.py", line 1105, in _step
self._draw_next_frame(framedata, self._blit)
File "C:\Users\Downloads\pythonProject1\venv\lib\site-packages\matplotlib\animation.py", line 1124, in _draw_next_frame
self._draw_frame(framedata)
File "C:\Users\Downloads\pythonProject1\venv\lib\site-packages\matplotlib\animation.py", line 1718, in _draw_frame
self._drawn_artists = self._func(framedata, *self._args)
File "C:\Users\Downloads\pythonProject1\main.py", line 38, in animate
ax.plot_surface(x, y, z, color=surface_color)
File "C:\Users\Downloads\pythonProject1\venv\lib\site-packages\matplotlib\_api\deprecation.py", line 415, in wrapper
return func(*inner_args, **inner_kwargs)
File "C:\Users\Downloads\pythonProject1\venv\lib\site-packages\mpl_toolkits\mplot3d\axes3d.py", line 1581, in plot_surface
raise ValueError("Argument Z must be 2-dimensional.")
ValueError: Argument Z must be 2-dimensional.
This is exactly what it says when I run the code
Upvotes: 0
Views: 315
Reputation: 568
Edited I made a better x_grid, y_grid, not using the original x, y, but rather a regular grid between their min and max values. FIrst, x and y might have a huge dimension, making plotting very slow and heavy. Second, they are probably sparse data, with no regular distribution.
You probably need to define the data on a grid. Having X(n), Y(n), Z(n) for 3D plots is not directly usable. You need something like:
from scipy.interpolate import griddata
import numpy as np
n_cells = 100
xg = np.linspace(x.min(), x.max(), n_cells)
yg = np.linspace(y.min(), y.max(), n_cells)
x_grid, y_grid = np.meshgrid(xg, yg)
z2d = griddata((x, y), z, (x_grid, y_grid), method='linear')
ax.plot_surface(x_grid, y_grid, z2d, color=surface_color)
I cannot test it directly because I do not quite know what your x, y, z
are, but I have seen that problem before and I solved it this way.
Upvotes: 1