Skip to content

Commit

Permalink
Add functions for executing MapLibre notebook (opengeos#806)
Browse files Browse the repository at this point in the history
* Add functions for executing MapLibre notebook

* Add GIF notebook example

* Improve function
  • Loading branch information
giswqs authored Jul 3, 2024
1 parent 6be8724 commit 3e1cb23
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 4 deletions.
81 changes: 81 additions & 0 deletions docs/maplibre/add_gif.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[![image](https://jupyterlite.rtfd.io/en/latest/_static/badge.svg)](https://demo.leafmap.org/lab/index.html?path=maplibre/add_gif.ipynb)\n",
"[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/opengeos/leafmap/blob/master/docs/maplibre/add_gif.ipynb)\n",
"[![image](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/opengeos/leafmap/HEAD)\n",
"\n",
"**Add GIF animations to the map**\n",
"\n",
"This example shows how to add GIF animations to the map.\n",
"\n",
"Uncomment the following line to install [leafmap](https://leafmap.org) if needed."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# %pip install \"leafmap[maplibre]\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import leafmap.maplibregl as leafmap"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"m = leafmap.Map(center=[-100, 40], zoom=3, style=\"positron\")\n",
"image = \"https://i.imgur.com/KeiAsTv.gif\"\n",
"m.add_image(image=image, width=250, height=250, position=\"bottom-right\")\n",
"text = \"I love sloth!🦥\"\n",
"m.add_text(text, fontsize=35, padding=\"20px\")\n",
"image2 = \"https://i.imgur.com/kZC2tpr.gif\"\n",
"m.add_image(image=image2, bg_color=\"transparent\", position=\"bottom-left\")\n",
"m"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![](https://i.imgur.com/auytBtD.png)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
6 changes: 6 additions & 0 deletions docs/maplibre/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ Add deck.gl layers to the map.

[![](https://i.imgur.com/rQR4687.png)](https://leafmap.org/maplibre/add_deckgl_layer)

## Add GIF animations to the map

Add GIF animations to the map.

[![](https://i.imgur.com/auytBtD.png)](https://leafmap.org/maplibre/add_gif)

## Add HTML content to the map

Add HTML content to the map.
Expand Down
122 changes: 122 additions & 0 deletions leafmap/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -13616,7 +13616,9 @@ def execute_notebook_dir(in_dir):
from pathlib import Path

in_dir = os.path.abspath(in_dir)

files = list(Path(in_dir).rglob("*.ipynb"))
files.sort()
count = len(files)
if files is not None:
for index, file in enumerate(files):
Expand All @@ -13625,6 +13627,126 @@ def execute_notebook_dir(in_dir):
execute_notebook(in_file)


def execute_maplibre_notebook_dir(
in_dir: str,
out_dir: str,
delete_html: bool = True,
replace_api_key: bool = True,
recursive: bool = False,
keep_notebook: bool = False,
index_html: bool = True,
) -> None:
"""
Executes Jupyter notebooks found in a specified directory, optionally replacing API keys and deleting HTML outputs.
Args:
in_dir (str): The input directory containing Jupyter notebooks to be executed.
out_dir (str): The output directory where the executed notebooks and their HTML outputs will be saved.
delete_html (bool, optional): If True, deletes any existing HTML files in the output directory before execution. Defaults to True.
replace_api_key (bool, optional): If True, replaces the API key in the output HTML. Defaults to True.
set "MAPTILER_KEY" and "MAPTILER_KEY_PUBLIC" to your MapTiler API key and public key, respectively.
recursive (bool, optional): If True, searches for notebooks in the input directory recursively. Defaults to False.
keep_notebook (bool, optional): If True, keeps the executed notebooks in the output directory. Defaults to False.
index_html (bool, optional): If True, generates an index.html file in the output directory listing all files. Defaults to True.
Returns:
None
"""
import shutil

if not os.path.exists(out_dir):
os.makedirs(out_dir)

if replace_api_key:
os.environ["MAPTILER_REPLACE_KEY"] = "True"

if delete_html:
html_files = find_files(out_dir, "*.html", recursive=recursive)
for file in html_files:
os.remove(file)

files = find_files(in_dir, "*.ipynb", recursive=recursive)
for index, file in enumerate(files):
print(f"Processing {index + 1}/{len(files)}: {file} ...")
basename = os.path.basename(file)
out_file = os.path.join(out_dir, basename)
shutil.copy(file, out_file)

with open(out_file, "r") as f:
lines = f.readlines()

out_lines = []
for line in lines:
if line.strip() == '"m"':
out_lines.append(line.replace("m", "m.to_html()"))
else:
out_lines.append(line)

with open(out_file, "w") as f:
f.writelines(out_lines)

out_html = os.path.basename(out_file).replace(".ipynb", ".html")
os.environ["MAPLIBRE_OUTPUT"] = out_html
execute_notebook(out_file)

if not keep_notebook:
all_files = find_files(out_dir, "*", recursive=recursive)
for file in all_files:
if not file.endswith(".html"):
os.remove(file)

if index_html:
generate_index_html(out_dir)


def generate_index_html(directory: str, output: str = "index.html") -> None:
"""
Generates an HTML file named 'index.html' in the specified directory, listing
all files in that directory as clickable links.
Args:
directory (str): The path to the directory for which to generate the index.html file.
output (str, optional): The name of the output HTML file. Defaults to "index.html".
Returns:
None
"""
# Get a list of files in the directory
files = sorted(
[f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))]
)

# Start the HTML content
html_content = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Index of {directory}</title>
</head>
<body>
<h1>Index of {directory}</h1>
<ul>
""".format(
directory=directory
)

# Add each file to the HTML list
for file in files:
html_content += ' <li><a href="{file}">{file}</a></li>\n'.format(
file=file
)

# Close the HTML content
html_content += """ </ul>
</body>
</html>"""

# Write the HTML content to index.html in the specified directory
with open(os.path.join(directory, output), "w") as f:
f.write(html_content)


def github_get_release_id_by_tag(username, repository, tag_name, access_token=None):
"""
Fetches the release ID by tag name for a given GitHub repository.
Expand Down
34 changes: 30 additions & 4 deletions leafmap/maplibregl.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,10 @@ def show(self) -> None:
def _repr_html_(self, **kwargs):
"""Displays the map."""

filename = os.environ.get("MAPLIBRE_HTML", None)
filename = os.environ.get("MAPLIBRE_OUTPUT", None)
replace_key = os.environ.get("MAPTILER_REPLACE_KEY", False)
if filename is not None:
self.to_html(filename, replace_key=False)
self.to_html(filename, replace_key=replace_key)

def add_layer(
self,
Expand Down Expand Up @@ -1177,6 +1178,7 @@ def to_html(
height: str = "100%",
replace_key: bool = False,
preview: bool = False,
overwrite: bool = False,
**kwargs,
):
"""Render the map to an HTML page.
Expand All @@ -1193,6 +1195,8 @@ def to_html(
The public API key is read from the environment variable `MAPTILER_KEY_PUBLIC`.
Defaults to False.
preview (bool, optional): Whether to preview the HTML file in a web browser.
Defaults to False.
overwrite (bool, optional): Whether to overwrite the output file if it already exists.
**kwargs: Additional keyword arguments that are passed to the
`maplibre.ipywidget.MapWidget.to_html()` method.
Expand Down Expand Up @@ -1226,13 +1230,22 @@ def to_html(
div_before = f"""<div id="pymaplibregl" style="height: {height};"></div>"""
html = html.replace(div_before, div_after)

if replace_key:
if replace_key or (os.getenv("MAPTILER_REPLACE_KEY") is not None):
key_before = get_api_key("MAPTILER_KEY")
key_after = get_api_key("MAPTILER_KEY_PUBLIC")
if key_after is not None:
html = html.replace(key_before, key_after)

output = os.getenv("MAPLIBRE_OUTPUT", None)

if output:

if not overwrite and os.path.exists(output):
import glob

num = len(glob.glob(output.replace(".html", "*.html")))
output = output.replace(".html", f"_{num}.html")

with open(output, "w") as f:
f.write(html)
if preview:
Expand Down Expand Up @@ -1893,8 +1906,21 @@ def add_image(
if id is None:
id = "image"

style = ""
if isinstance(width, int):
style += f"width: {width}px; "
elif isinstance(width, str) and width.endswith("px"):
style += f"width: {width}; "
if isinstance(height, int):
style += f"height: {height}px; "
elif isinstance(height, str) and height.endswith("px"):
style += f"height: {height}; "

if position is not None:
html = f'<img src="{image}">'
if style == "":
html = f'<img src="{image}">'
else:
html = f'<img src="{image}" style="{style}">'
self.add_html(html, position=position, **kwargs)
else:
if isinstance(image, str):
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ nav:
- maplibre/add_colorbar.ipynb
- maplibre/add_components.ipynb
- maplibre/add_deckgl_layer.ipynb
- maplibre/add_gif.ipynb
- maplibre/add_html.ipynb
- maplibre/add_image.ipynb
- maplibre/add_image_generated.ipynb
Expand Down

0 comments on commit 3e1cb23

Please sign in to comment.