2025, Sep 20 10:02

Сфера в Python: как обойти ошибку Matplotlib Input z must be 2D

Почему Matplotlib выдаёт Input z must be 2D при построении сферы в Python, и как это исправить: два подхода — 3D-скаттер для поля и параметрическая поверхность.

Построить сферу в Python кажется простым, пока не упираешься в неподходящее API. Часто начинают с вычисления F = x^2 + y^2 + z^2 − 9 на 3D‑сетке и пытаются отдать это в Matplotlib для построения контуров. Сразу всплывает ошибка: “Input z must be 2D.” Причина и тонкая, и очевидная: contour ожидает двумерные массивы; трёхмерные объёмы он не принимает. Разберёмся, что происходит, и покажем два рабочих способа визуализации — сначала как скалярного поля на 3D‑решётке, а затем как настоящей поверхности сферы.

Пример кода

Первый фрагмент визуализирует скалярное поле G = U^2 + V^2 + W^2 − 9 на регулярной 3D‑сетке, где цветом показано значение G в каждой точке. Второй фрагмент строит настоящую трёхмерную поверхность сферы через сферические координаты и отображает её.

import numpy as np
import matplotlib.pyplot as plt

# Скалярное поле на 3D‑сетке (G = U^2 + V^2 + W^2 - 9)
a = np.linspace(-5.0, 5.0, 10)
b = np.linspace(-5.0, 5.0, 10)
c = np.linspace(-5.0, 5.0, 10)

AA, BB, CC = np.meshgrid(a, b, c)
G = AA**2 + BB**2 + CC**2 - 9

fig1, axes1 = plt.subplots(subplot_kw={"projection": "3d"})
axes1.scatter3D(AA, BB, CC, c=G)
axes1.set_xlabel("X")
axes1.set_ylabel("Y")
axes1.set_zlabel("Z")
plt.show()
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# Параметрическая сфера через сферические координаты
fig2 = plt.figure()
axes2 = fig2.add_subplot(projection='3d')

r = 3
phi_vals = np.linspace(0, np.pi, 1000)
theta_vals = np.linspace(0, 2 * np.pi, 1000)
TH, PH = np.meshgrid(theta_vals, phi_vals)

XS = r * np.sin(PH) * np.cos(TH)
YS = r * np.sin(PH) * np.sin(TH)
ZS = r * np.cos(PH)

axes2.plot_surface(XS, YS, ZS, alpha=0.3)
axes2.contour(XS, YS, ZS)
axes2.set_xlabel('X-axis')
axes2.set_ylabel('Y-axis')
axes2.set_zlabel('Z-axis')
axes2.set_title('3D Sphere: $x^2 + y^2 + z^2 = 9$')
plt.show()

В чём реальная проблема

Выражение F = X**2 + Y**2 + Z**2 − 9, вычисленное на трёхмерной сетке, даёт скалярное поле в объёме, а не поверхность. То есть вы задаёте значения в каждой точке пространственного куба. Ошибка Matplotlib “Input z must be 2D” говорит прямо: contour ожидает двумерные входы — поверхность над X и Y с высотами Z. Передача 3D‑массивов по определению приводит к сбою. Поэтому вызов ax.contour(X, Y, Z, F) здесь не сработает: входные данные объёмные.

Проще говоря, у вас поле, которое удобнее показывать раскраской точек в 3D‑пространстве по их скалярным значениям — именно это делает метод scatter. Как показано в рабочем примере выше, такая картинка ближе к визуализации «четырёхмерного куба» (три пространственные оси плюс скаляр в цвете), чем к поверхности сферы.

Рабочие решения

Если нужно увидеть именно поле, используйте трёхмерный scatter и раскраску по скаляру. Это сохраняет исходный замысел: считать формулу на сетке и смотреть значения через цвет. Для более гладкой картинки аккуратно увеличивайте разрешение — слишком крупные сетки быстро съедают память.

Если цель — сама поверхность сферы, заданная x^2 + y^2 + z^2 = 9, перейдите к сферическим координатам, получите x, y, z из углов и радиуса и постройте параметрическую поверхность. Так получится аккуратная 3D‑сфера. Для выразительности можно добавить контуры по поверхности, как в примере.

Почему это важно

Выбор подходящего API для графики зависит от того, какой математический объект вы хотите показать. Объёмное скалярное поле и 3D‑поверхность — вещи разные и требуют разных стратегий. Путаница приводит к непонятным ошибкам и потере времени, особенно в 3D, где легко упереться в память и производительность. Понимание того, что contour ждёт 2D‑входы, избавляет от попыток кормить 3D‑массивы функции для двумерных данных.

Выводы

Когда вы считаете F = x^2 + y^2 + z^2 − 9 на 3D‑сетке, получается объёмное скалярное поле. Исследуйте его через трёхмерный scatter и раскраску по значениям. Когда нужна именно сфера, параметризуйте её сферическими координатами и отрисуйте поверхность. Держите размер сетки в разумных пределах — пересэмплинг быстро бьёт по памяти — и выбирайте метод, соответствующий задаче. При таком разделении и поле, и сфера визуализируются без лишних трудностей.

Статья основана на вопросе с StackOverflow от Nemelis и ответе от ThomasIsCoding.