user2297781
user2297781

Reputation:

scipy.optimize.curve_fit error- result from function not a proper array of floats

I'm trying to fit a 2-d voigt profile to a subsection of an image (impart), where position is an array that holds the corresponding x and y coordinates in the whole image for impart.

The following code seems to me like it really ought to work, based on the output of the two print statements.

Also, if anyone has any quick suggestions on how to construct the position array faster, I'd appreciate some advice with numpy ndarrays. I'm still a little new to them.

import numpy as np
from scipy.special import wofz
from scipy.optimize import curve_fit
from math import pi

def voigt2d(pos,a,bx,by,Gc,Lc):
    val = np.zeros((5,5))

    for y in range(5):
        for x in range(5):
            dst = np.sqrt((pos[y][x][0]-bx)**2+(pos[y][x][1]-by)**2)

            z = ((dst+(Lc*1j))/(Gc*np.sqrt(2)))
            val[y][x] = a*wofz(z).real/(Gc*np.sqrt(2*pi))
    print val
    print val.dtype
    return val

x = np.arange(93,98)
y = np.arange(7,12)

xpos = np.array([x,x,x,x,x])
ypos = np.array([y,y,y,y,y])
ypos = np.rot90(ypos,k=3)

position = np.dstack((xpos,ypos))

impart = np.array([
    [971, 2425, 4331, 4280, 2697,],
    [1199, 3416, 6517, 4813, 2412],
    [1333, 3957, 7210, 4019, 2183],
    [1494, 4115, 4817, 3085, 1758],
    [1185, 2273, 2805, 2811, 1797]
    ],dtype=np.float64)

p,cov = curve_fit(voigt2d,position,impart)

Upvotes: 1

Views: 2716

Answers (2)

Christian K.
Christian K.

Reputation: 2823

Regarding your second question, there is a convenient grid constructor in numpy:

y,x = pos = np.mgrid[7:12,93:98]

which will return exactly the arrays you constructed by hand. Also note, that numpy allows for operations between whole arrays not just scalars, eliminating the need for the two loops inside voigt2d:

def voigt2d(pos,a,bx,by,Gc,Lc):
    y,x = pos
    dst = np.sqrt((x-bx)**2+(y-by)**2)
    z = ((dst+(Lc*1j))/(Gc*np.sqrt(2)))
    val = a*wofz(z).real/(Gc*np.sqrt(2*pi))

As Bhajun said, curve_fit expects a 1D array, so you need to flatten the result:

    return np.ravel(val)

Hope that helps.

Upvotes: 1

Sajjan Singh
Sajjan Singh

Reputation: 2553

I'm not certain this will solve it for you, but I believe your issue is related to the fact curve_fit expects your model function to return a 1D array of model data. So the easiest thing to do would be to express your independent variables (position) as a 1D array:

>>> x = np.arange(93,98)
>>> y = np.arange(7,12)
>>> position = np.transpose([np.tile(x, len(x)), np.repeat(y, len(y))])
>>> position
array([[93,  7],
       [94,  7],
       [95,  7],
       [96,  7],
       [97,  7],
       [93,  8],
       [94,  8],
       [95,  8],
       [96,  8],
       [97,  8],
       [93,  9],
       [94,  9],
       [95,  9],
       [96,  9],
       [97,  9],
       [93, 10],
       [94, 10],
       [95, 10],
       [96, 10],
       [97, 10],
       [93, 11],
       [94, 11],
       [95, 11],
       [96, 11],
       [97, 11]])

Then you would have to adjust your model function to accommodate this new array.

Upvotes: 1

Related Questions