Search code examples
pythonbokehholoviews

How to use RangetoolLink with holoviews in an Overlayed plot


I am trying to use the holoviews Rangetool link in a holoviews Overlayed plot. But unable to achieve the range linking to work. Is it possible to achieve this.?

Based on these links example 1 and example 2 I tried the options with an overlayed plot instead of a single curve plot. But this didn't work. Below I provided an example with a similar dummy data.

import pandas as pd
import holoviews as hv
from holoviews import opts
import numpy as np

from holoviews.plotting.links import RangeToolLink

hv.extension('bokeh')


# Genrate Random Data
def randomDataGenerator(noOfSampleDataSets):
    for i in range(noOfSampleDataSets):
        res = np.random.randn(1000).cumsum()
        yield res


# Overlay Plots
overlaid_plot = hv.Overlay([hv.Curve(data)
                     .opts(width=800, height=600, axiswise=True, default_tools=[]) 
                            for data in randomDataGenerator(5)])
# Adjust Source Height
source = overlaid_plot.opts(height=200)

# adjust target plot attributes
target = source.opts(clone=True, width=800, labelled=['y'],)

# Link source and target
rtlink = RangeToolLink(source, target)

# Compose and plot.
(target + source).cols(1).opts(merge_tools=False)

I expect that the source plot will show up with a range tool as shown in the example and be able to select a range in it which should select the same data points in the target plot.


Solution

  • Following code works in my case. I slightly refactored the code. But the logic is still the same. So if we have a an overlaid plot, link one of the curves in the overlayed plot works fine with all the remaining curves.

    Following code works in a jupyter notebook. Its not tested in other environment.

    import holoviews as hv
    import numpy as np
    hv.extension('bokeh')
    from holoviews.plotting.links import RangeToolLink
    
    # Genrate Random Data
    def randomDataGenerator(noOfSampleDataSets):
        for i in range(noOfSampleDataSets):
            res = np.random.randn(1000).cumsum()
            yield res
    
    
    
    #generate all curves
    def getCurves(n):
        for data in randomDataGenerator(n):
            curve = hv.Curve(data)
            yield curve
    
    
    
    source_curves, target_curves  = [], []
    for curve in getCurves(10):
        # Without relabel, the curve somehow shares the ranging properties. opts with clone=True doesn't help either.
        src = curve.relabel('').opts(width=800, height=200, yaxis=None, default_tools=[]) 
        tgt = curve.opts(width=800, labelled=['y'], toolbar='disable')
        source_curves.append(src)
        target_curves.append(tgt)     
    
    # link RangeTool for the first curves in the list.
    RangeToolLink(source_curves[0],target_curves[0])
    
    #Overlay the source and target curves
    overlaid_plot_src = hv.Overlay(source_curves).relabel('Source')    
    overlaid_plot_tgt = hv.Overlay(target_curves).relabel('Target').opts(height=600)
    
    # layout the plot and render
    layout = (overlaid_plot_tgt + overlaid_plot_src).cols(1)
    layout.opts(merge_tools=False,shared_axes=False)