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

Clickable Map Widget #6183

Open
itsgifnotjiff opened this issue Apr 11, 2024 · 2 comments
Open

Clickable Map Widget #6183

itsgifnotjiff opened this issue Apr 11, 2024 · 2 comments

Comments

@itsgifnotjiff
Copy link

I find myself writing the same boilerplate code over and over again for a Clickable Map. I understand the components are there to build up custom applications but I feel on my end there is reason to believe a param.Parametrized class of a Map covering one or all of the following

  • Empty Map that when clicked will execute _click_callback
  • Map with geoviews.Points like elements on it that when clicked will execute _click_callback
  • Map with holoviews.[QuadMesh | Image | Overlay | NdOverlay] on it that when clicked will execute _click_callback

The idea is to gather the boilerplate code required such as the pandas/polars.DataFrame, xarray.Dataset, holoviews.DynamicMap, holoviews.streams.[Tap | DoubleTap | etc.]` into a one class that will accept a couple of arguments and will act like any other widget.

mapc = pnw.ClickableMap(
     tiles=gv.CartoDark(),
     responsive=True,
     callback=self._click_callback
     overlays=[
          ds.TT.isel(time=0, pres=-1).hvplot.quadmesh(crs=ccrs.PlatteCarree(),projection=ccrs.PlatteCarree()),
          gv.Points( ... ),
          ...
      ]
)

I have added a very minimal class that I know is not well written ( I am still learning and thanks to the new documentation in 1.4.0 I'm actually getting better). I have no idea how something like this is developed or how it would fit inside the library but I would love to see it added. Thank you Mr. @ahuang11 for guiding me this far.

class ClickableMap(pn.viewable.Viewer):
    def get_map(self):
        return (gv.tile_sources.CartoDark() * gv.Points([-122.76, 49.555]).opts(alpha=0)).opts(width=1000)

    def tap_series(self, x, y):
        lon, lat = to_lon_lat(x, y)
        self.figs_col.clear()
        self.figs_col.append( lon )
        # Hack since TapStream only accept hv elements and can not be None
        return hv.Div(
            """<hr style="border-top: 1px transparent; height: 1px;">"""
        ).opts(height=5)

    def __init__(self):
        self.figs_col = pn.Column()
        self.map = self.get_map()
        self.tap_stream = hv.streams.Tap(source=self.map, x=-122.76, y=49.555)
        self.dynamic_map = hv.DynamicMap(self.tap_series, streams=[self.tap_stream])
        super().__init__()

    def view(self):
        return pn.Column(self.dynamic_map, self.figs_col)


app = Example()

template = pn.template.MaterialTemplate(
    site="Panel",
    title="ClickableMap",
    main=[app.map, app.view],
    sidebar_width=200,
).servable()
@ahuang11
Copy link
Collaborator

I don't believe it should be a Panel widget; I think hvPlot is more suitable like Andrew's curve
https://hvplot.holoviz.org/reference/tabular/andrewscurves.html

@itsgifnotjiff
Copy link
Author

My intuition was to make it more reusible as a component/widget because I know for a fact people will customize it a bunch.

Imagine your beautiful example Mr. @ahuang11 .

I think Mr. @hoxbro would have the best idea but ultimately Mr. @philippjfr would have to chime in as I would love to expose the map's events a bit like OpenLayers's click, dbclick, precompose, postrender etc. and to make sure we do not lose access to the underlying overlays. We would all probably define our own custom HoverTools and Formatters.

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