CubeBrowser / cube-explorer

browser based exploration of iris cubes
BSD 3-Clause "New" or "Revised" License
8 stars 12 forks source link

Responsive slider widget interaction #39

Closed jlstevens closed 8 years ago

jlstevens commented 8 years ago

The lazy approach we are using to loading data results in plots that appear instantly and that only load and render data as the widgets are manipulated. This works very well in general but there are some responsiveness issues when using numeric sliders.

When moving sliders around, events are generated and are currently being queued. As it takes a while to load the data from a cube and render it, moving around numeric slider quickly creates a large queue of events that need to be processed before the plot reflects the final slider position.

There are number of different approaches I can think of that might help improve responsiveness:

  1. Throttling JavaScript events with some heuristic based on how quickly frames are being returned from Python.
  2. Throttling JavaScript events based on a parameter that is explicitly specified by the user.
  3. Maintaining a queue of render events in Python and skipping queued events if the length of the queue gets too long (or when Python notices that the queue is taking too long to process).
  4. Adding an 'Update' button which lets you move the sliders about quickly and only updates the plot when the button is pressed.

Each suggestion has pros and cons:

  1. No input from the user but needs to sample the behaviour before a suitable throttling value can be found. Maybe you base the throttling speed based on the time taken to return the last frame only?
  2. Explicit but requires user input and judgement.
  3. Can choose to respond to or ignore events generated even while the first frame is being computed. The main issue is that this is technically challenging and probably rather complicated.
  4. Solves the problem by removing the live update when dragging sliders. It hides lag at the cost of removing a compelling feature of working with widgets.

At this time, I have no opinion right about which approach is best. Whatever approach we pick, we need to make sure to test it with the nbagg backend to get a sense of what a user would experience when working with a real set of cubes.

philippjfr commented 8 years ago

Thanks for outlining these different proposals. First of all I just remembered that you can already adjust throttling behavior by adjusting the fps output magic option (corresponding to proposal 1.). That said I think a dynamic approach that bases the throttling on how long a plot actually takes to render is probably going to provide a better user experience. I've actually implemented something like when prototyping the datashader DynamicImage callback but we settled on a simple throttling parameter, because it turned out to be responsive enough. I can prototype something like it in HoloViews pretty quickly.

I can't currently envision how suggestion 3 would be implemented because you'd have to manage an event loop somewhere. Adding a button to validate a selection should also be straightforward but I think that degrades the user experience so much that it should only be used if the execution is very slow.

philippjfr commented 8 years ago

I have now introduced a PR in HoloViews to throttle events by measuring the speed of execution and queuing events which arrive faster than that (https://github.com/ioam/holoviews/pull/596). This works pretty robustly and improves the user experience. It doesn't deal with the slow speed of plotting in cartopy however and based on my profiling we can only generate about one frame per second for high resolution (800x600) Image cubes.

philippjfr commented 8 years ago

The PR to add throttling to holoviews widgets (https://github.com/ioam/holoviews/pull/596) has been merged. Will close this issue.