Как строить трехмерные графики

Следующим шагом мы с вами рассмотрим возможности построения трехмерных графиков в пакете matplotlib. Такая возможность появилась, начиная с версии 0.99, поэтому убедитесь, что ваш пакет поддерживает трехмерные графики.

Все дополнительные классы для работы в 3D находятся в модуле:

mpl_toolkits.mplot3d

и вначале мы его импортируем в нашу программу наряду с самим пакетом matplotlib и numpy:

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

А, затем, создадим трехмерную систему координат:

fig = plt.figure(figsize=(7, 4))
ax_3d = Axes3D(fig)
 
plt.show()

При выполнении этой простой программы, мы в окне увидим три пространственные оси, которые можно вращать с помощью курсора мышки:

Того же самого результат можно добиться, используя параметр projection при создании системы координат:

fig = plt.figure(figsize=(7, 4))
ax_3d = fig.add_subplot(projection='3d')

Как именно создавать трехмерные оси, зависит от вашего выбора и удобства при написании конкретных программ. Я остановлюсь на втором способе.

После создания координатных осей мы можем в них строить двумерные и трехмерные графики с помощью того же самого набора функций:

  • plot() – линейный 2D график в трех измерениях;
  • step() – ступенчатый 2D график в трех измерениях;
  • scatter() – точеный график 3D график.

Также нам становятся доступными следующие дополнительные функции:

  • plot_wireframe() – построение каркасной поверхности в 3D;
  • plot_surface() – построение непрерывной 3D поверхности.

Начнем с самого простого варианта – функции plot() для рисования косинусоиды в трех измерениях:

x = np.linspace(0, 10, 50)
z = np.cos(x)
ax_3d.plot(x, x, z)

То есть, мы здесь по координатам x, y выбираем одни и те же значения, а координата z (вертикаль) – это значение функции. Давайте подпишем оси, чтобы видеть, где какая расположена на этом графике:

ax_3d.set_xlabel('x')
ax_3d.set_ylabel('y')
ax_3d.set_zlabel('z')

Но то, что мы получили, это не совсем трехмерный график. Скорее, это двумерная косинусоида в трех измерениях. Давайте построим настоящее трехмерное изображение, например, вот такой функции:

Первое, что нам здесь нужно сделать – это сформировать двумерную сетку координат по осям x и y:

То есть, должны быть сформированы двумерные массивы x, y, которые для текущей точки с индексами (i, j) возвращают ее координаты в плоскости xy.

Для регулярных сеток эти массивы можно сформировать следующим образом. Определим множество координат x (для столбцов) и y (для строк), например, так:

x = [1, 2, 3]
y = [2, 5, 6, 8]

А, затем, используя функцию meshgrid() сформируем регулярную сетку на основе этих данных:

xgrid, ygrid = np.meshgrid(x, y)

На выходе получим двумерные массивы со значениями:

То есть, смотрите, теперь для любой пары индексов (i, j) мы легко сможем получить координаты точки в плоскости xy:

(xgrid[1, 2], ygrid[1, 2]) = (3, 5)
(xgrid[3, 0], ygrid[3, 0]) = (1, 8)

Но зачем было так все усложнять? Почему бы не использовать одномерные массивы x, y вместо двумерных xgrid, ygrid? Дело в том, что одномерные массивы, которые описывают расположение строк и столбов, могут формировать только регулярные сетки, то есть, прямоугольные. А что, если нужно сформировать гексагональную сетку, которая выглядит, следующим образом:

Здесь уже не получится обойтись указанными одномерными массивами, а нужно прописывать узлы двумерными массивами. Именно поэтому, в общем случае, и реализовано отображение через двумерные массивы трехмерных графиков.

Итак, давайте теперь построим полноценный трехмерный график синусоиды на регулярной сетке. Для этого мы сначала сформируем координаты узлов в плоскости xy:

x = np.arange(-2*np.pi, 2*np.pi, 0.2)
y = np.arange(-2*np.pi, 2*np.pi, 0.2)
xgrid, ygrid = np.meshgrid(x, y)

А, затем, вычислим значения синусоиды в этих узлах:

zgrid = np.sin(xgrid) * np.sin(ygrid) / (xgrid * ygrid)

Если для вывода такого графика воспользоваться функцией plot_wireframe():

ax_3d.plot_wireframe(xgrid, ygrid, zgrid)

то результат будет следующий:

Как видите, мы получили полноценный каркасный трехмерный график синусоиды. Или же можно построить полноценную поверхность в виде синусоиды, используя функцию plot_surface():

ax_3d.plot_surface(xgrid, ygrid, zgrid)

Фактически, только этим две эти функции и отличаются друг от друга: первая строит 3D-каркас, а вторая 3D-поверхность.

У этих функций есть следующие параметры для настройки внешнего вида графика:

Параметр

Описание

x, y, z

2D массивы для построения трехмерных графиков.

rcount, ccount

Максимальное число элементов каркаса по координатам x и y (по умолчанию 50).

rstride, cstride

Величина шага, с которым будут выбираться элементы из массивов x, y (параметры rstride, cstride и rcount, ccount – взаимоисключающие).

color

Цвет графика

cmap

Цветовая карта графика

Например, если установить параметры:

ax_3d.plot_surface(xgrid, ygrid, zgrid, rstride=5, cstride=5, cmap='plasma')

то получим следующий вид нашей синусоиды:

В заключение этого занятия приведу пример построения этого же графика набором точек, используя функцию scatter():

ax_3d.scatter(xgrid, ygrid, zgrid, s=1, color='g')

Увидим следующий результат:

Вот так в базовом варианте можно выполнять построения трехмерных графиков в пакете matplotlib. Этой информации достаточно для большинства прикладных задач. Ну а если потребуется реализовать что-то особенное, тогда прямой путь к документации:

https://matplotlib.org/stable/api/_as_gen/mpl_toolkits.mplot3d.axes3d.Axes3D.html