Как построить нулевой контур с допуском, указанным в Python? - PullRequest
0 голосов
/ 25 июня 2018

Я все еще изучаю Python / Matplotlib, поэтому, пожалуйста, потерпите меня.

У меня есть сложная функция foo(x,y) с двумя входными аргументами x и y.Я хочу построить нулевой контур этой функции foo.Я создал сетку в необходимом диапазоне, используя numpy.meshgrid, и попытался построить нулевой контур, используя команду plt.contour(X,Y,Z,levels=[0]).Это вернуло мне предупреждение: No contour levels were found within the data range.Я думаю, это потому, что функция оценивается по дискретному набору значений, где она точно никогда ноль, следовательно, нет контура.

Поэтому я хочу указать допуск для этого нуля.Может кто-нибудь предложить мне способ?Большое спасибо!

Ответы [ 2 ]

0 голосов
/ 26 июня 2018

Возможно, у вас другой подход, вы уже слышали о sympy? Это возможность делать символическую математику в Python (как с Mathematica или Maple).

После импорта

from sympy import *

Вы можете определять символы и применять их к переменным Python

x, y = symbols('x y')

Тогда вы можете определить выражения, которые описывают функции этих символов

f = (x - .5)**2 * (y - .5)**2

И поиск пересечения / касания нуля был бы нелинейной решающей задачей

result = nonlinsolve([f], [x, y])

result
{(0.499999999999937, y), (0.500000000000057, y), (x, 0.499999999999937), (x, 0.500000000000057)}

Очевидно, что у него все еще есть ошибка вычислительного покоя - но, по крайней мере, нет большой области артефакта, как в случае с plt.contour (...).

И, тем не менее, вы искали решение, которое возвращает некоторую терпимость, и результат можно интерпретировать следующим образом.

Существует даже функция, с помощью которой вы можете снова преобразовать эти результаты с помощью числовых выражений в массивы доступных для печати данных, она называется lambdify.
Однако этот следует использовать с осторожностью , так как он использует eval внутри, что может привести к произвольному коду, если вы не знаете источник выражения, введенного в него.

plt.figure()
numX = np.linspace(-1, 1, 1001)
numY = np.linspace(-1, 1, 1001)
for r in result:
    fx = lambdify(x, r[0], "numpy")
    fy = lambdify(y, r[1], "numpy")
    x_val = fx(numX)
    y_val = fy(numY)
    if np.shape(x_val) != np.shape(y_val):
        if len(np.shape(x_val)) < 1:
            x_val = np.ones(len(y_val)) * x_val
        else:
            y_val = np.ones(len(x_val)) * y_val
    plt.plot(x_val, y_val)

Это не слишком гладко, но это работает и приводит к такому результату, который является правильным для моей примерной функции: enter image description here

0 голосов
/ 25 июня 2018

Конечно, это зависит от вашей функции, но это , а не из-за отсутствия сетки. Точка вычисляется точно в ноль (фактически это сделает этот график совершенно бесполезным ...)

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

Подумайте о функции

f(x,y) = (x - .5)**2 * (y - .5)**2

Это будет ноль при x = .5 и y = .5.- но вы получите то же предупреждение, о котором вы сообщили выше.Определенно с x = y = [-1, 0, 1], но даже если 0.5 включено в векторы x и y, предупреждение все еще там - даже если большая часть решения отмечена правильно на графике.

enter image description here

Посмотрите на произведение искусства на перекрестке;это связано с предупреждением.

Как только вы действительно пересечете запрошенный уровень, ноль здесь, все в порядке, просто попробуйте:

f(x,y) = (x - .5)**2 * (y - .5)**2 -1

enter image description here

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...