Beispiel #1
0
def get_correlation(session, analyspar, rolling_win=4):
    """
    get_correlation(session, analyspar)

    Returns ROI correlations for a session.

    Required args:
        - session (Session):
            Session object
        - analyspar (AnalysPar): 
            named tuple containing analysis parameters

    Optional args:
        - rolling_win (int):
            window to use in rolling mean over individual traces before 
            computing correlation between ROIs (None for no smoothing)
            default: 4 

    Returns:
        - corr_triu (1D array):
            all correlations
    """
    
    if session.only_tracked_rois != analyspar.tracked:
        raise RuntimeError(
            "session.only_tracked_rois should match analyspar.tracked."
            )

    if analyspar.scale:
        raise ValueError(
            "analyspar.scale must be False for correlation analysis."
            )
    
    full_traces_df = session.get_roi_traces(
        fluor=analyspar.fluor, 
        rem_bad=analyspar.rem_bad 
        )

    full_traces = gen_util.reshape_df_data(full_traces_df, squeeze_cols=True)
    
    if rolling_win is not None:
        full_traces = math_util.rolling_mean(full_traces, win=rolling_win)

    corrs = np.corrcoef(full_traces)

    corr_triu = corrs[np.triu_indices(len(corrs), k=1)]

    return corr_triu
Beispiel #2
0
def run_autocorr(sessions,
                 analysis,
                 analyspar,
                 sesspar,
                 stimpar,
                 autocorrpar,
                 figpar,
                 datatype="roi"):
    """
    run_autocorr(sessions, analysis, analyspar, sesspar, stimpar, autocorrpar, 
                 figpar)

    Calculates and plots autocorrelation during stimulus blocks.
    Saves results and parameters relevant to analysis in a dictionary.

    Required args:
        - sessions (list)          : list of Session objects
        - analysis (str)           : analysis type (e.g., "a")
        - analyspar (AnalysPar)    : named tuple containing analysis parameters
        - sesspar (SessPar)        : named tuple containing session parameters
        - stimpar (StimPar)        : named tuple containing stimulus parameters
        - autocorrpar (AutocorrPar): named tuple containing autocorrelation 
                                     analysis parameters
        - figpar (dict)            : dictionary containing figure parameters

    Optional args:
        - datatype (str): type of data (e.g., "roi", "run")
    """

    sessstr_pr = sess_str_util.sess_par_str(sesspar.sess_n, stimpar.stimtype,
                                            sesspar.plane, stimpar.visflow_dir,
                                            stimpar.visflow_size, stimpar.gabk,
                                            "print")
    dendstr_pr = sess_str_util.dend_par_str(analyspar.dend, sesspar.plane,
                                            datatype, "print")

    datastr = sess_str_util.datatype_par_str(datatype)

    logger.info(
        f"Analysing and plotting {datastr} autocorrelations "
        f"({sessstr_pr}{dendstr_pr}).",
        extra={"spacing": "\n"})

    xrans = []
    stats = []
    for sess in sessions:
        if datatype == "roi" and (sess.only_tracked_rois != analyspar.tracked):
            raise RuntimeError(
                "sess.only_tracked_rois should match analyspar.tracked.")
        stim = sess.get_stim(stimpar.stimtype)
        all_segs = stim.get_segs_by_criteria(visflow_dir=stimpar.visflow_dir,
                                             visflow_size=stimpar.visflow_size,
                                             gabk=stimpar.gabk,
                                             by="block")
        sess_traces = []
        for segs in all_segs:
            if len(segs) == 0:
                continue
            segs = sorted(segs)
            # check that segs are contiguous
            if max(np.diff(segs)) > 1:
                raise NotImplementedError("Segments used for autocorrelation "
                                          "must be contiguous within blocks.")
            if datatype == "roi":
                frame_edges = stim.get_fr_by_seg(
                    [min(segs), max(segs)], fr_type="twop")
                fr = list(range(min(frame_edges[0]), max(frame_edges[1]) + 1))
                traces = gen_util.reshape_df_data(sess.get_roi_traces(
                    fr,
                    fluor=analyspar.fluor,
                    rem_bad=analyspar.rem_bad,
                    scale=analyspar.scale),
                                                  squeeze_cols=True)

            elif datatype == "run":
                if autocorrpar.byitem != False:
                    raise ValueError("autocorrpar.byitem must be False for "
                                     "running data.")
                frame_edges = stim.get_fr_by_seg(
                    [min(segs), max(segs)], fr_type="stim")
                fr = list(range(min(frame_edges[0]), max(frame_edges[1]) + 1))

                traces = sess.get_run_velocity_by_fr(
                    fr,
                    fr_type="stim",
                    rem_bad=analyspar.rem_bad,
                    scale=analyspar.scale).to_numpy().reshape(1, -1)

            sess_traces.append(traces)

        # Calculate autocorr stats while filtering some warnings
        msgs = ["Degrees of freedom", "invalid value encountered"]
        categs = [RuntimeWarning, RuntimeWarning]
        with gen_util.TempWarningFilter(msgs, categs):
            xran, ac_st = math_util.autocorr_stats(sess_traces,
                                                   autocorrpar.lag_s,
                                                   sess.twop_fps,
                                                   byitem=autocorrpar.byitem,
                                                   stats=analyspar.stats,
                                                   error=analyspar.error)

        if not autocorrpar.byitem:  # also add a 10x lag
            lag_fr = 10 * int(autocorrpar.lag_s * sess.twop_fps)
            _, ac_st_10x = math_util.autocorr_stats(sess_traces,
                                                    lag_fr,
                                                    byitem=autocorrpar.byitem,
                                                    stats=analyspar.stats,
                                                    error=analyspar.error)
            downsamp = range(0, ac_st_10x.shape[-1], 10)

            if len(downsamp) != ac_st.shape[-1]:
                raise RuntimeError("Failed to downsample correctly. "
                                   "Check implementation.")
            ac_st = np.stack([ac_st, ac_st_10x[:, downsamp]], axis=1)
        xrans.append(xran)
        stats.append(ac_st)

    autocorr_data = {
        "xrans": [xran.tolist() for xran in xrans],
        "stats": [stat.tolist() for stat in stats]
    }

    sess_info = sess_gen_util.get_sess_info(sessions,
                                            analyspar.fluor,
                                            incl_roi=(datatype == "roi"),
                                            rem_bad=analyspar.rem_bad)

    extrapar = {
        "analysis": analysis,
        "datatype": datatype,
    }

    info = {
        "analyspar": analyspar._asdict(),
        "sesspar": sesspar._asdict(),
        "stimpar": stimpar._asdict(),
        "extrapar": extrapar,
        "autocorrpar": autocorrpar._asdict(),
        "autocorr_data": autocorr_data,
        "sess_info": sess_info
    }

    fulldir, savename = gen_plots.plot_autocorr(figpar=figpar, **info)

    file_util.saveinfo(info, savename, fulldir, "json")
Beispiel #3
0
def run_full_traces(sessions,
                    analysis,
                    analyspar,
                    sesspar,
                    figpar,
                    datatype="roi"):
    """
    run_full_traces(sessions, analysis, analyspar, sesspar, figpar)

    Plots full traces across an entire session. If ROI traces are plotted,
    each ROI is scaled and plotted separately and an average is plotted.
    
    Saves results and parameters relevant to analysis in a dictionary.

    Required args:
        - sessions (list)      : list of Session objects
        - analysis (str)       : analysis type (e.g., "f")
        - analyspar (AnalysPar): named tuple containing analysis parameters
        - sesspar (SessPar)    : named tuple containing session parameters
        - figpar (dict)        : dictionary containing figure parameters
    
    Optional args:
        - datatype (str): type of data (e.g., "roi", "run")
    """

    dendstr_pr = sess_str_util.dend_par_str(analyspar.dend, sesspar.plane,
                                            datatype, "print")

    sessstr_pr = (f"session: {sesspar.sess_n}, "
                  f"plane: {sesspar.plane}{dendstr_pr}")

    datastr = sess_str_util.datatype_par_str(datatype)

    logger.info(
        f"Plotting {datastr} traces across an entire "
        f"session\n({sessstr_pr}).",
        extra={"spacing": "\n"})

    figpar = copy.deepcopy(figpar)
    if figpar["save"]["use_dt"] is None:
        figpar["save"]["use_dt"] = gen_util.create_time_str()

    all_tr, roi_tr, all_edges, all_pars = [], [], [], []
    for sess in sessions:
        # get the block edges and parameters
        edge_fr, par_descrs = [], []
        for stim in sess.stims:
            stim_str = stim.stimtype
            if stim.stimtype == "visflow":
                stim_str = "vis. flow"
            if datatype == "roi":
                fr_type = "twop"
            elif datatype == "run":
                fr_type = "stim"
            else:
                gen_util.accepted_values_error("datatype", datatype,
                                               ["roi", "run"])
            for b in stim.block_params.index:
                row = stim.block_params.loc[b]
                edge_fr.append([
                    int(row[f"start_frame_{fr_type}"]),
                    int(row[f"stop_frame_{fr_type}"])
                ])
                par_vals = [row[param] for param in stim.stim_params]
                pars_str = "\n".join([str(par) for par in par_vals][0:2])

                par_descrs.append(
                    sess_str_util.pars_to_descr(
                        f"{stim_str.capitalize()}\n{pars_str}"))

        if datatype == "roi":
            if sess.only_tracked_rois != analyspar.tracked:
                raise RuntimeError(
                    "sess.only_tracked_rois should match analyspar.tracked.")
            nanpol = None
            if not analyspar.rem_bad:
                nanpol = "omit"
            all_rois = gen_util.reshape_df_data(sess.get_roi_traces(
                None, analyspar.fluor, analyspar.rem_bad,
                analyspar.scale)["roi_traces"],
                                                squeeze_cols=True)
            full_tr = math_util.get_stats(all_rois,
                                          analyspar.stats,
                                          analyspar.error,
                                          axes=0,
                                          nanpol=nanpol).tolist()
            roi_tr.append(all_rois.tolist())
        elif datatype == "run":
            full_tr = sess.get_run_velocity(
                rem_bad=analyspar.rem_bad,
                scale=analyspar.scale).to_numpy().squeeze().tolist()
            roi_tr = None
        all_tr.append(full_tr)
        all_edges.append(edge_fr)
        all_pars.append(par_descrs)

    extrapar = {
        "analysis": analysis,
        "datatype": datatype,
    }

    trace_info = {
        "all_tr": all_tr,
        "all_edges": all_edges,
        "all_pars": all_pars
    }

    sess_info = sess_gen_util.get_sess_info(sessions,
                                            analyspar.fluor,
                                            incl_roi=(datatype == "roi"),
                                            rem_bad=analyspar.rem_bad)

    info = {
        "analyspar": analyspar._asdict(),
        "sesspar": sesspar._asdict(),
        "extrapar": extrapar,
        "sess_info": sess_info,
        "trace_info": trace_info
    }

    fulldir, savename = gen_plots.plot_full_traces(roi_tr=roi_tr,
                                                   figpar=figpar,
                                                   **info)
    file_util.saveinfo(info, savename, fulldir, "json")
Beispiel #4
0
def get_decoding_data(sess, analyspar, stimpar, comp="Dori", ctrl=False):
    """
    get_decoding_data(sess, analyspar, stimpar)

    Retrieves data for decoding.

    Required args:
        - sess (Session): 
            Session object
        - analyspar (AnalysPar): 
            named tuple containing analysis parameters
        - stimpar (StimPar): 
            named tuple containing stimulus parameters

    Optional args:
        - comp (str):
            comparison used to define classes ("Dori" or "Eori")
            default: "Dori"
        - ctrl (bool):
            if True, the number of examples per class for the unexpected data 
            is returned (applies to "Dori" comp only).
            default: False

    Returns:
        - all_input_data (3D array):
            input data, dims: seq x frames x ROIs
        - all_target_data (1D array):
            class target for each input sequence
        - ctrl_ns (list):
            number of examples per class for the unexpected data 
            (None if it doesn't apply)
    """

    if stimpar.stimtype != "gabors":
        raise ValueError("Expected stimpar.stimtype to be 'gabors'.")

    if comp == "Dori":
        unexp = 0
        ctrl_ns = []
    elif comp == "Uori":
        unexp = 1
        ctrl = False
        ctrl_ns = False
    else:
        gen_util.accepted_values_error("comp", comp, ["Dori", "Uori"])

    gab_oris = sess_gen_util.filter_gab_oris(comp[0], stimpar.gab_ori)

    stim = sess.get_stim(stimpar.stimtype)

    all_input_data = []
    all_target_data = []
    for g, gab_ori in enumerate(gab_oris):
        segs = stim.get_segs_by_criteria(gabfr=stimpar.gabfr,
                                         gabk=stimpar.gabk,
                                         gab_ori=gab_ori,
                                         unexp=unexp,
                                         remconsec=False,
                                         by="seg")
        fr_ns = stim.get_fr_by_seg(segs, start=True,
                                   fr_type="twop")["start_frame_twop"]

        # sample as many sequences as are usable for unexpected data
        if ctrl:
            ctrl_gab_ori = sess_gen_util.get_unexp_gab_ori(gab_ori)
            segs_ctrl = stim.get_segs_by_criteria(gabfr=stimpar.gabfr,
                                                  gabk=stimpar.gabk,
                                                  gab_ori=ctrl_gab_ori,
                                                  unexp=1,
                                                  remconsec=False,
                                                  by="seg")
            fr_ns_ctrl = stim.get_fr_by_seg(segs_ctrl,
                                            start=True,
                                            ch_fl=[stimpar.pre, stimpar.post],
                                            fr_type="twop")["start_frame_twop"]
            ctrl_ns.append(len(fr_ns_ctrl))

        ori_data_df = stim.get_roi_data(fr_ns,
                                        stimpar.pre,
                                        stimpar.post,
                                        rem_bad=analyspar.rem_bad,
                                        scale=analyspar.scale)
        # seq x frames x ROIs
        ori_data = np.transpose(
            gen_util.reshape_df_data(ori_data_df, squeeze_cols=True),
            [1, 2, 0])

        all_input_data.append(ori_data)
        all_target_data.append(np.full(len(ori_data), g))

    all_input_data = np.concatenate(all_input_data, axis=0)
    all_target_data = np.concatenate(all_target_data)

    return all_input_data, all_target_data, ctrl_ns
Beispiel #5
0
def get_stim_data(sess,
                  stimtype,
                  win_leng_s,
                  gabfr=0,
                  pre=0,
                  post=1.5,
                  unexp="any",
                  step_size=1,
                  gabk=16,
                  run=True,
                  run_mean=None,
                  run_std=None):
    """
    get_stim_data(sess, stimtype, win_leng_s)

    Returns stimulus data (x position, y position, size, orientation, each 
    scaled based on its maximal range), and optionally running for windows 
    taken for the each of the segments of interest.

    Required args:
        - sess (Session)    : session
        - stimtype (str)    : stimulus type ("gabors"or "visflow")
        - win_leng_s (num)  : window length in seconds
    
    Optional args:
        - gabfr (int)             : gabor reference frame for determining the
                                    2p frames in each sequence
                                    default: 0 
        - pre (num)               : number of frames to include before reference
                                    gabor frame in each sequence (in sec)
                                    default: 0
        - post (num)              : number of frames to include after reference
                                    gabor frame in each sequence (in sec)
                                    default: 1.5
        - unexp (str, list or int): unexpected value criteria for including 
                                    reference gabor frames (0, 1, or "any")
                                    default: "any"
        - step_size (int)         : step size between windows
                                    default: 1
        - gabk (int or list)      : gabor kappa criteria for including reference
                                    gabor frames (4, 16 or "any")
                                    default: 16
        - run (bool)              : if True, running data is appended to the
                                    end of the stimulus data
                                    default: True
        - run_mean (num)          : mean value with which to scale running 
                                    data, if running data is included. If 
                                    run_mean or run_std is None, both are 
                                    calculated from the running data retrieved 
                                    and returned as outputs.
                                    default: None
        - run_std (num)           : standard deviation value with which to 
                                    scale running data, if running data is 
                                    included. If run_mean or run_std is None, 
                                    both are calculated from the running data 
                                    retrieved and returned as outputs.
                                    default: None
    
    Returns:
        - stim_wins (3D array): array of stimulus data, structured as:
                                seq wins x frames x pars, where the pars are:
                                    - for each gabor: x_pos, y_pos, size, ori 
                                    - run velocity
        if run and run_mean or run_std is None:
        - (list):
            - run_mean (num)  : mean of retrieved running values
            - run_std (num)   : standard deviation of retrieved running values

    """

    if win_leng_s > (pre + post):
        raise ValueError("Windows cannot be longer than the sequences.")

    stim = sess.get_stim(stimtype)

    segs = stim.get_segs_by_criteria(gabfr=gabfr,
                                     gabk=gabk,
                                     unexp=unexp,
                                     by="seg")
    twopfr = stim.get_fr_by_seg(segs, start=True,
                                fr_type="twop")["start_frame_twop"]

    # get stim params in df with indices seg x frame x gabor x par
    # (x, y, ori, size). Each param scaled to between -1 and 1 based on known
    # ranges from which they were sampled
    pars_df = stim.get_stim_par_by_fr(twopfr,
                                      pre,
                                      post,
                                      scale=True,
                                      fr_type="twop")
    targ = [len(pars_df.index.unique(lev)) for lev in pars_df.index.names] + \
        [len(pars_df.columns.unique("parameters"))]
    targ[1] = -1  # 2p frame number is not repeated across sequences
    pars = pars_df.to_numpy().reshape(targ)

    if run:
        twop_fr_seqs = gen_util.reshape_df_data(sess.get_fr_ran(
            twopfr, pre, post, fr_type="twop"),
                                                squeeze_cols=True)
        run_velocity = gen_util.reshape_df_data(sess.get_run_velocity_by_fr(
            twop_fr_seqs, rem_bad=True, scale=False),
                                                squeeze_cols=True)

        # scale running array to mean 0 with std 1
        ret_run_stats = False
        if run_mean is None or run_std is None:
            ret_run_stats = True
            run_mean = np.mean(run_velocity)
            run_std = np.std(run_velocity)
        run_velocity = 2. * (run_velocity - run_mean) / run_std - 1.

    # stim params: seq x frame x flat (gab x pars)
    all_pars = pars.reshape([pars.shape[0], pars.shape[1], -1])
    if run:
        all_pars = np.concatenate([all_pars, run_velocity[:, :, np.newaxis]],
                                  axis=2)

    win_leng = int(np.floor(win_leng_s * sess.twop_fps))

    stim_wins = []
    for seq_pars in all_pars:
        stim_wins.append(
            data_util.window_2d(seq_pars, win_leng, step_size=step_size))

    stim_wins = np.concatenate(stim_wins, axis=0).transpose([0, 2, 1])

    if run and ret_run_stats:
        return stim_wins, [run_mean, run_std]
    else:
        return stim_wins
Beispiel #6
0
def get_roi_data(sess,
                 stimtype,
                 win_leng_s,
                 gabfr=0,
                 pre=0,
                 post=1.5,
                 unexp="any",
                 step_size=1,
                 gabk=16,
                 roi_means=None,
                 roi_stds=None):
    """
    get_roi_data(sess, stimtype, win_leng_s)

    Returns stimulus data (x position, y position, size, orientation, each 
    scaled based on its maximal range), and optionally running for windows 
    taken for the each of the segments of interest.

    Required args:
        - sess (Session)    : session
        - stimtype (str)    : stimulus type ("gabors"or "visflow")
        - win_leng_s (num)  : window length in seconds
    
    Optional args:
        - gabfr (int)             : gabor reference frame for determining the
                                    2p frames in each sequence
                                    default: 0 
        - pre (num)               : number of frames to include before reference
                                    gabor frame in each sequence (in sec)
                                    default: 0
        - post (num)              : number of frames to include after reference
                                    gabor frame in each sequence (in sec)
                                    default: 1.5
        - unexp (str, list or int): unexpected value criteria for including 
                                    reference gabor frames (0, 1, or "any")
                                    default: "any"
        - step_size (int)         : step size between windows
                                    default: 1
        - gabk (int or list)      : gabor kappa criteria for including reference
                                    gabor frames (4, 16 or "any")
                                    default: 16
        - roi_means (1D array)    : mean values for each ROI with which to 
                                    scale trace data. If roi_means or 
                                    roi_stds is None, both are calculated from 
                                    the trace data retrieved and returned as 
                                    outputs.
                                    default: None
        - roi_stds (1D array)     : standard deviation values for each ROI with 
                                    which to scale trace data. If roi_means 
                                    or roi_stds is None, both are calculated 
                                    from the trace data retrieved and returned  
                                    as outputs.
                                    default: None
    
    Returns:
        - xran (1D array)      : time values for the 2p frames
        - trace_wins (3D array): array of ROI data, structured as:
                                 seq wins x frames x ROI
        if roi_means or roi_stds is None:
        - (list):
            - roi_means (1D array): trace means for each ROI
            - roi_stds (1D array) : trace standard deviations for each ROI

    """

    if win_leng_s > (pre + post):
        raise ValueError("Windows cannot be longer than the sequences.")

    stim = sess.get_stim(stimtype)

    segs = stim.get_segs_by_criteria(gabfr=gabfr,
                                     gabk=gabk,
                                     unexp=unexp,
                                     by="seg")
    twopfr = stim.get_fr_by_seg(segs, start=True,
                                fr_type="twop")["start_frame_twop"]

    roi_data_df = stim.get_roi_data(twopfr,
                                    pre,
                                    post,
                                    rem_bad=True,
                                    scale=False)
    ret_roi_stats = False
    xran = roi_data_df.index.unique("time_values").to_numpy()
    traces = gen_util.reshape_df_data(roi_data_df, squeeze_cols=True)

    # scale each ROI to mean 0, std 1
    if roi_means is None or roi_stds is None:
        ret_roi_stats = True
        roi_means = np.mean(traces.reshape(traces.shape[0], -1), axis=1)
        roi_stds = np.std(traces.reshape(traces.shape[0], -1), axis=1)
    traces = 2. * (traces - roi_means.reshape([-1, 1, 1]))/ \
        roi_stds.reshape([-1, 1, 1]) - 1.
    # traces: seq x frames x ROI
    traces = traces.transpose(1, 2, 0)

    trace_wins = []
    win_leng = int(np.floor(sess.twop_fps * win_leng_s))
    for seq_traces in traces:
        # n_wins x n_ROIs x win_leng
        trace_wins.append(
            data_util.window_2d(seq_traces, win_leng, step_size=step_size))
    # concatenate windows
    trace_wins = np.concatenate(trace_wins, axis=0).transpose([0, 2, 1])

    if ret_roi_stats:
        return xran, trace_wins, [roi_means, roi_stds]
    else:
        return xran, trace_wins
def trace_stats_by_qu(stim, qu_segs, pre, post, analyspar, byroi=True, 
                      integ=False, ret_arr=False, nan_empty=False, 
                      baseline=None, datatype="roi"):
    """
    trace_stats_by_qu(stim, qu_seg, pre, post, analyspar)

    Returns trace statistics for the quantiles of interest. If ret_arr, also
    returns trace data arrays.

    Required args:
        - stim (Stim object)   : stim object
        - qu_segs (dict)       : list of sublists for each quantile, each 
                                 containing segment numbers for that quantile
        - pre (num)            : range of frames to include before each frame 
                                 reference (in s)
        - post (num)           : range of frames to include after each frame 
                                 reference (in s)
        - analyspar (AnalysPar): named tuple containing analysis parameters
    
    Optional args:
        - byroi (bool)    : If datatype is "roi", if True, returns statistics 
                            for each ROI. If False, returns statistics 
                            across ROIs.
                            default: True
        - integ (bool)    : if True, dF/F is integrated over sequences
                            default: False
        - ret_arr (bool)  : if True, data arrays are returned also
                            default: False
        - nan_empty (bool): if a quantile is empty, returns NaN arrays instead
                            of an error (1 sequence, for qu_array) 
                            default: False
        - baseline (num)  : number of seconds to use as baseline. If None,
                            data is not baselined.
                            default: None
        - datatype (str)  : datatype, i.e. ROIs or running
                            default: "roi"

    Returns:
        - xran (1D array)          : time values for the 2p frames (None if 
                                     integ)
        - qu_stats (2 to 4D array) : trace data statistics, structured as:
                                         quantiles x
                                         stats (me, err) x
                                         (ROIs if byroi x)
                                         (frames if not integ)
        if ret_arr, also:
        - qu_array (list)          : list per quantile of 1-3D arrays of trace 
                                     data structured as:
                                        (ROIs x) sequences 
                                        (x frames if not integ)
    """
    
    if datatype == "roi" and (stim.sess.only_tracked_rois != analyspar.tracked):
        raise RuntimeError(
            "stim.sess.only_tracked_rois should match analyspar.tracked."
            )

    qu_stats, qu_array = [], []
    xran = None
    for segs in qu_segs:
        rep_nan = False
        for _ in range(2): # allows retrying if nan_empty is True
            try:
                if datatype == "roi":
                    twop_fr = stim.get_fr_by_seg(
                        segs, start=True, fr_type="twop")["start_frame_twop"]
                    trace_df = stim.get_roi_stats_df(twop_fr, pre, post, 
                        byroi=byroi, fluor=analyspar.fluor, 
                        rem_bad=analyspar.rem_bad, 
                        stats=analyspar.stats, error=analyspar.error,
                        integ=integ, ret_arr=ret_arr, scale=analyspar.scale,
                        baseline=baseline)
                elif datatype == "run":
                    stim_fr = stim.get_fr_by_seg(
                        segs, start=True, fr_type="stim")["start_frame_stim"]
                    trace_df = stim.get_run_stats_df(stim_fr, pre, post, 
                        rem_bad=analyspar.rem_bad,
                        stats=analyspar.stats, error=analyspar.error,
                        integ=integ, ret_arr=ret_arr, scale=analyspar.scale,
                        baseline=baseline)
                else:
                    gen_util.accepted_values_error(
                        "datatype", datatype, ["roi", "run"])
                break # break out of for loop if successful
            except Exception as err: # RuntimeError or ValueError
                empty = ("No frames" in str(err) or "No segments" in str(err))
                if nan_empty and empty:
                    segs = [10]     # dummy segment to use
                    rep_nan = True # later, replace values with NaNs
                else:
                    raise err

        if not integ:
            xran = trace_df.index.unique("time_values").to_numpy()
        
        # array: stats [me, err] (x ROI) (x frames)
        # (catch performance warning for unsorted large dataframes)
        msg, categ = ["indexing past lexsort", pd.errors.PerformanceWarning]
        with gen_util.TempWarningFilter(msg, categ):
            trace_stats = gen_util.reshape_df_data(
                trace_df.loc["stats", ], squeeze_cols=True)

        if datatype == "roi":
            if not byroi:
                trace_stats = trace_stats.squeeze(0)
            else:
                trace_stats = trace_stats.transpose(
                    1, 0, *range(len(trace_stats.shape))[2:])
        if rep_nan: # replace dummy values with NaNs
            trace_stats = np.full_like(trace_stats, np.nan)
        qu_stats.append(trace_stats)
        if ret_arr:
            trace_array = gen_util.reshape_df_data(
                trace_df.loc["data", ], squeeze_cols=True)
            if rep_nan: # replace dummy values with NaNs
                trace_array = np.full_like(trace_array, np.nan)
            qu_array.append(trace_array)

    qu_stats = np.asarray(qu_stats)

    if ret_arr:
        return xran, qu_stats, qu_array
    else:
        return xran, qu_stats
Beispiel #8
0
def get_data(stim,
             refs,
             analyspar,
             pre=0,
             post=1,
             ch_fl=None,
             integ=False,
             ref_type="segs",
             datatype="roi"):
    """
    get_data(stim, refs, analyspar)

    Returns data for a specific stimulus around sequence references provided.

    Required args:
        - stim (Stim):
            Stimulus object
        - refs (1D array):
            Sequences references (either segments or frames, specified by 
            ref_type)
        - analyspar (AnalysPar): 
            named tuple containing analysis parameters

    Optional args:
        - pre (num): 
            number of seconds to keep before refs
            default: 0
        - post (num): 
            number of seconds to keep after refs
            default: 1
        - ch_fl (list):
            flanks to check for discarding refs with insufficient flanks
            default: None
        - integ (bool):
            if True, sequence data is integrated
            default: False
        - ref_type (str):
            type of references provided 
            (segments, twop frames or stimulus frames)
            ("segs", "twop", "stim")
            default: "segs"
        - datatype (str):
            type of data to return ("roi", "run" or "pupil")
            default: "roi"

    Returns:
        - data_arr (1-3D array):
            sequence data array
            dims: (ROIs x) seq (x frames)
        - time_values (1D array):
            values for each frame, in seconds
    """

    if stim.sess.only_tracked_rois != analyspar.tracked:
        raise RuntimeError(
            "stim.sess.only_tracked_rois should match analyspar.tracked.")

    fr_ns, _ = get_frame_numbers(stim,
                                 refs,
                                 ch_fl=ch_fl,
                                 ref_type=ref_type,
                                 datatype=datatype)

    # obtain data
    if datatype == "roi":
        data_df = stim.get_roi_data(fr_ns,
                                    pre,
                                    post,
                                    rem_bad=analyspar.rem_bad,
                                    scale=analyspar.scale)
        col_name = "roi_traces"
        integ_dt = stim.sess.twop_fps
    elif datatype == "run":
        data_df = stim.get_run_data(fr_ns,
                                    pre,
                                    post,
                                    rem_bad=analyspar.rem_bad,
                                    scale=analyspar.scale)
        col_name = "run_velocity"
        integ_dt = stim.sess.stim_fps
    elif datatype == "pupil":
        data_df = stim.get_pup_diam_data(fr_ns,
                                         pre,
                                         post,
                                         rem_bad=analyspar.rem_bad,
                                         scale=analyspar.scale)
        col_name = "pup_diam"
        integ_dt = stim.sess.twop_fps
    else:
        gen_util.accepted_values_error("datatype", datatype,
                                       ["roi", "run", "pupil"])

    time_values = data_df.index.unique("time_values").to_numpy()

    data_arr = gen_util.reshape_df_data(data_df[col_name], squeeze_cols=True)

    if integ:
        nanpol = None if analyspar.rem_bad else "omit"
        data_arr = math_util.integ(data_arr,
                                   1. / integ_dt,
                                   axis=-1,
                                   nanpol=nanpol)

    return data_arr, time_values
Beispiel #9
0
def calc_tune_curvs(sess,
                    analyspar,
                    stimpar,
                    nrois="all",
                    ngabs="all",
                    grp2="unexp",
                    comb_gabs=True,
                    vm_estim=False,
                    collapse=True,
                    parallel=True):
    """
    calc_tune_curvs(sess, analyspar, stimpar)

    Returns orientations and corresponding fluorescence levels for the sessions
    of interest.

    Required args:
        - sess (Session)       : session
        - analyspar (AnalysPar): named tuple containing analysis parameters
        - stimpar (StimPar)    : named tuple containing stimulus parameters

    Optional args:
        - nrois (int)     : number of ROIs to include in analysis
                            default: "all"
        - ngabs (int)     : number of gabors to include in analysis (set to 1 
                            if comb_gabs, as all gabors are combined)
                            default: "all"
        - grp2 (str)      : second group: either unexp, exp or rand (random 
                            subsample of exp, the size of unexp)
                            default: "unexp"
        - comb_gabs (bool): if True, all gabors have been combined for 
                            gab_oris and roi_data 
                            default: False
        - vm_estim (bool) : if True, analysis is run using a von Mises tuning 
                            curve estimation method
        - collapse (bool) : if True, opposite orientations in the 0 to 360 
                            range are collapsed to the 0 to 180 range 
        - parallel (bool) : if True, some of the analysis is parallelized 
                            across CPU cores

    Returns:
        - tc_oris (list)     : list of orientation values corresponding to the 
                               tc_data:
                                   unexp x gabor (1 if comb_gabs) x oris
        - tc_data (list)     : list of mean integrated fluorescence data per 
                               orientation, for each ROI, structured as 
                                  ROI x unexp x gabor (1 if comb_gabs) 
                                      x oris
        - tc_nseqs (list)    : number of sequences per unexp

        if vm_estim, also:
        - tc_vm_pars (list)  : nested list of Von Mises parameters for each ROI: 
                                  ROI x unexp x gabor (1 if comb_gabs) x par
        - tc_vm_mean (list)  : nested list of mean Von Mises means for each ROI, 
                               not weighted by kappa value or weighted (if not 
                               comb_gabs) (in rad): 
                                   ROI x unexp x kappa weighted (False, (True))
        - tc_hist_pars (list): parameters used to convert tc_data to histogram 
                               values (sub, mult) used in Von Mises parameter 
                               estimation, structured as:
                                   ROI x unexp x gabor (1 if comb_gabs) x 
                                   param (sub, mult)
    """

    if sess.only_tracked_rois != analyspar.tracked:
        raise RuntimeError(
            "sess.only_tracked_rois should match analyspar.tracked.")

    gabfrs = gen_util.list_if_not(stimpar.gabfr)
    if len(gabfrs) == 1:
        gabfrs = gabfrs * 2
    if grp2 == "unexp":
        unexps = [0, 1]
    elif grp2 in ["exp", "rand"]:
        unexps = [0, 0]
    else:
        gen_util.accepted_values_error("grp2", grp2, ["unexp", "exp", "rand"])

    stim = sess.get_stim(stimpar.stimtype)
    nrois_tot = sess.get_nrois(analyspar.rem_bad, analyspar.fluor)
    ngabs_tot = stim.n_patches
    if nrois == "all":
        sess_nrois = nrois_tot
    else:
        sess_nrois = np.min([nrois_tot, nrois])

    if ngabs == "all":
        sess_ngabs = stim.n_patches
    else:
        sess_ngabs = np.min([stim.n_patches, ngabs])

    tc_data, tc_oris, tc_nseqs = [], [], []
    # estimate tuning curves by fitting a Von Mises distribution
    if vm_estim:
        tc_vm_pars, tc_vm_mean, tc_hist_pars = [], [], []

    for i, (gf, e) in enumerate(zip(gabfrs, unexps)):
        # get segments
        segs = stim.get_segs_by_criteria(gabfr=gf,
                                         visflow_dir=stimpar.visflow_dir,
                                         visflow_size=stimpar.visflow_size,
                                         gabk=stimpar.gabk,
                                         unexp=e,
                                         by="seg")

        if grp2 == "rand" and i == 1:
            n_segs = len(
                stim.get_segs_by_criteria(gabfr=gf,
                                          visflow_dir=stimpar.visflow_dir,
                                          visflow_size=stimpar.visflow_size,
                                          gabk=stimpar.gabk,
                                          unexp=1,
                                          by="seg"))
            np.random.shuffle(segs)
            segs = sorted(segs[:n_segs])
        tc_nseqs.append(len(segs))
        twopfr = stim.get_fr_by_seg(segs, start=True,
                                    fr_type="twop")["start_frame_twop"]
        # ROI x seq
        roi_data = gen_util.reshape_df_data(stim.get_roi_data(
            twopfr,
            stimpar.pre,
            stimpar.post,
            analyspar.fluor,
            integ=True,
            rem_bad=analyspar.rem_bad,
            scale=analyspar.scale)["roi_traces"],
                                            squeeze_cols=True)[:sess_nrois]

        # gab x seq
        gab_oris = gen_util.reshape_df_data(stim.get_stim_par_by_seg(
            segs, pos=False, ori=True, size=False),
                                            squeeze_cols=True).T
        if collapse:
            gab_oris = collapse_dir(gab_oris)

        if comb_gabs:
            ngabs = 1
            gab_oris = gab_oris.reshape([1, -1])
            roi_data = np.tile(roi_data, [1, ngabs_tot])

        tc_oris.append(gab_oris.tolist())
        tc_data.append(roi_data.tolist())

        # estimate tuning curves by fitting a Von Mises distribution
        if vm_estim:
            [
                gab_tc_oris, gab_tc_data, gab_vm_pars, gab_vm_mean,
                gab_hist_pars
            ] = tune_curv_estims(gab_oris,
                                 roi_data,
                                 ngabs_tot,
                                 sess_nrois,
                                 sess_ngabs,
                                 comb_gabs,
                                 collapse=False,
                                 parallel=parallel)
            tc_oris[i] = gab_tc_oris
            tc_data[i] = gab_tc_data
            tc_vm_pars.append(gab_vm_pars)
            tc_vm_mean.append(gab_vm_mean)
            tc_hist_pars.append(gab_hist_pars)

    if vm_estim:
        return tc_oris, tc_data, tc_nseqs, tc_vm_pars, tc_vm_mean, tc_hist_pars
    else:
        return tc_oris, tc_data, tc_nseqs
Beispiel #10
0
def peristim_data(sess,
                  stimpar,
                  ran_s=None,
                  datatype="both",
                  returns="diff",
                  fluor="dff",
                  stats="mean",
                  rem_bad=True,
                  scale=False,
                  first_unexp=True,
                  trans_all=False):
    """
    peristim_data(sess, stimpar)

    Returns pupil, ROI and run data around unexpected onset, or the difference 
    between post and pre unexpected onset, or both.

    Required args:
        - sess (Session)   : session object
        - stimpar (StimPar): named tuple containing stimulus parameters

    Optional args:
        - ran_s (dict, list or num): number of frames to take before and after 
                                     unexpected for each datatype (ROI, run, 
                                     pupil) (in sec).  
                                         If dictionary, expected keys are:
                                            "pup_pre", "pup_post", 
                                            ("roi_pre", "roi_post"), 
                                            ("run_pre", "run_post"), 
                                        If list, should be structured as 
                                        [pre, post] and the same values will be 
                                        used for all datatypes. 
                                        If num, the same value will be used 
                                            for all keys. 
                                        If None, the values are taken from the
                                            stimpar pre and post attributes.
                                     default: None
        - datatype (str)           : type of data to include with pupil data, 
                                     "roi", "run" or "both"
                                     default: "roi" 
        - returns (str)            : type of data to return (data around 
                                     unexpected, difference between post and pre 
                                     unexpected)
                                     default: "diff"
        - fluor (str)              : if "dff", dF/F is used, if "raw", ROI 
                                     traces
                                     default: "dff"
        - stats (str)              : measure on which to take the pre and post
                                     unexpected difference: either mean ("mean") 
                                     or median ("median")
                                     default: "mean"
        - rem_bad (bool)           : if True, removes ROIs with NaN/Inf values 
                                     anywhere in session and running array with
                                     NaNs linearly interpolated is used. If 
                                     False, NaNs are ignored in calculating 
                                     statistics for the ROI and running data 
                                     (always ignored for pupil data)
                                     default: True
        - scale (bool)             : if True, data is scaled
                                     default: False
        - first_unexp (bool)        : if True, only the first of consecutive 
                                     unexpecteds are retained
                                     default: True
        - trans_all (bool)         : if True, only ROIs with transients are 
                                     retained
                                     default: False

    Returns:
        if datatype == "data" or "both":
        - datasets (list): list of 2-3D data arrays, structured as
                               datatype (pupil, (ROI), (running)) x 
                               [trial x frames (x ROI)]
        elif datatype == "diff" or "both":
        - diffs (list)   : list of 1-2D data difference arrays, structured as
                               datatype (pupil, (ROI), (running)) x 
                               [trial (x ROI)]    
    """

    stim = sess.get_stim(stimpar.stimtype)

    # initialize ran_s dictionary if needed
    if ran_s is None:
        ran_s = [stimpar.pre, stimpar.post]
    ran_s = get_ran_s(ran_s, datatype)

    if first_unexp:
        unexp_segs = stim.get_segs_by_criteria(
            visflow_dir=stimpar.visflow_dir,
            visflow_size=stimpar.visflow_size,
            gabk=stimpar.gabk,
            unexp=1,
            remconsec=True,
            by="seg")
        if stimpar.stimtype == "gabors":
            unexp_segs = [seg + stimpar.gabfr for seg in unexp_segs]
    else:
        unexp_segs = stim.get_segs_by_criteria(
            visflow_dir=stimpar.visflow_dir,
            visflow_size=stimpar.visflow_size,
            gabk=stimpar.gabk,
            gabfr=stimpar.gabfr,
            unexp=1,
            remconsec=False,
            by="seg")

    unexp_twopfr = stim.get_fr_by_seg(unexp_segs, start=True,
                                      fr_type="twop")["start_frame_twop"]
    unexp_stimfr = stim.get_fr_by_seg(unexp_segs, start=True,
                                      fr_type="stim")["start_frame_stim"]
    # get data dataframes
    pup_data = gen_util.reshape_df_data(stim.get_pup_diam_data(
        unexp_twopfr,
        ran_s["pup_pre"],
        ran_s["pup_post"],
        rem_bad=rem_bad,
        scale=scale)["pup_diam"],
                                        squeeze_cols=True)

    datasets = [pup_data]
    datanames = ["pup"]
    if datatype in ["roi", "both"]:
        # ROI x trial x fr
        roi_data = gen_util.reshape_df_data(stim.get_roi_data(
            unexp_twopfr,
            ran_s["roi_pre"],
            ran_s["roi_post"],
            fluor=fluor,
            integ=False,
            rem_bad=rem_bad,
            scale=scale,
            transients=trans_all)["roi_traces"],
                                            squeeze_cols=True)
        datasets.append(roi_data.transpose([1, 2, 0]))  # ROIs last
        datanames.append("roi")
    if datatype in ["run", "both"]:
        run_data = gen_util.reshape_df_data(stim.get_run_data(
            unexp_stimfr,
            ran_s["run_pre"],
            ran_s["run_post"],
            rem_bad=rem_bad,
            scale=scale),
                                            squeeze_cols=True)
        datasets.append(run_data)
        datanames.append("run")

    if rem_bad:
        nanpolgen = None
    else:
        nanpolgen = "omit"

    if returns in ["diff", "both"]:
        for key in ran_s.keys():
            if "pre" in key and ran_s[key] == 0:
                raise ValueError(
                    "Cannot set pre to 0 if returns is 'diff' or 'both'.")
        # get avg for first and second halves
        diffs = []
        for dataset, name in zip(datasets, datanames):
            if name == "pup":
                nanpol = "omit"
            else:
                nanpol = nanpolgen
            n_fr = dataset.shape[1]
            pre_s = ran_s[f"{name}_pre"]
            post_s = ran_s[f"{name}_post"]
            split = int(np.round(pre_s / (pre_s + post_s) *
                                 n_fr))  # find 0 mark
            pre = math_util.mean_med(dataset[:, :split], stats, 1, nanpol)
            post = math_util.mean_med(dataset[:, split:], stats, 1, nanpol)
            diffs.append(post - pre)

    if returns == "data":
        return datasets
    elif returns == "diff":
        return diffs
    elif returns == "both":
        return datasets, diffs
    else:
        gen_util.accepted_values_error("returns", returns,
                                       ["data", "diff", "both"])