Skip to content

Commit

Permalink
Merge pull request #1353 from ioam/clear_by_precedence
Browse files Browse the repository at this point in the history
Stream clear method now supports policies by precedence
  • Loading branch information
philippjfr committed Apr 23, 2017
2 parents b62b373 + 7266f26 commit e93b23a
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 8 deletions.
4 changes: 2 additions & 2 deletions holoviews/plotting/bokeh/plot.py
Expand Up @@ -296,7 +296,7 @@ def __init__(self, layout, ranges=None, layout_num=1, keys=None, **params):
if self.top_level:
self.comm = self.init_comm()
self.traverse(lambda x: setattr(x, 'comm', self.comm))
self.traverse(lambda x: attach_streams(self, x.hmap, 1),
self.traverse(lambda x: attach_streams(self, x.hmap, 2),
[GenericElementPlot])


Expand Down Expand Up @@ -490,7 +490,7 @@ def __init__(self, layout, keys=None, **params):
if self.top_level:
self.comm = self.init_comm()
self.traverse(lambda x: setattr(x, 'comm', self.comm))
self.traverse(lambda x: attach_streams(self, x.hmap, 1),
self.traverse(lambda x: attach_streams(self, x.hmap, 2),
[GenericElementPlot])

def _init_layout(self, layout):
Expand Down
4 changes: 2 additions & 2 deletions holoviews/plotting/mpl/plot.py
Expand Up @@ -334,7 +334,7 @@ def __init__(self, layout, axis=None, create_axes=True, ranges=None,
if self.top_level:
self.comm = self.init_comm()
self.traverse(lambda x: setattr(x, 'comm', self.comm))
self.traverse(lambda x: attach_streams(self, x.hmap, 1),
self.traverse(lambda x: attach_streams(self, x.hmap, 2),
[GenericElementPlot])

def _get_size(self):
Expand Down Expand Up @@ -755,7 +755,7 @@ def __init__(self, layout, keys=None, **params):
if self.top_level:
self.comm = self.init_comm()
self.traverse(lambda x: setattr(x, 'comm', self.comm))
self.traverse(lambda x: attach_streams(self, x.hmap, 1),
self.traverse(lambda x: attach_streams(self, x.hmap, 2),
[GenericElementPlot])


Expand Down
2 changes: 1 addition & 1 deletion holoviews/plotting/plot.py
Expand Up @@ -792,7 +792,7 @@ def __init__(self, overlay, ranges=None, batched=True, keys=None, **params):
if self.top_level:
self.comm = self.init_comm()
self.traverse(lambda x: setattr(x, 'comm', self.comm))
self.traverse(lambda x: attach_streams(self, x.hmap, 1),
self.traverse(lambda x: attach_streams(self, x.hmap, 2),
[GenericElementPlot])


Expand Down
2 changes: 1 addition & 1 deletion holoviews/plotting/util.py
Expand Up @@ -408,7 +408,7 @@ def dim_axis_label(dimensions, separator=', '):
return separator.join([d.pprint_label for d in dimensions])


def attach_streams(plot, obj, precedence=0):
def attach_streams(plot, obj, precedence=1.1):
"""
Attaches plot refresh to all streams on the object.
"""
Expand Down
25 changes: 23 additions & 2 deletions holoviews/streams.py
Expand Up @@ -150,11 +150,26 @@ def subscribers(self):
return [s for p, s in sorted(self._subscribers)]


def clear(self):
def clear(self, policy='all'):
"""
Clear all subscribers registered to this stream.
The default policy of 'all' clears all subscribers. If policy is
set to 'user', only subscribers defined by the user are cleared
(precedence between zero and one). A policy of 'internal' clears
subscribers with precedence greater than unity used internally
by HoloViews.
"""
self._subscribers = []
policies = ['all', 'user', 'internal']
if policy not in policies:
raise ValueError('Policy for clearing subscribers must be one of %s' % policies)
if policy == 'all':
remaining = []
elif policy == 'user':
remaining = [(p,s) for (p,s) in self._subscribers if p > 1]
else:
remaining = [(p,s) for (p,s) in self._subscribers if p <= 1]
self._subscribers = remaining


def reset(self):
Expand All @@ -172,6 +187,12 @@ def add_subscriber(self, subscriber, precedence=0):
Register a callable subscriber to this stream which will be
invoked either when event is called or when this stream is
passed to the trigger classmethod.
Precedence allows the subscriber ordering to be
controlled. Users should only add subscribers with precedence
between zero and one while HoloViews itself reserves the use of
higher precedence values. Subscribers with high precedence are
invoked later than ones with low precedence.
"""
if not callable(subscriber):
raise TypeError('Subscriber must be a callable.')
Expand Down
39 changes: 39 additions & 0 deletions tests/testdynamic.py
Expand Up @@ -444,6 +444,45 @@ def history_callback(x, history=deque(maxlen=10)):
self.assertEqual(dmap[()], Curve([1, 1, 1, 2, 2, 2]))


class StreamSubscribersAddandClear(ComparisonTestCase):

def setUp(self):
self.fn1 = lambda x: x
self.fn2 = lambda x: x**2
self.fn3 = lambda x: x**3
self.fn4 = lambda x: x**4

def test_subscriber_clear_all(self):
pointerx = PointerX(x=2)
pointerx.add_subscriber(self.fn1, precedence=0)
pointerx.add_subscriber(self.fn2, precedence=1)
pointerx.add_subscriber(self.fn3, precedence=1.5)
pointerx.add_subscriber(self.fn4, precedence=10)
self.assertEqual(pointerx.subscribers, [self.fn1,self.fn2,self.fn3,self.fn4])
pointerx.clear('all')
self.assertEqual(pointerx.subscribers, [])

def test_subscriber_clear_user(self):
pointerx = PointerX(x=2)
pointerx.add_subscriber(self.fn1, precedence=0)
pointerx.add_subscriber(self.fn2, precedence=1)
pointerx.add_subscriber(self.fn3, precedence=1.5)
pointerx.add_subscriber(self.fn4, precedence=10)
self.assertEqual(pointerx.subscribers, [self.fn1,self.fn2,self.fn3,self.fn4])
pointerx.clear('user')
self.assertEqual(pointerx.subscribers, [self.fn3,self.fn4])


def test_subscriber_clear_internal(self):
pointerx = PointerX(x=2)
pointerx.add_subscriber(self.fn1, precedence=0)
pointerx.add_subscriber(self.fn2, precedence=1)
pointerx.add_subscriber(self.fn3, precedence=1.5)
pointerx.add_subscriber(self.fn4, precedence=10)
self.assertEqual(pointerx.subscribers, [self.fn1,self.fn2,self.fn3,self.fn4])
pointerx.clear('internal')
self.assertEqual(pointerx.subscribers, [self.fn1,self.fn2])


class DynamicStreamReset(ComparisonTestCase):

Expand Down

0 comments on commit e93b23a

Please sign in to comment.