Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smooth datashader zoom/pan updates #6404

Open
droumis opened this issue Oct 4, 2024 · 3 comments
Open

Smooth datashader zoom/pan updates #6404

droumis opened this issue Oct 4, 2024 · 3 comments
Labels
TRIAGE Needs triaging

Comments

@droumis
Copy link
Member

droumis commented Oct 4, 2024

Is your feature request related to a problem? Please describe.

The update from a zoom/pan interaction on a datashaded plot is currently choppy/course/(all at once), as soon as the new raster is received.

Describe the solution you'd like

Would be nice to have a smooth transition that doesn't noticeably impact latency.

Describe alternatives you've considered

Could we use CSS transition from one image to the next?

@droumis droumis added the TRIAGE Needs triaging label Oct 4, 2024
@jbednar
Copy link
Member

jbednar commented Oct 6, 2024

I'd like to see a mockup or similar approach in some other library to know what's being requested here.

@ahuang11
Copy link
Collaborator

ahuang11 commented Oct 8, 2024

I presume something like Google Maps where it comes by tile, and the next pyramid level comes pretty quickly

@droumis
Copy link
Member Author

droumis commented Oct 8, 2024

I'd like to see a mockup or similar approach in some other library to know what's being requested here.

Here are clips of zooming/panning on the same 1 million point dataset. Of course there are significant tradeoffs and drawbacks to jupyter-scatter and pydeck/deckGL, but the point is to show the difference in the smoothness of interaction updates between solutions.

Attractor func
def roesslerAttractor(num):
    from math import inf
    
    points = []

    xn = 2.644838333129883
    yn = 4.060488700866699
    zn = 2.8982460498809814
    a = 0.2
    b = 0.2
    c = 5.7
    dt = 0.006

    minX = inf
    maxX = -inf
    minY = inf
    maxY = -inf
    for i in range(num):
        dx = -yn - zn
        dy = xn + a * yn
        dz = b + zn * (xn - c)

        xh = xn + 0.5 * dt * dx
        yh = yn + 0.5 * dt * dy
        zh = zn + 0.5 * dt * dz

        dx = -yh - zh
        dy = xh + a * yh
        dz = b + zh * (xh - c)

        xn1 = xn + dt * dx
        yn1 = yn + dt * dy
        zn1 = zn + dt * dz

        points.append([xn1, yn1])

        minX = min(xn1, minX)
        maxX = max(xn1, maxX)
        minY = min(yn1, minY)
        maxY = max(yn1, maxY)

        xn = xn1;
        yn = yn1;
        zn = zn1;


    dX = maxX - minX
    dY = maxY - minY

    for i in range(num):
        points[i][0] -= minX
        points[i][0] /= dX / 2
        points[i][0] -= 1
        points[i][1] -= minY
        points[i][1] /= dY / 2
        points[i][1] -= 1

    return points

jupyter-scatter

Code
import numpy as np
import pandas as pd
import jscatter

points = np.asarray(roesslerAttractor(1000000))
jscatter.plot(points[:,0], points[:,1], height=640)
GMT20241008-222001_Clip_Jupyter-Scatter_smooth.mp4

pydeck (deckGL)

GMT20241008-223616_Clip_PyDeck_DeckGL_smooth.mp4
Code
import numpy as np
import pandas as pd
import pydeck as pdk

points = np.asarray(roesslerAttractor(1000000))
df = pd.DataFrame(points, columns=["x", "y"])

layer = pdk.Layer(
    "ScatterplotLayer",
    data=df,
    get_position=["x", "y"],
    get_radius=0.005,
    get_fill_color=[0, 0, 0, 128], # ~50% transparency 128/255
)

view_state = pdk.data_utils.compute_view(df[['x', 'y']], view_proportion=1)
deck = pdk.Deck(layers=[layer], initial_view_state=view_state, map_style=None)
deck.show()

datashader/holoviews/bokeh

Code
import numpy as np
import holoviews as hv
from holoviews.operation.datashader import rasterize, datashade, dynspread
from bokeh.models import HoverTool

hv.extension('bokeh')

points = np.asarray(roesslerAttractor(1000000))
ds_points = dynspread(rasterize(hv.Points(points, kdims=['x', 'y'])))

ds_points.opts(
    width=800, height=800,
    tools=['hover'],
    active_tools=['wheel_zoom'],
    cmap='greys',
)
GMT20241008-230410_Clip_Datashader.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
TRIAGE Needs triaging
Projects
None yet
Development

No branches or pull requests

3 participants