Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blackened and ruffed #244

Merged
merged 2 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Normalize line endings
89ea7df05f77475bcfd874f3bccab878d653af6a
89ea7df05f77475bcfd874f3bccab878d653af6a
947eb6c1f701050a03d319feee168260f2a485a0
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
default_language_version:
python: python3.11

files: "^(docker|aeon\/dj_pipeline)\/.*$"
files: "^(test|aeon(?!\/dj_pipeline\/).*)$"
jkbhagatio marked this conversation as resolved.
Show resolved Hide resolved
repos:
- repo: meta
hooks:
Expand All @@ -30,7 +30,7 @@ repos:
hooks:
- id: black
args: [--check, --config, ./pyproject.toml]

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.286
hooks:
Expand Down
55 changes: 29 additions & 26 deletions aeon/analysis/movies.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import cv2
import math

import cv2
import numpy as np
import pandas as pd
import aeon.io.video as video

from aeon.io import video


def gridframes(frames, width, height, shape=None):
'''
Arranges a set of frames into a grid layout with the specified
"""Arranges a set of frames into a grid layout with the specified
pixel dimensions and shape.

:param list frames: A list of frames to include in the grid layout.
Expand All @@ -16,15 +18,15 @@ def gridframes(frames, width, height, shape=None):
Either the number of frames to include, or the number of rows and columns
in the output grid image layout.
:return: A new image containing the arrangement of the frames in a grid.
'''
"""
if shape is None:
shape = len(frames)
if type(shape) not in [list,tuple]:
if type(shape) not in [list, tuple]:
shape = math.ceil(math.sqrt(shape))
shape = (shape, shape)

dsize = (height, width, 3)
cellsize = (height // shape[0], width // shape[1],3)
cellsize = (height // shape[0], width // shape[1], 3)
grid = np.zeros(dsize, dtype=np.uint8)
for i in range(shape[0]):
for j in range(shape[1]):
Expand All @@ -39,19 +41,20 @@ def gridframes(frames, width, height, shape=None):
grid[i0:i1, j0:j1] = cv2.resize(frame, (cellsize[1], cellsize[0]))
return grid


def averageframes(frames):
"""Returns the average of the specified collection of frames."""
return cv2.convertScaleAbs(sum(np.multiply(1 / len(frames), frames)))


def groupframes(frames, n, fun):
'''
Applies the specified function to each group of n-frames.
"""Applies the specified function to each group of n-frames.

:param iterable frames: A sequence of frames to process.
:param int n: The number of frames in each group.
:param callable fun: The function used to process each group of frames.
:return: An iterable returning the results of applying the function to each group.
'''
"""
i = 0
group = []
for frame in frames:
Expand All @@ -61,9 +64,9 @@ def groupframes(frames, n, fun):
group.clear()
i = i + 1


def triggerclip(data, events, before=pd.Timedelta(0), after=pd.Timedelta(0)):
'''
Split video data around the specified sequence of event timestamps.
"""Split video data around the specified sequence of event timestamps.

:param DataFrame data:
A pandas DataFrame where each row specifies video acquisition path and frame number.
Expand All @@ -72,7 +75,7 @@ def triggerclip(data, events, before=pd.Timedelta(0), after=pd.Timedelta(0)):
:param Timedelta after: The right offset from each timestamp used to clip the data.
:return:
A pandas DataFrame containing the frames, clip and sequence numbers for each event timestamp.
'''
"""
if before is not pd.Timedelta:
before = pd.Timedelta(before)
if after is not pd.Timedelta:
Expand All @@ -81,30 +84,30 @@ def triggerclip(data, events, before=pd.Timedelta(0), after=pd.Timedelta(0)):
events = events.index

clips = []
for i,index in enumerate(events):
clip = data.loc[(index-before):(index+after)].copy()
clip['frame_sequence'] = list(range(len(clip)))
clip['clip_sequence'] = i
for i, index in enumerate(events):
clip = data.loc[(index - before) : (index + after)].copy()
clip["frame_sequence"] = list(range(len(clip)))
clip["clip_sequence"] = i
clips.append(clip)
return pd.concat(clips)


def collatemovie(clipdata, fun):
'''
Collates a set of video clips into a single movie using the specified aggregation function.
"""Collates a set of video clips into a single movie using the specified aggregation function.

:param DataFrame clipdata:
A pandas DataFrame where each row specifies video path, frame number, clip and sequence number.
This DataFrame can be obtained from the output of the triggerclip function.
:param callable fun: The aggregation function used to process the frames in each clip.
:return: The sequence of processed frames representing the collated movie.
'''
clipcount = len(clipdata.groupby('clip_sequence').frame_sequence.count())
allframes = video.frames(clipdata.sort_values(by=['frame_sequence', 'clip_sequence']))
"""
clipcount = len(clipdata.groupby("clip_sequence").frame_sequence.count())
allframes = video.frames(clipdata.sort_values(by=["frame_sequence", "clip_sequence"]))
return groupframes(allframes, clipcount, fun)


def gridmovie(clipdata, width, height, shape=None):
'''
Collates a set of video clips into a grid movie with the specified pixel dimensions
"""Collates a set of video clips into a grid movie with the specified pixel dimensions
and grid layout.

:param DataFrame clipdata:
Expand All @@ -116,5 +119,5 @@ def gridmovie(clipdata, width, height, shape=None):
Either the number of frames to include, or the number of rows and columns
in the output grid movie layout.
:return: The sequence of processed frames representing the collated grid movie.
'''
return collatemovie(clipdata, lambda g:gridframes(g, width, height, shape))
"""
return collatemovie(clipdata, lambda g: gridframes(g, width, height, shape))
25 changes: 8 additions & 17 deletions aeon/analysis/plotting.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import math

import matplotlib.colors as colors
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib import colors
from matplotlib.collections import LineCollection

from aeon.analysis.utils import *


def heatmap(position, frequency, ax=None, **kwargs):
"""
Draw a heatmap of time spent in each location from specified position data and sampling frequency.
"""Draw a heatmap of time spent in each location from specified position data and sampling frequency.

:param Series position: A series of position data containing x and y coordinates.
:param number frequency: The sampling frequency for the position data.
Expand All @@ -33,8 +32,7 @@ def heatmap(position, frequency, ax=None, **kwargs):


def circle(x, y, radius, fmt=None, ax=None, **kwargs):
"""
Plot a circle centered at the given x, y position with the specified radius.
"""Plot a circle centered at the given x, y position with the specified radius.

:param number x: The x-component of the circle center.
:param number y: The y-component of the circle center.
Expand Down Expand Up @@ -62,8 +60,7 @@ def rateplot(
ax=None,
**kwargs,
):
"""
Plot the continuous event rate and raster of a discrete event sequence, given the specified
"""Plot the continuous event rate and raster of a discrete event sequence, given the specified
window size and sampling frequency.

:param Series events: The discrete sequence of events.
Expand All @@ -79,9 +76,7 @@ def rateplot(
:param Axes, optional ax: The Axes on which to draw the rate plot and raster.
"""
label = kwargs.pop("label", None)
eventrate = rate(
events, window, frequency, weight, start, end, smooth=smooth, center=center
)
eventrate = rate(events, window, frequency, weight, start, end, smooth=smooth, center=center)
jkbhagatio marked this conversation as resolved.
Show resolved Hide resolved
if ax is None:
ax = plt.gca()
ax.plot(
Expand All @@ -90,14 +85,11 @@ def rateplot(
label=label,
**kwargs,
)
ax.vlines(
sessiontime(events.index, eventrate.index[0]), -0.2, -0.1, linewidth=1, **kwargs
)
ax.vlines(sessiontime(events.index, eventrate.index[0]), -0.2, -0.1, linewidth=1, **kwargs)


def set_ymargin(ax, bottom, top):
"""
Set the vertical margins of the specified Axes.
"""Set the vertical margins of the specified Axes.

:param Axes ax: The Axes for which to specify the vertical margin.
:param number bottom: The size of the bottom margin.
Expand All @@ -121,8 +113,7 @@ def colorline(
ax=None,
**kwargs,
):
"""
Plot a dynamically colored line on the specified Axes.
"""Plot a dynamically colored line on the specified Axes.

:param array-like x, y: The horizontal / vertical coordinates of the data points.
:param array-like, optional z:
Expand Down
Loading
Loading