-
Notifications
You must be signed in to change notification settings - Fork 52
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
Changes from 1 commit
2c00596
10aeca8
f19c9c1
ac6c67a
ad6a8d6
95e77a1
71eb48f
e203cff
0f22531
16922e7
70a3be6
a999094
bc688fc
24fb5a5
7667224
b3767ff
462f098
7099783
c523c28
38a3f3a
9309b41
a6b53ee
0cb73ca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,6 @@ | |
|
||
from abc import ABC, abstractmethod | ||
from dataclasses import dataclass | ||
# from .linecollection import LineCollection | ||
|
||
class Graphic: | ||
def __init__( | ||
|
@@ -74,14 +73,12 @@ def __repr__(self): | |
|
||
class Interaction(ABC): | ||
@property | ||
@abstractmethod | ||
def indices(self) -> Any: | ||
pass | ||
return self.indices | ||
|
||
@indices.setter | ||
@abstractmethod | ||
def indices(self, indices: Any): | ||
pass | ||
self.indices = indices | ||
|
||
@property | ||
@abstractmethod | ||
|
@@ -93,34 +90,53 @@ def _set_feature(self, feature: str, new_data: Any, indices: Any): | |
pass | ||
|
||
@abstractmethod | ||
def _reset_feature(self, feature: str, old_data: Any, indices: Any): | ||
def _reset_feature(self, feature: str, old_data: Any): | ||
pass | ||
|
||
def link(self, event_type: str, target: Graphic, feature: str, new_data: Any, indices_mapper: callable = None): | ||
def link(self, event_type: str, target: Any, feature: str, new_data: Any, indices_mapper: callable = None): | ||
valid_events = ["click"] | ||
if event_type in valid_events: | ||
self.world_object.add_event_handler(self.event_handler, event_type) | ||
else: | ||
raise ValueError("event not possible") | ||
|
||
if isinstance(target.data, List): | ||
old_data = list() | ||
for line in target.data: | ||
old_data.append(getattr(line, feature).copy()) | ||
else: | ||
old_data = getattr(target, feature).copy() | ||
|
||
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)) | ||
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.
To elaborate:
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. with #78 it might be possible for us to just pass the GraphicFeature instance directly instead of the string name when calling
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. If info for resetting feature is moved to 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. we should still have a |
||
else: | ||
self.registered_callbacks[event_type] = list() | ||
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)) | ||
|
||
def event_handler(self, event): | ||
clewis7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if event.type == "click": | ||
# storing click information for each click in self.indices | ||
#self.indices(np.array(event.pick_info["index"])) | ||
click_info = np.array(event.pick_info["index"]) | ||
if event.type in self.registered_callbacks.keys(): | ||
for target_info in self.registered_callbacks[event.type]: | ||
target_info.target._reset_feature(feature=target_info.feature, old_data=target_info.old_data, indices=None) | ||
target_info.target._set_feature(feature=target_info.feature, new_data=target_info.new_data, indices=None) | ||
# 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) | ||
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. an
And the user can write their function to take in all 3 and do whatever they want. 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. yes, I assumed that some general form would need to be established |
||
else: | ||
indices = None | ||
# reset feature of target using stored old data | ||
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. 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 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. 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! |
||
target_info.target._reset_feature(feature=target_info.feature, old_data=target_info.old_data) | ||
# set feature of target at indice using new data | ||
target_info.target._set_feature(feature=target_info.feature, new_data=target_info.new_data[indices], indices=indices) | ||
|
||
@dataclass | ||
class CallbackData: | ||
"""Class for keeping track of the info necessary for interactivity after event occurs.""" | ||
target: Graphic | ||
target: Any | ||
feature: str | ||
new_data: Any | ||
old_data: Any | ||
indices_mapper: callable = None |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,10 +2,9 @@ | |
import pygfx | ||
from typing import Union, List | ||
|
||
from .line import LineGraphic | ||
from fastplotlib.graphics.line import LineGraphic | ||
clewis7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
from typing import * | ||
from ._base import Interaction | ||
|
||
from fastplotlib.graphics._base import Interaction | ||
clewis7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
from abc import ABC, abstractmethod | ||
|
||
|
||
|
@@ -26,7 +25,7 @@ def __init__(self, data: List[np.ndarray], z_position: Union[List[float], float] | |
if not len(data) == len(cmap): | ||
raise ValueError("args must be the same length") | ||
|
||
self.collection = list() | ||
self.data = list() | ||
|
||
for i, d in enumerate(data): | ||
if isinstance(z_position, list): | ||
|
@@ -49,33 +48,30 @@ def __init__(self, data: List[np.ndarray], z_position: Union[List[float], float] | |
else: | ||
_cmap = cmap | ||
|
||
self.collection.append(LineGraphic(d, _z, _size, _colors, _cmap)) | ||
|
||
def _reset_feature(self): | ||
pass | ||
|
||
@property | ||
def indices(self) -> Any: | ||
pass | ||
|
||
@indices.setter | ||
@abstractmethod | ||
def indices(self, indices: Any): | ||
pass | ||
self.data.append(LineGraphic(d, _z, _size, _colors, _cmap)) | ||
|
||
@property | ||
def features(self) -> List[str]: | ||
pass | ||
return ["colors", "data"] | ||
|
||
def _set_feature(self, feature: str, new_data: Any, indices: Any): | ||
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. I think that for the |
||
if feature in ["colors", "data"]: | ||
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}") | ||
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. the way it's written it'll only work with single integer indices, we can chat about it 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. once we implement this it'll be much easier #76 (comment) it would become |
||
# if indices is a single indices or list of indices | ||
self.data[indices].update_colors(new_data) | ||
else: | ||
raise ValueError("name arg is not a valid feature") | ||
|
||
def _reset_feature(self, feature: str, old_data: Any): | ||
if feature in self.features: | ||
#update_func = getattr(self, f"update_{feature}") | ||
for i, line in enumerate(self.data): | ||
line.update_colors(old_data[i]) | ||
else: | ||
raise ValueError("name arg is not a valid feature") | ||
|
||
def __getitem__(self, item): | ||
return self.collection[item] | ||
return self.data[item] | ||
|
||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.