holoviz / holoviews

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

When Tapping quickly multiple times only the first tap is caught #5076

Open MarcSkovMadsen opened 3 years ago

MarcSkovMadsen commented 3 years ago

I'm trying to help a user create a clickeable heatmap https://discourse.holoviz.org/t/updating-heatmap-pixel-value-on-click/2759/14.

I can see that if I click the heatmap twice quickly, only the first click is catched.

This makes updating the heatmap slow.

In the video I first do a double click quickly. Then slowly. There is a difference.

https://user-images.githubusercontent.com/42288570/132083954-cee6e443-6a1e-4dd6-8f0c-f89595d03a78.mp4

import numpy as np
import panel as pn
import holoviews as hv
import xarray as xr
import hvplot.xarray
import param

pn.extension(sizing_mode="stretch_width")
hv.extension("bokeh")

building_components = [
    "foundations",
    "basements",
    "superstructure (floor and roof)",
    "exterior closures (exterior wall, windows, doors)",
    "roofing (coverings and openings",
    "Doors and partitions",
    "staircases",
    "interior finishes (wall, floor and ceiling finishes)",
    "conveying systems (e.g. elevators)",
    "Plumbing (water supply, sewage, drainage, etc.)",
    "Mechnical heating systems",
    "Mechanical cooling systems",
    "Additional/specialized HVAC systems",
    "Fire protection (includes sprinklers and hoses)",
    "Electrical",
]

climate_hazards = [
    "marine coastal flooding",
    "river and lake spring flooding",
    "extreme rain flooding",
    "ice jam flooding",
    "extreme snow",
    "extreme cold",
    "permafrost loss",
    "wildfire",
]

dataset = xr.DataArray(
    np.zeros((len(climate_hazards), len(building_components))),
    dims=["climate_hazards", "building_components"],
    coords=dict(climate_hazards=climate_hazards, building_components=building_components),
    name="Vulnerability Level",
)

I = 0

points = hv.Points([])
stream = hv.streams.Tap(source=points, x=None, y=None)
increment = pn.widgets.Checkbox(value=True, name="Increment")
reset = pn.widgets.Button(name="Reset")

class Update(param.Parameterized):
    updates = param.Integer()

update = Update()

def reset_dataset(event):
    dataset[:,:]=0
    print("resets", update.updates+1)
    update.updates +=1
reset.on_click(reset_dataset)

def increment_dataset(hazard=None, component=None):
    if hazard and component:
        if increment.value:
            inc=1
        else:
            inc=-1

        value = float(dataset.loc[{"climate_hazards": hazard, "building_components": component}].values)
        value += inc
        value = max(min(value, 5.),0.)
        dataset.loc[{"climate_hazards": hazard, "building_components": component}] = value
        stream.reset()
        print("increments", hazard, component, update.updates+1)
        update.updates +=1
pn.bind(increment_dataset, hazard=stream.param.x, component=stream.param.y, watch=True)

def get_heatmap(updates):
    print("update", updates)
    return dataset.hvplot.heatmap(
        x="climate_hazards",
        y="building_components",
        C="Vulnerability Level",
        cmap=["#ffffff", "#ebf4fb", "#c5e0f3", "#9fccec", "#79b7e5", "#4099da"],
        clim=(0, 5),
        tools=[],
        title="User driven vulnerability assessment matrix",
        rot=45,
        grid=True,
        framewise=True,
        min_height=600,
        responsive=True,
    ).opts(line_width=1, line_color="gray")
get_heatmap = pn.bind(get_heatmap, updates=update.param.updates)

def vulnerability(updates):
    return f"Dummy Vulnerability Score: {int(dataset.sum())}"
vulnerability = pn.bind(vulnerability, updates=update.param.updates)

component = pn.Column(
    pn.panel(hv.DynamicMap(get_heatmap)*points, sizing_mode="stretch_both"),
    vulnerability,
    pn.Row(reset, increment, sizing_mode="fixed", width=200),
    min_height=600,
    sizing_mode="stretch_both",
    name="Building Component Inventory",
)

ACCENT_BASE_COLOR = "#4099da"

template = pn.template.FastListTemplate(
    site="Awesome Panel",
    title="User driven vulnerability assessment matrix",
    logo="https://panel.holoviz.org/_static/logo_stacked.png",
    header_background=ACCENT_BASE_COLOR,
    accent_base_color=ACCENT_BASE_COLOR,
    main=[component],
).servable()
jlstevens commented 3 years ago

On one hand this looks a bug but on the other hand, I think that you can't optimize for every use case which means we would need user facing settings to customize how quickly events are processed/debounced etc per plot. As such I think this is more of a feature request.

philippjfr commented 3 years ago

This should be filed upstream in bokeh, we cannot control event gesture event handling at the HoloViews level.

philippjfr commented 3 years ago

Actually maybe @jlstevens is right and this is down to the debouncing window, worth checking.

jlstevens commented 3 years ago

@philippjfr did you get a chance to check whether it was down to debouncing? At any rate, I'll assign this to v2.0.