diff --git a/fastplotlib/graphics/_base.py b/fastplotlib/graphics/_base.py index a0b4881fb..eea78142c 100644 --- a/fastplotlib/graphics/_base.py +++ b/fastplotlib/graphics/_base.py @@ -8,7 +8,7 @@ from pygfx import WorldObject -from ._features import GraphicFeature, PresentFeature, GraphicFeatureIndexable +from ._features import GraphicFeature, PresentFeature, GraphicFeatureIndexable, Deleted # dict that holds all world objects for a given python kernel/session # Graphic objects only use proxies to WorldObjects @@ -45,6 +45,12 @@ def __init_subclass__(cls, **kwargs): class Graphic(BaseGraphic): + feature_events = {} + + def __init_subclass__(cls, **kwargs): + # all graphics give off a feature event when deleted + cls.feature_events = {*cls.feature_events, "deleted"} + def __init__( self, name: str = None, @@ -72,6 +78,8 @@ def __init__( # store hex id str of Graphic instance mem location self.loc: str = hex(id(self)) + self.deleted = Deleted(self, False) + @property def world_object(self) -> WorldObject: """Associated pygfx WorldObject. Always returns a proxy, real object cannot be accessed directly.""" @@ -168,6 +176,7 @@ def _cleanup(self): pass def __del__(self): + self.deleted = True del WORLD_OBJECTS[self.loc] diff --git a/fastplotlib/graphics/_features/__init__.py b/fastplotlib/graphics/_features/__init__.py index a6ce9c3a3..a1769b010 100644 --- a/fastplotlib/graphics/_features/__init__.py +++ b/fastplotlib/graphics/_features/__init__.py @@ -5,6 +5,7 @@ from ._thickness import ThicknessFeature from ._base import GraphicFeature, GraphicFeatureIndexable, FeatureEvent, to_gpu_supported_dtype from ._selection_features import LinearSelectionFeature, LinearRegionSelectionFeature +from ._deleted import Deleted __all__ = [ "ColorFeature", @@ -23,4 +24,5 @@ "to_gpu_supported_dtype", "LinearSelectionFeature", "LinearRegionSelectionFeature", + "Deleted", ] diff --git a/fastplotlib/graphics/_features/_deleted.py b/fastplotlib/graphics/_features/_deleted.py new file mode 100644 index 000000000..2fca1c719 --- /dev/null +++ b/fastplotlib/graphics/_features/_deleted.py @@ -0,0 +1,41 @@ +from ._base import GraphicFeature, FeatureEvent + + +class Deleted(GraphicFeature): + """ + Used when a graphic is deleted, triggers events that can be useful to indicate this graphic has been deleted + + **event pick info:** + + ==================== ======================== ========================================================================= + key type description + ==================== ======================== ========================================================================= + "collection-index" int the index of the graphic within the collection that triggered the event + "world_object" pygfx.WorldObject world object + ==================== ======================== ========================================================================= + """ + + def __init__(self, parent, value: bool): + super(Deleted, self).__init__(parent, value) + + def _set(self, value: bool): + value = self._parse_set_value(value) + self._feature_changed(key=None, new_data=value) + + def _feature_changed(self, key, new_data): + # this is a non-indexable feature so key=None + + pick_info = { + "index": None, + "collection-index": self._collection_index, + "world_object": self._parent.world_object, + "new_data": new_data, + } + + event_data = FeatureEvent(type="deleted", pick_info=pick_info) + + self._call_event_handlers(event_data) + + def __repr__(self) -> str: + s = f"DeletedFeature for {self._parent}" + return s diff --git a/fastplotlib/graphics/image.py b/fastplotlib/graphics/image.py index 10f09eefb..3d629c10f 100644 --- a/fastplotlib/graphics/image.py +++ b/fastplotlib/graphics/image.py @@ -196,7 +196,7 @@ def _add_plot_area_hook(self, plot_area): class ImageGraphic(Graphic, Interaction, _AddSelectorsMixin): - feature_events = ("data", "cmap", "present") + feature_events = {"data", "cmap", "present"} def __init__( self, @@ -345,10 +345,11 @@ def col_chunk_index(self, index: int): class HeatmapGraphic(Graphic, Interaction, _AddSelectorsMixin): - feature_events = ( + feature_events = { "data", "cmap", - ) + "present" + } def __init__( self, diff --git a/fastplotlib/graphics/line.py b/fastplotlib/graphics/line.py index d6f061ab0..9ac7568a7 100644 --- a/fastplotlib/graphics/line.py +++ b/fastplotlib/graphics/line.py @@ -12,7 +12,7 @@ class LineGraphic(Graphic, Interaction): - feature_events = ("data", "colors", "cmap", "thickness", "present") + feature_events = {"data", "colors", "cmap", "thickness", "present"} def __init__( self, diff --git a/fastplotlib/graphics/line_collection.py b/fastplotlib/graphics/line_collection.py index 38597a830..a5c398130 100644 --- a/fastplotlib/graphics/line_collection.py +++ b/fastplotlib/graphics/line_collection.py @@ -15,7 +15,7 @@ class LineCollection(GraphicCollection, Interaction): child_type = LineGraphic.__name__ - feature_events = ("data", "colors", "cmap", "thickness", "present") + feature_events = {"data", "colors", "cmap", "thickness", "present"} def __init__( self, diff --git a/fastplotlib/graphics/scatter.py b/fastplotlib/graphics/scatter.py index 961324c23..63689fad9 100644 --- a/fastplotlib/graphics/scatter.py +++ b/fastplotlib/graphics/scatter.py @@ -9,7 +9,7 @@ class ScatterGraphic(Graphic): - feature_events = ("data", "sizes", "colors", "cmap", "present") + feature_events = {"data", "sizes", "colors", "cmap", "present"} def __init__( self,