def fit_powerlaw_covariance(xdata, ydata, yerr = None, should_plot=True, debug=False):
    '''
        Implements http://www.scipy.org/Cookbook/FittingData

        We actually compute the standard deviation for each x-value, and use this
        when computing the fit.

    '''

    assert not (ydata.ndim == 1 and yerr is None), 'Use another function or provide yerr, this function requires the standard deviation'

    if ydata.ndim == 2:
        # Y data 2-dim, compute the standard errors, along the second dimension
        yerr = np.std(ydata, axis=1)
        ydata = np.mean(ydata, axis=1)

    logx = np.log(xdata.astype('float'))
    logy = np.log(ydata)
    logyerr = yerr/ydata

    # define our (line) fitting function
    fitfunc = lambda p, x: p[0] + p[1] * x
    errfunc = lambda p, x, y, err: (y - fitfunc(p, x)) / err

    # Initial parameters
    pinit = np.array([1.0, -1.0])
    out = spopt.leastsq(errfunc, pinit, args=(logx, logy, logyerr), full_output=1)

    pfinal = out[0]
    covar = out[1]

    index = pfinal[1]
    amp = np.exp(pfinal[0])


    if debug:
        indexErr = np.sqrt( covar[0][0] )
        ampErr = np.sqrt( covar[1][1] ) * amp

        print pfinal
        print 'Ampli = %5.2f +/- %5.2f' % (amp, ampErr)
        print 'Index = %5.2f +/- %5.2f' % (index, indexErr)

    ##########
    # Plotting data
    ##########
    if should_plot:
        plot_powerlaw_fit(xdata, ydata, amp, index, yerr=yerr)


    return np.array([index, amp])
def fit_powerlaw(xdata, ydata, should_plot=False, debug=False):
    '''
        Fit a power law to the provided data.
        y = a x**p
        Actually fit to the mean of the provided data, if multiple columns given (axis 1)

        Look for next function in order to fit a powerlaw while taking std dev into account.

        returns (power p, amplitude a)
    '''

    ##########
    # Fitting the data -- Least Squares Method
    ##########

    # Power-law fitting is best done by first converting
    # to a linear equation and then fitting to a straight line.
    #
    #  y = a * x^b
    #  log(y) = log(a) + b*log(x)
    #

    if ydata.ndim == 1:
        # We have a 1D array, need a flat 2D array...
        ydata = ydata[:, np.newaxis]

    if xdata.ndim == 1:
        # We need to tile the x values appropriately, to fit the size of y
        # (just because leastsq is not funny)
        xdata = np.tile(xdata, (ydata.shape[1], 1)).T

    logx = np.log(xdata.astype('float'))
    logy = np.log(ydata)

    if np.any(np.isnan(logy)):
        # Something went wrong, just stop here...
        return np.array([np.nan, np.nan])

    # define our (line) fitting function
    fitfunc = lambda p, x: p[0] + p[1] * x
    errfunc = lambda p, x, y: np.mean(y - fitfunc(p, x), axis=1)

    # Initial parameters
    pinit = np.array([1.0, -1.0])
    out = spopt.leastsq(errfunc, pinit, args=(logx, logy), full_output=1)
    # out = spopt.fmin(errfunc_mse, pinit, args=(logx, logy))

    pfinal = out[0]

    index = pfinal[1]
    amp = np.exp(pfinal[0])

    if debug:
        print pfinal
        print 'Ampli = %5.2f' % amp
        print 'Index = %5.2f' % index

    ##########
    # Plotting data
    ##########
    if should_plot:
        plot_powerlaw_fit(xdata, ydata, amp, index)


    return np.array([index, amp])