Сегодня мы поговорим про то, как построить математический график при помощи языка 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() Запустив его, мы получим такой результат:
Поиграйтесь сами и посмотрите, какие удивительные параметрические кривые можно создать!
С некоторыми модификациями данный скрипт также можно использовать и для построения двумерных параметрических кривых.
Например, давайте построим двумерный график, полученный путем оценки выражения 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».
Если вы ищете работу на Python, на Talanto.work сейчас есть варианты для junior, middle, senior…
Рынок Python-вакансий большой, но удобным его назвать сложно. Формально вакансий много, однако в реальном поиске…
Срезы в Python — это больше, чем a[2:7]. В статье — быстрый разбор полезных приёмов:…
В этой статье мы рассмотрим возведение в степень в Python с помощью различных методов, от…
Дубликаты в списке Python — частая проблема. В статье показано, как быстро убрать повторы, в…
Услуга виртуального хостинга на SpaceWeb позволяет арендовать часть сервера (shared-сервера) и разместить на нём свой…