question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Easier access to available streams on HoloViews objects

See original GitHub issue

Right now a user can pretty easily set up a streams object with a HoloViews object as its source:

import panel as pn, xarray as xr, holoviews as hv, hvplot.xarray
pn.extension()

ds = xr.tutorial.open_dataset('air_temperature')
image = ds.hvplot('lon', 'lat')
stream = hv.streams.PointerXY(source=image, x=-88+360, y=40)
timeseries = ds.interactive.sel(lon=stream.param.x, 
                                lat=stream.param.y, 
                                method="nearest").hvplot('time')

pn.Column(image, timeseries.dmap())

However, discovering which streams might be applicable to a given HoloViews object requires studying the docs, and actually instantiating them requires importing HoloViews even if I’m otherwise working in hvPlot as I am here.

Could there be a .stream accessor object on HoloViews objects that can be dir() listed or tab completed to show the streams that are applicable to this object, and letting a user refer to them without having to come up with the invocation out of nothing? I’m thinking of something like:

import panel as pn, xarray as xr, holoviews as hv, hvplot.xarray
pn.extension()

ds = xr.tutorial.open_dataset('air_temperature')
image = ds.hvplot('lon', 'lat')
timeseries = ds.interactive.sel(lon=image.stream.hover.param.x, 
                                lat=image.stream.hover.param.y, 
                                method="nearest").hvplot('time')

pn.Column(image, timeseries.dmap())

Seems like this would make streams much more visible and accessible to users, and would make the workflow smoother for hvPlot users.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:8 (8 by maintainers)

github_iconTop GitHub Comments

2reactions
philippjfrcommented, Dec 4, 2020

Here’s a little hacky version I put together to play with this:

class StreamAccessor(object):
     
     def __init__(self, owner):
         self._owner = owner
         self._streams = {}
 
     @property
     def hover(self):
         if 'hover' not in self._streams:
             self._streams['hover'] = PointerXY(x=0, y=0, source=self._owner)
         return self._streams['hover']
 
     @property
     def box_select(self):
         if 'box_select' not in self._streams:
             self._streams['box_select'] = SelectionXY(
                 source=self._owner,
                 x_selection=(0, 0),
                 y_selection=(0, 0)
             )
         return self._streams['box_select']
     
     @property
     def tap(self):
         if 'tap' not in self._streams:
             self._streams['tap'] = Tap(x=0, y=0, source=self._owner)
         return self._streams['tap']
     
 def stream(self):
     if not hasattr(self, '_stream'):
         self._stream = StreamAccessor(self)
     return self._stream
 
 hv.Element.stream = property(stream)
 hv.DynamicMap.stream = property(stream)
0reactions
jbednarcommented, Jan 8, 2021

How would you set the initialization? The first example sets x and y in:

Note that I didn’t want to set the initialization; I simply wanted it to work, and without some initial values this code fails with KeyError: nan. I’d really rather that be done for me, i.e. that somehow the stream has an initial value that correctly reflects some actual value it could eventually have in practice. I have no idea if that’s achievable, but really I want that part to be done for me, rather than for me to have a convenient way to do it myself.

I support the idea of making it easier to find available streams but I am not too fond of this accessor idea.

Sounds like we’re on the same page. I believe strongly that there is an opportunity here (i.e. a problem that users face), and would be happy with any good solution. The accessor idea seems pretty good to me, but a better one would be even better!

Maybe hvplot.streams(image).hover.x

I guess that would be ok, but one thing that’s attractive to me about the accessor is the impression it gives that the streams are just always there ready to tap into if I want, which is conceptually clean and lets me not worry about holding pointers to objects, object lifetimes, etc. Of course that’s a fiction, but it’s a useful one, because I can act like it’s true and reason about it and make the right decisions.

Whereas with a standalone function, as a user I would expect to have to retain a pointer to the object if I want to first pass x and then pass y separately as shown above:

h = hvplot.streams(image).hover
timeseries = ds.interactive.sel(lon=h.param.x, h.param.y, 
                                method="nearest").hvplot('time')

I.e., I now have this object h to worry about, right? Being able to grab a pointer to h is great; having to grab a pointer to it just so I can pass x to one argument and y to another is not.

This kind of accessor would be more appropriate at the hvplot level

Deciding between hvPlot and HoloViews seems difficult; by dependencies it belongs in HoloViews, since it relies on nothing from hvPlot, but all the motivation that I can think of for it is at the hvPlot level, not for direct HoloViews users. Tricky!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Working with Streaming Data — HoloViews v1.15.3
This makes it perfectly suited to work with Buffer . With the StreamingDataFrame we can easily stream data, apply computations such as cumulative...
Read more >
Custom Interactivity — HoloViews v1.15.3
To use and visualize DynamicMap with linked Stream objects you need to be running ... Additionally there a streams to access plotting selections...
Read more >
Responding to Events — HoloViews v1.15.3
Simple streams example#. We can now supply this streams object to a DynamicMap using the same lissajous_crosshair callback from above by adding it...
Read more >
Source code for holoviews.streams
Parameterized): """ A Stream is simply a parameterized object with parameters ... of the stream, which are available on the instance as the...
Read more >
Transforming Elements — HoloViews v1.15.2
HoloViews objects provide a convenient way of wrapping your data along with some ... As soon as the task becomes more complex, it...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found