Repository navigation
Make zarr time axis dense #291
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
Merged
Merged
Changes from 10 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
e400487
Review proposal from claude
sfmig 1a30d0b
Review output array shape
sfmig f746245
Fix output video script
sfmig 78968ae
First reviewed proposal draft
sfmig 445f33c
Final reviewed proposal
sfmig a8a8474
Remove sam2 plan
sfmig cd9e0ce
Anchor the tracks zarr `time` coordinate to the clip
sfmig f94b883
Assert the values of `time` and `escape_state`, not just their presence
sfmig 84030dd
Document what `time` means in the tracks zarr store
sfmig 1bc3070
Remove plan
sfmig 57e0612
Review tests
sfmig 4aa3137
Apply batched suggestions from code review
sfmig 0ed7597
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] b20586f
Wrap lines that exceeded the 79-char limit
sfmig eb4c280
Small edits
sfmig 9a57dd1
Check http?
sfmig d09372d
Revert "Check http?"
sfmig cab4ceb
Try swc gin
sfmig d8289a9
Fix url
sfmig File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |||||||||||||
| from contextlib import nullcontext as does_not_raise | ||||||||||||||
| from pathlib import Path | ||||||||||||||
|
|
||||||||||||||
| import numpy as np | ||||||||||||||
| import pandas as pd | ||||||||||||||
| import pytest | ||||||||||||||
| import xarray as xr | ||||||||||||||
|
|
@@ -24,11 +25,16 @@ | |||||||||||||
| def sample_via_tracks_file_factory(tmp_path): | ||||||||||||||
| """Return factory of VIA tracks files with custom filenames.""" | ||||||||||||||
|
|
||||||||||||||
| def _sample_via_tracks_file(filename): | ||||||||||||||
| """Create a mock VIA tracks file.""" | ||||||||||||||
| def _sample_via_tracks_file(filename, frame_indices=None): | ||||||||||||||
| """Create a mock VIA tracks file. | ||||||||||||||
|
|
||||||||||||||
| By default the file holds boxes for a sparse set of frames of a | ||||||||||||||
| 101-frame clip, which is the case the dense `time` axis is about. | ||||||||||||||
| Pass `frame_indices` to write boxes for a different set of frames. | ||||||||||||||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
| """ | ||||||||||||||
| # Add a few frames with bounding box annotations | ||||||||||||||
| via_data = [] | ||||||||||||||
| for frame_idx in [0, 10, 20, 50, 60, 80, 100]: | ||||||||||||||
| for frame_idx in frame_indices or [0, 10, 20, 50, 60, 80, 100]: | ||||||||||||||
| via_data.append( | ||||||||||||||
| { | ||||||||||||||
| "filename": f"frame_{frame_idx:08d}.png", | ||||||||||||||
|
|
@@ -151,6 +157,96 @@ def test_load_extended_ds( | |||||||||||||
| assert "clip_escape_first_frame_0idx" in ds.coords | ||||||||||||||
| assert "clip_escape_type" in ds.coords | ||||||||||||||
|
|
||||||||||||||
| # Check time spans the full clip, as the clip's 0-based frame index | ||||||||||||||
| assert ds.sizes["time"] == 101 | ||||||||||||||
| assert np.array_equal(ds.time.values, np.arange(101)) | ||||||||||||||
|
|
||||||||||||||
| # Check the escape starts at clip frame 51 | ||||||||||||||
| # (global frame 150, clip starting at global frame 99) | ||||||||||||||
| escape_state = ds.escape_state.values.ravel() | ||||||||||||||
| assert int(np.argmax(escape_state)) == 51 | ||||||||||||||
| assert escape_state.sum() == 101 - 51 | ||||||||||||||
|
|
||||||||||||||
| # Check frames with no boxes are all-NaN rows, rather than missing | ||||||||||||||
| # (the VIA tracks file holds boxes for frames 0, 10, 20, 50, 60, 80, 100) | ||||||||||||||
| assert ds.position.isel(time=1).isnull().all() | ||||||||||||||
| assert not ds.position.isel(time=10).isnull().any() | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| def test_load_extended_ds_contiguous_file( | ||||||||||||||
| sample_via_tracks_file_factory, sample_metadata_df_factory | ||||||||||||||
| ): | ||||||||||||||
| """Test a VIA tracks file with one row per frame of the clip. | ||||||||||||||
|
|
||||||||||||||
| It should give the same `time` and `escape_state` as the sparse file, | ||||||||||||||
| and no NaN rows. | ||||||||||||||
| """ | ||||||||||||||
| via_tracks_path = sample_via_tracks_file_factory( | ||||||||||||||
| "04.09.2023-01-Right-Loop05_tracks.csv", | ||||||||||||||
| frame_indices=list(range(101)), | ||||||||||||||
| ) | ||||||||||||||
| df_metadata = sample_metadata_df_factory([via_tracks_path]) | ||||||||||||||
|
|
||||||||||||||
| ds = load_extended_ds(via_tracks_path, df_metadata) | ||||||||||||||
|
|
||||||||||||||
| assert np.array_equal(ds.time.values, np.arange(101)) | ||||||||||||||
| escape_state = ds.escape_state.values.ravel() | ||||||||||||||
| assert int(np.argmax(escape_state)) == 51 | ||||||||||||||
| assert escape_state.sum() == 101 - 51 | ||||||||||||||
| assert not ds.position.isnull().any() | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| @pytest.mark.parametrize( | ||||||||||||||
| "frame_indices", | ||||||||||||||
| [ | ||||||||||||||
| pytest.param( | ||||||||||||||
| list(range(99, 200)), | ||||||||||||||
| id="tracked_on_full_video_or_wrong_metadata_row", | ||||||||||||||
| ), | ||||||||||||||
| pytest.param( | ||||||||||||||
| list(range(102)), id="cut_clip_longer_than_metadata_states" | ||||||||||||||
| ), | ||||||||||||||
| ], | ||||||||||||||
| ) | ||||||||||||||
| def test_load_extended_ds_frames_out_of_clip_range( | ||||||||||||||
| frame_indices, sample_via_tracks_file_factory, sample_metadata_df_factory | ||||||||||||||
| ): | ||||||||||||||
| """Test the guard on frame numbers outside the clip's frame range. | ||||||||||||||
|
|
||||||||||||||
| Without it, `reindex` would silently drop the out-of-range rows. | ||||||||||||||
| """ | ||||||||||||||
| via_tracks_path = sample_via_tracks_file_factory( | ||||||||||||||
| "04.09.2023-01-Right-Loop05_tracks.csv", frame_indices=frame_indices | ||||||||||||||
| ) | ||||||||||||||
| df_metadata = sample_metadata_df_factory([via_tracks_path]) | ||||||||||||||
|
|
||||||||||||||
| with pytest.raises(ValueError) as exc_info: | ||||||||||||||
| load_extended_ds(via_tracks_path, df_metadata) | ||||||||||||||
|
|
||||||||||||||
| # The message reports the file's own range and the clip's range | ||||||||||||||
| message = str(exc_info.value) | ||||||||||||||
| assert f"{frame_indices[0]}-{frame_indices[-1]}" in message | ||||||||||||||
| assert "0-100" in message | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| def test_load_extended_ds_escape_frame_out_of_clip_range( | ||||||||||||||
| sample_via_tracks_file_factory, sample_metadata_df_factory | ||||||||||||||
| ): | ||||||||||||||
| """Test the guard on an escape frame outside the clip's frame range.""" | ||||||||||||||
| via_tracks_path = sample_via_tracks_file_factory( | ||||||||||||||
| "04.09.2023-01-Right-Loop05_tracks.csv" | ||||||||||||||
| ) | ||||||||||||||
| df_metadata = sample_metadata_df_factory([via_tracks_path]) | ||||||||||||||
|
|
||||||||||||||
| # Clip spans global frames 99-199; put the escape past its end | ||||||||||||||
| df_metadata.loc[0, "escape_START_frame_0_based_idx"] = 250 | ||||||||||||||
|
|
||||||||||||||
| with pytest.raises(ValueError) as exc_info: | ||||||||||||||
| load_extended_ds(via_tracks_path, df_metadata) | ||||||||||||||
|
|
||||||||||||||
| assert "escape start frame" in str(exc_info.value) | ||||||||||||||
| assert "0-100" in str(exc_info.value) | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| @pytest.mark.parametrize( | ||||||||||||||
| "list_files, expected_exception", | ||||||||||||||
|
|
||||||||||||||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.