Closed giswqs closed 1 year ago
I don't believe this is an anywidget bug. JupyterLab and Google Colab are related to how the the output areas in the DOM that JupyterLab and Google Colab provide (i.e., the DOM Node view.el
). This is not something that anywidget has control over, and the same results would occur if you created a custom Jupyter widget with one of the cookiecutter templates.
The VS Code issue seems to be with your Python environment, and likely ipywidgets
. Can you create a fresh environment?
actually these errors in VS Code are just adding noise. The issue is that the loadScript
fails to add maplibregl
as a global in the VSCode context leading to a ReferenceError
because it isn't defined and you try to access maplibregl
in the render function. Again, this issue stems from the the finicky nature of trying to load JavaScript that is not a standard module (ESM).
It's a hack and there will always be edge cases due to naming conflicts and environment globals in the various front-end environments (Colab, JupyterLab, VSCode). ESM is an official standard and avoids these issues all together by not allowing the import to rely on globals. anywidget can't fix this problem for you, but using ESM will.
I notice that maplibregl
is on NPM. I'd suggest not using unpkg for this code and instead pick a modern CDN like esm.sh which mirrors NPM like unpkg, but additionally compiles/translates any non ESM JavaScript to ESM. This means you can ditch the loadScript
code and use a valid ESM import.
I highly recommend learning more about ESM and reading the "getting started" section of our documentation: https://anywidget.dev/en/jupyter-widgets-the-good-parts/#tips-for-beginners
class MapWidget(anywidget.AnyWidget):
_esm = """
import maplibregl from "https://esm.sh/maplibre-gl@2.4.0";
export function render(view) {
const div = document.createElement("div");
div.style.width = "100%";
div.style.height = "500px";
const map = new maplibregl.Map({
container: div,
style: 'https://demotiles.maplibre.org/style.json', // stylesheet location
center: [0, 20], // starting position [lng, lat]
zoom: 2 // starting zoom
});
view.el.appendChild(div);
}
"""
_css = "https://esm.sh/maplibre-gl@2.4.0?css"
MapWidget()
@manzt Perfect! It works like a charm. Thank you.
How do you find out if a JS library is included in esm.sh? The esm.sh site does not seem to provide any search functionality like NPM. For now, I simply enter https://esm.sh/maplibre-gl and it redirects to https://esm.sh/maplibre-gl@2.4.0, and add ?css
to get https://esm.sh/maplibre-gl@2.4.0?css. Is this the correct way?
Sorry for the delay in my response. esm.sh is a CDN that mirrors the npm registry, so packages that are on npm should be available via esm.sh under https://esm.sh/<package-name>
. (read: you should be able to look up a package on npm and at least try to request it from esm.sh). An easy way to check is to copy and paste the esm.sh url in the browser.
The "magic" of esm.sh is that it will try to transform any JS that is not valid ESM to be compatible. This means that packages that don't publish ESM to npm can still be used via import
from esm.sh domain.
The other thing you mentioned is with regard to the REST api that esm.sh exposes for requesting specific assets or versions from the CDN. The URL esm.sh/maplibre-gl automatically links to the latest version. It is best practice to check in the version in your package, however if you scroll down on the esm.sh landing page there are a lot of details about how to request a specific semver range, for example. The ?css
is also described further down on the page, as a way to request styles. As a fallback, you can always request the exact files like on unpkg: https://esm.sh/maplibre-gl@2.4.0/dist/maplibre-gl.css
Thanks for the advice. That's very helpful.
After switch to ESM, now the map widget works perfectly on both VS Code and Google Colab. However, this map size is always fixed with Jupyter Lab and Jupyter Notebook no matter what width and height values are specified. Any advice?
import anywidget
import traitlets
class MapWidget(anywidget.AnyWidget):
_esm = """
import maplibregl from "https://esm.sh/maplibre-gl@2.4.0";
export function render(view) {
let center = view.model.get("center");
center.reverse();
let zoom = view.model.get("zoom");
let width = view.model.get("width");
let height = view.model.get("height");
const div = document.createElement("div");
div.style.width = width;
div.style.height = height;
const map = new maplibregl.Map({
container: div,
style: 'https://demotiles.maplibre.org/style.json', // stylesheet location
center: center, // starting position [lng, lat]
zoom: zoom // starting zoom
});
view.el.appendChild(div);
}
"""
_css = "https://esm.sh/maplibre-gl@2.4.0/dist/maplibre-gl.css"
center = traitlets.List([20, 0]).tag(sync=True, o=True)
zoom = traitlets.Int(2).tag(sync=True, o=True)
width = traitlets.Unicode("100%").tag(sync=True, o=True)
height = traitlets.Unicode("600px").tag(sync=True, o=True)
m = MapWidget(center=[20, 0], zoom=2)
m
I am exploring the maplibre library with anywidget. The following code works perfectly with Colab. Jupyter Lab can display the map, but the map size is always fixed no matter what
div.style.width
anddiv.style.height
values. VS Code throws errors. Any advice?Colab:
Jupyter Lab:
VS Code: