Gaussian fit: find the X values for a given Y - python

I did the best fit for my Gaussian curve with Python. Once I have the best fit curve, I would like to know for a given Y value, the correspondent X values.
Since it is a Gaussian curve, I should have two values of X for a given Y ( less than the max value of Y).
How could I do it on Python?
Thank you

Let's take for instance your Gaussian : g(x) = a * exp(-(x - x0) ** 2 / (2 * sigma ** 2)) with a, x0 and sigma being your found parameters from the fit.
And now you want to find y such as y = g(x)
<=> y = a * exp(-(x - x0) ** 2 / (2 * sigma ** 2))
<=> ln|y/a| = -(x - x0) ** 2 / (2 * sigma ** 2))
<=> - ln|y/a| * (2 * sigma ** 2)) =(x - x0) ** 2
<=> sqrt(- ln|y/a| * (2 * sigma ** 2))) = +/- (x - x0)
<=> x = +/- (x0 + sqrt(- ln|y/a| * (2 * sigma ** 2))))
Then, you can use:
def inv_gaus(y, a, x0, sigma):
x = x0 + np.sqrt(-2 * np.log(y / a) * sigma ** 2)
return -x, x
And therefore you have 2 x for one y :)

Related

Find the domain of x and y from the intersection line of two surfaces

I have two point cloud and I use scipy.optimize.curve_fit to get the equations representing two surfaces:
z1 = F1(x, y) = (A1 * x ** 2) + (B1 * y ** 2) + (C1 * x * y) + (D1 * x) + (E1 * y) + F1
z2 = F2(x, y) = (A2 * x ** 2) + (B2 * y ** 2) + (C2 * x * y) + (D2 * x) + (E2 * y) + F2
And the equation of their intersection line is:
MY GOAL: Find the domain of x and y
For example: if x0 is in the domain of the intersection line, what is the range of y corresponding to x0?
I have tried some methods with sympy or scipy, but cannot get the domian.

Equilibria of complex non linear system

When i run the following code i get
TypeError: can't multiply sequence by non-int of type "Add'
Can anyone explain why I get this error?
from sympy.core.symbol import symbols
from sympy.solvers.solveset import nonlinsolve
x, y, z, r, R, a, m, n, b, k1, k2 = symbols('x,y,z,r,R,a,m,n,b,k1,k2', positive=True)
f1 = r * x * (1 - x / k1) - (a * z * x ** (n + 1)) / (x ** n + y ** n)
f2 = R * y * (1 - y / k2) - (b * z * y ** (n + 1)) / (x ** n + y ** n)
f3 = z * (a * x ** (n + 1) + b * y ** (n + 1)) / (x ** n + y ** n) - m * z
f = [f1, f2, f3]
nonlinsolve(f, [x, y, z])
The error message is not really descriptive but the full stack trace indicates where the problem was: SymPy tries to work with the expression as if it was a polynomial, and finds that impossible because the exponent n is a symbol rather than a concrete integer.
Simply put, SymPy does not have an algorithm for solving systems like that one (and I'm not sure if any CAS has).
When written in polynomial form, the system has monomials of total degree n+2. So, already for n = 1 this is utterly hopeless: a system of three cubic equations with three unknowns. SymPy can solve the case n = 0, and I wouldn't expect anything more than that.

Python error: operands could not be broadcast together with shapes

I'm going to do 2D Gaussian fit in Python 3 by:
def gaussian_fit_2_d(data, amplitude, x0, y0, sigma_x, sigma_y, theta, offset):
x0 = np.float64(x0)
y0 = np.float64(y0)
a = (np.cos(theta) ** 2) / (2 * sigma_x ** 2) + (np.sin(theta) ** 2) / (2 * sigma_y ** 2)
b = -np.sin(2 * theta) / (4 * sigma_x ** 2) + np.sin(2 * theta) / (4 * sigma_y ** 2)
c = (np.sin(theta) ** 2) / (2 * sigma_x ** 2) + (np.cos(theta) ** 2) / (2 * sigma_y ** 2)
x = data["x"]
y = data["y"]
f = offset + amplitude * np.exp(-((a * (x - x0)) ** 2 + 2 * b * (x - x0) * (y - y0) + c * (y - y0) ** 2))
return f.ravel()
image = sio.loadmat("File Name")
intensity = np.float64(np. array(image["p1"]))
data_size = intensity.shape
x = np.arange(0, data_size[1])
y = np.arange(0, data_size[0])
# print(data_size)
# print(x)
[X, Y] = np.meshgrid(x, y)
data = {"x": X, "y": Y}
popt, pcov = opt.curve_fit(gaussian_fit_2_d, data, intensity)
,but in the last line I got the following error:
ValueError: operands could not be broadcast together with shapes
(1558,) (41,38)
any idea?

using fsolve to find the solution

import numpy as np
from scipy.optimize import fsolve
musun = 132712000000
T = 365.25 * 86400 * 2 / 3
e = 581.2392124070273
def f(x):
return ((T * musun ** 2 / (2 * np.pi)) ** (1 / 3) * np.sqrt(1 - x ** 2)
- np.sqrt(.5 * musun ** 2 / e * (1 - x ** 2)))
x = fsolve(f, 0.01)
f(x)
print x
What is wrong with this code? It seems to not work.
Because sqrt returns NaN for negative argument, your function f(x) is not calculable for all real x. I changed your function to use numpy.emath.sqrt() which can output complex values when the argument < 0, and returns the absolute value of the expression.
import numpy as np
from scipy.optimize import fsolve
sqrt = np.emath.sqrt
musun = 132712000000
T = 365.25 * 86400 * 2 / 3
e = 581.2392124070273
def f(x):
return np.abs((T * musun ** 2 / (2 * np.pi)) ** (1 / 3) * sqrt(1 - x ** 2)
- sqrt(.5 * musun ** 2 / e * (1 - x ** 2)))
x = fsolve(f, 0.01)
x, f(x)
Then you can get the right result:
(array([ 1.]), array([ 121341.22302275]))
the solution is very close to the true root, but f(x) is still very large because f(x) has a very large factor: musun.
fsolve() returns the roots of f(x) = 0 (see here).
When I plotted the values of f(x) for x in the range -1 to 1, I found that there are roots at x = -1 and x = 1. However, if x > 1 or x < -1, both of the sqrt() functions will be passed a negative argument, which causes the error invalid value encountered in sqrt.
It doesn't surprise me that fsolve() fails to find roots that are at the very ends of the valid range for the function.
I find that it is always a good idea to plot the graph of a function before trying to find its roots, as that can indicate how likely (or in this case, unlikely) it is that the roots will be found by any root-finding algorithm.

Matplotlib contour isn't working

I'm trying to plot the batman equation. A solution in sympy or matplotlib will be great (sage isn't cool because I'm using windows). The problem is that if I comment out certain parts the part of the figure appears but with all the F *= parts, I get a blank plot.
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
from numpy import sqrt
from numpy import real
delta = 0.01
xrange = arange(-7.0, 7.0, delta)
yrange = arange(-3.0, 3.0, delta)
x, y = meshgrid(xrange,yrange)
F = 1
F *= (((x/7) ** 2) * sqrt(abs(abs(x) - 3)/(abs(x) - 3)) + ((y / 3) ** 2) * sqrt(abs(y + (3 * sqrt(33)) / 7)/(y + (3 * sqrt(33)) / 7)) - 1)
F *= (abs(x/2) - ((3 * sqrt(33) - 7)/112) * x**2 - 3 + sqrt(1 - (abs(abs(x) - 2) - 1) ** 2 ) - y)
F *= (9 * sqrt(abs((abs(x) - 1) * (abs(x) - 3/4))/((1 - abs(x)) * (abs(x) - 3/4))) - 8 * abs(x) - y)
F *= (3 * abs(x) + 0.75 * sqrt(abs((abs(x) - 3/4) * (abs(x) - 1/2))/((3/4 - abs(x)) * (abs(x) - 1/2))) - y)
F *= ((9/4) * sqrt(abs((x - 1/2) * (x + 1/2))/((1/2 - x) * (1/2 + x))) - y)
F *= ((6 * sqrt(10)) / 7 + (3/2 - abs(x)/2) * sqrt(abs(abs(x) - 1)/(abs(x) - 1)) - ((6 * sqrt(10))/ 14) * sqrt(4 - (abs(x) - 1) ** 2 ) - y)
G = 0
matplotlib.pyplot.contour(x, y, (F - G), [0])
matplotlib.pyplot.show()
What's going on here? If the graph is zero for one multiplicand, it should still be so no matter which other multiplicands I throw in there.
source of the batman equation: http://www.reddit.com/r/pics/comments/j2qjc/do_you_like_batman_do_you_like_math_my_math/
The parameter of sqrt is negative for many points, so the finally products are all NaN. You can plot every factor as following:
from __future__ import division # this is important, otherwise 1/2 will be 0
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
from numpy import sqrt
from numpy import real
delta = 0.01
xrange = arange(-7.0, 7.0, delta)
yrange = arange(-3.0, 3.0, delta)
x, y = meshgrid(xrange,yrange)
F1 = (((x/7) ** 2) * sqrt(abs(abs(x) - 3)/(abs(x) - 3)) + ((y / 3) ** 2) * sqrt(abs(y + (3 * sqrt(33)) / 7)/(y + (3 * sqrt(33)) / 7)) - 1)
F2 = (abs(x/2) - ((3 * sqrt(33) - 7)/112) * x**2 - 3 + sqrt(1 - (abs(abs(x) - 2) - 1) ** 2 ) - y)
F3 = (9 * sqrt(abs((abs(x) - 1) * (abs(x) - 3/4))/((1 - abs(x)) * (abs(x) - 3/4))) - 8 * abs(x) - y)
F4 = (3 * abs(x) + 0.75 * sqrt(abs((abs(x) - 3/4) * (abs(x) - 1/2))/((3/4 - abs(x)) * (abs(x) - 1/2))) - y)
F5 = ((9/4) * sqrt(abs((x - 1/2) * (x + 1/2))/((1/2 - x) * (1/2 + x))) - y)
F6 = ((6 * sqrt(10)) / 7 + (3/2 - abs(x)/2) * sqrt(abs(abs(x) - 1)/(abs(x) - 1)) - ((6 * sqrt(10))/ 14) * sqrt(4 - (abs(x) - 1) ** 2 ) - y)
for f in [F1,F2,F3,F4,F5,F6]:
matplotlib.pyplot.contour(x, y, f, [0])
matplotlib.pyplot.show()
the result plot:
I know this might seem lame, but how about creating a list of x values, and then computing the value of "batman" at each of those positions, and storing in another list. You could define a function "batman" which computes the y value for each x value you pass in.
Then just plot those lists with matplotlib.
EDIT: Since you've made numpy arrays already to store the results, you could use those when computing the y values.
I'm not even sure how this equation would work, since I see divisions by zero arising in the first term (under the first square root, when abs(x) = 3), and imaginary numbers showing up in the last term (under the last square root, when {abs(x)-1}^2 > 4, ie x > 3 or x < -3).
What am I missing here? Is only the real part of the result used, and are divisions by zero ignored or approximated?
Running this, I do indeed see lots of RunTimeWarnings, and it is not unlikely matplotlib would get totally confused what numbers to work with (NaNs, Infs; trying print F at the end). Looks like it still manages when there's only a relatively low number of NaNs or Infs, which would explain that you're seeing part of the figure.
I'd think matplotlib's contour is fine, just confused by the input.

Categories

Resources