Show individual points when zoomed, else datashade

Making sure this doesn’t get lost because it’s too cool!

points = hv.Points(np.random.multivariate_normal((0,0), [[0.1, 0.1], [0.1, 1.0]], (500000,)))

def filter_points(points, x_range, y_range):
    if x_range is None or y_range is None:
        return points
    return points[x_range, y_range]

def hover_points(points, threshold=5000):
    if len(points) > threshold:
        return points.iloc[:0]
    return points

range_stream = hv.streams.RangeXY(source=points)

filtered = points.apply(filter_points, streams=streams)
shaded = datashade(filtered, width=400, height=400, streams=streams)
hover = filtered.apply(hover_points)

dynamic_hover = (shaded * hover).opts(
    hv.opts.Points(tools=['hover'], alpha=0.1, hover_alpha=0.2, size=10))

Would be cool if users can just set some keyword to True and all this magic happens

I’d be happy to see that in hvplot. Maybe datashade=5000 or rasterize=5000 instead of datashade=True or rasterize=True, indicating that if there are more than 5000 points visible in the current viewport then datashade it, else use raw Bokeh plotting? There are various complications like categorical plotting (supported very differently in datashader and bokeh), styling (colors, sizes, etc.). But in principle, yes.


Worth noting that there’s now a helper for this in the form of apply_when:

import holoviews as hv

from holoviews.operation.datashader import rasterize
from holoviews.operation import apply_when

points = hv.Points(np.random.randn(100000, 2))

apply_when(points, operation=rasterize, predicate=lambda x: len(x) > 5000)

Is there a way to apply x_sampling + y_sampling using this method?

Oh just wrap a function

    def _rasterize_new(self, points):
        return rasterize(points, x_sampling=0.25, y_sampling=0.25, aggregator="max")

apply_when(points, operation=self._rasterize_new, predicate=lambda x: len(x) > 5000)

But maybe apply_when can accept **kwds?

You can make an instance of any operation and override kwargs like this:

my_custom_rasterize = rasterize.instance(x_sampling=0.25, y_sampling=0.25, aggregator="max")
1 Like

Thanks, learning a lot of new stuff!

I thought updating to this method would fix this: datashading error when zoomed on region without any points (maybe geoviews projection + responsive too) · Issue #4910 · holoviz/holoviews · GitHub, but I am still encountering

    t_idx = int(np.ceil(t_m-0.5))
ValueError: cannot convert float NaN to integer