Exemplo n.º 1
0
def mean_position(path, print_pos=False):
    """Calculate the mean position in a collection of obsids

    Args:
        path (str): path to text file with obsids, new line delimited
    
    Keyword Args:
        print_pos (bool): print the RA, Dec out to stdout (default is False)
    """
    obsids = read_obsids_file(path)

    df = obsids_from_db(obsids)

    positions = SkyCoord(df["ra_pointing"],
                         df["dec_pointing"],
                         unit=(u.deg, u.deg))
    # The use of circmean is accurate only when delta(dec) is small. For the
    # GLEAM-X declination strips this is the case.
    mean_ra = circmean(positions.ra)
    mean_dec = positions.dec.mean()
    mean_pos = SkyCoord(mean_ra, mean_dec)

    if print_pos:
        print(f"{mean_pos.ra.deg} {mean_pos.dec.deg}")

    return mean_pos.ra.deg, mean_pos.dec.deg
Exemplo n.º 2
0
def test_circmean_against_scipy():
    # testing against scipy.stats.circmean function
    # the data is the same as the test before, but in radians
    data = np.array(
        [0.89011792, 1.1693706, 0.6981317, 1.90240888, 0.54105207, 6.24827872])
    answer = scipy.stats.circmean(data)
    assert_equal(np.around(answer, 2), np.around(circmean(data), 2))
Exemplo n.º 3
0
def tuning_curve_stats(tuning_curve, **kwargs):
    """ Calculate statistics about a turning curve
    
    STATUS : EXPERIMENTAL

    Calculates various statistics for a turning curve.
    1. Mean vector length of a head direction rate map.
    The value will range from 0 to 1. 0 means that there are so much dispersion
    that a mean angle cannot be described. 1 means that all data are
    concentrated at the same direction. Note that 0 does not necessarily
    indicate a uniform distribution.
    Calculation is based on Section 26.4, J.H Zar - Biostatistical Analysis 5th edition,
    see eq. 26.13, 26.14.

    Parameters
    ----------
    tuning_curve : np.ma.MaskedArray
        Smoothed turning curve of firing rate as a function of angle
        Nx1 array
    kwargs
        percentile : float
            Percentile value for the head direction arc calculation
            Arc is between two points with values around
            globalPeak * percentile. Value should be in range [0, 1]

    Returns
    -------
    tcstat : dict
        hd_score         : float
            Score for how strongly modulated by angle the cell is
        hd_mvl           : float
            mean vector length
        hd_peak_rate     : float
            Peak firing rate  [Hz]
        hd_mean_rate     : float
            Mean firing rate [Hz]
        hd_peak_direction : float
            Direction of peak firing rate [degrees]
        hd_peak_direction_rad : float
            Direction of peak firing rate
        hd_mean_direction: float
            Direction of mean firing rate [degrees]
        hd_mean_direction_rad: float
            Direction of mean firing rate
        hd_stdev         : float
            Circular standard deviation [degrees]
        halfCwInd  : int
            Indicies of at the start, end of the range defined by percentile
            (clockwise).
        halfCcwInd : int
            Indicies of at the start, end of the range defined by percentile
            (counter-clockwise).
        halfCwRad : float
            Angle of the start, end of the range defined by percentile
        halfCcwRad  : float
            Angle of the start, end of the range defined by percentile
        arc_angle_rad : float
            Angle of the arc defined by percentile
        arc_angle_rad : float
            Angle of the arc defined by percentile

    Notes
    --------
    BNT.+analyses.tcStatistics

    Copyright (C) 2019 by Simon Ball

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    """

    debug = kwargs.get("debug", False)
    percentile = kwargs.get('percentile', default.hd_percentile)
    ndim = tuning_curve.ndim
    if ndim != 1:
        raise error.DimensionMismatchError(
            "tuning_curve should be a 1D array. You have provided {} dimensions"
            .format(ndim))
    if not 0 <= percentile <= 1:
        raise error.ArgumentError(
            "Keyword 'percentile' should be in the range [0, 1]. You provided  {:.2f.}"
            .format(percentile))
    if type(tuning_curve) != np.ma.MaskedArray:
        tuning_curve = np.ma.masked_invalid(tuning_curve)

    num_bin = tuning_curve.size
    bin_width = 2 * np.pi / num_bin
    hb = bin_width / 2
    bin_centres = np.linspace(hb, (2 * np.pi) - hb, num_bin)

    if debug:
        print("Num_bin: %d" % num_bin)
        print("Therefore, bin_width = %.3g deg = %.3g rad" %
              (np.degrees(bin_width), bin_width))

    #### Calculate the simple values
    tcstat = {}
    # The average of the values of angles, weighted by the firing rate at those angles
    mean_dir_radians = cs.circmean(data=bin_centres, weights=tuning_curve)
    tcstat['hd_mean_direction_rad'] = mean_dir_radians
    tcstat['hd_mean_direction'] = np.degrees(mean_dir_radians)

    # The direction in which the highest firing rate occurs
    peak_dir_index = np.nanargmax(tuning_curve)
    peak_dir_angle_radians = _index_to_angle(peak_dir_index, bin_width)
    tcstat['hd_peak_direction_rad'] = peak_dir_angle_radians
    tcstat['hd_peak_direction'] = np.degrees(peak_dir_angle_radians)

    # The peak firing rate IN Hz
    peak_rate_hz = np.nanmax(tuning_curve)
    tcstat['hd_peak_rate'] = peak_rate_hz

    # The mean firing rate across all angles IN Hz
    if tuning_curve.mask.all():
        #### Added to cope with numpy bug in nanmean with fully masked array
        mean_rate_hz = np.nan
    else:
        mean_rate_hz = np.nanmean(tuning_curve)
    tcstat['hd_mean_rate'] = mean_rate_hz

    #### Calculate the more complex ones:
    # mvl
    mvl = np.sum(tuning_curve * np.exp(1j * bin_centres))
    mvl = np.abs(mvl) / np.sum(tuning_curve)
    tcstat['hd_mvl'] = mvl

    # hd_stdev
    # Eq. 26.20 from J. H. Zar
    tcstat['hd_stdev'] = np.sqrt(2 * (1 - mvl))

    # Percentile arc
    half_peak = peak_rate_hz * percentile

    # Because Python doesn't natively handle circular arrays, reshape such that
    # the peak rate occurs at the centre of the array - then don't have to worry
    # about whether the arc goes off one edge of the array or not
    # Must be careful to keep track of the array to which the indicies point
    tuning_curve_re = np.zeros_like(tuning_curve)
    centre_index = int(num_bin / 2)
    offset = centre_index - peak_dir_index
    tuning_curve_re = np.roll(tuning_curve, offset)
    # A positive offset means that the peak angle was in the range [0, pi], and
    # is now at the central index. Therefore, to get the "proper" index,
    # subtract offset from index in tuning_curve_re

    if debug:
        print("Centre index: %d, value" % centre_index)
        print("Peak index: %d" % peak_dir_index)
        print("Offset: %d" % offset)

    # Clockwise and counter-clockwise edges of arc around peak defined by
    # percentile. ccw index +1 to account for width of central peak
    cw_hp_index = np.where(tuning_curve_re >= (half_peak))[0][0] - offset
    ccw_hp_index = np.where(tuning_curve_re >= (half_peak))[0][-1] - offset + 1

    cw_hp_ang = _index_to_angle(cw_hp_index, bin_width)
    ccw_hp_ang = _index_to_angle(ccw_hp_index, bin_width)
    arc_angle = ccw_hp_ang - cw_hp_ang

    if debug:
        print("CW: %d, %.3g rad" % (cw_hp_index, cw_hp_ang))
        print("CCW: %d, %.3g rad" % (ccw_hp_index, ccw_hp_ang))
        print("Arc: %.3g rad" % arc_angle)

    score = 1 - (arc_angle / np.pi)
    tcstat['halfCwInd'] = cw_hp_index
    tcstat['halfCcwInd'] = ccw_hp_index
    tcstat['halfCwRad'] = cw_hp_ang
    tcstat['halfCcwRad'] = ccw_hp_ang
    tcstat['arc_angle_rad'] = arc_angle
    tcstat['arc_angle_deg'] = np.degrees(arc_angle)
    tcstat['hd_score'] = score

    return tcstat
Exemplo n.º 4
0
def hro(Imap,
        Qmap,
        Umap,
        steps=10,
        hsize=15,
        minI=0.,
        mask=0,
        ksz=1,
        w=None,
        convention='Planck',
        sigmaQQ=None,
        sigmaUU=None,
        mcflag=None,
        nruns=10,
        errorbar=None,
        segmap=None,
        debug=False):

    #if (convention=='Planck'):
    #   Qmap0=Qmap
    #   Umap0=Umap
    #else:
    #   Qmap0=Qmap
    #   Umap0=-1.*Umap

    if np.logical_or(np.logical_and(sigmaQQ is None, sigmaUU is None), mcflag):

        output0 = hroLITE(Imap,
                          Qmap,
                          Umap,
                          steps=steps,
                          hsize=hsize,
                          minI=minI,
                          mask=mask,
                          ksz=ksz,
                          w=w,
                          convention=convention,
                          segmap=segmap,
                          debug=debug)
        isteps = output0['csteps']
        asteps = output0['asteps']
        hros = output0['hros']
        shros = output0['s_hros']

        zeta = output0['xi']  #roms[0]
        Zx = output0['Zx']  #roms[1]
        Zy = output0['Zy']
        mphi = output0['meanphi']  #roms[2]

        s_zeta = output0['s_xi']  #sroms[0]
        s_Zx = output0['s_Zx']  #sroms[1]
        s_Zy = output0['s_Zy']
        s_mphi = output0['s_meanphi']  #sroms[2]

        Amap = output0['Amap']

    else:

        assert Qmap.shape == sigmaQQ.shape, "Dimensions of Qmap and sigmaQQ must match"
        assert Umap.shape == sigmaUU.shape, "Dimensions of Umap and sigmaUU must match"

        hrosvec = np.zeros([nruns, steps, hsize])

        zetavecMC = np.zeros([nruns, steps])
        ZxvecMC = np.zeros([nruns, steps])
        ZyvecMC = np.zeros([nruns, steps])
        mphivecMC = np.zeros([nruns, steps])
        mrlMC = np.zeros([nruns, steps])

        s_zetavecMC = np.zeros([nruns, steps])
        s_ZxvecMC = np.zeros([nruns, steps])
        s_ZyvecMC = np.zeros([nruns, steps])
        s_mphivecMC = np.zeros([nruns, steps])
        s_mrlMC = np.zeros([nruns, steps])

        Acube = np.zeros([nruns, Qmap.shape[0], Qmap.shape[1]])

        pbar = tqdm(total=nruns)

        for i in range(0, nruns):

            QmapR = np.random.normal(loc=Qmap, scale=sigmaQQ)
            UmapR = np.random.normal(loc=Umap, scale=sigmaUU)
            hrooutput = hroLITE(Imap,
                                QmapR,
                                UmapR,
                                steps=steps,
                                hsize=hsize,
                                minI=minI,
                                mask=mask,
                                ksz=ksz,
                                w=w,
                                convention=convention,
                                segmap=segmap,
                                debug=False)

            zetavecMC[i, :] = hrooutput['xi']
            ZxvecMC[i, :] = hrooutput['Zx']
            ZyvecMC[i, :] = hrooutput['Zy']
            mphivecMC[i, :] = hrooutput['meanphi']
            mrlMC[i, :] = hrooutput['mrl']

            s_zetavecMC[i, :] = hrooutput['s_xi']
            s_ZxvecMC[i, :] = hrooutput['s_Zx']
            s_ZyvecMC[i, :] = hrooutput['s_Zy']
            s_mphivecMC[i, :] = hrooutput['s_meanphi']

            hrosvec[i, :, :] = hrooutput['hros']

            Acube[i, :, :] = hrooutput['Amap']

            pbar.update()

        pbar.close()

        zeta = zetavecMC.mean(axis=0)
        Zx = ZxvecMC.mean(axis=0)
        Zy = ZyvecMC.mean(axis=0)
        meanphi = circstats.circmean(mphivecMC, axis=0)
        mrl = mrlMC.mean(axis=0)

        Amap = circstats.circmean(Acube, axis=0)

        if (errorbar == 'MC'):
            s_zeta = s_zetavecMC.std(axis=0)
            s_Zx = s_ZxvecMC.std(axis=0)
            s_Zy = s_ZyvecMC.std(axis=0)
            s_meanphi = circ.descriptive.mean(s_mphivecMC, axis=0)
        else:
            s_zeta = hrooutput[
                's_xi']  #np.max([s_zetavecMC.std(axis=0),hrooutput['s_xi']], axis=0)
            s_Zx = hrooutput[
                's_Zx']  #np.max([s_prsvecMC.std(axis=0),hrooutput['s_prs']], axis=0)
            s_Zy = hrooutput['s_Zy']
            s_meanphi = hrooutput[
                's_meanphi']  #np.max([circ.descriptive.mean(s_mphivecMC, axis=0),hrooutput['s_meanphi']], axis=0)
        s_mrl = mrlMC.std(axis=0)

        csteps = hrooutput['csteps']
        asteps = hrooutput['asteps']
        Smap = hrooutput['Smap']

        outhros = hrosvec.mean(axis=0)
        s_outhros = hrosvec.std(axis=0)

    return {
        'csteps': csteps,
        'xi': zeta,
        's_xi': s_zeta,
        'Zx': Zx,
        's_Zx': s_Zx,
        'Zy': Zy,
        's_Zy': s_Zy,
        'meanphi': meanphi,
        's_meanphi': s_meanphi,
        'asteps': asteps,
        'hros': outhros,
        's_hros': s_outhros,
        'mrl': mrl,
        's_mrl': s_mrl,
        'Smap': Smap,
        'Amap': Amap
    }
Exemplo n.º 5
0
def test_circmean():
    # testing against R CircStats package
    # Ref[1], page 23
    data = np.array([51, 67, 40, 109, 31, 358]) * u.deg
    answer = 48.63 * u.deg
    assert_equal(answer, np.around(circmean(data), 2))