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
rebase
  • Loading branch information
Caitlin Lewis committed Dec 28, 2022
commit cfa0aa9c664d4aa23f0b3116af1d80645a328514
75 changes: 47 additions & 28 deletions fastplotlib/graphics/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def __init__(
"""

self.name = name
self.registered_callbacks = dict()
self.present = PresentFeature(parent=self)

valid_features = ["visible"]
Expand Down Expand Up @@ -80,40 +81,58 @@ def __repr__(self):
return f"'{self.name}' fastplotlib.{self.__class__.__name__} @ {hex(id(self))}"
else:
return f"fastplotlib.{self.__class__.__name__} @ {hex(id(self))}"
<<<<<<< HEAD
=======

class Interaction(ABC):
# make them abstract properties
@property
@abstractmethod
def indices(self) -> Any:
pass

@indices.setter
@abstractmethod
def indices(self, indices: Any):
pass

@property
@abstractmethod
def features(self) -> List[str]:
pass

class Interaction(ABC):
@abstractmethod
def _set_feature(self, name: str, new_data: Any, indices: Any):
def _set_feature(self, feature: str, new_data: Any, indices: Any):
pass

@abstractmethod
def link(self, event: str, feature: Any, feature_data: Any, target: Graphic, target_feature: Any, target_data: Any, indices_mapper: Any):
# event occurs, causes change in feature of current graphic to data indices from pick_info,
# also causes change in target graphic to target feature at target data with corresponding or mapped
# indices based on the indice_mapper function

# events can be feature changes, when feature changes want to trigger an event

# indice mapper takes in source features and maps to target features
def _reset_feature(self, feature: str):
pass

def link(self, event_type: str, target: Any, feature: str, new_data: Any, indices_mapper: callable = None):
if event_type in self._pygfx_events:
self.world_object.add_event_handler(self.event_handler, event_type)
elif event_type in self._feature_events:
feature = getattr(self, event_type)
Comment thread
clewis7 marked this conversation as resolved.
Outdated
feature.add_event_handler(self.event_handler, event_type)
else:
raise ValueError("event not possible")

>>>>>>> 2c00596 (beginning base logic for interactivity impl)
if event_type in self.registered_callbacks.keys():
self.registered_callbacks[event_type].append(
CallbackData(target=target, feature=feature, new_data=new_data, indices_mapper=indices_mapper))
else:
self.registered_callbacks[event_type] = list()
self.registered_callbacks[event_type].append(
CallbackData(target=target, feature=feature, new_data=new_data, indices_mapper=indices_mapper))

def event_handler(self, event):
event_info = event.pick_info
#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]:
if target_info.indices_mapper is not None:
indices = target_info.indices_mapper(source=self, target=target_info.target, indices=click_info)
else:
indices = None
# 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)


@dataclass
class CallbackData:
"""Class for keeping track of the info necessary for interactivity after event occurs."""
target: Any
feature: str
new_data: Any
indices_mapper: callable = None


@dataclass
class PreviouslyModifiedData:
"""Class for keeping track of previously modified data at indices"""
previous_data: Any
previous_indices: Any
55 changes: 1 addition & 54 deletions fastplotlib/graphics/heatmap.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
import numpy as np
import pygfx
from typing import *
<<<<<<< HEAD

from fastplotlib.graphics._base import Graphic

=======
>>>>>>> c523c28 (accidentally deleted heatmap file)
from .image import ImageGraphic

from ..utils import quick_min_max, get_cmap_texture

<<<<<<< HEAD
from ._base import Interaction

=======
>>>>>>> c523c28 (accidentally deleted heatmap file)

default_selection_options = {
"mode": "single",
Expand Down Expand Up @@ -51,26 +40,7 @@ def __init__(
self.callbacks = callbacks


<<<<<<< HEAD
class HeatmapGraphic(ImageGraphic, Interaction):
@property
def indices(self) -> Any:
pass

@property
def features(self) -> List[str]:
pass

def _set_feature(self, name: str, new_data: Any, indices: Any):
pass

def link(self, event: str, feature: Any, feature_data: Any, target: Graphic, target_feature: Any, target_data: Any,
indices_mapper: Any):
pass

=======
class HeatmapGraphic(ImageGraphic):
>>>>>>> c523c28 (accidentally deleted heatmap file)
def __init__(
self,
data: np.ndarray,
Expand All @@ -83,37 +53,18 @@ def __init__(
):
"""
Create a Heatmap Graphic
<<<<<<< HEAD

=======
>>>>>>> c523c28 (accidentally deleted heatmap file)
Parameters
----------
data: array-like, must be 2-dimensional
| array-like, usually numpy.ndarray, must support ``memoryview()``
| Tensorflow Tensors also work _I think_, but not thoroughly tested
<<<<<<< HEAD

vmin: int, optional
minimum value for color scaling, calculated from data if not provided

vmax: int, optional
maximum value for color scaling, calculated from data if not provided

cmap: str, optional
colormap to use to display the image data, default is ``"plasma"``

selection_options

=======
vmin: int, optional
minimum value for color scaling, calculated from data if not provided
vmax: int, optional
maximum value for color scaling, calculated from data if not provided
cmap: str, optional
colormap to use to display the image data, default is ``"plasma"``
selection_options
>>>>>>> c523c28 (accidentally deleted heatmap file)
args:
additional arguments passed to Graphic
kwargs:
Expand Down Expand Up @@ -183,8 +134,4 @@ def add_highlight(self, event):
self.world_object.add(self.selection_graphic)
self._highlights.append(self.selection_graphic)

<<<<<<< HEAD
return rval
=======
return rval
>>>>>>> c523c28 (accidentally deleted heatmap file)
return rval
15 changes: 0 additions & 15 deletions fastplotlib/graphics/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,50 +20,35 @@ def __init__(
):
"""
Create an Image Graphic

Parameters
----------
data: array-like, must be 2-dimensional
| array-like, usually numpy.ndarray, must support ``memoryview()``
| Tensorflow Tensors also work _I think_, but not thoroughly tested

vmin: int, optional
minimum value for color scaling, calculated from data if not provided

vmax: int, optional
maximum value for color scaling, calculated from data if not provided

cmap: str, optional, default "nearest"
colormap to use to display the image data, default is ``"plasma"``

filter: str, optional, default "nearest"
interpolation filter, one of "nearest" or "linear"

args:
additional arguments passed to Graphic

kwargs:
additional keyword arguments passed to Graphic

Examples
--------

.. code-block:: python

from fastplotlib import Plot

# create a `Plot` instance
plot = Plot()

# make some random 2D image data
data = np.random.rand(512, 512)

# plot the image data
plot.add_image(data=data)

# show the plot
plot.show()

"""

super().__init__(*args, **kwargs)
Expand Down
36 changes: 34 additions & 2 deletions fastplotlib/graphics/line.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
import numpy as np
import pygfx

from ._base import Graphic
from ._base import Graphic, Interaction, PreviouslyModifiedData
from .features import PointsDataFeature, ColorFeature, CmapFeature
from ..utils import get_colors


class LineGraphic(Graphic):
class LineGraphic(Graphic, Interaction):
def __init__(
self,
data: Any,
Expand Down Expand Up @@ -83,3 +83,35 @@ def __init__(

if z_position is not None:
self.world_object.position.z = z_position

def _set_feature(self, feature: str, new_data: Any, indices: Any = None):
if not hasattr(self, "_previous_data"):
self._previous_data = {}
Comment thread
clewis7 marked this conversation as resolved.
Outdated
elif hasattr(self, "_previous_data"):
self._reset_feature(feature)
if feature in self._feature_events:
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
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)
Comment thread
clewis7 marked this conversation as resolved.
Outdated
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
Comment thread
clewis7 marked this conversation as resolved.
Outdated
3 changes: 2 additions & 1 deletion fastplotlib/graphics/linecollection.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
import pygfx
from typing import *

from ._base import Interaction, PreviouslyModifiedData
from ._collection import GraphicCollection
from .line import LineGraphic
from ..utils import get_colors
from typing import *


class LineCollection(GraphicCollection):
class LineCollection(GraphicCollection, Interaction):
"""Line Collection graphic"""
child_type = LineGraphic

Expand Down