Skip to content

Commit

Permalink
Merge pull request #2446 from jfoster17/support-dynamic-components
Browse files Browse the repository at this point in the history
Support dynamic components
  • Loading branch information
astrofrog authored Oct 23, 2023
2 parents df7599f + 4c2c07a commit fdc9157
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 2 deletions.
2 changes: 1 addition & 1 deletion glue/core/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -1543,7 +1543,7 @@ def update_components(self, mapping):

# alert hub of the change
if self.hub is not None:
msg = NumericalDataChangedMessage(self)
msg = NumericalDataChangedMessage(self, components_changed=list(mapping.keys()))
self.hub.broadcast(msg)

for subset in self.subsets:
Expand Down
6 changes: 6 additions & 0 deletions glue/core/layer_artist.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@ def _check_subset_state_changed(self):
self._changed = True
self._state = state

def _on_components_changed(self, components_changed):
"""
React to a change to one or more of the components in this layer.
"""
pass

def __str__(self):
return "%s for %s" % (self.__class__.__name__, self.layer.label)

Expand Down
4 changes: 3 additions & 1 deletion glue/core/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,9 @@ def __init__(self, sender, attribute, tag=None):


class NumericalDataChangedMessage(DataMessage):
pass
def __init__(self, sender, components_changed=None, tag=None):
super(NumericalDataChangedMessage, self).__init__(sender, tag=tag)
self.components_changed = components_changed


class DataCollectionMessage(Message):
Expand Down
45 changes: 45 additions & 0 deletions glue/core/tests/test_components_changed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""
Test that data.update_components() sends a NumericalDataChangedMessage
that conveys which components have been changed.
"""
from glue.core.data import Data
from glue.core.hub import HubListener
from glue.core.data_collection import DataCollection
from glue.core.message import NumericalDataChangedMessage

import numpy as np
from numpy.testing import assert_array_equal


def test_message_carries_components():

test_data = Data(x=np.array([1, 2, 3, 4, 5]), y=np.array([1, 2, 3, 4, 5]), label='test_data')
data_collection = DataCollection([test_data])

class CustomListener(HubListener):

def __init__(self, hub):
self.received = 0
self.components_changed = None
hub.subscribe(self, NumericalDataChangedMessage,
handler=self.receive_message)

def receive_message(self, message):
self.received += 1
try:
self.components_changed = message.components_changed
except AttributeError:
self.components_changed = None

listener = CustomListener(data_collection.hub)
assert listener.received == 0
assert listener.components_changed is None

cid_to_change = test_data.id['x']
new_data = [5, 2, 6, 7, 10]
test_data.update_components({cid_to_change: new_data})

assert listener.received == 1
assert cid_to_change in listener.components_changed

assert_array_equal(test_data['x'], new_data)
58 changes: 58 additions & 0 deletions glue/viewers/common/tests/test_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from glue.core import Data
from glue.viewers.common.viewer import Viewer
from glue.viewers.common.layer_artist import LayerArtist
from glue.core.message import NumericalDataChangedMessage


def test_custom_layer_artist_maker():
Expand Down Expand Up @@ -45,3 +46,60 @@ def custom_maker(viewer, data):
viewer.add_data(data2)
assert len(viewer.layers) == 2
assert type(viewer.layers[1]) is CustomLayerArtist


def test_viewer_update_data():
"""
Test that we can have a LayerArtist that can respond
to a NumericalDataChangedMessage.
"""

class CustomUpdateLayerArtist(LayerArtist):

def _on_components_changed(self, components_changed):
self.called_component_limits = True
self.num_components_changed = len(components_changed)

class CustomApplication(Application):
def add_widget(self, *args, **kwargs):
pass

@layer_artist_maker('custom_maker_for_update')
def custom_maker_for_update(viewer, data):
if hasattr(data, 'custom_for_update'):
return CustomUpdateLayerArtist(viewer.state, layer=data)
if hasattr(data.data, 'custom_for_update'):
return CustomUpdateLayerArtist(viewer.state, layer=data)

app = CustomApplication()

data1 = Data(x=[1, 2, 3], label='test1')
data1.custom_for_update = True

app.data_collection.append(data1)

viewer = app.new_data_viewer(Viewer)

assert len(viewer.layers) == 0

# NOTE: Check exact type, not using isinstance
viewer.add_data(data1)
assert len(viewer.layers) == 1
assert type(viewer.layers[0]) is CustomUpdateLayerArtist

msg = NumericalDataChangedMessage(data1, components_changed=[data1.id['x']])

viewer._update_data(msg)
assert viewer.layers[0].called_component_limits
assert viewer.layers[0].num_components_changed == 1

subset = data1.new_subset()
subset.subset_state = data1.id['x'] > 2

assert len(viewer.layers) == 2
assert type(viewer.layers[1]) is CustomUpdateLayerArtist

msg = NumericalDataChangedMessage(data1, components_changed=[data1.id['x']])
viewer._update_data(msg)
assert viewer.layers[1].called_component_limits
assert viewer.layers[1].num_components_changed == 1
11 changes: 11 additions & 0 deletions glue/viewers/common/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,20 @@ def _update_data(self, message):
if isinstance(layer_artist.layer, Subset):
if layer_artist.layer.data is message.data:
layer_artist.update()
try:
components_changed = message.components_changed
layer_artist._on_components_changed(components_changed)
except AttributeError:
pass

else:
if layer_artist.layer is message.data:
layer_artist.update()
try:
components_changed = message.components_changed
layer_artist._on_components_changed(components_changed)
except AttributeError:
pass

def _update_subset(self, message):
if message.attribute == 'style':
Expand Down

0 comments on commit fdc9157

Please sign in to comment.