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

Synced slider with frame index rather than active keyframe #99

Merged
merged 5 commits into from
Jul 8, 2021

Conversation

Fifourche
Copy link
Contributor

A PR to link the AnimationSlider with the frame index being set.

Before it was synced with the change of key_frames.selection.active, and now with the signal of an Emitter : frame_index, added to Animation. This way, if we use set_movie_frame_index, it'll put the slider at the frame's position and not at the closest key frame.

For some context, the idea I had was to sync the slider with a frame_index signal to prepare the way for a "previewer" capability. The preview would be launched via a method of Animation, or a button next to the slider.

…. Frame sequence changed to contain the first keyframe.
@codecov
Copy link

codecov bot commented May 29, 2021

Codecov Report

Merging #99 (643e5fc) into main (aab5909) will increase coverage by 0.51%.
The diff coverage is 90.38%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #99      +/-   ##
==========================================
+ Coverage   90.08%   90.59%   +0.51%     
==========================================
  Files          20       20              
  Lines         827      851      +24     
==========================================
+ Hits          745      771      +26     
+ Misses         82       80       -2     
Impacted Files Coverage Δ
napari_animation/animation.py 86.17% <83.33%> (+7.34%) ⬆️
napari_animation/_qt/animation_widget.py 85.55% <88.88%> (-2.36%) ⬇️
napari_animation/frame_sequence.py 98.83% <95.83%> (-1.17%) ⬇️
napari_animation/_tests/test_frame_sequence.py 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update aab5909...643e5fc. Read the comment docs.

Copy link
Collaborator

@alisterburt alisterburt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @Fifourche - I love the idea but am not 100% on the implementation, especially the generation of the whole list to obtain the required index

Could you explain the purpose of the extra code you added into the cache too? 🙂

Comment on lines 132 to 139
def _on_frame_index_changed(self, event=None):
frame_index = event.value
self.animationSlider.blockSignals(True)
self.animationSlider.setValue(frame_index)
self.animationSlider.blockSignals(False)

def _on_active_keyframe_changed(self, event):
active_keyframe = event.value
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just making sure I understand what's going on here

frame_index is linked to the frame in the whole animation, active keyframe is linked to the key-frame in the key-frames list?

If I've got that right, would you mind adding some docstrings to these methods?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and yes ! will do :)

Comment on lines 46 to 58
self.__set_frame_index = 0
self.events = EmitterGroup(source=self, _set_frame_index=None)

@property
def _set_frame_index(self):
return self.__set_frame_index

@_set_frame_index.setter
def _set_frame_index(self, frame_index):
if frame_index != self._set_frame_index:
self.__set_frame_index = frame_index
self.events._set_frame_index(value=frame_index)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about renaming this to _frame_index? I feel like it doesn't make sense to 'get' a _set_frame_index property

@@ -208,6 +230,12 @@ def animate(
if not save_as_folder:
writer.close()

def _keyframe_frame_index(self, keyframe):
n_frames = len(self._frames)
kf1_list = [self._frames._frame_index[n][0] for n in range(n_frames)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it feels quite heavy to generate the whole list of keyframes to get an index... maybe we can find a better way?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm switching back to something I wrote on a previous version. I hope it feels lighter ! :)

Comment on lines 64 to 73
else:
f = 0
if len(self._key_frames) == 1:
kf1 = self._key_frames[0]
else:
for kf0, kf1 in pairwise(self._key_frames):
for s in range(kf1.steps):
fraction = s / kf1.steps
self._frame_index[f] = (kf0, kf1, fraction)
f += 1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you remove the outer else here to make the whole block less nested?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still kept an elif, for probably a better readability !

else:
f = 0
if len(self._key_frames) == 1:
kf1 = self._key_frames[0]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand the purpose of this little section, could you explain it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, if there was only one keyframe, it was not added as a frame and _frames was empty. I just added this here so _frames would be empty only when there are no keyframes at all.

@alisterburt
Copy link
Collaborator

alisterburt commented Jun 1, 2021 via email

@Fifourche
Copy link
Contributor Author

Wasn't sure of what you meant, as it's mostly the number of key frames that is needed there. Would you still go for an attribute for this ?

Okay cool! Maybe we could refactor this logic into a ‘has_frames’ properly rather than adding it here?

On 1 Jun 2021, at 12:19, Fifourche @.***> wrote:  @Fifourche commented on this pull request. In napari_animation/frame_sequence.py: > self.events.n_frames(value=len(self)) return - f = 0 - for kf0, kf1 in pairwise(self._key_frames): - for s in range(kf1.steps): - fraction = s / kf1.steps - self._frame_index[f] = (kf0, kf1, fraction) - f += 1 + else: + f = 0 + if len(self._key_frames) == 1: + kf1 = self._key_frames[0] Previously, if there was only one keyframe, it was not added as a frame and _frames was empty. I just added this here so _frames would be empty only when there are no keyframes at all. — You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

@Fifourche
Copy link
Contributor Author

Hey :)
I'm changing a bit this PR to switch the current frame index attribute from animation to FrameSequence ! In my eyes it makes FrameSequence a bit more like an virtual slider, which would be relevant to connect to the GUI slider, and thus prepare the ground for a play button with #100 .

Copy link
Collaborator

@alisterburt alisterburt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @Fifourche - this is looking really nice now! Thanks for your patience with my reviewing here, let's get this in!

Comment on lines +221 to +223
steps_to_keyframe = [
kf.steps for kf in self.key_frames[1 : keyframe_index + 1]
]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is looking much nicer! 🙂

Comment on lines +178 to +186
@property
def _current_index(self):
return self.__current_index

@_current_index.setter
def _current_index(self, frame_index):
if frame_index != self._frame_index:
self.__current_index = frame_index
self.events._current_index(value=frame_index)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like having this directly on the FrameSequence

@alisterburt alisterburt merged commit 34ee43b into napari:main Jul 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants