holoviz / holoviews

With Holoviews, your data visualizes itself.
https://holoviews.org
BSD 3-Clause "New" or "Revised" License
2.66k stars 396 forks source link

Hold streams together for faster plot callbacks #6247

Closed ahuang11 closed 1 month ago

ahuang11 commented 1 month ago

Philipp suggested this; not sure if the following is necessary:

                if self.plot.comm:
                    push_on_root(self.plot.root.ref['id'])
codecov[bot] commented 1 month ago

Codecov Report

All modified and coverable lines are covered by tests :white_check_mark:

Project coverage is 88.47%. Comparing base (2ba3d78) to head (1afb3a8). Report is 8 commits behind head on main.

Additional details and impacted files ```diff @@ Coverage Diff @@ ## main #6247 +/- ## ========================================== + Coverage 88.39% 88.47% +0.08% ========================================== Files 323 323 Lines 67620 67642 +22 ========================================== + Hits 59770 59849 +79 + Misses 7850 7793 -57 ```

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

ahuang11 commented 1 month ago

I tried this too, but I'm not sure why self.plot.root is a Row instead of a bokeh figure

            with self.plot.root.hold_render():
                with set_curdoc(self.plot.document):
                    Stream.trigger(streams)
philippjfr commented 1 month ago

but I'm not sure why self.plot.root is a Row instead of a bokeh figure

The root is the Bokeh root on the Bokeh document and will change depending on whether you are rendering the plot on its own or inside some Panel component.

philippjfr commented 1 month ago

I'd suggest using:

            with self.plot.state.hold_render():
philippjfr commented 1 month ago

@ahuang11 Can you confirm whether this still gives the expected speedups?

ahuang11 commented 1 month ago

It seems so.

This is self.plot.state.hold_render(B)

https://github.com/holoviz/holoviews/assets/15331990/6fc4ab3c-6d7e-4b69-bb5d-489ecd01e0a4

And this is self.plot.document.hold() (A, original)

https://github.com/holoviz/holoviews/assets/15331990/c5f8f8e4-247f-4be5-a410-3c52ec63ea4c

hold_render (B) seems to do it in batches, and potentially seem a little faster because upon wheel zoom, it throttles vs non-throttle. I do like how (A) updates each line individually for a sense of progress.

ahuang11 commented 1 month ago

Seems like it works in notebook (VSCode)

https://github.com/holoviz/holoviews/assets/15331990/863935b6-27e1-46d9-9bc2-539ad16eaa1f

philippjfr commented 1 month ago

That looks much slower than what we saw originally, no?

ahuang11 commented 1 month ago

We previewed it on @droumis 's machine last time. Also, not sure if he used the same resampled data tree as me.

A is the "original" method.

droumis commented 1 month ago

Seeing 2:4 second lag on my end for render updates for this self.plot.state.hold_render approach. I'm also including in here Philipp's fix to the rangetoolink to work with subcoordinate_y.

I'm not seeing the blanking when box-zooming, but I'm also not subselecting channels based on the viewport, just time slicing. Andrew, can you show me your channel-slicing approach? Here's the version of the code I used for this.

https://github.com/holoviz/holoviews/assets/6613202/14000a09-e4f2-4d5c-ab4c-72c4d091411c

What was the code block we initially saw very good speed with? I'll try that again too

droumis commented 1 month ago

What was the code block we initially saw very good speed with? I'll try that again too

Assuming the 'original' code block was the following

                self.plot.document.hold()
                try:
                    Stream.trigger(streams)
                finally:
                    self.plot.document.unhold()

With the original approach, I'm seeing slightly faster times, ~1-3 seconds for updates (also, still not channel slicing):

https://github.com/holoviz/holoviews/assets/6613202/fd37fdd8-1725-4b67-820c-23dcc66652e2

philippjfr commented 1 month ago

Someone should dig into this with the browser performance profiler like we did last time to see what it's doing while you wait for the update.

ahuang11 commented 1 month ago

I'd define channel_slice like this:


    channel_slice = slice(y_range[0], y_range[1])

    # calculate the appropriate pyramid level and

    ...
    # extract new data and re-paint the plot
    ds = _extract_ds(ts_dt, pyramid_level, channels).sel(time=time_slice, channel=channel_slice).load()

    ...
    for channel in ds["channel"].values.tolist():
droumis commented 1 month ago

Ok, I've added the channel slicing. The performance is better now all around, even without holding the render. But now I'm seeing a lot of fragility with the channel y-ticks while navigating around.. e.g.:

image

@ahuang11 , do you see this as well? Is it the same thing as mentioned here?

droumis commented 1 month ago

Initial Profiling:

Baseline (with channel slicing, no render holding): https://github.com/holoviz/holoviews/assets/6613202/7bf743e0-03be-40d3-8fe4-d88f0384ad19
plot.document.hold https://github.com/holoviz/holoviews/assets/6613202/82307a8c-b728-4b81-ba97-25d2f836bff5
plot.state.hold_render Sometimes can take very long to update, other times very quick https://github.com/holoviz/holoviews/assets/6613202/99f88b9f-a45f-4b0f-9d1d-c565e23a9ba1
ahuang11 commented 1 month ago

@ahuang11 , do you see this as well? Is it the same thing as mentioned https://github.com/holoviz/holoviews/pull/6256#issuecomment-2150258611?

Yes that's the same issue.

Thanks for doing the profiling!

philippjfr commented 1 month ago

Closing in favor of https://github.com/holoviz/holoviews/pull/6265