Сегодня мы поговорим про то, как построить математический график при помощи языка Python за 10 минут. Мы рассмотрим построение параметрических кривых в трехмерном и двумерном пространстве с использованием различных примеров.
У многих из нас со школьной скамьи остались не самые приятные воспоминания о математике. Кто-то воспринимал её как необходимое зло: сложное и скучное, но обязательное. Кто-то же отказывался понимать математику от слова совсем.
Так или иначе, но наше школьное образование было ориентировано скорее на запоминание и заучивание, а не на размышления. По большому счету не было никакой мотивации разбираться в основах математики или в том, как она на самом деле работает. Идея заключалась в том, чтобы просто узнать, какие задачи решает определенная формула, запомнить правильный набор шагов и воспроизвести все это на экзамене.
Однако математика намного обширнее и интереснее того, что мы учили в школе. Если взять, например, кинематику, можно увидеть настоящую магию математики. Кинематика известна как «геометрия движения» – это изучение взаимодействия между движущимися телами во времени. Хотя бы раз увидите такое визуальное представление математических функций — и они оживут для вас. Возможно, в тот момент вы почувствуете, что впервые понимаете их правильно.
Итак, давайте научимся самостоятельно моделировать данные и начнем писать собственные скрипты. Сегодня мы поговорим о параметрических кривых и как их строить, используя Python и такие библиотеки, как NumPy, SymPy и Matplotlib.
Построение параметрических кривых
Параметрические кривые поистине завораживают! Если говорить простым языком, параметрическую кривую можно понимать как след, оставляемый движением частицы в пространстве. Говоря более формально, этот след моделируется функцией, определяемой от интервала I до различных точек в пространстве E.
Для трехмерного случая, если x, y и z заданы как функции переменной t в I (это параметр), мы получаем уравнения x = f(t), y = g(t) и z = h(t). Оценивая каждое значение параметра t в каждом из этих уравнений, мы получаем точку p(t) = (x(t),y(t),z(t)) в пространстве. Проделав эту процедуру для значений t, меняющихся в интервале I, мы получим параметрическую кривую.
Проведя небольшое исследование, попробовав несколько моделей вручную и потратив много часов на работу над сценарием, мы нашли решение. Оно выглядит следующим образом:
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
t = sp.Symbol('t')
function_x = sp.sympify('sin(t)')
function_y = sp.sympify('cos(t)')
function_z = sp.sympify('t**2')
interval = np.arange(0, 100, 0.1)
x_values = [function_x.subs(t, value) for value in interval]
y_values = [function_y.subs(t, value) for value in interval]
z_values = [function_z.subs(t, value) for value in interval]
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection='3d')
ax.plot(x_values, y_values, z_values)
plt.show()
Приведенный выше скрипт позволяет нам генерировать графики для параметрических кривых. К примеру, вот так выглядит график параметрической спирали p(t) = (sin(t),cos(t),sqrt(t3)), для интервала от 0 до 100.

Как работает скрипт
Скрипт, который мы привели выше, использует такие библиотеки, как SymPy, NumPy и Matplotlib. Давайте разберемся со всем по порядку.
SymPy — это библиотека Python для символьной математики. Она стремится стать полнофункциональной системой компьютерной алгебры (CAS). При этом сохраняется максимально простой код (а значит, понятный и масштабируемый). Библиотека SymPy, кстати, полностью написана на Python.
NumPy — это основной пакет для научных вычислений в Python. Эта библиотека предоставляет:
- объекты многомерного массива,
- различные производные объекты (такие как маскированные массивы и матрицы)
- набор подпрограмм для быстрых операций с массивами, включая математические и логические, манипуляции с фигурами, сортировку, выборку, ввод-вывод, дискретные преобразования Фурье, основные операции линейной алгебры, основные статистические операции и случайное моделирование.
И последняя библиотека из нашего списка — Matplotlib. Это обширная библиотека для создания статических, анимированных и интерактивных визуализаций на Python.
Подготовка
Чтобы использовать перечисленные выше библиотеки в нашем скрипте, мы должны сначала установить их на свой компьютер, выполнив следующую инструкцию в терминале:
pip install numpy sympy matplotlib
Теперь, когда библиотеки установлены, мы можем импортировать их в нашу программу:
import sympy as sp import numpy as np import matplotlib.pyplot as plt
Построение графика трехмерной параметрической кривой
Символьные вычисления в SymPy выполняются с помощью символов. Переменные SymPy являются объектами класса Symbols. Выражение t = sp.Symbol('t') присваивает символ t переменной t, с которой мы теперь можем работать как с математической переменной.
Выглядит это следующим образом:
t = sp.Symbol('t')
print(t ** 2)
>>> t ^ 2
В рамках этой задачи нам нужно работать с составными выражениями, хранящимися в строке. Поэтому нам нужно сделать преобразование строки в математическое выражение понятным для SymPy. Для этого мы используем функцию sympify.sp.sympify(expression), которая преобразует параметрическое выражение в общее математическое выражение.
К примеру, наш код будет выглядеть так:
function_z = sp.sympify('t^2')
print(function_z + 2)
>>> t ^ 2 + 2
Теперь переменная function_z содержит математическое выражение t2+2.
Следующим шагом является возможность оценить параметр t внутри математического выражения. Функция subs() в SymPy позволит нам оценить выражение с заданным значением. Мы можем использовать его следующим образом: expression.subs(t, value).
Наш код будет выглядеть следующим образом:
value = function_z.subs(t, 5) print(value) >>> 5 ^ 2 = 25
Поскольку мы говорим о параметрических функциях, нас интересует оценка функции на последовательности вещественных значений в пределах интервала. Для этого мы используем функцию arange() в NumPy.
Функция np.arange(start, stop, step) создает массив NumPy со значениями в интервале (start,stop) с приращением шага, то есть мы идем от start до stop-1 с определенным шагом step.
Наш код будет выглядеть так:
interval = np.arange(0, 10, 1) print(interval) >>> array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
После создания массива интервалов нам нужно перебрать значения t и оценить каждое значение внутри функции. Для этого мы будем использовать генератор списков в Python и функцию subs() библиотеки SimPy.
О генераторах списков можно почитать в статье «Генераторы списков в Python для начинающих».
Функция subs() получает символ t (который мы сохранили в переменной t) и значение каждого из элемента в качестве параметров.
Выглядит это примерно следующим образом:
z_values = [function_z.subs(t, value) for value in interval] print(z_values) >>> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Мы повторяем эту процедуру для значений x_values и y_values и таким образом получаем массивы со значениями для построения.
Наконец, с помощью библиотеки Matplotlib мы создаем график, соответствующий нашей параметрической кривой. В трехмерном случае, чтобы указать Matplotlib, что мы хотим сделать трехмерный график, мы используем следующий оператор:
ax = plt.axes(projection='3d')
Кроме того, мы можем заменить функции и интервал на новые и получить самые разные кривые. Давайте попробуем еще раз, но с другими значениями.
Например, напишем следующий код:
function_x = sp.sympify('2*t + 10')
function_y = sp.sympify('t**2')
function_z = sp.sympify('sin(t**2) + cos(t**2)')
interval = np.arange(-5, 5, 0.05)
Запустим наш код и получим такой график:

Немного поэкспериментируем
Давайте немного поэкспериментируем с нашим кодом: попробуем различные значения и посмотрим, что получится. С помощью параметрических кривых можно создать множество фигур. Некоторые комбинации могут генерировать кривые с уникальной симметрией и красотой.
Если вы хотите поиграть со скриптом самостоятельно, можете открыть эту ссылку и заменить значения для function_x, function_y, function_z и interval.
К примеру, можно взять следующий код:
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
symbol_x = sp.Symbol('t')
function_x = sp.sympify('sin(t)')
function_y = sp.sympify('t^2+2*t')
function_z = sp.sympify('t^2')
interval = np.arange(-10, 10, 0.1)
x_values = [function_x.subs(symbol_x, value) for value in interval]
y_values = [function_y.subs(symbol_x, value) for value in interval]
z_values = [function_z.subs(symbol_x, value) for value in interval]
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection='3d')
ax.plot(x_values, y_values, z_values)
plt.show()
Запустив его, мы получим такой результат:

Поиграйтесь сами и посмотрите, какие удивительные параметрические кривые можно создать!
Построение 2D параметрических кривых
С некоторыми модификациями данный скрипт также можно использовать и для построения двумерных параметрических кривых.
Например, давайте построим двумерный график, полученный путем оценки выражения x = t − 1,6 ∗ cos(24 ∗ t) и y = t − 1,6 ∗ sin(25 ∗ t) на интервале I=[1.5,20.5].
Выглядеть это будет примерно следующим образом:

Для того, чтобы смоделировать параметрическую кривую, показанную выше, можно воспользоваться следующим скриптом:
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
t = sp.Symbol('t')
function_x = sp.sympify('t - 1.6*cos(24*t)')
function_y = sp.sympify('t - 1.6*sin(25*t)')
interval = np.arange(1.5, 20.5, 0.01)
x_values = [function_x.subs(t, value) for value in interval]
y_values = [function_y.subs(t, value) for value in interval]
plt.figure(figsize=(10, 10))
plt.plot(x_values, y_values)
plt.show()
Давайте проверим наш код с другими функциями и новым интервалом. К примеру, возьмем следующие значения:
function_x = sp.sympify('4*sin(5*t)')
function_y = sp.sympify('5*cos(3*t)')
interval = np.arange(0, 6.5, 0.001)
Запустим наш скрипт и получим следующий график:

Теперь давайте проделаем это ещё раз, но уже с новыми значениями:
function_x = sp.sympify('cos(16*t) + (cos(6*t) / 2) + (sin(10*t) / 3)')
function_y = sp.sympify('sin(16*t) + (sin(6*t) / 2) + (cos(10*t) / 3)')
interval = np.arange(0, 3.16, 0.01)
Тогда результат будет таким:

Удивительно! Не правда ли?
Построение математических функций
Как только мы закончили написание скрипта для моделирования параметрических кривых, приходит осознание, что с помощью всего нескольких строк кода мы можем создать плоттер для математических функций как в двух, так и в трех измерениях! Невероятно! Это же так удобно!
К примеру, давайте рассмотрим скрипт для построения графиков математических функций в двух и трех измерениях в интервале от a до b. То есть, консоль запросит у пользователя как функцию, так и значения a и b для интервала. Вот такой код у нас получится:
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
symbol_x = sp.Symbol('x')
symbol_y = sp.Symbol('y')
def get_vector(a, b):
return np.arange(a, b + 1, 0.1)
def plot_2d_function(function, a, b):
# Create the sympy function f(x)
f_x = sp.sympify(function)
# Create domain and image
domain_x = get_vector(a, b)
image = [f_x.subs(symbol_x, value) for value in domain_x]
# Plot the 2D function graph
fig = plt.figure(figsize=(10, 10))
plt.plot(domain_x, image)
plt.show()
def plot_3d_function(function, a, b):
# Create sympy function f(x, y)
f_xy = sp.lambdify((symbol_x, symbol_y), sp.sympify(function))
# Create domains and image
domain_x = get_vector(a, b)
domain_y = get_vector(a, b)
domain_x, domain_y = np.meshgrid(domain_x, domain_y)
image = f_xy(domain_x, domain_y)
# Plot the 3D function graph
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection='3d')
ax.plot_surface(domain_x, domain_y, image,
rstride=1, cstride=1, cmap='viridis')
plt.show()
function = input('>> Enter the function: ')
a_value = float(input('>> Enter the [a, ] value: '))
b_value = float(input('>> Enter the [, b] value: '))
if "x" and not "y" in function:
plot_2d_function(function, a_value, b_value)
elif "x" and "y" in function:
plot_3d_function(function, a_value, b_value)
else:
print("You must enter a function in terms of x and/or y")
Вы можете протестировать приведенный выше скрипт здесь. Запустите скрипт и введите свою конфигурацию функции и интервала.
Например, возьмем следующий код:
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
symbol_x = sp.Symbol('x')
symbol_y = sp.Symbol('y')
def get_vector(a, b):
return np.arange(a, b + 1, 0.1)
def plot_2d_function(function, a, b):
# Create the sympy function f(x)
f_x = sp.sympify(function)
# Create domain and image
domain_x = get_vector(a, b)
image = [f_x.subs(symbol_x, value) for value in domain_x]
# Plot the 2D function graph
fig = plt.figure(figsize=(10, 10))
plt.plot(domain_x, image)
plt.show()
def plot_3d_function(function, a, b):
# Create sympy function f(x, y)
f_xy = sp.lambdify((symbol_x, symbol_y), sp.sympify(function))
# Create domains and image
domain_x = get_vector(a, b)
domain_y = get_vector(a, b)
domain_x, domain_y = np.meshgrid(domain_x, domain_y)
image = f_xy(domain_x, domain_y)
# Plot the 3D function graph
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection='3d')
ax.plot_surface(domain_x, domain_y, image, rstride=1, cstride=1, cmap='viridis')
plt.show()
function = "x*cos(5*x)"
a_value = 0
b_value = 10
if "x" and not "y" in function:
plot_2d_function(function, a_value, b_value)
elif "x" and "y" in function:
plot_3d_function(function, a_value, b_value)
else:
print("You must enter a function in terms of x and/or y")
Запустим его и получим следующий результат:

А теперь давайте поменяем значения на следующие:
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
symbol_x = sp.Symbol('x')
symbol_y = sp.Symbol('y')
def get_vector(a, b):
return np.arange(a, b + 1, 0.1)
def plot_2d_function(function, a, b):
# Create the sympy function f(x)
f_x = sp.sympify(function)
# Create domain and image
domain_x = get_vector(a, b)
image = [f_x.subs(symbol_x, value) for value in domain_x]
# Plot the 2D function graph
fig = plt.figure(figsize=(10, 10))
plt.plot(domain_x, image)
plt.show()
def plot_3d_function(function, a, b):
# Create sympy function f(x, y)
f_xy = sp.lambdify((symbol_x, symbol_y), sp.sympify(function))
# Create domains and image
domain_x = get_vector(a, b)
domain_y = get_vector(a, b)
domain_x, domain_y = np.meshgrid(domain_x, domain_y)
image = f_xy(domain_x, domain_y)
# Plot the 3D function graph
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection='3d')
ax.plot_surface(domain_x, domain_y, image, rstride=1, cstride=1, cmap='viridis')
plt.show()
function = "x**2 + cos(y**2)"
a_value = -3
b_value = 3
if "x" and not "y" in function:
plot_2d_function(function, a_value, b_value)
elif "x" and "y" in function:
plot_3d_function(function, a_value, b_value)
else:
print("You must enter a function in terms of x and/or y")
Если мы это запустим, то получим такой график:

Заключение
Что ж, вот вы и дошли до конца этой статьи, поздравляем! Сегодня мы обсудили, как построить математический график на Python всего за 10 минут. Мы поговорили про построение различных параметрических кривых в двумерном и трёхмерном пространстве и разобрали процесс построения на примерах. Теперь вы видите, какой завораживающей на самом деле может быть математика! Кроме того, построение параметрических кривых, как вы понимаете, не такой уж и сложный процесс.
Надеемся, данная статья была вам полезна! Успехов в написании кода!
Перевод статьи «How to Plot Mathematical Functions in 10 Lines of Python».

