Calculating the centroids of two superposed gaussian functions - statistics

I am trying to find a solution to the following problem. I have a set of points which should model a sum of 2 Gaussian functions centered at different points. I need to find these two points. Up to now my approach has been to find the centroid of the whole set and cut the set of date below and above it. Then I calculate the centroid of each piece and those are my centers. This approach however cuts the information of, say, the left Gaussian which leaks into the right half of the data. This makes the procedure fail when the Gaussians are close together. Is there way to do this more intelligently? Due to the computational difficulty I would prefer if the solution didn't involve curve fitting.

As the OP does not show any data, it is not clear how noisy the data is. Furthermore, it is not clear how "close together" is defined here. In the following I have a simple approximation that works with low noise and the assumption that the left hand side data is dominated by the left Gaussian, while the right hand side is dominated by the right Gaussian. This gives some restrictions to position, height, and especially standard deviation.
It surely works for a single peak, but is quite OK for mixed double peaks ( within the above mentioned restrictions )
#!/usr/bin/python
import matplotlib.pyplot as plt
import numpy as np
def gaussian( x, x0, s, a):
return a * np.exp( -( x - x0 )**2 / ( 2 * s**2 ) ) / np.sqrt( 2 * np.pi * s**2 )
def get_x0( x1, x2, x3, y1, y2, y3 ):
l12= np.log( y1 / y2 )
l13= np.log( y1 / y3 )
return ( ( x2 + x1 )/2. - ( x3 + x1 )/2. * l12/l13 * ( x3 - x1 ) / ( x2 - x1 ) ) / ( 1 - l12 / l13 * (x3 - x1 ) / ( x2 - x1 ) )
fig = plt.figure( )
ax = fig.add_subplot( 2, 1, 1 )
xL = np.linspace(-8, 8, 150 )
yL = np.fromiter( ( gaussian( x,-2.1, 1.2, 8 ) for x in xL ), np.float )
marker=[10,15,20]
x1 = xL[ marker[0] ]
x2 = xL[ marker[1] ]
x3 = xL[ marker[2] ]
y1 = yL[ marker[0] ]
y2 = yL[ marker[1] ]
y3 = yL[ marker[2] ]
print get_x0( x1, x2, x3, y1, y2, y3 )
ax.plot( xL, yL )
ax.scatter( [ x1, x2, x3 ],[ y1, y2, y3 ])
bx = fig.add_subplot( 2, 1, 2 )
yL = np.fromiter( ( gaussian( x,-2.1, 1.2, 8) + gaussian( x,0.7, 1.4, 6 ) for x in xL ), np.float )
marker=[10,15,20]
x1 = xL[ marker[0] ]
x2 = xL[ marker[1] ]
x3 = xL[ marker[2] ]
y1 = yL[ marker[0] ]
y2 = yL[ marker[1] ]
y3 = yL[ marker[2] ]
bx.scatter( [ x1, x2, x3 ],[ y1, y2, y3 ])
print get_x0( x1, x2, x3, y1, y2, y3 )
marker=[-20,-25,-30]
x1 = xL[ marker[0] ]
x2 = xL[ marker[1] ]
x3 = xL[ marker[2] ]
y1 = yL[ marker[0] ]
y2 = yL[ marker[1] ]
y3 = yL[ marker[2] ]
bx.scatter( [ x1, x2, x3 ],[ y1, y2, y3 ])
print get_x0( x1, x2, x3, y1, y2, y3 )
bx.plot( xL, yL )
plt.show()
Shows:
#Single
-2.0999999999999455
#Double
-2.0951188129317813
0.6998760921436634
which is pretty close to -2.1 and 0.7
In case of noise some averaging might be required.

Related

How to generate the plot of custom shape using numpy or other python libraries

I am interested in generating some random plots for data-based classification problems. These plots are generated inside the x-y plane. The maximum value of x and y is one. The main purpose of this is to generate a dummy dataset for a classification algorithm. The below figure is an example of the expected plot. Other than this I am also written a small code.
import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(0.15, 0.95, 100, endpoint = True)
x= x.reshape(100, 1)
noise =np.random.normal(0,0.1, [100,1])*0.25
x=x+noise;
s=(100,1);
y=0.5*(np.ones(s));
xy=np.hstack((x,y));
plt.plot(x,y)
x1 = np.linspace(0.15*np.pi, 0.95*np.pi, 100)
x1max=max(x1)
x1=x1/x1max;
y1 = 2*np.cosh(x1/2)
y1max=max(y1)
y1=y1/y1max;
plt.plot(x1, y1)
x2 = np.linspace(0.15*np.pi, 2*np.pi, 100)
x2max=max(x2)
x2=x2/x2max;
y2 = np.sin(x2)
y2max=max(y2)
y2=y2/y2max;
plt.plot(x2, y2)
def cart2pol(a, b):
rho = np.sqrt(a**2 +b**2)
theta = np.arctan2(b,a)
return(rho, theta)
def pol2cart(rho, phi):
a = rho * np.cos(theta)
b = rho * np.sin(theta)
return(a, b)
[x3,y3]=cart2pol(x,y)
x3max=max(x3)
x3=x3/x2max;
y3max=max(y3)
y3=y3/y3max;
plt.plot(x3, y3)
[x4,y4]=cart2pol(x1,y1)
x4max=max(x4)
x4=x4/x4max;
y4max=max(y4)
y4=y4/y4max;
plt.plot(x4, y4)

3D plane plot with wireframes matplotlib

I have created a 3d plot that contains two wireframes of half sheres and a point:
now i want to add to it a plane that touches both the point and the tops of the wireframes.
the point is at [0,0,0].
the first sphere is centered at [4.73 , 4.73 , 0] with radius r = 0.29
the second shpere is centered at [0, 9.46 , 0] with radius r = 2.176
This is the code i have so far. Anyone can suggest how to add the plane in the same plot?
theta, phi = np.linspace(0, np.pi, 10), np.linspace(0,2* np.pi, 13)
THETA, PHI = np.meshgrid(theta, phi)
R2 = r_2
X2 = R2 * np.sin(THETA) * np.cos(PHI) + x_in[1]
Y2 = R2 *np.sin(THETA) * np.sin(PHI) + y_in[1]
Z2 = R2 *np.absolute(np.cos(THETA))
R3 = r_3
X3 = R3 * np.sin(THETA) * np.cos(PHI) + x_in[2]
Y3 = R3 *np.sin(THETA) * np.sin(PHI) + y_in[2]
Z3 = R3 *np.absolute(np.cos(THETA))
fig = plt.figure(figsize = (10,10))
ax = fig.add_subplot(1,1,1, projection='3d')
plot = ax.plot_wireframe(X2, Y2, Z2, rstride=1, cstride=1, linewidth=1,antialiased=False,\
alpha=1)
plot = ax.plot_wireframe(X3, Y3, Z3, rstride=1, cstride=1, linewidth=1, antialiased=False,\
alpha=1)
ax.scatter(x_in[0] , y_in[0] , 0, color='blue')
plt.show()

Coloring the area between two curves with bokeh

I've got a code with bokeh. There is two math functions where there is an area zone between these two functions in the interval [0, 2]. How can I fill this area zone with a color? I can't use polygon because it is not a polygon.
Here's the code:
import numpy as np
from bokeh.plotting import *
N = 300
x0 = np.linspace(-1, 4, N)
x1 = np.linspace(0, 4, N)
y0 = 0.5 * (x0 ** 2)
y1 = np.sqrt(2 * x1)
y2 = -y1
# output to static HTML file
output_file('plotting_areas.html')
TOOLS = 'pan, wheel_zoom, box_zoom, reset,save, box_select, lasso_select'
p = figure(tools=TOOLS, width=350, height=350,
title=None, x_range=(-1, 5), y_range=(-5, 5))
p.line(x0, y0)
p.line(x1, y1)
p.line(x1, y2)
show(p)
And here is an image for more details.
Thanks
There is nothing built in to Bokeh that will do, e.g. a flood fill, which is really what would be needed. Your best bet is to compute a polygonal approximation to the area yourself.
Otherwise you could (in principle) create a custom extension to perform a flood-fill in JavaScript, but I'm not sure how much effort that would take.
Ok, I've found the solution with bokeh and it is very simple and possible. The key is making two vectors (arrays) with the images of every two math functions between the OX interval. For each vector make a polygon with patch bokeh instruction without border line.
Here is the code:
import numpy as np
from bokeh.plotting import *
N = 300
x0 = np.linspace(-1, 4, N)
x1 = np.linspace(0, 4, N)
y0 = 0.5 * (x0 ** 2)
y1 = np.sqrt(2 * x1)
y2 = -y1
def f1(x):
return 0.5 * (x**2)
def f2(x):
return np.sqrt(2 * x)
z = np.zeros(N)
w = np.zeros(N)
x = np.linspace(0, 2, N)
for i in np.arange(len(x)):
z[i] = f1(x[i])
w[i] = f2(x[i])
# output to static HTML file
output_file('plotting_areas.html')
TOOLS = 'pan, wheel_zoom, box_zoom, reset,save, box_select, lasso_select'
p = figure(tools=TOOLS, width=350, height=350,
title=None, x_range=(-1, 5), y_range=(-5, 5))
p.line(x0, y0)
p.line(x1, y1)
p.line(x1, y2)
p.patch(x, z, color='red')
p.patch(x, w, color='red')
show(p)
And here is an image with the optimal solution:
Thanks
There is VArea now which should do the trick. Perhaps you might want to restict the plotting range to f1 > f2.

How do i fix 'TypeError: cannot unpack non-iterable numpy.float64 object' error in python

9 break
10 else:
---> 11 result = pipeline(frame)
12 cv2.imshow("Frame", result)
13 key = cv2.waitKey(1) & 0xFF
<ipython-input-2-d9c587a1d603> in pipeline(image)
90 ### Draw lines and return final image
91 line_img = np.copy((image)*0)
---> 92 draw_lines(line_img, lines, thickness=10)
93
94 line_img = region_of_interest(line_img, v)
<ipython-input-2-d9c587a1d603> in draw_lines(image, lines, color, thickness)
26 def draw_lines(image, lines, color=[255, 0, 0], thickness=4):
27 for line in lines:
---> 28 for x1, y1, x2, y2 in line:
29 cv2.line(image, (x1, y1), (x2, y2), color, thickness)
30
TypeError: cannot unpack non-iterable numpy.float64 object
I want to have coordinates of the beginning and end of the lane from lane list those coordinates are mentioned as x1, y1, x2, y2. And also when i printed the line it has 8 float numbers containing.
x1, y1, x2, y2 = line
Unpack the line list into variables. What happens under the hood is
(x1, y1, x2, y2) = (0, 0, 5, 5)
And hence
x1 = 0
y1 = 0 and so on...
Remove for x1, y1, x2, y2 in line loop.

Calculate the coordinates of a point in a line

I have a game represented like this :
I would like to calculate the coordinates of the point x4,y4.
What I know is :
y4 = y3, x4 is on the line x1,y1,x2,y2 and the line is 45° (degree)
I tried x4 = y4 - y1 + x1 but it doesn't work very well..
Any ideas ?
m= (y2-y1)/(x2-x1) = (y4-y1)/(x4-x1)=1 as slope is 45 degree.
so x4=x1+y4-y1;
substitute y4=y3;
then X4 = x1+y3-y1;
This video should help you to get the right formula.
Should be:
m = (y2 - y1) / (x2 - x1)
b = y2 - m * x2
x4 = (y3 - b) / m
Since the line is at a 45° angle, dx=dy between two points on the line. Thus:
x4 = x1+(y1-y4)

Resources