Skip to content

Commit

Permalink
Merge branch 'main' of github.com:eodaGmbH/py-maplibregl into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Kuethe committed Jun 28, 2024
2 parents 601cc21 + 79f5a2f commit e18d100
Show file tree
Hide file tree
Showing 24 changed files with 576 additions and 127 deletions.
67 changes: 67 additions & 0 deletions _experimental/layer_switcher_control.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Shiny Express App

import json
import webbrowser

from maplibre import Map, MapOptions, render_maplibregl
from maplibre.basemaps import Carto
from maplibre.controls import (
ControlPosition,
InfoBoxControl,
LayerSwitcherControl,
NavigationControl,
ScaleControl,
)
from shiny.express import input, render, ui

m = Map(
MapOptions(
style=Carto.POSITRON,
center=(-122.4, 37.74),
zoom=12,
hash=True,
pitch=40,
)
)
m.add_control(NavigationControl())
m.add_control(ScaleControl(), ControlPosition.BOTTOM_LEFT)

# m.add_call(
# "addControl",
# "InfoBoxControl",
# {
# "cssText": "padding: 20px; font-size: 20px;font-family: monospace;",
# "content": "<h1>Awesome control.</h1><p>And some text.</p>",
# },
# ControlPosition.TOP_LEFT.value,
# )

m.add_control(InfoBoxControl(content="Toggle layers"), ControlPosition.TOP_LEFT)
m.add_control(
LayerSwitcherControl(
layer_ids=["water", "landcover"],
theme="default",
# css_text="padding: 10px; border: 1px solid black; border-radius: 3x;font-size: 15px;",
),
ControlPosition.TOP_LEFT,
)


@render_maplibregl
def maplibre():
return m


@render.code
def selected_features():
obj = input.maplibre_draw_features_selected()
print(obj)
return json.dumps(obj["features"], indent=2) if obj else "Pick some features!"


if __name__ == "__main__":
filename = "docs/examples/mapbox_draw_plugin/app.html"
with open(filename, "w") as f:
f.write(m.to_html())

webbrowser.open(filename)
4 changes: 4 additions & 0 deletions docs/api/controls.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@
::: maplibre.controls.NavigationControl

::: maplibre.controls.GeolocateControl

::: maplibre.controls.InfoBoxControl

::: maplibre.controls.LayerSwitcherControl
5 changes: 5 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog for MapLibre for Python

## maplibre v0.2.5

* Add custom `LayerSwitcherControl` (#69)
* Add custom `InfoBoxControl` (#74)

## maplibre v0.2.4

* Add `MapboxDraw` plugin (#59)
Expand Down
12 changes: 7 additions & 5 deletions docs/examples/deckgl_layer/app.html

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions docs/examples/layer_switcher/app.html

Large diffs are not rendered by default.

94 changes: 94 additions & 0 deletions docs/examples/layer_switcher/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Example taken from here: https://maplibre.org/maplibre-gl-js/docs/examples/pmtiles/

import webbrowser

from maplibre import Layer, LayerType, Map, MapOptions, render_maplibregl
from maplibre.basemaps import construct_basemap_style
from maplibre.controls import (
ControlPosition,
InfoBoxControl,
LayerSwitcherControl,
NavigationControl,
)
from shiny.express import input, render, ui

PMTILES_URL = "https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles"

pmtiles_source = {
"type": "vector",
"url": f"pmtiles://{PMTILES_URL}",
"attribution": '© <a href="https://openstreetmap.org">OpenStreetMap</a>',
}

custom_basemap = construct_basemap_style(
sources={"pmtiles": pmtiles_source},
layers=[
Layer(
id="buildings",
source="pmtiles",
source_layer="landuse",
type=LayerType.FILL,
paint={"fill-color": "red"},
layout={"visibility": "none"},
),
Layer(
id="roads",
source="pmtiles",
source_layer="roads",
type=LayerType.LINE,
paint={"line-color": "black"},
),
Layer(
id="mask",
source="pmtiles",
source_layer="mask",
type=LayerType.FILL,
paint={"fill-color": "yellow"},
layout={"visibility": "none"},
),
],
)


map_options = MapOptions(
style=custom_basemap,
# hash=True,
# bounds=(11.154026, 43.7270125, 11.3289395, 43.8325455),
center=(11.2415, 43.7798),
zoom=12.5,
)


def create_map():
m = Map(map_options)
m.add_control(NavigationControl())
m.add_control(
InfoBoxControl(
content="Toggle layers of PMTiles source",
css_text="padding: 10px; background-color: yellow; color: steelblue; font-weight: bold;",
),
ControlPosition.TOP_LEFT,
)
m.add_control(
LayerSwitcherControl(
layer_ids=["buildings", "roads", "mask"],
css_text="padding: 5px; border: 1px solid darkgrey; border-radius: 4px;",
),
position=ControlPosition.TOP_LEFT,
)
return m


@render_maplibregl
def render_map():
return create_map()


if __name__ == "__main__":
file_name = "docs/examples/layer_switcher/app.html"

m = create_map()
with open(file_name, "w") as f:
f.write(m.to_html())

webbrowser.open(file_name)
13 changes: 13 additions & 0 deletions docs/examples/layer_switcher/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- <a href="app.html" target="_blank">See example in action</a> -->

<iframe src="app.html" height="620px", width="100%" style="border:none;"></iframe>

```python
-8<-- "layer_switcher/app.py"
```

Run example:

``` bash
shiny run docs/examples/layer_switcher/app.py
```
2 changes: 1 addition & 1 deletion maplibre/_constants.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "0.2.4"
__version__ = "0.2.5"
_shiny_output_class = "shiny-maplibregl-output"

# TODO: Remove from here
Expand Down
33 changes: 30 additions & 3 deletions maplibre/controls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
from enum import Enum
from typing import Literal, Union

from pydantic import BaseModel as PydanticBaseModel
from pydantic import ConfigDict, Field
from pydantic import Field

from ._utils import BaseModel

Expand Down Expand Up @@ -146,6 +145,34 @@ class ScaleUnit(Enum):
class ScaleControl(Control):
"""Scale control"""

# _name: str = ControlType.SCALE.value
max_width: int = Field(None, serialization_alias="maxWidth")
unit: Literal["imperial", "metric", "nautical"] = "metric"


# -------------------------
# Custom controls
# -------------------------
class LayerSwitcherControl(Control):
"""Layer switcher control
Attributes:
layer_ids (list): A list of layer ids to be shown in the layer switcher control.
theme (Literal["default", "simple"]): The theme of the layer switcher control.
css_text (str): Optional inline style declaration of the control.
"""

layer_ids: list = Field([], serialization_alias="layerIds")
theme: Literal["default", "simple"] = "default"
css_text: str = Field(None, serialization_alias="cssText")


class InfoBoxControl(Control):
"""InfoBox control
Attributes:
content (str): Content (HTML or plain text) to be displayed in the info box.
css_text (str): Optional inline style declaration of the control.
"""

content: str
css_text: str = Field(None, serialization_alias="cssText")
5 changes: 3 additions & 2 deletions maplibre/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,10 @@ def to_html(self, title: str = "My Awesome Map", **kwargs) -> str:
>>> with open("/tmp/map.html", "w") as f:
... f.write(map.to_html(style="height: 800px;") # doctest: +SKIP
"""
js_lib = read_internal_file("srcjs", "index.js")
js_lib = read_internal_file("srcjs", "pywidget.js")
js_snippet = Template(js_template).render(data=json.dumps(self.to_dict()))
headers = []
css = read_internal_file("srcjs", "pywidget.css")
headers = [f"<style>{css}</style>"]

# Deck.GL headers
add_deckgl_headers = "addDeckOverlay" in [
Expand Down
12 changes: 0 additions & 12 deletions maplibre/srcjs/index.js

This file was deleted.

2 changes: 1 addition & 1 deletion maplibre/srcjs/ipywidget.css

Large diffs are not rendered by default.

194 changes: 97 additions & 97 deletions maplibre/srcjs/ipywidget.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions maplibre/srcjs/pywidget.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions maplibre/srcjs/pywidget.js

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions maplibre/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"pymaplibregl",
version=__version__,
source={"package": "maplibre", "subdir": "srcjs"},
script={"src": "index.js", "type": "module"},
script={"src": "pywidget.js", "type": "module"},
stylesheet={"href": "pywidget.css"},
all_files=False,
)

Expand Down Expand Up @@ -51,7 +52,7 @@ def output_maplibregl(id_: str, height: [int | str] = 200) -> Tag:
)

# TODO: Remove duplicated constant
DECKGL_VERSION = "9.0.16"
# DECKGL_VERSION = "9.0.16"

deckgl_json_dep = HTMLDependency(
name="deckgljson",
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ nav:
- Multiple Deck.GL Layers: examples/deckgl_multiple_layers/index.md
- PMTiles: examples/pmtiles/index.md
- Mapbox Draw Plugin: examples/mapbox_draw_plugin/index.md
- Layer Switcher: examples/layer_switcher/index.md
plugins:
- search:
- mkdocstrings:
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"name": "pymaplibregl",
"version": "0.2.4",
"version": "0.2.5",
"description": "...",
"main": "index.js",
"directories": {
"example": "examples",
"test": "tests"
},
"scripts": {
"build": "esbuild srcjs/index.js --bundle --minify --outfile=maplibre/srcjs/index.js",
"build-dev": "esbuild srcjs/index.js --bundle --outfile=maplibre/srcjs/index.js",
"build": "esbuild srcjs/index.js --bundle --minify --outfile=maplibre/srcjs/pywidget.js",
"build-dev": "esbuild srcjs/index.js --bundle --outfile=maplibre/srcjs/pywidget.js",
"build-ipywidget": "esbuild srcjs/ipywidget.js --bundle --minify --format=esm --outfile=maplibre/srcjs/ipywidget.js",
"build-ipywidget-dev": "esbuild srcjs/ipywidget.js --bundle --format=esm --outfile=maplibre/srcjs/ipywidget.js",
"build-rwidget": "esbuild srcjs/rwidget.js --bundle --minify --outfile=../r-maplibregl/inst/htmlwidgets/maplibre.js",
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "maplibre"
version = "0.2.4"
version = "0.2.5"
description = "Python bindings for MapLibre GL JS"
authors = ["Stefan Kuethe <[email protected]>"]
readme = "README.md"
Expand Down
Loading

0 comments on commit e18d100

Please sign in to comment.