SainsburyWellcomeCentre / aeon_mecha

Project Aeon's main library for interfacing with acquired data. Contains modules for raw data file io, data querying, data processing, data qc, database ingestion, and building computational data pipelines.
BSD 3-Clause "New" or "Revised" License
6 stars 6 forks source link

added working 'get_foraging_bouts' function #410

Closed jkbhagatio closed 1 month ago

ttngu207 commented 2 months ago

Looks good @jkbhagatio

See below for my proposed table design to store this


@schema
class BlockSubjectForaging(dj.Computed):
    definition = """
    -> BlockSubjectAnalysis
    ---
    bout_count: int  # number of foraging bouts in the block
    """

    class Bout(dj.Part):
        definition = """
        -> master
        -> BlockAnalysis.Subject
        bout_start: datetime(6)
        ---
        bout_end: datetime(6)
        bout_duration: decimal(5, 3)  # (hour)
        pellet_count: int  # number of pellets consumed during the bout
        cum_wheel_dist: float  # cumulative distance travelled during the bout
        """

    def make(self, key):
        foraging_bout_df = get_foraging_bouts(key)
        foraging_bout_df.rename(
            columns={
                "subject_name": "subject",
                "bout_start": "start",
                "bout_end": "end",
                "pellet_count": "n_pellets",
                "cum_wheel_dist": "cum_wheel_dist",
            },
            inplace=True,
        )

        foraging_bout_df["bout_duration"] = (
            foraging_bout_df["bout_start"] - foraging_bout_df["bout_end"]
        ).dt.total_seconds() / 3600
        self.insert1({**key, "bout_count": len(foraging_bout_df)})
        self.Bout.insert({**key, **row} for _, row in foraging_bout_df.iterrows())
lochhh commented 2 months ago

I'm not sure if the current foraging detection logic is robust or we need better default values. In the example below, the dotted vertical black lines mark the start ('2023-12-02 08:28:45.500000') and end of a foraging bout ('2023-12-02 08:30:26.900000095') but this foraging bout excludes the third pellet delivery (blue vertical line at '2023-12-02T08:30:27.219264030')

block_key = {
        'experiment_name': 'social0.1-aeon3',
        'block_start': datetime.datetime(2023, 12, 2, 8, 17)
}

output

jkbhagatio commented 1 month ago

Looks good @jkbhagatio

See below for my proposed table design to store this


@schema
class BlockSubjectForaging(dj.Computed):
    definition = """
    -> BlockSubjectAnalysis
    ---
    bout_count: int  # number of foraging bouts in the block
    """

    class Bout(dj.Part):
        definition = """
        -> master
        -> BlockAnalysis.Subject
        bout_start: datetime(6)
        ---
        bout_end: datetime(6)
        bout_duration: decimal(5, 3)  # (hour)
        pellet_count: int  # number of pellets consumed during the bout
        cum_wheel_dist: float  # cumulative distance travelled during the bout
        """

    def make(self, key):
        foraging_bout_df = get_foraging_bouts(key)
        foraging_bout_df.rename(
            columns={
                "subject_name": "subject",
                "bout_start": "start",
                "bout_end": "end",
                "pellet_count": "n_pellets",
                "cum_wheel_dist": "cum_wheel_dist",
            },
            inplace=True,
        )

        foraging_bout_df["bout_duration"] = (
            foraging_bout_df["bout_start"] - foraging_bout_df["bout_end"]
        ).dt.total_seconds() / 3600
        self.insert1({**key, "bout_count": len(foraging_bout_df)})
        self.Bout.insert({**key, **row} for _, row in foraging_bout_df.iterrows())

Maybe we can remove saving 'bout_duration' in the table as its trivial for the user to compute given the start and end?