Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

beginning base logic for interactivity impl #61

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

Closed
wants to merge 23 commits into from
Closed

Conversation

clewis7
Copy link
Member

@clewis7 clewis7 commented Dec 12, 2022

starting #39

@kushalkolar
Copy link
Member

maybe an even simpler way to implement this:

Interaction.link is just a very simple method that sets the "feature" at the given indices with the new data for any Graphic that is passed, not just self.

def link(
  self,
  event: str, 
  target: Graphic, 
  feature: str, 
  new_data: Any, 
  indices_mapper: callable = None
):
    # event picks subset of self.indices -> indices_mapper() -> indices_subset -> target._set_feature(new_data, indices_subset)

@kushalkolar kushalkolar mentioned this pull request Dec 13, 2022
14 tasks
fastplotlib/graphics/line.py Outdated Show resolved Hide resolved
fastplotlib/graphics/line.py Outdated Show resolved Hide resolved
fastplotlib/graphics/line.py Outdated Show resolved Hide resolved
fastplotlib/graphics/_base.py Outdated Show resolved Hide resolved
fastplotlib/graphics/_base.py Show resolved Hide resolved
fastplotlib/graphics/line.py Outdated Show resolved Hide resolved
fastplotlib/graphics/_base.py Outdated Show resolved Hide resolved
fastplotlib/graphics/_base.py Outdated Show resolved Hide resolved
fastplotlib/graphics/line.py Outdated Show resolved Hide resolved
Copy link
Member

@kushalkolar kushalkolar left a comment

Choose a reason for hiding this comment

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

almost there :D

fastplotlib/graphics/line.py Outdated Show resolved Hide resolved
fastplotlib/graphics/line.py Outdated Show resolved Hide resolved
@clewis7
Copy link
Member Author

clewis7 commented Dec 17, 2022

Made the changes that you requested, I'm sure there are further changes needed to be made

going to move on to linecollection and try to get that up and running!

fastplotlib/graphics/_base.py Show resolved Hide resolved
fastplotlib/graphics/_base.py Outdated Show resolved Hide resolved
fastplotlib/graphics/line.py Outdated Show resolved Hide resolved
fastplotlib/graphics/line.py Outdated Show resolved Hide resolved
fastplotlib/graphics/linecollection.py Outdated Show resolved Hide resolved
@clewis7
Copy link
Member Author

clewis7 commented Dec 19, 2022

sorry for all of the commits, git was not my friend for a moment but everything should be fine now I hope

@clewis7
Copy link
Member Author

clewis7 commented Dec 20, 2022

So, I got it to work with line collection

things are not perfect by any means but got a nice dopamine rush...hopefully indicative of things moving in the right direction

Copy link
Member

@kushalkolar kushalkolar left a comment

Choose a reason for hiding this comment

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

great work! you can continue playing with it, once #78 is ready (very soon!) it'll be much easier to do the rest

if event_type in self.registered_callbacks.keys():
self.registered_callbacks[event_type].append(
CallbackData(target=target, feature=feature, new_data=new_data, old_data=getattr(target, feature).copy()))
CallbackData(target=target, feature=feature, new_data=new_data, old_data=old_data, indices_mapper=indices_mapper))
Copy link
Member

Choose a reason for hiding this comment

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

old_data shouldn't be in CallbackData, old_data should be managed by the target graphic event time it handles an event. When the target graphic handles an event, it should have a copy of the feature data at the indices that are being modified and reset the feature at those indices, and then set the feature w.r.t. to the new CallbackData.

To elaborate:

  1. The target graphic keeps a private dict of (features, orig_vals) that were modified at certain indices from the previous callback, something in the form {"feature": (indices, orig_vals_at_indices)}, you could call it self._previous_modified. And with the new GraphicFeature class from indexable graphic attributes #78 we won't even need a dict for it, we can just add _modified_indices and _orig_vals_at_modified_indices as private attributes to GraphicFeature 😄 .

  2. In _set_feature() it first uses the information from above to reset the feature at those indices to their original values

Copy link
Member

Choose a reason for hiding this comment

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

with #78 it might be possible for us to just pass the GraphicFeature instance directly instead of the string name when calling link, for example:

graphic.link(event_type, target=some_graphic, feature=some_graphic.color...

Copy link
Member Author

Choose a reason for hiding this comment

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

If info for resetting feature is moved to _set_feature() graphic, then we will no longer need method for _reset_feature()?

Copy link
Member

Choose a reason for hiding this comment

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

we should still have a _reset_feature() to separate functionality

indices = target_info.indices_mapper(target=target_info.target, indices=click_info)
else:
indices = None
# reset feature of target using stored old data
Copy link
Member

Choose a reason for hiding this comment

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

ah I see you've done it like this, but it's better for the target graphic to handle old data because we want the "feature resetting at previously modified indices" to happen regardless of the event type. For example, if we've registered different types of callbacks to keyboard events, and different mouse events, we want the same reset to happen regardless of what previous event.type triggered the previous feature data to change.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree! Just wasn't sure at the time the best way to implement, but now that graphic features exist it should be a lot easier to store old data!

fastplotlib/graphics/image.py Show resolved Hide resolved
fastplotlib/graphics/linecollection.py Show resolved Hide resolved
fastplotlib/graphics/linecollection.py Show resolved Hide resolved
update_func = getattr(self, f"update_{feature}")
self.collection[indices].update_func(new_data)
if feature in self.features:
update_func = getattr(self.data[indices], f"update_{feature}")
Copy link
Member

Choose a reason for hiding this comment

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

the way it's written it'll only work with single integer indices, we can chat about it

Copy link
Member

Choose a reason for hiding this comment

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

once we implement this it'll be much easier #76 (comment)

it would become getattr(self, feature)[indices] = new_data


@property
def features(self) -> List[str]:
pass
return ["colors", "data"]

def _set_feature(self, feature: str, new_data: Any, indices: Any):
Copy link
Member

Choose a reason for hiding this comment

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

I think that for the _set_feature method in each Graphic or GraphicCollection we can replace Any for the indices to the indices that are appropriate for that graphic type.

for target_info in self.registered_callbacks[event.type]:
# need to map the indices to the target using indices_mapper
if target_info.indices_mapper is not None:
indices = target_info.indices_mapper(target=target_info.target, indices=click_info)
Copy link
Member

Choose a reason for hiding this comment

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

an indices_mapper function should be given source and target, something like this:

indices_mapper(source=self, target=target_info.target, event_indices=click_info

And the user can write their function to take in all 3 and do whatever they want.

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, I assumed that some general form would need to be established

@kushalkolar
Copy link
Member

Now that #78 brings events to GraphicFeatures we want to make link() work seamlessly for both pygfx events and GraphicFeature events. Something like this should work:

def link(self, event_type: str, target: Any, ...):
  pygfx_events = ["click", ...]
  graphic_feature_events = ["colors", "data", "present", ...]

  if event_type in pygfx_events:
    self.world_object.add_event_handler(...)

  elif event_type in graphic_feature_events:
    feature = getattr(self, event_type)
    feature.add_event_handler(...)

@kushalkolar
Copy link
Member

should probably also generalize the indices_mapper to just be an event mapper that get access to the source, target, and all event info. For example if we want click events on a contour to toggle the present feature of some other graphic it's diff from indices mapping.

@clewis7 clewis7 closed this Dec 24, 2022
@kushalkolar kushalkolar mentioned this pull request Dec 24, 2022
@kushalkolar kushalkolar deleted the interaction branch January 7, 2023 03:22
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
Morty Proxy This is a proxified and sanitized view of the page, visit original site.