Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
line collection, fixing feature event names
  • Loading branch information
Caitlin Lewis committed Dec 29, 2022
commit e2eb1c8787eb95c48d410d7465da369401b9f40e
212 changes: 212 additions & 0 deletions examples/line_collection_event.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "f02f7349-ac1a-49b7-b304-d5b701723e0f",
"metadata": {},
"outputs": [],
"source": [
"%load_ext autoreload\n",
"%autoreload 2"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "d9f54448-7718-4212-ac6d-163a2d3be146",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from fastplotlib.graphics import LineGraphic, LineCollection, ImageGraphic\n",
"from fastplotlib.plot import Plot\n",
"import pickle"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "b683c6d1-d926-43e3-a221-4ec6450e3677",
"metadata": {},
"outputs": [],
"source": [
"contours = pickle.load(open(\"/home/caitlin/Downloads/contours.pickle\", \"rb\"))"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "26ced005-c52f-4696-903d-a6974ae6cefc",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "2bc75fa52d484cd1b03006a6530f10b3",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"RFBOutputContext()"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"MESA-INTEL: warning: Performance support disabled, consider sysctl dev.i915.perf_stream_paranoid=0\n",
"\n"
]
}
],
"source": [
"plot = Plot()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "1aea0a61-db63-41e1-b330-5a922da4bac5",
"metadata": {},
"outputs": [],
"source": [
"line_collection = LineCollection(contours, cmap=\"Oranges\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "310fd5b3-49f2-4dbb-831e-cb9f369d58c8",
"metadata": {},
"outputs": [],
"source": [
"plot.add_graphic(line_collection)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "661a5991-0de3-44d7-a626-2ae72704dcec",
"metadata": {},
"outputs": [],
"source": [
"image = ImageGraphic(data=np.ones((180, 180)))"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "816f6382-f4ea-4cd4-b9f3-2dc5c232b0a5",
"metadata": {},
"outputs": [],
"source": [
"plot.add_graphic(image)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8187fd25-18e1-451f-b2fe-8cd2e7785c8b",
"metadata": {},
"outputs": [],
"source": [
"plot.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d5ddd3c4-84e2-44a3-a14f-74871aa0bb8f",
"metadata": {},
"outputs": [],
"source": [
"black = np.array([0.0, 0.0, 0.0, 1.0])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6ac64f1c-21e0-4c21-b968-3953e7858848",
"metadata": {},
"outputs": [],
"source": [
"from typing import *"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d0d0c971-aac9-4c77-b88c-de9d79c7d74e",
"metadata": {},
"outputs": [],
"source": [
"def callback_function(source: Any, target: Any, event, new_data: Any):\n",
" # calculate coms of line collection\n",
" indices = np.array(event.pick_info[\"index\"])\n",
" \n",
" coms = list()\n",
"\n",
" for contour in target.items:\n",
" coors = contour.data.feature_data[~np.isnan(contour.data.feature_data).any(axis=1)]\n",
" com = coors.mean(axis=0)\n",
" coms.append(com)\n",
"\n",
" # euclidean distance to find closest index of com \n",
" indices = np.append(indices, [0])\n",
" \n",
" ix = np.linalg.norm((coms - indices), axis=1).argsort()[0]\n",
" \n",
" ix = int(ix)\n",
" \n",
" print(ix)\n",
" \n",
" target._set_feature(feature=\"colors\", new_data=new_data, indices=ix)\n",
" \n",
" return None"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1a46d148-3007-4c7a-bf2b-91057eba855d",
"metadata": {},
"outputs": [],
"source": [
"image.link(event_type=\"click\", target=line_collection, feature=\"colors\", new_data=black, callback_function=callback_function)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8040456e-24a5-423b-8822-99a20e7ea470",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
11 changes: 8 additions & 3 deletions fastplotlib/graphics/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,11 @@ def event_handler(self, event):
if target_info.callback_function is not None:
# if callback_function is not None, then callback function should handle the entire event
target_info.callback_function(source=self, target=target_info.target, event=event, new_data=target_info.new_data)
elif isinstance(target_info.target, GraphicCollection):
elif isinstance(self, GraphicCollection):
# if target is a GraphicCollection, then indices will be stored in collection_index
indices = event.pick_info["collection_index"]
target_info.target._set_feature(feature=target_info.feature, new_data=target_info.new_data, indices=indices)
# indices = event.pick_info["collection_index"]
# target_info.target._set_feature(feature=target_info.feature, new_data=target_info.new_data, indices=indices)
print(event.pick_info)
else:
# if target is a single graphic, then indices do not matter
target_info.target._set_feature(feature=target_info.feature, new_data=target_info.new_data,
Expand All @@ -140,10 +141,14 @@ class PreviouslyModifiedData:


class GraphicCollection(BaseGraphic):
pygfx_events = [
"click"
]
"""Graphic Collection base class"""
def __init__(self, name: str = None):
self.name = name
self._items: List[Graphic] = list()
self.registered_callbacks = dict()

@property
def world_object(self) -> Group:
Expand Down
2 changes: 1 addition & 1 deletion fastplotlib/graphics/features/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class FeatureEvent:
"""
type: <feature_name>-<changed>, example: "color-changed"
type: <feature_name>, example: "colors"
pick_info: dict in the form:
{
"index": indices where feature data was changed, ``range`` object or List[int],
Expand Down
4 changes: 2 additions & 2 deletions fastplotlib/graphics/features/_colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ def _feature_changed(self, key, new_data):
"new_data": new_data,
}

event_data = FeatureEvent(type="color-changed", pick_info=pick_info)
event_data = FeatureEvent(type="color", pick_info=pick_info)

self._call_event_handlers(event_data)

Expand Down Expand Up @@ -241,6 +241,6 @@ def _feature_changed(self, key, new_data):
"new_data": new_data
}

event_data = FeatureEvent(type="cmap-changed", pick_info=pick_info)
event_data = FeatureEvent(type="cmap", pick_info=pick_info)

self._call_event_handlers(event_data)
4 changes: 2 additions & 2 deletions fastplotlib/graphics/features/_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def _feature_changed(self, key, new_data):
"new_data": new_data
}

event_data = FeatureEvent(type="data-changed", pick_info=pick_info)
event_data = FeatureEvent(type="data", pick_info=pick_info)

self._call_event_handlers(event_data)

Expand Down Expand Up @@ -145,6 +145,6 @@ def _feature_changed(self, key, new_data):
"new_data": new_data
}

event_data = FeatureEvent(type="data-changed", pick_info=pick_info)
event_data = FeatureEvent(type="data", pick_info=pick_info)

self._call_event_handlers(event_data)
2 changes: 1 addition & 1 deletion fastplotlib/graphics/features/_present.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ def _feature_changed(self, key, new_data):
"new_data": new_data
}

event_data = FeatureEvent(type="present-changed", pick_info=pick_info)
event_data = FeatureEvent(type="present", pick_info=pick_info)

self._call_event_handlers(event_data)
2 changes: 1 addition & 1 deletion fastplotlib/graphics/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
class ImageGraphic(Graphic, Interaction):
feature_events = [
"data",
"cmap",
"colors",
]
def __init__(
self,
Expand Down
1 change: 0 additions & 1 deletion fastplotlib/graphics/line.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ class LineGraphic(Graphic, Interaction):
feature_events = [
"data",
"colors",
"cmap",
]
def __init__(
self,
Expand Down
44 changes: 20 additions & 24 deletions fastplotlib/graphics/linecollection.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
from .line import LineGraphic
from ..utils import get_colors
from typing import *
from copy import deepcopy


class LineCollection(GraphicCollection, Interaction):
"""Line Collection graphic"""
child_type = LineGraphic
feature_events = [
"data-changed",
"color-changed",
"cmap-changed",
"data",
"colors",
]
def __init__(
self,
Expand Down Expand Up @@ -118,34 +118,30 @@ def __init__(

self.add_graphic(lg, reset_index=False)

def _set_feature(self, feature: str, new_data: Any, indices: Union[int, range]):
def _set_feature(self, feature: str, new_data: Any, indices: Any):
if not hasattr(self, "_previous_data"):
self._previous_data = {}
self._previous_data = dict()
elif hasattr(self, "_previous_data"):
self._reset_feature(feature)
#if feature in # need a way to check if feature is in
feature_instance = getattr(self, feature)
if indices is not None:
previous = feature_instance[indices].copy()
feature_instance[indices] = new_data
else:
previous = feature_instance[:].copy()
feature_instance[:] = new_data

coll_feature = getattr(self[indices], feature)

data = list()
for cf in coll_feature:
data += cf
data = np.array(data)

previous = data
coll_feature._set(new_data)

if feature in self._previous_data.keys():
self._previous_data[feature].previous_data = previous
self._previous_data[feature].previous_indices = indices
else:
self._previous_data[feature] = PreviouslyModifiedData(previous_data=previous, previous_indices=indices)
# else:
# raise ValueError("name arg is not a valid feature")

def _reset_feature(self, feature: str):
if feature not in self._previous_data.keys():
raise ValueError("no previous data registered for this feature")
else:
feature_instance = getattr(self, feature)
if self._previous_data[feature].previous_indices is not None:
feature_instance[self._previous_data[feature].previous_indices] = self._previous_data[
feature].previous_data
else:
feature_instance[:] = self._previous_data[feature].previous_data
# implemented for a single index at moment
prev_ixs = self._previous_data[feature].previous_indices
coll_feature = getattr(self[prev_ixs], feature)
coll_feature._set(self._previous_data[feature].previous_data)