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

match_aspect parameter for bokeh's BoxZoomTool is not working #6211

Open
1 task
MP-MaximilianLattka opened this issue Apr 26, 2024 · 4 comments
Open
1 task

Comments

@MP-MaximilianLattka
Copy link

MP-MaximilianLattka commented Apr 26, 2024

ALL software version info

Python: 3.11.9
JupyterLab: 4.1.5
Holoviews: 1.18.3
Bokeh: 3.3.4 and 3.4.1

Description of expected behavior and the observed behavior

I’ve been plotting map data using holoviews and geoviews with the bokeh backend.

Bokeh has a zoom tool called BoxZoomTool, which allows drawing a rectangle to zoom in. Setting the kwarg match_aspect=True results in maintaining the aspect ratio, which is meaningful when working with maps. Apparently, holoviews doesn’t properly use pass the BoxZoomTool to bokeh as match_aspect=True does not have any effect.

Complete, minimal, self-contained example code that reproduces the issue

Working BoxZoomTool with native bokeh only (version 3.4.1 and 3.3.4, both working as expected)
import bokeh
from bokeh.plotting import figure, show
from bokeh.models import BoxZoomTool

print(f"{bokeh.__version__=}")

fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']
counts = [5, 3, 4, 2, 4, 6]

box_zoom = BoxZoomTool(match_aspect=True)

p = figure(x_range=fruits, height=350, title="Fruit Counts",
           toolbar_location=None, tools=[box_zoom])

p.vbar(x=fruits, top=counts, width=0.9)

p.xgrid.grid_line_color = None
p.y_range.start = 0

show(p)
Non-working holoviews code (version 1.18.3)
import numpy as np
import holoviews as hv
from bokeh.models import BoxZoomTool

hv.extension("bokeh")

print(f"{hv.__version__=}")


x,y = np.mgrid[-50:51, -50:51] * 0.1

box_zoom = BoxZoomTool(match_aspect=True)

img = hv.Image(np.sin(x**2+y**2), bounds=(-1,-1,1,1))

(img.relabel('Image') * img.sample(x=0).relabel('Cross-section')).opts(
    tabs=True,
    tools=[box_zoom])
Non-working minimal example of my code (version 1.18.3)
data = [{
    'STATENAME': 'District of Columbia',
    'LAT': (-77.035264, -76.909294, -77.040741, -77.117418, -77.035264),
    'LONG': (38.993869, 38.895284, 38.791222, 38.933623, 38.993869)
}]

box_zoom = BoxZoomTool(match_aspect=True)

tiles = hv.Tiles("https://tile.openstreetmap.org/{Z}/{X}/{Y}.png", name="OSM").opts(
    #"Image", # Does not respect width and height parameter
    width=1400,
    height=800,
    #tools=[box_zoom], # This alone does not preserve match_aspect=True
)

choropleth = gv.Polygons(data, ["LAT", "LONG"], ["STATENAME"]).opts(
    #"Image", # Incompatible with line_color parameter
    xaxis=None,
    yaxis=None,
    line_color="black",
    cmap="bwr",
    alpha=1.0,
    #tools=[box_zoom], # This alone does not preserve match_aspect=True
)
(tiles * choropleth).opts(
    #"Image",
    #tools=[box_zoom], # This alone does not preserve match_aspect=True
)

Stack traceback and/or browser JavaScript console output

Screenshots or screencasts of the bug in action

  • I may be interested in making a pull request to address this
@ahuang11
Copy link
Collaborator

ahuang11 commented Apr 26, 2024

I believe the issue arises when tabs=True.

A workaround is using Panel:

import panel as pn
import numpy as np
import holoviews as hv
from bokeh.models import BoxZoomTool

pn.extension()
hv.extension("bokeh")

print(f"{hv.__version__=}")


x, y = np.mgrid[-50:51, -50:51] * 0.1

box_zoom = BoxZoomTool(match_aspect=True)

img = hv.Image(np.sin(x**2 + y**2), bounds=(-1, -1, 1, 1))

pn.Tabs(
    img.relabel("Image").opts(default_tools=[box_zoom]),
    img.sample(x=0).relabel("Cross-section"),
)

@ahuang11
Copy link
Collaborator

ahuang11 commented Apr 26, 2024

I think the tools are dropped when tabs=True.

import numpy as np
import holoviews as hv
from bokeh.models import BoxZoomTool

hv.extension("bokeh")

print(f"{hv.__version__=}")


x,y = np.mgrid[-50:51, -50:51] * 0.1

box_zoom = BoxZoomTool(match_aspect=True)

img = hv.Image(np.sin(x**2+y**2), bounds=(-1,-1,1,1))

(img.relabel('Image') * img.sample(x=0).relabel('Cross-section')).opts(
   tabs=True, default_tools=[box_zoom], data_aspect=1, tools=[box_zoom], active_tools=[box_zoom])

i.e. the pan, zoom tools are still here even though I explicitly set everything.
image

@ahuang11
Copy link
Collaborator

ahuang11 commented Apr 26, 2024

I suppose if you specify 'Image', it works:

import numpy as np
import holoviews as hv
from bokeh.models import BoxZoomTool

hv.extension("bokeh")

print(f"{hv.__version__=}")


x,y = np.mgrid[-50:51, -50:51] * 0.1

box_zoom = BoxZoomTool(match_aspect=True)

img = hv.Image(np.sin(x**2+y**2), bounds=(-1,-1,1,1))

(img.relabel('Image') * img.sample(x=0).relabel('Cross-section')).opts(
   "Image", default_tools=[box_zoom], active_tools=[box_zoom]).opts(tabs=True, )
image

@MP-MaximilianLattka
Copy link
Author

Specifying "Image" may be a workaround sometimes apparently.

However, I'm working with map data and therefore different objects and this does not suit my issue.

I spent some time creating a minimal example of my particular situation and will update the original description of this issue.

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

No branches or pull requests

2 participants