- - - + + + + + + + add_control() + + + + + + + + add_layer() + + - - - Map - - - - - - - - pymaplibregl.Map - - - - - - - - Bases: object - + + + + + + add_marker() + + - Map - - + + + + + + add_popup() + + + + + + + + + add_source() + + + + + + + + + add_tooltip() + + + + + + + + + set_filter() + + + + + + + + + set_layout_property() + + + + + + + + + set_paint_property() + + + + + + + + + to_html() + + + + + + + + + + + + + + + +
+ + + + + + + + Map + + + + + + + + pymaplibregl.Map + + + + + + + + Bases: object + + + Map + + Parameters: @@ -1190,7 +1501,32 @@ 199 200 201 -202class Map(object): +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227class Map(object): """Map Args: @@ -1209,129 +1545,154 @@ MESSAGE = "not implemented yet" def __init__(self, map_options: MapOptions = MapOptions(), **kwargs): - self._map_options = map_options.to_dict() | kwargs - self._calls = [] + self.map_options = map_options.to_dict() | kwargs + self._message_queue = [] def __iter__(self): for k, v in self.to_dict().items(): yield k, v def to_dict(self) -> dict: - return {"mapOptions": self._map_options, "calls": self._calls} + return {"mapOptions": self.map_options, "calls": self._message_queue} - @property - def sources(self) -> list: - return [item["data"] for item in self._calls if item["name"] == "addSource"] - - @property - def layers(self) -> list: - return [item["data"] for item in self._calls if item["name"] == "addLayer"] - - # TODO: Rename to add_map_call - def add_call(self, func_name: str, params: list) -> None: - self._calls.append( - {"name": "applyFunc", "data": {"funcName": func_name, "params": params}} - ) - - def add_control( - self, - control: Control, - position: [str | ControlPosition] = ControlPosition.TOP_RIGHT, - ) -> None: - """Add a control to the map - - Args: - control (Control): The control to be add to the map. - position (str | ControlPosition): The position of the control. - """ - data = { - "type": control.type, - "options": control.to_dict(), - "position": ControlPosition(position).value, - } - self._calls.append({"name": "addControl", "data": data}) - - def add_source(self, id: str, source: [Source | dict]) -> None: - """Add a source to the map""" - if isinstance(source, Source): - source = source.to_dict() - - self._calls.append({"name": "addSource", "data": {"id": id, "source": source}}) - - def add_layer(self, layer: [Layer | dict]) -> None: - """Add a layer to the map - - Args: - layer (Layer | dict): The Layer to be added to the map. - """ - if isinstance(layer, Layer): - layer = layer.to_dict() - - self._calls.append({"name": "addLayer", "data": layer}) + """ + @property + def sources(self) -> list: + return [item["data"] for item in self._calls if item["name"] == "addSource"] + + @property + def layers(self) -> list: + return [item["data"] for item in self._calls if item["name"] == "addLayer"] + """ + + # TODO: Rename to add_map_call + def add_call_(self, func_name: str, params: list) -> None: + self._message_queue.append( + {"name": "applyFunc", "data": {"funcName": func_name, "params": params}} + ) + + def add_call(self, method_name: str, *args) -> None: + """Add a method call that is executed on the map instance + + Args: + method_name (str): The name of the map method to be executed. + *args (any): The arguments to be passed to the map method. + """ + # TODO: Pass as dict? {"name": method_name, "args": args} + call = [method_name, args] + self._message_queue.append(call) + + def add_control( + self, + control: Control, + position: [str | ControlPosition] = ControlPosition.TOP_RIGHT, + ) -> None: + """Add a control to the map + + Args: + control (Control): The control to be added to the map. + position (str | ControlPosition): The position of the control. + """ + self.add_call( + "addControl", + control.type, + control.to_dict(), + ControlPosition(position).value, + ) + + def add_source(self, id: str, source: [Source | dict]) -> None: + """Add a source to the map""" + if isinstance(source, Source): + source = source.to_dict() - def add_marker(self, marker: Marker) -> None: - """Add a marker to the map - - Args: - marker (Marker): The marker to be added to the map. - """ - self._calls.append({"name": "addMarker", "data": marker.to_dict()}) - - def add_popup(self, layer_id: str, prop: str) -> None: - """Add a popup to the map""" - self._calls.append( - {"name": "addPopup", "data": {"layerId": layer_id, "property": prop}} - ) - - def set_filter(self, layer_id: str, filter_: list): - """Update the filter of a layer - - Args: - layer_id (str): The name of the layer to be updated. - filter_ (list): The filter expression that is applied to the source of the layer. - """ - self.add_call("setFilter", [layer_id, filter_]) - - def set_paint_property(self, layer_id: str, prop: str, value: any) -> None: - """Update the paint property of a layer - - Args: - layer_id (str): The name of the layer to be updated. - prop (str): The name of the paint property to be updated. - value (any): The new value of the paint property. - """ - self.add_call("setPaintProperty", [layer_id, prop, value]) + self.add_call("addSource", id, source) + + def add_layer(self, layer: [Layer | dict]) -> None: + """Add a layer to the map + + Args: + layer (Layer | dict): The Layer to be added to the map. + """ + if isinstance(layer, Layer): + layer = layer.to_dict() + + self.add_call("addLayer", layer) + + def add_marker(self, marker: Marker) -> None: + """Add a marker to the map + + Args: + marker (Marker): The marker to be added to the map. + """ + self.add_call("addMarker", marker.to_dict()) + + def add_popup(self, layer_id: str, prop: str) -> None: + """Add a popup to the map + + Args: + layer_id (str): The layer to which the popup is added. + prop (str): The property of the source to be displayed. + """ + self.add_call("addPopup", layer_id, prop) + + def add_tooltip(self, layer_id: str, prop: str) -> None: + """Add a tooltip to the map - def set_layout_property(self, layer_id: str, prop: str, value: any) -> None: - """Update a layout property of a layer - - Args: - layer_id (str): The name of the layer to be updated. - prop (str): The name of the layout property to be updated. - value (any): The new value of the layout property. - """ - self.add_call("setLayoutProperty", [layer_id, prop, value]) - - def to_html(self, **kwargs) -> str: - """Render to html - - Args: - **kwargs (Any): Additional keyword arguments that are passed to the template. - Currently, `style` is the only supported keyword argument. - - Examples: - >>> from pymaplibregl import Map - - >>> map = Map() - >>> with open("/tmp/map.html", "w") as f: - ... f.write(map.to_html(style="height: 800px;") - """ - js_lib = read_internal_file("srcjs", "index.js") - js_snippet = Template(js_template).render(data=json.dumps(self.to_dict())) - output = Template(html_template).render( - js="\n".join([js_lib, js_snippet]), **kwargs - ) - return output + Args: + layer_id (str): The layer to which the tooltip is added. + prop (str): The property of the source to be displayed. + """ + self.add_call("addTooltip", layer_id, prop) + + def set_filter(self, layer_id: str, filter_: list): + """Update the filter of a layer + + Args: + layer_id (str): The name of the layer to be updated. + filter_ (list): The filter expression that is applied to the source of the layer. + """ + self.add_call("setFilter", layer_id, filter_) + + def set_paint_property(self, layer_id: str, prop: str, value: any) -> None: + """Update the paint property of a layer + + Args: + layer_id (str): The name of the layer to be updated. + prop (str): The name of the paint property to be updated. + value (any): The new value of the paint property. + """ + self.add_call("setPaintProperty", layer_id, prop, value) + + def set_layout_property(self, layer_id: str, prop: str, value: any) -> None: + """Update a layout property of a layer + + Args: + layer_id (str): The name of the layer to be updated. + prop (str): The name of the layout property to be updated. + value (any): The new value of the layout property. + """ + self.add_call("setLayoutProperty", layer_id, prop, value) + + def to_html(self, **kwargs) -> str: + """Render to html + + Args: + **kwargs (Any): Additional keyword arguments that are passed to the template. + Currently, `style` is the only supported keyword argument. + + Examples: + >>> from pymaplibregl import Map + + >>> map = Map() + >>> 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_snippet = Template(js_template).render(data=json.dumps(self.to_dict())) + output = Template(html_template).render( + js="\n".join([js_lib, js_snippet]), **kwargs + ) + return output @@ -1353,15 +1714,15 @@ - - add_control(control, position=ControlPosition.TOP_RIGHT) + + add_call(method_name, *args) - Add a control to the map + Add a method call that is executed on the map instance @@ -1377,13 +1738,13 @@ - control + method_name - Control + str - The control to be add to the map. + The name of the map method to be executed. @@ -1391,17 +1752,17 @@ - position + *args - str | ControlPosition + any - The position of the control. + The arguments to be passed to the map method. - TOP_RIGHT + () @@ -1409,9 +1770,7 @@ Source code in pymaplibregl/map.py - 104 -105 -106 + 106 107 108 109 @@ -1420,28 +1779,16 @@ 112 113 114 -115 -116 -117 -118 -119 -120def add_control( - self, - control: Control, - position: [str | ControlPosition] = ControlPosition.TOP_RIGHT, -) -> None: - """Add a control to the map - - Args: - control (Control): The control to be add to the map. - position (str | ControlPosition): The position of the control. - """ - data = { - "type": control.type, - "options": control.to_dict(), - "position": ControlPosition(position).value, - } - self._calls.append({"name": "addControl", "data": data}) +115def add_call(self, method_name: str, *args) -> None: + """Add a method call that is executed on the map instance + + Args: + method_name (str): The name of the map method to be executed. + *args (any): The arguments to be passed to the map method. + """ + # TODO: Pass as dict? {"name": method_name, "args": args} + call = [method_name, args] + self._message_queue.append(call) @@ -1454,15 +1801,15 @@ - - add_layer(layer) + + add_control(control, position=ControlPosition.TOP_RIGHT) - Add a layer to the map + Add a control to the map @@ -1478,43 +1825,71 @@ - layer + control - Layer | dict + Control - The Layer to be added to the map. + The control to be added to the map. required + + position + + str | ControlPosition + + + + The position of the control. + + + + TOP_RIGHT + + Source code in pymaplibregl/map.py - 129 + 117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 130 131 132 -133 -134 -135 -136 -137 -138def add_layer(self, layer: [Layer | dict]) -> None: - """Add a layer to the map - - Args: - layer (Layer | dict): The Layer to be added to the map. - """ - if isinstance(layer, Layer): - layer = layer.to_dict() - - self._calls.append({"name": "addLayer", "data": layer}) +133def add_control( + self, + control: Control, + position: [str | ControlPosition] = ControlPosition.TOP_RIGHT, +) -> None: + """Add a control to the map + + Args: + control (Control): The control to be added to the map. + position (str | ControlPosition): The position of the control. + """ + self.add_call( + "addControl", + control.type, + control.to_dict(), + ControlPosition(position).value, + ) @@ -1527,15 +1902,15 @@ - - add_marker(marker) + + add_layer(layer) - Add a marker to the map + Add a layer to the map @@ -1551,13 +1926,13 @@ - marker + layer - Marker + Layer | dict - The marker to be added to the map. + The Layer to be added to the map. @@ -1569,19 +1944,25 @@ Source code in pymaplibregl/map.py - 140 -141 -142 + 142 143 144 145 -146def add_marker(self, marker: Marker) -> None: - """Add a marker to the map - - Args: - marker (Marker): The marker to be added to the map. - """ - self._calls.append({"name": "addMarker", "data": marker.to_dict()}) +146 +147 +148 +149 +150 +151def add_layer(self, layer: [Layer | dict]) -> None: + """Add a layer to the map + + Args: + layer (Layer | dict): The Layer to be added to the map. + """ + if isinstance(layer, Layer): + layer = layer.to_dict() + + self.add_call("addLayer", layer) @@ -1594,62 +1975,61 @@ - - add_popup(layer_id, prop) + + add_marker(marker) - Add a popup to the map - - - Source code in pymaplibregl/map.py - 148 -149 -150 -151 -152def add_popup(self, layer_id: str, prop: str) -> None: - """Add a popup to the map""" - self._calls.append( - {"name": "addPopup", "data": {"layerId": layer_id, "property": prop}} - ) - - - - - - - - - - - - - - add_source(id, source) + Add a marker to the map - - - - Add a source to the map + Parameters: + + + + Name + Type + Description + Default + + + + + marker + + Marker + + + + The marker to be added to the map. + + + + required + + + + Source code in pymaplibregl/map.py - 122 -123 -124 -125 -126 -127def add_source(self, id: str, source: [Source | dict]) -> None: - """Add a source to the map""" - if isinstance(source, Source): - source = source.to_dict() - - self._calls.append({"name": "addSource", "data": {"id": id, "source": source}}) + 153 +154 +155 +156 +157 +158 +159def add_marker(self, marker: Marker) -> None: + """Add a marker to the map + + Args: + marker (Marker): The marker to be added to the map. + """ + self.add_call("addMarker", marker.to_dict()) @@ -1662,15 +2042,15 @@ - - set_filter(layer_id, filter_) + + add_popup(layer_id, prop) - Update the filter of a layer + Add a popup to the map @@ -1692,7 +2072,7 @@ - The name of the layer to be updated. + The layer to which the popup is added. @@ -1700,7 +2080,208 @@ - filter_ + prop + + str + + + + The property of the source to be displayed. + + + + required + + + + + + + Source code in pymaplibregl/map.py + 161 +162 +163 +164 +165 +166 +167 +168def add_popup(self, layer_id: str, prop: str) -> None: + """Add a popup to the map + + Args: + layer_id (str): The layer to which the popup is added. + prop (str): The property of the source to be displayed. + """ + self.add_call("addPopup", layer_id, prop) + + + + + + + + + + + + + + add_source(id, source) + + + + + + + Add a source to the map + + + Source code in pymaplibregl/map.py + 135 +136 +137 +138 +139 +140def add_source(self, id: str, source: [Source | dict]) -> None: + """Add a source to the map""" + if isinstance(source, Source): + source = source.to_dict() + + self.add_call("addSource", id, source) + + + + + + + + + + + + + + add_tooltip(layer_id, prop) + + + + + + + Add a tooltip to the map + + + + Parameters: + + + + Name + Type + Description + Default + + + + + layer_id + + str + + + + The layer to which the tooltip is added. + + + + required + + + + prop + + str + + + + The property of the source to be displayed. + + + + required + + + + + + + Source code in pymaplibregl/map.py + 170 +171 +172 +173 +174 +175 +176 +177def add_tooltip(self, layer_id: str, prop: str) -> None: + """Add a tooltip to the map + + Args: + layer_id (str): The layer to which the tooltip is added. + prop (str): The property of the source to be displayed. + """ + self.add_call("addTooltip", layer_id, prop) + + + + + + + + + + + + + + set_filter(layer_id, filter_) + + + + + + + Update the filter of a layer + + + + Parameters: + + + + Name + Type + Description + Default + + + + + layer_id + + str + + + + The name of the layer to be updated. + + + + required + + + + filter_ list @@ -1718,21 +2299,21 @@ Source code in pymaplibregl/map.py - 154 -155 -156 -157 -158 -159 -160 -161def set_filter(self, layer_id: str, filter_: list): - """Update the filter of a layer - - Args: - layer_id (str): The name of the layer to be updated. - filter_ (list): The filter expression that is applied to the source of the layer. - """ - self.add_call("setFilter", [layer_id, filter_]) + 179 +180 +181 +182 +183 +184 +185 +186def set_filter(self, layer_id: str, filter_: list): + """Update the filter of a layer + + Args: + layer_id (str): The name of the layer to be updated. + filter_ (list): The filter expression that is applied to the source of the layer. + """ + self.add_call("setFilter", layer_id, filter_) @@ -1815,23 +2396,23 @@ Source code in pymaplibregl/map.py - 173 -174 -175 -176 -177 -178 -179 -180 -181def set_layout_property(self, layer_id: str, prop: str, value: any) -> None: - """Update a layout property of a layer - - Args: - layer_id (str): The name of the layer to be updated. - prop (str): The name of the layout property to be updated. - value (any): The new value of the layout property. - """ - self.add_call("setLayoutProperty", [layer_id, prop, value]) + 198 +199 +200 +201 +202 +203 +204 +205 +206def set_layout_property(self, layer_id: str, prop: str, value: any) -> None: + """Update a layout property of a layer + + Args: + layer_id (str): The name of the layer to be updated. + prop (str): The name of the layout property to be updated. + value (any): The new value of the layout property. + """ + self.add_call("setLayoutProperty", layer_id, prop, value) @@ -1914,23 +2495,23 @@ Source code in pymaplibregl/map.py - 163 -164 -165 -166 -167 -168 -169 -170 -171def set_paint_property(self, layer_id: str, prop: str, value: any) -> None: - """Update the paint property of a layer - - Args: - layer_id (str): The name of the layer to be updated. - prop (str): The name of the paint property to be updated. - value (any): The new value of the paint property. - """ - self.add_call("setPaintProperty", [layer_id, prop, value]) + 188 +189 +190 +191 +192 +193 +194 +195 +196def set_paint_property(self, layer_id: str, prop: str, value: any) -> None: + """Update the paint property of a layer + + Args: + layer_id (str): The name of the layer to be updated. + prop (str): The name of the paint property to be updated. + value (any): The new value of the paint property. + """ + self.add_call("setPaintProperty", layer_id, prop, value) @@ -1996,45 +2577,45 @@ Source code in pymaplibregl/map.py - 183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202def to_html(self, **kwargs) -> str: - """Render to html - - Args: - **kwargs (Any): Additional keyword arguments that are passed to the template. - Currently, `style` is the only supported keyword argument. - - Examples: - >>> from pymaplibregl import Map - - >>> map = Map() - >>> with open("/tmp/map.html", "w") as f: - ... f.write(map.to_html(style="height: 800px;") - """ - js_lib = read_internal_file("srcjs", "index.js") - js_snippet = Template(js_template).render(data=json.dumps(self.to_dict())) - output = Template(html_template).render( - js="\n".join([js_lib, js_snippet]), **kwargs - ) - return output + 208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227def to_html(self, **kwargs) -> str: + """Render to html + + Args: + **kwargs (Any): Additional keyword arguments that are passed to the template. + Currently, `style` is the only supported keyword argument. + + Examples: + >>> from pymaplibregl import Map + + >>> map = Map() + >>> 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_snippet = Template(js_template).render(data=json.dumps(self.to_dict())) + output = Template(html_template).render( + js="\n".join([js_lib, js_snippet]), **kwargs + ) + return output @@ -2172,6 +2753,952 @@ + + + + + + + + + + + + + pymaplibregl.ipywidget.MapWidget + + + + + + + + Bases: AnyWidget, Map + + + + Source code in pymaplibregl/ipywidget.py + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106class MapWidget(AnyWidget, Map): + _esm = join(Path(__file__).parent, "srcjs", "ipywidget.js") + _css = join(Path(__file__).parent, "srcjs", "maplibre-gl.css") + _rendered = traitlets.Bool(False, config=True).tag(sync=True) + map_options = traitlets.Dict().tag(sync=True) + height = traitlets.Union([traitlets.Int(), traitlets.Unicode()]).tag(sync=True) + lng_lat = traitlets.Dict().tag(sync=True) + + def __init__(self, map_options=MapOptions(), **kwargs) -> None: + # self.map_options = map_options.to_dict() + # self._message_queue = [] + # super().__init__(**kwargs) + AnyWidget.__init__(self, **kwargs) + Map.__init__(self, map_options, **kwargs) + + @traitlets.default("height") + def _default_height(self): + return "400px" + + @traitlets.validate("height") + def _validate_height(self, proposal): + height = proposal["value"] + if isinstance(height, int): + return f"{height}px" + + return height + + @traitlets.observe("_rendered") + def _on_rendered(self, change): + self.send({"calls": self._message_queue, "msg": "init"}) + self._message_queue = [] + + def add_call(self, method_name: str, *args) -> None: + call = [method_name, args] + if not self._rendered: + self._message_queue.append(call) + return + + self.send({"calls": [call], "msg": "custom call"}) + + + + + + + + + + + + + + + + + + + + + + + add_control(control, position=ControlPosition.TOP_RIGHT) + + + + + + + Add a control to the map + + + + Parameters: + + + + Name + Type + Description + Default + + + + + control + + Control + + + + The control to be added to the map. + + + + required + + + + position + + str | ControlPosition + + + + The position of the control. + + + + TOP_RIGHT + + + + + + + Source code in pymaplibregl/map.py + 117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133def add_control( + self, + control: Control, + position: [str | ControlPosition] = ControlPosition.TOP_RIGHT, +) -> None: + """Add a control to the map + + Args: + control (Control): The control to be added to the map. + position (str | ControlPosition): The position of the control. + """ + self.add_call( + "addControl", + control.type, + control.to_dict(), + ControlPosition(position).value, + ) + + + + + + + + + + + + + + add_layer(layer) + + + + + + + Add a layer to the map + + + + Parameters: + + + + Name + Type + Description + Default + + + + + layer + + Layer | dict + + + + The Layer to be added to the map. + + + + required + + + + + + + Source code in pymaplibregl/map.py + 142 +143 +144 +145 +146 +147 +148 +149 +150 +151def add_layer(self, layer: [Layer | dict]) -> None: + """Add a layer to the map + + Args: + layer (Layer | dict): The Layer to be added to the map. + """ + if isinstance(layer, Layer): + layer = layer.to_dict() + + self.add_call("addLayer", layer) + + + + + + + + + + + + + + add_marker(marker) + + + + + + + Add a marker to the map + + + + Parameters: + + + + Name + Type + Description + Default + + + + + marker + + Marker + + + + The marker to be added to the map. + + + + required + + + + + + + Source code in pymaplibregl/map.py + 153 +154 +155 +156 +157 +158 +159def add_marker(self, marker: Marker) -> None: + """Add a marker to the map + + Args: + marker (Marker): The marker to be added to the map. + """ + self.add_call("addMarker", marker.to_dict()) + + + + + + + + + + + + + + add_popup(layer_id, prop) + + + + + + + Add a popup to the map + + + + Parameters: + + + + Name + Type + Description + Default + + + + + layer_id + + str + + + + The layer to which the popup is added. + + + + required + + + + prop + + str + + + + The property of the source to be displayed. + + + + required + + + + + + + Source code in pymaplibregl/map.py + 161 +162 +163 +164 +165 +166 +167 +168def add_popup(self, layer_id: str, prop: str) -> None: + """Add a popup to the map + + Args: + layer_id (str): The layer to which the popup is added. + prop (str): The property of the source to be displayed. + """ + self.add_call("addPopup", layer_id, prop) + + + + + + + + + + + + + + add_source(id, source) + + + + + + + Add a source to the map + + + Source code in pymaplibregl/map.py + 135 +136 +137 +138 +139 +140def add_source(self, id: str, source: [Source | dict]) -> None: + """Add a source to the map""" + if isinstance(source, Source): + source = source.to_dict() + + self.add_call("addSource", id, source) + + + + + + + + + + + + + + add_tooltip(layer_id, prop) + + + + + + + Add a tooltip to the map + + + + Parameters: + + + + Name + Type + Description + Default + + + + + layer_id + + str + + + + The layer to which the tooltip is added. + + + + required + + + + prop + + str + + + + The property of the source to be displayed. + + + + required + + + + + + + Source code in pymaplibregl/map.py + 170 +171 +172 +173 +174 +175 +176 +177def add_tooltip(self, layer_id: str, prop: str) -> None: + """Add a tooltip to the map + + Args: + layer_id (str): The layer to which the tooltip is added. + prop (str): The property of the source to be displayed. + """ + self.add_call("addTooltip", layer_id, prop) + + + + + + + + + + + + + + set_filter(layer_id, filter_) + + + + + + + Update the filter of a layer + + + + Parameters: + + + + Name + Type + Description + Default + + + + + layer_id + + str + + + + The name of the layer to be updated. + + + + required + + + + filter_ + + list + + + + The filter expression that is applied to the source of the layer. + + + + required + + + + + + + Source code in pymaplibregl/map.py + 179 +180 +181 +182 +183 +184 +185 +186def set_filter(self, layer_id: str, filter_: list): + """Update the filter of a layer + + Args: + layer_id (str): The name of the layer to be updated. + filter_ (list): The filter expression that is applied to the source of the layer. + """ + self.add_call("setFilter", layer_id, filter_) + + + + + + + + + + + + + + set_layout_property(layer_id, prop, value) + + + + + + + Update a layout property of a layer + + + + Parameters: + + + + Name + Type + Description + Default + + + + + layer_id + + str + + + + The name of the layer to be updated. + + + + required + + + + prop + + str + + + + The name of the layout property to be updated. + + + + required + + + + value + + any + + + + The new value of the layout property. + + + + required + + + + + + + Source code in pymaplibregl/map.py + 198 +199 +200 +201 +202 +203 +204 +205 +206def set_layout_property(self, layer_id: str, prop: str, value: any) -> None: + """Update a layout property of a layer + + Args: + layer_id (str): The name of the layer to be updated. + prop (str): The name of the layout property to be updated. + value (any): The new value of the layout property. + """ + self.add_call("setLayoutProperty", layer_id, prop, value) + + + + + + + + + + + + + + set_paint_property(layer_id, prop, value) + + + + + + + Update the paint property of a layer + + + + Parameters: + + + + Name + Type + Description + Default + + + + + layer_id + + str + + + + The name of the layer to be updated. + + + + required + + + + prop + + str + + + + The name of the paint property to be updated. + + + + required + + + + value + + any + + + + The new value of the paint property. + + + + required + + + + + + + Source code in pymaplibregl/map.py + 188 +189 +190 +191 +192 +193 +194 +195 +196def set_paint_property(self, layer_id: str, prop: str, value: any) -> None: + """Update the paint property of a layer + + Args: + layer_id (str): The name of the layer to be updated. + prop (str): The name of the paint property to be updated. + value (any): The new value of the paint property. + """ + self.add_call("setPaintProperty", layer_id, prop, value) + + + + + + + + + + + + + + to_html(**kwargs) + + + + + + + Render to html + + + + Parameters: + + + + Name + Type + Description + Default + + + + + **kwargs + + Any + + + + Additional keyword arguments that are passed to the template. +Currently, style is the only supported keyword argument. + + + + {} + + + + + + + +Examples: + >>> from pymaplibregl import Map + + >>> map = Map() +>>> with open("/tmp/map.html", "w") as f: +... f.write(map.to_html(style="height: 800px;") + + + + Source code in pymaplibregl/map.py + 208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227def to_html(self, **kwargs) -> str: + """Render to html + + Args: + **kwargs (Any): Additional keyword arguments that are passed to the template. + Currently, `style` is the only supported keyword argument. + + Examples: + >>> from pymaplibregl import Map + + >>> map = Map() + >>> 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_snippet = Template(js_template).render(data=json.dumps(self.to_dict())) + output = Template(html_template).render( + js="\n".join([js_lib, js_snippet]), **kwargs + ) + return output + + + + + + + + @@ -2223,7 +3750,7 @@ - + diff --git a/api/sources/index.html b/api/sources/index.html index 2da7a7d1..a0783fc2 100644 --- a/api/sources/index.html +++ b/api/sources/index.html @@ -20,7 +20,7 @@ - Sources - Pymaplibregl + Sources - py-maplibregl @@ -90,9 +90,11 @@ - + + + - + @@ -106,7 +108,7 @@ - Pymaplibregl + py-maplibregl @@ -176,14 +178,8 @@ - - - - - - @@ -247,7 +243,13 @@ - + + + + + + + @@ -266,13 +268,13 @@ - + - Pymaplibregl + py-maplibregl @@ -340,7 +342,7 @@ - Welcome to Pymaplibregl + Welcome to py-maplibregl @@ -357,11 +359,53 @@ - + - Examples + Layers + + + + + + + + + + + + + + + + + + + + + Shiny + + + + + + + + + + + + + + + + + + + + + Jupyter @@ -677,6 +721,27 @@ + + + + + + Vancouver property value + + + + + + + + + + + + + + + @@ -1203,7 +1268,7 @@ - + diff --git a/examples/3d_indoor_mapping/__pycache__/app.cpython-39.pyc b/examples/3d_indoor_mapping/__pycache__/app.cpython-39.pyc new file mode 100644 index 00000000..31c26f55 Binary files /dev/null and b/examples/3d_indoor_mapping/__pycache__/app.cpython-39.pyc differ diff --git a/examples/3d_indoor_mapping/index.html b/examples/3d_indoor_mapping/index.html index 369e1923..6785396d 100644 --- a/examples/3d_indoor_mapping/index.html +++ b/examples/3d_indoor_mapping/index.html @@ -20,7 +20,7 @@ - 3D Indoor mapping - Pymaplibregl + 3D Indoor mapping - py-maplibregl @@ -85,9 +85,11 @@ - + + + - + @@ -101,7 +103,7 @@ - Pymaplibregl + py-maplibregl @@ -171,14 +173,8 @@ - - - - - - @@ -242,7 +238,13 @@ - + + + + + + + @@ -261,13 +263,13 @@ - + - Pymaplibregl + py-maplibregl @@ -335,7 +337,7 @@ - Welcome to Pymaplibregl + Welcome to py-maplibregl @@ -352,11 +354,53 @@ - + - Examples + Layers + + + + + + + + + + + + + + + + + + + + + Shiny + + + + + + + + + + + + + + + + + + + + + Jupyter @@ -594,6 +638,27 @@ + + + + + + Vancouver property value + + + + + + + + + + + + + + + @@ -831,7 +896,7 @@ 3D Indoor mapping - + diff --git a/examples/__pycache__/basic_usage_shiny.cpython-39.pyc b/examples/__pycache__/basic_usage_shiny.cpython-39.pyc deleted file mode 100644 index b773b014..00000000 Binary files a/examples/__pycache__/basic_usage_shiny.cpython-39.pyc and /dev/null differ diff --git a/examples/airports/index.html b/examples/airports/index.html index 0329a477..9aca2ed2 100644 --- a/examples/airports/index.html +++ b/examples/airports/index.html @@ -20,7 +20,7 @@ - Airport markers - Pymaplibregl + Airport markers - py-maplibregl @@ -85,9 +85,11 @@ - + + + - + @@ -101,7 +103,7 @@ - Pymaplibregl + py-maplibregl @@ -171,14 +173,8 @@ - - - - - - @@ -242,7 +238,13 @@ - + + + + + + + @@ -261,13 +263,13 @@ - + - Pymaplibregl + py-maplibregl @@ -335,7 +337,7 @@ - Welcome to Pymaplibregl + Welcome to py-maplibregl @@ -352,11 +354,53 @@ - + - Examples + Layers + + + + + + + + + + + + + + + + + + + + + Shiny + + + + + + + + + + + + + + + + + + + + + Jupyter @@ -594,6 +638,27 @@ + + + + + + Vancouver property value + + + + + + + + + + + + + + + @@ -867,7 +932,7 @@ Airport markers - + diff --git a/examples/custom_basemap/index.html b/examples/custom_basemap/index.html index a4561425..354a549b 100644 --- a/examples/custom_basemap/index.html +++ b/examples/custom_basemap/index.html @@ -18,7 +18,7 @@ - Custom basemap - Pymaplibregl + Custom basemap - py-maplibregl @@ -83,9 +83,11 @@ - + + + - + @@ -99,7 +101,7 @@ - Pymaplibregl + py-maplibregl @@ -169,14 +171,8 @@ - - - - - - @@ -240,7 +236,13 @@ - + + + + + + + @@ -259,13 +261,13 @@ - + - Pymaplibregl + py-maplibregl @@ -333,7 +335,7 @@ - Welcome to Pymaplibregl + Welcome to py-maplibregl @@ -350,11 +352,53 @@ - + - Examples + Layers + + + + + + + + + + + + + + + + + + + + + Shiny + + + + + + + + + + + + + + + + + + + + + Jupyter @@ -592,6 +636,27 @@ + + + + + + Vancouver property value + + + + + + + + + + + + + + + @@ -837,7 +902,7 @@ Custom basemap - + diff --git a/examples/earthquake_clusters/__pycache__/app.cpython-39.pyc b/examples/earthquake_clusters/__pycache__/app.cpython-39.pyc index dad8d154..b5be3ddf 100644 Binary files a/examples/earthquake_clusters/__pycache__/app.cpython-39.pyc and b/examples/earthquake_clusters/__pycache__/app.cpython-39.pyc differ diff --git a/examples/earthquake_clusters/app.py b/examples/earthquake_clusters/app.py index dde8d8ab..c0230e85 100644 --- a/examples/earthquake_clusters/app.py +++ b/examples/earthquake_clusters/app.py @@ -77,12 +77,12 @@ def server(input, output, session): @render_maplibregl - async def maplibre(): + def maplibre(): m = Map(map_options) m.add_source(EARTHQUAKE_SOURCE, earthquakes_source) m.add_layer(earthquake_clusters) m.add_layer(earthquake_circles) - m.add_popup(EARTHQUAKE_CLUSTERS, "maxMag") + m.add_tooltip(EARTHQUAKE_CLUSTERS, "maxMag") m.add_layer(earthquake_labels) return m diff --git a/examples/earthquake_clusters/index.html b/examples/earthquake_clusters/index.html index 513410c9..6641819b 100644 --- a/examples/earthquake_clusters/index.html +++ b/examples/earthquake_clusters/index.html @@ -9,7 +9,7 @@ - + @@ -20,7 +20,7 @@ - Earthquake clusters - Pymaplibregl + Earthquake clusters - py-maplibregl @@ -85,9 +85,11 @@ - + + + - + @@ -101,7 +103,7 @@ - Pymaplibregl + py-maplibregl @@ -171,14 +173,8 @@ - - - - - - @@ -242,7 +238,13 @@ - + + + + + + + @@ -261,13 +263,13 @@ - + - Pymaplibregl + py-maplibregl @@ -335,7 +337,7 @@ - Welcome to Pymaplibregl + Welcome to py-maplibregl @@ -352,11 +354,53 @@ - + - Examples + Layers + + + + + + + + + + + + + + + + + + + + + Shiny + + + + + + + + + + + + + + + + + + + + + Jupyter @@ -592,6 +636,27 @@ + + + + + + + + Vancouver property value + + + + + + + + + + + + + @@ -802,12 +867,12 @@ Earthquake clusters def server(input, output, session): @render_maplibregl - async def maplibre(): + def maplibre(): m = Map(map_options) m.add_source(EARTHQUAKE_SOURCE, earthquakes_source) m.add_layer(earthquake_clusters) m.add_layer(earthquake_circles) - m.add_popup(EARTHQUAKE_CLUSTERS, "maxMag") + m.add_tooltip(EARTHQUAKE_CLUSTERS, "maxMag") m.add_layer(earthquake_labels) return m @@ -871,7 +936,7 @@ Earthquake clusters - + diff --git a/examples/every_person_in_manhattan/__pycache__/app.cpython-39.pyc b/examples/every_person_in_manhattan/__pycache__/app.cpython-39.pyc index 9b1c4861..be8e15b6 100644 Binary files a/examples/every_person_in_manhattan/__pycache__/app.cpython-39.pyc and b/examples/every_person_in_manhattan/__pycache__/app.cpython-39.pyc differ diff --git a/examples/every_person_in_manhattan/app.py b/examples/every_person_in_manhattan/app.py index c9f635f6..e3600ee9 100644 --- a/examples/every_person_in_manhattan/app.py +++ b/examples/every_person_in_manhattan/app.py @@ -12,6 +12,7 @@ render_maplibregl, ) from pymaplibregl.basemaps import Carto +from pymaplibregl.controls import ScaleControl from pymaplibregl.sources import GeoJSONSource from pymaplibregl.utils import df_to_geojson from shiny import App, reactive, ui @@ -60,8 +61,9 @@ def server(input, output, session): @render_maplibregl - async def maplibre(): + def maplibre(): m = Map(map_options) + m.add_control(ScaleControl(), position="bottom-left") m.add_layer(every_person_in_manhattan_circles) return m diff --git a/examples/every_person_in_manhattan/index.html b/examples/every_person_in_manhattan/index.html index 6db6766e..62190042 100644 --- a/examples/every_person_in_manhattan/index.html +++ b/examples/every_person_in_manhattan/index.html @@ -12,7 +12,7 @@ - + @@ -20,7 +20,7 @@ - Every person in manhattan - Pymaplibregl + Every person in manhattan - py-maplibregl @@ -85,9 +85,11 @@ - + + + - + @@ -101,7 +103,7 @@ - Pymaplibregl + py-maplibregl @@ -171,14 +173,8 @@ - - - - - - @@ -242,7 +238,13 @@ - + + + + + + + @@ -261,13 +263,13 @@ - + - Pymaplibregl + py-maplibregl @@ -335,7 +337,7 @@ - Welcome to Pymaplibregl + Welcome to py-maplibregl @@ -352,11 +354,53 @@ - + - Examples + Layers + + + + + + + + + + + + + + + + + + + + + Shiny + + + + + + + + + + + + + + + + + + + + + Jupyter @@ -602,6 +646,27 @@ + + + + + + Vancouver property value + + + + + + + + + + + + + + + @@ -737,70 +802,72 @@ Every person in manhattan render_maplibregl, ) from pymaplibregl.basemaps import Carto -from pymaplibregl.sources import GeoJSONSource -from pymaplibregl.utils import df_to_geojson -from shiny import App, reactive, ui - -MALE_COLOR = "rgb(0, 128, 255)" -FEMALE_COLOR = "rgb(255, 0, 128)" -LAYER_ID = "every-person-in-manhattan-circles" -CIRCLE_RADIUS = 2 - -point_data = pd.read_json( - "https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/scatterplot/manhattan.json" -) - -point_data.columns = ["lng", "lat", "sex"] - -every_person_in_manhattan_source = GeoJSONSource( - data=df_to_geojson(point_data, properties=["sex"]), -) - -bbox = shapely.bounds( - shapely.from_geojson(json.dumps(every_person_in_manhattan_source.data)) -) - -every_person_in_manhattan_circles = Layer( - type=LayerType.CIRCLE, - id=LAYER_ID, - source=every_person_in_manhattan_source, - paint={ - "circle-color": ["match", ["get", "sex"], 1, MALE_COLOR, FEMALE_COLOR], - "circle-radius": CIRCLE_RADIUS, - }, -) - -map_options = MapOptions( - style=Carto.POSITRON, - bounds=tuple(bbox), - fit_bounds_options={"padding": 20}, -) - -app_ui = ui.page_fluid( - ui.panel_title("Every Person in Manhattan"), - output_maplibregl("maplibre", height=600), - ui.input_slider("radius", "Radius", value=CIRCLE_RADIUS, min=1, max=5), -) - +from pymaplibregl.controls import ScaleControl +from pymaplibregl.sources import GeoJSONSource +from pymaplibregl.utils import df_to_geojson +from shiny import App, reactive, ui + +MALE_COLOR = "rgb(0, 128, 255)" +FEMALE_COLOR = "rgb(255, 0, 128)" +LAYER_ID = "every-person-in-manhattan-circles" +CIRCLE_RADIUS = 2 + +point_data = pd.read_json( + "https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/scatterplot/manhattan.json" +) + +point_data.columns = ["lng", "lat", "sex"] + +every_person_in_manhattan_source = GeoJSONSource( + data=df_to_geojson(point_data, properties=["sex"]), +) + +bbox = shapely.bounds( + shapely.from_geojson(json.dumps(every_person_in_manhattan_source.data)) +) + +every_person_in_manhattan_circles = Layer( + type=LayerType.CIRCLE, + id=LAYER_ID, + source=every_person_in_manhattan_source, + paint={ + "circle-color": ["match", ["get", "sex"], 1, MALE_COLOR, FEMALE_COLOR], + "circle-radius": CIRCLE_RADIUS, + }, +) + +map_options = MapOptions( + style=Carto.POSITRON, + bounds=tuple(bbox), + fit_bounds_options={"padding": 20}, +) + +app_ui = ui.page_fluid( + ui.panel_title("Every Person in Manhattan"), + output_maplibregl("maplibre", height=600), + ui.input_slider("radius", "Radius", value=CIRCLE_RADIUS, min=1, max=5), +) -def server(input, output, session): - @render_maplibregl - async def maplibre(): - m = Map(map_options) - m.add_layer(every_person_in_manhattan_circles) - return m - - @reactive.Effect - @reactive.event(input.radius, ignore_init=True) - async def radius(): - async with MapContext("maplibre") as m: - m.set_paint_property(LAYER_ID, "circle-radius", input.radius()) - - -app = App(app_ui, server) + +def server(input, output, session): + @render_maplibregl + def maplibre(): + m = Map(map_options) + m.add_control(ScaleControl(), position="bottom-left") + m.add_layer(every_person_in_manhattan_circles) + return m + + @reactive.Effect + @reactive.event(input.radius, ignore_init=True) + async def radius(): + async with MapContext("maplibre") as m: + m.set_paint_property(LAYER_ID, "circle-radius", input.radius()) + -if __name__ == "__main__": - app.run() +app = App(app_ui, server) + +if __name__ == "__main__": + app.run() Run example: poetry run uvicorn docs.examples.every_person_in_manhattan.app:app --reload @@ -851,7 +918,7 @@ Every person in manhattan - + diff --git a/examples/getting_started/__pycache__/reactivity.cpython-39.pyc b/examples/getting_started/__pycache__/reactivity.cpython-39.pyc new file mode 100644 index 00000000..b731c151 Binary files /dev/null and b/examples/getting_started/__pycache__/reactivity.cpython-39.pyc differ diff --git a/examples/getting_started/__pycache__/shiny_ui.cpython-39.pyc b/examples/getting_started/__pycache__/shiny_ui.cpython-39.pyc new file mode 100644 index 00000000..3c824bd3 Binary files /dev/null and b/examples/getting_started/__pycache__/shiny_ui.cpython-39.pyc differ diff --git a/examples/basic_usage.py b/examples/getting_started/basic_usage.py similarity index 84% rename from examples/basic_usage.py rename to examples/getting_started/basic_usage.py index 0990a953..2cb7d315 100644 --- a/examples/basic_usage.py +++ b/examples/getting_started/basic_usage.py @@ -7,7 +7,12 @@ data="https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/geojson/vancouver-blocks.json", ) -map_options = MapOptions(center=(-123.1256, 49.24658), zoom=12, hash=True, pitch=35) +map_options = MapOptions( + center=(-123.1256, 49.24658), + zoom=12, + hash=True, + pitch=35, +) m = Map(map_options) m.add_layer( diff --git a/examples/basic_usage_shiny.py b/examples/getting_started/basic_usage_shiny.py similarity index 100% rename from examples/basic_usage_shiny.py rename to examples/getting_started/basic_usage_shiny.py diff --git a/examples/getting_started/reactivity.py b/examples/getting_started/reactivity.py new file mode 100644 index 00000000..1512de8c --- /dev/null +++ b/examples/getting_started/reactivity.py @@ -0,0 +1,69 @@ +from pymaplibregl import ( + Layer, + LayerType, + Map, + MapContext, + output_maplibregl, + render_maplibregl, +) +from pymaplibregl.sources import GeoJSONSource +from shiny import App, reactive, render, ui + +LAYER_ID = "earthquakes" +CIRCLE_RADIUS = 5 + +app_ui = ui.page_fluid( + # + # Render map + # + ui.panel_title("MapLibre"), + output_maplibregl("maplibre", height=600), + # + # Show coords + # + ui.div("Click on the map to print the coords.", style="padding: 10px;"), + ui.output_text_verbatim("coords", placeholder=True), + # + # Show props of a feature + # + ui.div("Click on a feature to print its props.", style="padding: 10px;"), + ui.output_text_verbatim("props", placeholder=True), + # + # Change radius + # + ui.input_slider("radius", "Radius", value=CIRCLE_RADIUS, min=1, max=10), +) + + +def server(input, output, session): + @render_maplibregl + def maplibre(): + m = Map(zoom=3) + m.add_layer( + Layer( + type=LayerType.CIRCLE, + id=LAYER_ID, + source=GeoJSONSource( + data="https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson" + ), + paint={"circle-color": "yellow"}, + ) + ) + return m + + @render.text + def coords(): + return str(input.maplibre()) + + @render.text + def props(): + return str(input.maplibre_layer_earthquakes()) + + @reactive.Effect + @reactive.event(input.radius) + async def radius(): + async with MapContext("maplibre") as m: + m.set_paint_property(LAYER_ID, "circle-radius", input.radius()) + + +app = App(app_ui, server) diff --git a/examples/jupyter/getting_started.ipynb b/examples/jupyter/getting_started.ipynb new file mode 100644 index 00000000..09b64734 --- /dev/null +++ b/examples/jupyter/getting_started.ipynb @@ -0,0 +1,307 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 7, + "id": "8ae5dd75-d944-4304-88c6-ec2db700dcec", + "metadata": {}, + "outputs": [], + "source": [ + "import ipywidgets as widgets\n", + "\n", + "from pymaplibregl import MapOptions, Layer, LayerType\n", + "from pymaplibregl.sources import GeoJSONSource\n", + "from pymaplibregl.controls import ScaleControl, Marker\n", + "from pymaplibregl.ipywidget import MapWidget as Map" + ] + }, + { + "cell_type": "markdown", + "id": "fdd23345-7451-4bea-a91d-664a1d84cee0", + "metadata": {}, + "source": [ + "# Create a source" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "e7395a31-1f92-4100-abbe-bc0eae14ff83", + "metadata": {}, + "outputs": [], + "source": [ + "earthquakes = GeoJSONSource(\n", + " data=\"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c87b8cd2-ee14-47f1-b072-baf14bf53fb8", + "metadata": {}, + "source": [ + "# Create a layer" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "d715d455-2d0b-4415-9ed7-722cd6e6ad21", + "metadata": {}, + "outputs": [], + "source": [ + "layer_id = \"earthquakes\"\n", + "\n", + "earthquake_circles = Layer(\n", + " type=LayerType.CIRCLE,\n", + " id=layer_id,\n", + " source=earthquakes,\n", + " paint={\"circle-color\": \"yellow\"}\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "087d0f4a-4396-48e2-9fda-aa59dcdd6b38", + "metadata": {}, + "source": [ + "# Render map" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "e6e2284c-1862-4697-ad94-f535b3682197", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3a3a1fa7a1d44875b6186d30418fcda9", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "MapWidget(height='400px', map_options={'style': 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.j…" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m = Map()\n", + "m.add_control(ScaleControl(), position=\"bottom-left\")\n", + "m.add_layer(earthquake_circles)\n", + "m.add_tooltip(layer_id, \"mag\")\n", + "m.add_marker(Marker(lng_lat=(100.507, 13.745)))\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "9cc3f3c4-0a5c-46d5-ba87-d60db412d7f8", + "metadata": {}, + "source": [ + "# Change radius" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "356960fa-b866-42c8-a58e-0c9a417c28eb", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3bd7acb77eab47f5943d6f84b5e67573", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(IntSlider(value=5, description='radius', max=15, min=-5), Output()), _dom_classes=('widg…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "(radius)>" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "widgets.interact(\n", + " lambda radius: m.set_paint_property(layer_id, \"circle-radius\", radius),\n", + " radius=5\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "18933f67-19ce-4681-bd3d-cd54459b09a9", + "metadata": {}, + "source": [ + "# Change color" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "8ecd93a6-f471-4350-a052-7a9171fa1606", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "579df0bed72f4f42a0c95d419b884c7b", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(Dropdown(description='color', options=('green', 'yellow', 'orange', 'red'), value='green…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "(color)>" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "widgets.interact(\n", + " lambda color: m.set_paint_property(layer_id, \"circle-color\", color),\n", + " color=[\"green\", \"yellow\", \"orange\", \"red\"]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f72b8eeb-18d8-4181-8bee-94593c5472a3", + "metadata": {}, + "source": [ + "# Set filter on mag" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "0b73f056-f35a-46bb-a092-d899c64cd67e", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "1f28e632817142f28441cd7ee67f4106", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(IntSlider(value=3, description='mag_min', max=9, min=-3), Output()), _dom_classes=('widg…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "(mag_min)>" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "widgets.interact(\n", + " lambda mag_min: m.set_filter(layer_id, [\">=\", [\"get\", \"mag\"], mag_min]),\n", + " mag_min=3\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "04372035-0dcb-4217-b01a-83e82b4c79f5", + "metadata": {}, + "source": [ + "# Observe map click event" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "a9c5ddf7-074e-45b0-8cfe-15750fd0b4d5", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "a0a98cf1681841a7abc1cdbc29d239dd", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import clear_output\n", + "\n", + "output = widgets.Output()\n", + "\n", + "def log_lng_lat(lng_lat):\n", + " with output:\n", + " clear_output()\n", + " print(lng_lat.new)\n", + "\n", + "\n", + "m.observe(log_lng_lat, names=\"lng_lat\")\n", + "output" + ] + } + ], + "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.9.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/vancouver_blocks/__pycache__/app.cpython-39.pyc b/examples/vancouver_blocks/__pycache__/app.cpython-39.pyc new file mode 100644 index 00000000..1627b6f6 Binary files /dev/null and b/examples/vancouver_blocks/__pycache__/app.cpython-39.pyc differ diff --git a/examples/vancouver_blocks/app.py b/examples/vancouver_blocks/app.py new file mode 100644 index 00000000..6e612101 --- /dev/null +++ b/examples/vancouver_blocks/app.py @@ -0,0 +1,100 @@ +from pymaplibregl import ( + Layer, + LayerType, + Map, + MapContext, + MapOptions, + output_maplibregl, + render_maplibregl, +) +from pymaplibregl.basemaps import Carto +from pymaplibregl.controls import ScaleControl +from pymaplibregl.sources import GeoJSONSource +from shiny import App, reactive, ui + +SOURCE_ID = "vancouver-blocks" +LAYER_ID_LINES = "vancouver-blocks-lines" +LAYER_ID_FILL = "vancouver-blocks-fill-extrusion" +MAX_FILTER_VALUE = 1000000 + +vancouver_blocks_source = GeoJSONSource( + data="https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/geojson/vancouver-blocks.json" +) + +vancouver_blocks_lines = Layer( + type=LayerType.LINE, + id=LAYER_ID_LINES, + source=SOURCE_ID, + paint={ + "line-color": "white", + "line-width": 2, + }, +) + +vancouver_blocks_fill = Layer( + type=LayerType.FILL_EXTRUSION, + id=LAYER_ID_FILL, + source=SOURCE_ID, + paint={ + "fill-extrusion-color": { + "property": "valuePerSqm", + "stops": [ + [0, "grey"], + [1000, "yellow"], + [5000, "orange"], + [10000, "red"], + [50000, "darkred"], + ], + }, + "fill-extrusion-height": ["*", 10, ["sqrt", ["get", "valuePerSqm"]]], + "fill-extrusion-opacity": 0.9, + }, +) + +map_options = MapOptions( + style=Carto.DARK_MATTER, + center=(-123.13, 49.254), + zoom=11, + pitch=45, + bearing=0, +) + +app_ui = ui.page_fluid( + ui.panel_title("Vancouver Property Value"), + ui.div( + "Height of polygons - average property value per square meter of lot", + style="padding: 10px;", + ), + output_maplibregl("maplibre", height=700), + ui.input_select( + "filter", + "max property value per square meter", + choices=[0, 1000, 5000, 10000, 50000, 100000, MAX_FILTER_VALUE], + selected=MAX_FILTER_VALUE, + ), +) + + +def server(input, output, session): + @render_maplibregl + def maplibre(): + m = Map(map_options) + m.add_control(ScaleControl(), position="bottom-left") + m.add_source(SOURCE_ID, vancouver_blocks_source) + m.add_layer(vancouver_blocks_lines) + m.add_layer(vancouver_blocks_fill) + m.add_tooltip(LAYER_ID_FILL, "valuePerSqm") + return m + + @reactive.Effect + @reactive.event(input.filter) + async def filter(): + async with MapContext("maplibre") as m: + filter_ = ["<=", ["get", "valuePerSqm"], int(input.filter())] + m.set_filter(LAYER_ID_FILL, filter_) + + +app = App(app_ui, server) + +if __name__ == "__main__": + app.run() diff --git a/examples/vancouver_blocks/index.html b/examples/vancouver_blocks/index.html new file mode 100644 index 00000000..e2187388 --- /dev/null +++ b/examples/vancouver_blocks/index.html @@ -0,0 +1,948 @@ + + + + + + + + + + + + + + + + + + + + + + + Vancouver property value - py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + py-maplibregl + + + + + + Vancouver property value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Initializing search + + + + + + + + + + + + + + + + + py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + Get started + + + + + + + + + + + + + + + + + + API Documentation + + + + + + + + + + + + + + + + + + + + Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + py-maplibregl + + + + + + + + + + py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get started + + + + + + + + + + Get started + + + + + + + + + + + + + + + Welcome to py-maplibregl + + + + + + + + + + + + + + + + + + + + + Layers + + + + + + + + + + + + + + + + + + + + + Shiny + + + + + + + + + + + + + + + + + + + + + Jupyter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + API Documentation + + + + + + + + + + API Documentation + + + + + + + + + + + + + + + Map + + + + + + + + + + + + + + + + + + + + + Layer + + + + + + + + + + + + + + + + + + + + + Sources + + + + + + + + + + + + + + + + + + + + + Basemaps + + + + + + + + + + + + + + + + + + + + + Markers and controls + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Examples + + + + + + + + + + Examples + + + + + + + + + + + + + + + Every person in manhattan + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vancouver property value + + + + + + + + + + + + + + + + + + + + + + Earthquake clusters + + + + + + + + + + + + + + + + + + + + + Airport markers + + + + + + + + + + + + + + + + + + + + + 3D Indoor mapping + + + + + + + + + + + + + + + + + + + + + Custom basemap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vancouver property value + +from pymaplibregl import ( + Layer, + LayerType, + Map, + MapContext, + MapOptions, + output_maplibregl, + render_maplibregl, +) +from pymaplibregl.basemaps import Carto +from pymaplibregl.controls import ScaleControl +from pymaplibregl.sources import GeoJSONSource +from shiny import App, reactive, ui + +SOURCE_ID = "vancouver-blocks" +LAYER_ID_LINES = "vancouver-blocks-lines" +LAYER_ID_FILL = "vancouver-blocks-fill-extrusion" +MAX_FILTER_VALUE = 1000000 + +vancouver_blocks_source = GeoJSONSource( + data="https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/geojson/vancouver-blocks.json" +) + +vancouver_blocks_lines = Layer( + type=LayerType.LINE, + id=LAYER_ID_LINES, + source=SOURCE_ID, + paint={ + "line-color": "white", + "line-width": 2, + }, +) + +vancouver_blocks_fill = Layer( + type=LayerType.FILL_EXTRUSION, + id=LAYER_ID_FILL, + source=SOURCE_ID, + paint={ + "fill-extrusion-color": { + "property": "valuePerSqm", + "stops": [ + [0, "grey"], + [1000, "yellow"], + [5000, "orange"], + [10000, "red"], + [50000, "darkred"], + ], + }, + "fill-extrusion-height": ["*", 10, ["sqrt", ["get", "valuePerSqm"]]], + "fill-extrusion-opacity": 0.9, + }, +) + +map_options = MapOptions( + style=Carto.DARK_MATTER, + center=(-123.13, 49.254), + zoom=11, + pitch=45, + bearing=0, +) + +app_ui = ui.page_fluid( + ui.panel_title("Vancouver Property Value"), + ui.div( + "Height of polygons - average property value per square meter of lot", + style="padding: 10px;", + ), + output_maplibregl("maplibre", height=700), + ui.input_select( + "filter", + "max property value per square meter", + choices=[0, 1000, 5000, 10000, 50000, 100000, MAX_FILTER_VALUE], + selected=MAX_FILTER_VALUE, + ), +) + + +def server(input, output, session): + @render_maplibregl + def maplibre(): + m = Map(map_options) + m.add_control(ScaleControl(), position="bottom-left") + m.add_source(SOURCE_ID, vancouver_blocks_source) + m.add_layer(vancouver_blocks_lines) + m.add_layer(vancouver_blocks_fill) + m.add_tooltip(LAYER_ID_FILL, "valuePerSqm") + return m + + @reactive.Effect + @reactive.event(input.filter) + async def filter(): + async with MapContext("maplibre") as m: + filter_ = ["<=", ["get", "valuePerSqm"], int(input.filter())] + m.set_filter(LAYER_ID_FILL, filter_) + + +app = App(app_ui, server) + +if __name__ == "__main__": + app.run() + +Run example: +poetry run uvicorn docs.examples.vancouver_blocks.app:app --reload + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html index 28ad9125..c221ecbb 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@ - + @@ -18,7 +18,7 @@ - Welcome to Pymaplibregl - Pymaplibregl + Welcome to py-maplibregl - py-maplibregl @@ -76,7 +76,7 @@ - + Skip to content @@ -88,9 +88,11 @@ - + + + - + @@ -104,13 +106,13 @@ - Pymaplibregl + py-maplibregl - Welcome to Pymaplibregl + Welcome to py-maplibregl @@ -174,14 +176,8 @@ - - - - - - @@ -245,7 +241,13 @@ - + + + + + + + @@ -264,13 +266,13 @@ - + - Pymaplibregl + py-maplibregl @@ -349,7 +351,7 @@ - Welcome to Pymaplibregl + Welcome to py-maplibregl @@ -360,7 +362,7 @@ - Welcome to Pymaplibregl + Welcome to py-maplibregl @@ -439,11 +441,53 @@ - + - Examples + Layers + + + + + + + + + + + + + + + + + + + + + Shiny + + + + + + + + + + + + + + + + + + + + + Jupyter @@ -679,6 +723,27 @@ + + + + + + Vancouver property value + + + + + + + + + + + + + + + @@ -850,8 +915,8 @@ -Pymaplibregl -Pymaplibregl provides Python bindings for maplibre-gl-js. +py-maplibregl +py-maplibregl provides Python bindings for maplibre-gl-js. It integrates seamlessly into py-shiny. Installation # Stable @@ -871,23 +936,28 @@ Standalone data="https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/geojson/vancouver-blocks.json", ) -map_options = MapOptions(center=(-123.1256, 49.24658), zoom=12, hash=True, pitch=35) - -m = Map(map_options) -m.add_layer( - Layer( - type=LayerType.LINE, - source=vancouver_blocks, - paint={"line-color": "white"}, - ) -) - -temp_file = "/tmp/pymaplibregl.html" - -with open(temp_file, "w") as f: - f.write(m.to_html(style="height: 800px;")) +map_options = MapOptions( + center=(-123.1256, 49.24658), + zoom=12, + hash=True, + pitch=35, +) + +m = Map(map_options) +m.add_layer( + Layer( + type=LayerType.LINE, + source=vancouver_blocks, + paint={"line-color": "white"}, + ) +) -webbrowser.open(temp_file) +temp_file = "/tmp/pymaplibregl.html" + +with open(temp_file, "w") as f: + f.write(m.to_html(style="height: 800px;")) + +webbrowser.open(temp_file) Shiny integration from pymaplibregl import Map, MapContext, output_maplibregl, render_maplibregl @@ -964,7 +1034,7 @@ Shiny integration - + diff --git a/jupyter/index.html b/jupyter/index.html new file mode 100644 index 00000000..e1ae6c33 --- /dev/null +++ b/jupyter/index.html @@ -0,0 +1,907 @@ + + + + + + + + + + + + + + + + + + + + + + + Jupyter - py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + py-maplibregl + + + + + + Jupyter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Initializing search + + + + + + + + + + + + + + + + + py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + + + Get started + + + + + + + + + + + + + + + + + + API Documentation + + + + + + + + + + + + + + + + + + Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + py-maplibregl + + + + + + + + + + py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get started + + + + + + + + + + Get started + + + + + + + + + + + + + + + Welcome to py-maplibregl + + + + + + + + + + + + + + + + + + + + + Layers + + + + + + + + + + + + + + + + + + + + + Shiny + + + + + + + + + + + + + + + + + + + + + + + + + + + + Jupyter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + API Documentation + + + + + + + + + + API Documentation + + + + + + + + + + + + + + + Map + + + + + + + + + + + + + + + + + + + + + Layer + + + + + + + + + + + + + + + + + + + + + Sources + + + + + + + + + + + + + + + + + + + + + Basemaps + + + + + + + + + + + + + + + + + + + + + Markers and controls + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Examples + + + + + + + + + + Examples + + + + + + + + + + + + + + + Every person in manhattan + + + + + + + + + + + + + + + + + + + + + Vancouver property value + + + + + + + + + + + + + + + + + + + + + Earthquake clusters + + + + + + + + + + + + + + + + + + + + + Airport markers + + + + + + + + + + + + + + + + + + + + + 3D Indoor mapping + + + + + + + + + + + + + + + + + + + + + Custom basemap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Jupyter + +Use MapWidget in your Juyper Notebook. +import ipywidgets as widgets + +from pymaplibregl import MapOptions, Layer, LayerType +from pymaplibregl.sources import GeoJSONSource +from pymaplibregl.controls import ScaleControl, Marker +from pymaplibregl.ipywidget import MapWidget as Map + +# Create a source +earthquakes = GeoJSONSource( + data="https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson" +) + +# Creat a layer +layer_id = "earthquakes" + +earthquake_circles = Layer( + type=LayerType.CIRCLE, + id=layer_id, + source=earthquakes, + paint={"circle-color": "yellow"} +) + +# Render map +m = Map() +m.add_control(ScaleControl(), position="bottom-left") +m.add_layer(earthquake_circles) +m.add_tooltip(layer_id, "mag") +m.add_marker(Marker(lng_lat=(100.507, 13.745))) +m + +# Change radius +widgets.interact( + lambda radius: m.set_paint_property(layer_id, "circle-radius", radius), + radius=5 +) + +# Change color +widgets.interact( + lambda color: m.set_paint_property(layer_id, "circle-color", color), + color=["green", "yellow", "orange", "red"] +) + +# Set filter on magnitude +widgets.interact( + lambda mag_min: m.set_filter(layer_id, [">=", ["get", "mag"], mag_min]), + mag_min=3 +) + +# Observe map-on-click event +from IPython.display import clear_output + +output = widgets.Output() + +def log_lng_lat(lng_lat): + with output: + clear_output() + print(lng_lat.new) + + +m.observe(log_lng_lat, names="lng_lat") +output + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/layers/index.html b/layers/index.html new file mode 100644 index 00000000..ec93b802 --- /dev/null +++ b/layers/index.html @@ -0,0 +1,881 @@ + + + + + + + + + + + + + + + + + + + + + + + Layers - py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + py-maplibregl + + + + + + Layers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Initializing search + + + + + + + + + + + + + + + + + py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + + + Get started + + + + + + + + + + + + + + + + + + API Documentation + + + + + + + + + + + + + + + + + + Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + py-maplibregl + + + + + + + + + + py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get started + + + + + + + + + + Get started + + + + + + + + + + + + + + + Welcome to py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + + + + + + Layers + + + + + + + + + + + + + + + + + + + + + + Shiny + + + + + + + + + + + + + + + + + + + + + Jupyter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + API Documentation + + + + + + + + + + API Documentation + + + + + + + + + + + + + + + Map + + + + + + + + + + + + + + + + + + + + + Layer + + + + + + + + + + + + + + + + + + + + + Sources + + + + + + + + + + + + + + + + + + + + + Basemaps + + + + + + + + + + + + + + + + + + + + + Markers and controls + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Examples + + + + + + + + + + Examples + + + + + + + + + + + + + + + Every person in manhattan + + + + + + + + + + + + + + + + + + + + + Vancouver property value + + + + + + + + + + + + + + + + + + + + + Earthquake clusters + + + + + + + + + + + + + + + + + + + + + Airport markers + + + + + + + + + + + + + + + + + + + + + 3D Indoor mapping + + + + + + + + + + + + + + + + + + + + + Custom basemap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Layers + +The paint and layout properties for the layers depend on the type of the layer. +They are passed as a dict corresponding to the Layer Style Spec. +For example, to set the radius and the color for a circle layer, the paint property looks like this: +paint = { + "circle-radius": 5, + "circle-color": "yellow" +} + +The value for any layout property, paint property, or filter may also be specified as an expression. +For details see Expressions. +For example, if the source of your layer has a color property that contains the color of the feature, +you can use the following expression: +paint = { + "circle-radius": 5, + "circle-color": ["get", "color"] +} + +A more complex expression where the color depends on the type property of the layer's source might look like this: +paint={ + "circle-color": [ + "match", + ["get", "type"], + # darkred if type == "mid" + "mid", + "darkred", + # darkgreen if type == "major" + "major", + "darkgreen", + # else blue + "darkblue", + ] +} + +Filter features of a source according to its magnitude property: +# Only show features where magnitude >= 5 +filter = [">=", ["get", "magnitude"], 5] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv index 0f36519c..e9a06ee1 100644 Binary files a/objects.inv and b/objects.inv differ diff --git a/search/search_index.json b/search/search_index.json index edcfc17c..5f7228e8 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Pymaplibregl","text":"Pymaplibregl provides Python bindings for maplibre-gl-js. It integrates seamlessly into py-shiny."},{"location":"#installation","title":"Installation","text":"# Stable\npip install git+https://github.com/eodaGmbH/py-maplibregl\n\n# Dev\npip install git+https://github.com/eodaGmbH/py-maplibregl@dev\n"},{"location":"#basic-usage","title":"Basic usage","text":""},{"location":"#standalone","title":"Standalone","text":"import webbrowser\n\nfrom pymaplibregl import Layer, LayerType, Map, MapOptions\nfrom pymaplibregl.sources import GeoJSONSource\n\nvancouver_blocks = GeoJSONSource(\n data=\"https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/geojson/vancouver-blocks.json\",\n)\n\nmap_options = MapOptions(center=(-123.1256, 49.24658), zoom=12, hash=True, pitch=35)\n\nm = Map(map_options)\nm.add_layer(\n Layer(\n type=LayerType.LINE,\n source=vancouver_blocks,\n paint={\"line-color\": \"white\"},\n )\n)\n\ntemp_file = \"/tmp/pymaplibregl.html\"\n\nwith open(temp_file, \"w\") as f:\n f.write(m.to_html(style=\"height: 800px;\"))\n\nwebbrowser.open(temp_file)\n"},{"location":"#shiny-integration","title":"Shiny integration","text":"from pymaplibregl import Map, MapContext, output_maplibregl, render_maplibregl\nfrom pymaplibregl.controls import Marker\nfrom shiny import App, reactive, ui\n\napp_ui = ui.page_fluid(\n output_maplibregl(\"maplibre\", height=600),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre():\n m = Map()\n return m\n\n @reactive.Effect\n @reactive.event(input.maplibre)\n async def coords():\n async with MapContext(\"maplibre\") as m:\n print(input.maplibre())\n m.add_marker(Marker(lng_lat=input.maplibre()[\"coords\"].values()))\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n app.run()\n"},{"location":"api/basemaps/","title":"Basemaps","text":""},{"location":"api/basemaps/#pymaplibregl.basemaps.Carto","title":"pymaplibregl.basemaps.Carto","text":" Bases: Enum Carto basemap styles Attributes: DARK_MATTER \u2013 dark-matter POSITRON \u2013 positron VOYAGER \u2013 voyager POSITRON_NOLABELS \u2013 positron-nolabels DARK_MATTER_NOLABELS \u2013 dark-matter-nolabels VOYAGER_NOLABELS \u2013 voyager-nolabels Examples: >>> from pymaplibregl import Map, MapOptions\n>>> from pymaplibregl.basemaps import Carto\n >>> map = Map(MapOptions(style=Carto.DARK_MATTER))\n Source code in pymaplibregl/basemaps.py class Carto(Enum):\n \"\"\"Carto basemap styles\n\n Attributes:\n DARK_MATTER: dark-matter\n POSITRON: positron\n VOYAGER: voyager\n POSITRON_NOLABELS: positron-nolabels\n DARK_MATTER_NOLABELS: dark-matter-nolabels\n VOYAGER_NOLABELS: voyager-nolabels\n\n Examples:\n >>> from pymaplibregl import Map, MapOptions\n >>> from pymaplibregl.basemaps import Carto\n\n >>> map = Map(MapOptions(style=Carto.DARK_MATTER))\n \"\"\"\n\n DARK_MATTER = \"dark-matter\"\n POSITRON = \"positron\"\n VOYAGER = \"voyager\"\n POSITRON_NOLABELS = \"positron-nolabels\"\n DARK_MATTER_NOLABELS = \"dark-matter-nolabels\"\n VOYAGER_NOLABELS = \"voyager-nolabels\"\n"},{"location":"api/basemaps/#pymaplibregl.basemaps.construct_basemap_style","title":"pymaplibregl.basemaps.construct_basemap_style(name='nice-style', sources={}, layers=[])","text":"Construct a basemap style Parameters: Name Type Description Default name str The name of the basemap style. 'nice-style' sources dict The sources to be used for the basemap style. {} layers list The layers to be used for the basemap style. [] Source code in pymaplibregl/basemaps.py def construct_basemap_style(\n name: str = \"nice-style\", sources: dict = {}, layers: list = []\n) -> dict:\n \"\"\"Construct a basemap style\n\n Args:\n name (str): The name of the basemap style.\n sources (dict): The sources to be used for the basemap style.\n layers (list): The layers to be used for the basemap style.\n \"\"\"\n layers = [\n layer.to_dict() if isinstance(layer, Layer) else layer for layer in layers\n ]\n return {\"name\": name, \"version\": 8, \"sources\": sources, \"layers\": layers}\n"},{"location":"api/controls/","title":"Markers and controls","text":""},{"location":"api/controls/#pymaplibregl.controls.Popup","title":"pymaplibregl.controls.Popup","text":" Bases: BaseModel Popup Attributes: Name Type Description text str The Text of the popup. options PopupOptions | dict Popup options. Source code in pymaplibregl/controls.py class Popup(BaseModel):\n \"\"\"Popup\n\n Attributes:\n text: The Text of the popup.\n options (PopupOptions | dict): Popup options.\n \"\"\"\n\n text: str\n options: Union[PopupOptions, dict] = {}\n"},{"location":"api/controls/#pymaplibregl.controls.PopupOptions","title":"pymaplibregl.controls.PopupOptions","text":" Bases: BaseModel Popup options Source code in pymaplibregl/controls.py class PopupOptions(BaseModel):\n \"\"\"Popup options\"\"\"\n\n anchor: str = None\n close_button: bool = Field(False, serialization_alias=\"closeButton\")\n close_on_click: bool = Field(None, serialization_alias=\"closeOnClick\")\n close_on_move: bool = Field(None, serialization_alias=\"closeOnMove\")\n max_width: int = Field(None, serialization_alias=\"maxWidth\")\n offset: Union[int, list, dict] = None\n"},{"location":"api/controls/#pymaplibregl.controls.Marker","title":"pymaplibregl.controls.Marker","text":" Bases: BaseModel Marker Attributes: Name Type Description lng_lat tuple | list Required. The longitude and latitude of the marker. popup Popup | dict The Popup that is displayed when a user clicks on the marker. options MarkerOptions | dict Marker options. Source code in pymaplibregl/controls.py class Marker(BaseModel):\n \"\"\"Marker\n\n Attributes:\n lng_lat (tuple |list): **Required.** The longitude and latitude of the marker.\n popup (Popup | dict): The Popup that is displayed when a user clicks on the marker.\n options (MarkerOptions | dict): Marker options.\n \"\"\"\n\n lng_lat: Union[tuple, list] = Field(None, serialization_alias=\"lngLat\")\n popup: Union[Popup, dict] = None\n options: Union[MarkerOptions, dict] = {}\n"},{"location":"api/controls/#pymaplibregl.controls.MarkerOptions","title":"pymaplibregl.controls.MarkerOptions","text":" Bases: BaseModel Marker options Source code in pymaplibregl/controls.py class MarkerOptions(BaseModel):\n \"\"\"Marker options\"\"\"\n\n anchor: str = None\n color: str = None\n draggable: bool = None\n offset: Union[tuple, list] = None\n pitch_alignment: str = Field(None, serialization_alias=\"pitchAlignment\")\n rotation: int = None\n rotation_alignment: str = Field(None, serialization_alias=\"rotationAlignment\")\n scale: int = None\n"},{"location":"api/controls/#pymaplibregl.controls.ControlPosition","title":"pymaplibregl.controls.ControlPosition","text":" Bases: Enum Control position Attributes: TOP_LEFT \u2013 top-left TOP_RIGHT \u2013 top-right BOTTOM_LEFT \u2013 bottom-left BOTTOM_RIGHT \u2013 bottom-right Source code in pymaplibregl/controls.py class ControlPosition(Enum):\n \"\"\"Control position\n\n Attributes:\n TOP_LEFT: top-left\n TOP_RIGHT: top-right\n BOTTOM_LEFT: bottom-left\n BOTTOM_RIGHT: bottom-right\n \"\"\"\n\n TOP_LEFT = \"top-left\"\n TOP_RIGHT = \"top-right\"\n BOTTOM_LEFT = \"bottom-left\"\n BOTTOM_RIGHT = \"bottom-right\"\n"},{"location":"api/controls/#pymaplibregl.controls.FullscreenControl","title":"pymaplibregl.controls.FullscreenControl","text":" Bases: Control Fullscreen control Examples: >>> from pymaplibregl import Map\n>>> from pymaplibregl.controls import FullscreenControl, ControlPosition\n >>> map = Map()\n>>> map.add_control(FullscreenControl(), ControlPosition.BOTTOM_LEFT)\n Source code in pymaplibregl/controls.py class FullscreenControl(Control):\n \"\"\"Fullscreen control\n\n Examples:\n >>> from pymaplibregl import Map\n >>> from pymaplibregl.controls import FullscreenControl, ControlPosition\n\n >>> map = Map()\n >>> map.add_control(FullscreenControl(), ControlPosition.BOTTOM_LEFT)\n \"\"\"\n\n # _name: str = ControlType.FULLSCREEN.value\n pass\n"},{"location":"api/layer/","title":"Layer","text":""},{"location":"api/layer/#pymaplibregl.Layer","title":"pymaplibregl.Layer","text":" Bases: BaseModel Layer properties Notes See layers for more details. Attributes: Name Type Description id str Required. The unique ID of the layer. Defaults to str(uuid4()). type str | LayerType Required. The type of the layer. filter list The filter expression that is applied to the source of the layer. layout dict The layout properties of the layer. max_zoom int The maximum zoom level for the layer. min_zoom int The minimum zoom level for the layer. paint dict The paint properties of the layer. source str | Source The name (unique ID) of a source or a source object to be used for the layer. source_layer str The layer to use from a vector tile source. Examples: >>> from pymaplibregl.layer import Layer, LayerType\n >>> layer = Layer(id=\"test-layer\", type=LayerType.CIRCLE, source=\"test-source\")\n Source code in pymaplibregl/layer.py class Layer(BaseModel):\n \"\"\"Layer properties\n\n Notes:\n See [layers](https://maplibre.org/maplibre-style-spec/layers/) for more details.\n\n Attributes:\n id (str): **Required.** The unique ID of the layer. Defaults to `str(uuid4())`.\n type (str | LayerType): **Required.** The type of the layer.\n filter (list): The filter expression that is applied to the source of the layer.\n layout (dict): The layout properties of the layer.\n max_zoom (int): The maximum zoom level for the layer.\n min_zoom (int): The minimum zoom level for the layer.\n paint (dict): The paint properties of the layer.\n source (str | Source): The name (unique ID) of a source or a source object to be used for the layer.\n source_layer (str): The layer to use from a vector tile source.\n\n Examples:\n >>> from pymaplibregl.layer import Layer, LayerType\n\n >>> layer = Layer(id=\"test-layer\", type=LayerType.CIRCLE, source=\"test-source\")\n \"\"\"\n\n id: str = Field(default_factory=lambda: str(uuid4()))\n type: LayerType\n filter: list = None\n layout: dict = None\n max_zoom: int = Field(None, serialization_alias=\"maxzoom\")\n metadata: dict = None\n min_zoom: int = Field(None, serialization_alias=\"minzoom\")\n paint: dict = None\n source: Union[str, Source, dict, None] = None\n source_layer: str = Field(None, serialization_alias=\"source-layer\")\n\n @field_validator(\"source\")\n def validate_source(cls, v):\n if isinstance(v, Source):\n return v.to_dict()\n\n return v\n\n @field_validator(\"paint\", \"layout\")\n def fix_paint(cls, v):\n if isinstance(v, dict):\n return fix_keys(v)\n\n return v\n"},{"location":"api/layer/#pymaplibregl.LayerType","title":"pymaplibregl.LayerType","text":" Bases: Enum Rendering type of layer Attributes: CIRCLE \u2013 A filled circle. FILL \u2013 A filled polygon with an optional stroked border. FILL_EXTRUSION \u2013 An extruded polygon. LINE \u2013 A stroked line. SYMBOL \u2013 An icon or a text label. RASTER \u2013 Raster map textures such as satellite imagery. HEATMAP \u2013 A heatmap. HILLSHADE \u2013 A Client-side hillshading visualization based on DEM data. BACKGROUND \u2013 A background color or pattern. Source code in pymaplibregl/layer.py class LayerType(Enum):\n \"\"\"Rendering type of layer\n\n Attributes:\n CIRCLE: A filled circle.\n FILL: A filled polygon with an optional stroked border.\n FILL_EXTRUSION: An extruded polygon.\n LINE: A stroked line.\n SYMBOL: An icon or a text label.\n RASTER: Raster map textures such as satellite imagery.\n HEATMAP: A heatmap.\n HILLSHADE: A Client-side hillshading visualization based on DEM data.\n BACKGROUND: A background color or pattern.\n \"\"\"\n\n CIRCLE = \"circle\"\n FILL = \"fill\"\n FILL_EXTRUSION = \"fill-extrusion\"\n LINE = \"line\"\n SYMBOL = \"symbol\"\n RASTER = \"raster\"\n HEATMAP = \"heatmap\"\n HILLSHADE = \"hillshade\"\n BACKGROUND = \"background\"\n"},{"location":"api/map/","title":"Map","text":""},{"location":"api/map/#pymaplibregl.Map","title":"pymaplibregl.Map","text":" Bases: object Map Parameters: Name Type Description Default map_options MapOptions Map options. MapOptions() **kwargs Keyword arguments that are appended to the MapOptions object. {} Examples: >>> from pymaplibregl.map import Map, MapOptions\n >>> map_options = MapOptions(center=(9.5, 51.31667), zoom=8)\n>>> map = Map(map_options)\n>>> dict(map)\n{'mapOptions': {'center': (9.5, 51.31667), 'style': 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json', 'zoom': 8}, 'calls': []}\n Source code in pymaplibregl/map.py class Map(object):\n \"\"\"Map\n\n Args:\n map_options (MapOptions): Map options.\n **kwargs: Keyword arguments that are appended to the `MapOptions` object.\n\n Examples:\n >>> from pymaplibregl.map import Map, MapOptions\n\n >>> map_options = MapOptions(center=(9.5, 51.31667), zoom=8)\n >>> map = Map(map_options)\n >>> dict(map)\n {'mapOptions': {'center': (9.5, 51.31667), 'style': 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json', 'zoom': 8}, 'calls': []}\n \"\"\"\n\n MESSAGE = \"not implemented yet\"\n\n def __init__(self, map_options: MapOptions = MapOptions(), **kwargs):\n self._map_options = map_options.to_dict() | kwargs\n self._calls = []\n\n def __iter__(self):\n for k, v in self.to_dict().items():\n yield k, v\n\n def to_dict(self) -> dict:\n return {\"mapOptions\": self._map_options, \"calls\": self._calls}\n\n @property\n def sources(self) -> list:\n return [item[\"data\"] for item in self._calls if item[\"name\"] == \"addSource\"]\n\n @property\n def layers(self) -> list:\n return [item[\"data\"] for item in self._calls if item[\"name\"] == \"addLayer\"]\n\n # TODO: Rename to add_map_call\n def add_call(self, func_name: str, params: list) -> None:\n self._calls.append(\n {\"name\": \"applyFunc\", \"data\": {\"funcName\": func_name, \"params\": params}}\n )\n\n def add_control(\n self,\n control: Control,\n position: [str | ControlPosition] = ControlPosition.TOP_RIGHT,\n ) -> None:\n \"\"\"Add a control to the map\n\n Args:\n control (Control): The control to be add to the map.\n position (str | ControlPosition): The position of the control.\n \"\"\"\n data = {\n \"type\": control.type,\n \"options\": control.to_dict(),\n \"position\": ControlPosition(position).value,\n }\n self._calls.append({\"name\": \"addControl\", \"data\": data})\n\n def add_source(self, id: str, source: [Source | dict]) -> None:\n \"\"\"Add a source to the map\"\"\"\n if isinstance(source, Source):\n source = source.to_dict()\n\n self._calls.append({\"name\": \"addSource\", \"data\": {\"id\": id, \"source\": source}})\n\n def add_layer(self, layer: [Layer | dict]) -> None:\n \"\"\"Add a layer to the map\n\n Args:\n layer (Layer | dict): The Layer to be added to the map.\n \"\"\"\n if isinstance(layer, Layer):\n layer = layer.to_dict()\n\n self._calls.append({\"name\": \"addLayer\", \"data\": layer})\n\n def add_marker(self, marker: Marker) -> None:\n \"\"\"Add a marker to the map\n\n Args:\n marker (Marker): The marker to be added to the map.\n \"\"\"\n self._calls.append({\"name\": \"addMarker\", \"data\": marker.to_dict()})\n\n def add_popup(self, layer_id: str, prop: str) -> None:\n \"\"\"Add a popup to the map\"\"\"\n self._calls.append(\n {\"name\": \"addPopup\", \"data\": {\"layerId\": layer_id, \"property\": prop}}\n )\n\n def set_filter(self, layer_id: str, filter_: list):\n \"\"\"Update the filter of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n filter_ (list): The filter expression that is applied to the source of the layer.\n \"\"\"\n self.add_call(\"setFilter\", [layer_id, filter_])\n\n def set_paint_property(self, layer_id: str, prop: str, value: any) -> None:\n \"\"\"Update the paint property of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n prop (str): The name of the paint property to be updated.\n value (any): The new value of the paint property.\n \"\"\"\n self.add_call(\"setPaintProperty\", [layer_id, prop, value])\n\n def set_layout_property(self, layer_id: str, prop: str, value: any) -> None:\n \"\"\"Update a layout property of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n prop (str): The name of the layout property to be updated.\n value (any): The new value of the layout property.\n \"\"\"\n self.add_call(\"setLayoutProperty\", [layer_id, prop, value])\n\n def to_html(self, **kwargs) -> str:\n \"\"\"Render to html\n\n Args:\n **kwargs (Any): Additional keyword arguments that are passed to the template.\n Currently, `style` is the only supported keyword argument.\n\n Examples:\n >>> from pymaplibregl import Map\n\n >>> map = Map()\n >>> with open(\"/tmp/map.html\", \"w\") as f:\n ... f.write(map.to_html(style=\"height: 800px;\")\n \"\"\"\n js_lib = read_internal_file(\"srcjs\", \"index.js\")\n js_snippet = Template(js_template).render(data=json.dumps(self.to_dict()))\n output = Template(html_template).render(\n js=\"\\n\".join([js_lib, js_snippet]), **kwargs\n )\n return output\n"},{"location":"api/map/#pymaplibregl.Map.add_control","title":"add_control(control, position=ControlPosition.TOP_RIGHT)","text":"Add a control to the map Parameters: Name Type Description Default control Control The control to be add to the map. required position str | ControlPosition The position of the control. TOP_RIGHT Source code in pymaplibregl/map.py def add_control(\n self,\n control: Control,\n position: [str | ControlPosition] = ControlPosition.TOP_RIGHT,\n) -> None:\n \"\"\"Add a control to the map\n\n Args:\n control (Control): The control to be add to the map.\n position (str | ControlPosition): The position of the control.\n \"\"\"\n data = {\n \"type\": control.type,\n \"options\": control.to_dict(),\n \"position\": ControlPosition(position).value,\n }\n self._calls.append({\"name\": \"addControl\", \"data\": data})\n"},{"location":"api/map/#pymaplibregl.Map.add_layer","title":"add_layer(layer)","text":"Add a layer to the map Parameters: Name Type Description Default layer Layer | dict The Layer to be added to the map. required Source code in pymaplibregl/map.py def add_layer(self, layer: [Layer | dict]) -> None:\n \"\"\"Add a layer to the map\n\n Args:\n layer (Layer | dict): The Layer to be added to the map.\n \"\"\"\n if isinstance(layer, Layer):\n layer = layer.to_dict()\n\n self._calls.append({\"name\": \"addLayer\", \"data\": layer})\n"},{"location":"api/map/#pymaplibregl.Map.add_marker","title":"add_marker(marker)","text":"Add a marker to the map Parameters: Name Type Description Default marker Marker The marker to be added to the map. required Source code in pymaplibregl/map.py def add_marker(self, marker: Marker) -> None:\n \"\"\"Add a marker to the map\n\n Args:\n marker (Marker): The marker to be added to the map.\n \"\"\"\n self._calls.append({\"name\": \"addMarker\", \"data\": marker.to_dict()})\n"},{"location":"api/map/#pymaplibregl.Map.add_popup","title":"add_popup(layer_id, prop)","text":"Add a popup to the map Source code in pymaplibregl/map.py def add_popup(self, layer_id: str, prop: str) -> None:\n \"\"\"Add a popup to the map\"\"\"\n self._calls.append(\n {\"name\": \"addPopup\", \"data\": {\"layerId\": layer_id, \"property\": prop}}\n )\n"},{"location":"api/map/#pymaplibregl.Map.add_source","title":"add_source(id, source)","text":"Add a source to the map Source code in pymaplibregl/map.py def add_source(self, id: str, source: [Source | dict]) -> None:\n \"\"\"Add a source to the map\"\"\"\n if isinstance(source, Source):\n source = source.to_dict()\n\n self._calls.append({\"name\": \"addSource\", \"data\": {\"id\": id, \"source\": source}})\n"},{"location":"api/map/#pymaplibregl.Map.set_filter","title":"set_filter(layer_id, filter_)","text":"Update the filter of a layer Parameters: Name Type Description Default layer_id str The name of the layer to be updated. required filter_ list The filter expression that is applied to the source of the layer. required Source code in pymaplibregl/map.py def set_filter(self, layer_id: str, filter_: list):\n \"\"\"Update the filter of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n filter_ (list): The filter expression that is applied to the source of the layer.\n \"\"\"\n self.add_call(\"setFilter\", [layer_id, filter_])\n"},{"location":"api/map/#pymaplibregl.Map.set_layout_property","title":"set_layout_property(layer_id, prop, value)","text":"Update a layout property of a layer Parameters: Name Type Description Default layer_id str The name of the layer to be updated. required prop str The name of the layout property to be updated. required value any The new value of the layout property. required Source code in pymaplibregl/map.py def set_layout_property(self, layer_id: str, prop: str, value: any) -> None:\n \"\"\"Update a layout property of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n prop (str): The name of the layout property to be updated.\n value (any): The new value of the layout property.\n \"\"\"\n self.add_call(\"setLayoutProperty\", [layer_id, prop, value])\n"},{"location":"api/map/#pymaplibregl.Map.set_paint_property","title":"set_paint_property(layer_id, prop, value)","text":"Update the paint property of a layer Parameters: Name Type Description Default layer_id str The name of the layer to be updated. required prop str The name of the paint property to be updated. required value any The new value of the paint property. required Source code in pymaplibregl/map.py def set_paint_property(self, layer_id: str, prop: str, value: any) -> None:\n \"\"\"Update the paint property of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n prop (str): The name of the paint property to be updated.\n value (any): The new value of the paint property.\n \"\"\"\n self.add_call(\"setPaintProperty\", [layer_id, prop, value])\n"},{"location":"api/map/#pymaplibregl.Map.to_html","title":"to_html(**kwargs)","text":"Render to html Parameters: Name Type Description Default **kwargs Any Additional keyword arguments that are passed to the template. Currently, style is the only supported keyword argument. {} Examples: >>> from pymaplibregl import Map\n >>> map = Map()\n>>> with open(\"/tmp/map.html\", \"w\") as f:\n... f.write(map.to_html(style=\"height: 800px;\")\n Source code in pymaplibregl/map.py def to_html(self, **kwargs) -> str:\n \"\"\"Render to html\n\n Args:\n **kwargs (Any): Additional keyword arguments that are passed to the template.\n Currently, `style` is the only supported keyword argument.\n\n Examples:\n >>> from pymaplibregl import Map\n\n >>> map = Map()\n >>> with open(\"/tmp/map.html\", \"w\") as f:\n ... f.write(map.to_html(style=\"height: 800px;\")\n \"\"\"\n js_lib = read_internal_file(\"srcjs\", \"index.js\")\n js_snippet = Template(js_template).render(data=json.dumps(self.to_dict()))\n output = Template(html_template).render(\n js=\"\\n\".join([js_lib, js_snippet]), **kwargs\n )\n return output\n"},{"location":"api/map/#pymaplibregl.MapOptions","title":"pymaplibregl.MapOptions","text":" Bases: BaseModel Map options Note See mapOptions for more details. Source code in pymaplibregl/map.py class MapOptions(BaseModel):\n \"\"\"Map options\n\n Note:\n See [mapOptions](https://maplibre.org/maplibre-gl-js/docs/API/types/maplibregl.MapOptions/) for more details.\n \"\"\"\n\n model_config = ConfigDict(\n validate_assignment=True, extra=\"forbid\", use_enum_values=False\n )\n antialias: bool = None\n attribution_control: bool = Field(None, serialization_alias=\"attributionControl\")\n bearing: int = None\n bearing_snap: int = Field(None, serialization_alias=\"bearingSnap\")\n bounds: tuple = None\n box_zoom: bool = Field(None, serialization_alias=\"boxZoom\")\n center: tuple = None\n click_tolerance: int = Field(None, serialization_alias=\"clickTolerance\")\n custom_attribution: bool = Field(None, serialization_alias=\"customAttribution\")\n double_click_zoom: bool = Field(None, serialization_alias=\"doubleClickZoom\")\n fade_duration: int = Field(None, serialization_alias=\"fadeDuration\")\n fit_bounds_options: dict = Field(None, serialization_alias=\"fitBoundsOptions\")\n hash: Union[bool, str] = None\n interactive: bool = None\n keyword: bool = None\n max_bounds: tuple = Field(None, serialization_alias=\"maxBounds\")\n max_pitch: int = Field(None, serialization_alias=\"maxPitch\")\n max_zoom: int = Field(None, serialization_alias=\"maxZoom\")\n min_pitch: int = Field(None, serialization_alias=\"minPitch\")\n min_zoom: int = Field(None, serialization_alias=\"minZoom\")\n pitch: int = None\n scroll_zoom: bool = Field(None, serialization_alias=\"scrollZoom\")\n style: Union[str, Carto, dict] = construct_carto_basemap_url(Carto.DARK_MATTER)\n zoom: int = None\n\n @field_validator(\"style\")\n def validate_style(cls, v):\n if isinstance(v, Carto):\n return construct_carto_basemap_url(v)\n\n return v\n"},{"location":"api/sources/","title":"Sources","text":""},{"location":"api/sources/#pymaplibregl.sources","title":"pymaplibregl.sources","text":""},{"location":"api/sources/#pymaplibregl.sources.GeoJSONSource","title":"GeoJSONSource","text":" Bases: Source GeoJSON Source Examples: >>> from pymaplibregl.sources import GeoJSONSource\n >>> source = GeoJSONSource(data=\"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\")\n Source code in pymaplibregl/sources.py class GeoJSONSource(Source):\n \"\"\"GeoJSON Source\n\n Examples:\n >>> from pymaplibregl.sources import GeoJSONSource\n\n >>> source = GeoJSONSource(data=\"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\")\n \"\"\"\n\n data: Union[str, dict]\n attribution: str = None\n buffer: int = None\n cluster: bool = None\n cluster_max_zoom: int = Field(None, serialization_alias=\"clusterMaxZoom\")\n cluster_min_points: int = Field(None, serialization_alias=\"clusterMinPoints\")\n cluster_properties: dict = Field(None, serialization_alias=\"clusterProperties\")\n cluster_radius: int = Field(None, serialization_alias=\"clusterRadius\")\n filter: list = None\n generate_id: bool = Field(None, serialization_alias=\"generateId\")\n line_metrics: bool = Field(None, serialization_alias=\"lineMetrics\")\n maxzoom: int = None\n promote_id: Union[str, dict] = Field(None, serialization_alias=\"promoteId\")\n tolerance: float = None\n\n @computed_field\n @property\n def type(self) -> str:\n return SourceType.GEOJSON.value\n"},{"location":"api/sources/#pymaplibregl.sources.RasterTileSource","title":"RasterTileSource","text":" Bases: Source Raster tile source Examples: >>> from pymaplibregl.sources import RasterTileSource\n>>> raster_source = RasterTileSource(\n... tiles=[\"https://tile.openstreetmap.org/{z}/{x}/{y}.png\"],\n... tile_size=256,\n... min_zoom=0,\n... max_zoom=19,\n... )\n Source code in pymaplibregl/sources.py class RasterTileSource(Source):\n \"\"\"Raster tile source\n\n Examples:\n >>> from pymaplibregl.sources import RasterTileSource\n >>> raster_source = RasterTileSource(\n ... tiles=[\"https://tile.openstreetmap.org/{z}/{x}/{y}.png\"],\n ... tile_size=256,\n ... min_zoom=0,\n ... max_zoom=19,\n ... )\n \"\"\"\n\n attribution: str = None\n bounds: tuple = None\n max_zoom: int = Field(None, serialization_alias=\"maxzoom\")\n min_zoom: int = Field(None, serialization_alias=\"minzoom\")\n scheme: str = None\n tile_size: int = Field(None, serialization_alias=\"tileSize\")\n tiles: Union[tuple, list] = None\n url: str = None\n volatile: bool = None\n\n @computed_field\n @property\n def type(self) -> str:\n return SourceType.RASTER.value\n"},{"location":"api/sources/#pymaplibregl.sources.SourceType","title":"SourceType","text":" Bases: Enum Source types Source code in pymaplibregl/sources.py class SourceType(Enum):\n \"\"\"Source types\"\"\"\n\n RASTER = \"raster\"\n VECTOR = \"vector\"\n RASTER_DEM = \"raster-dem\"\n GEOJSON = \"geojson\"\n IMAGE = \"image\"\n VIDEO = \"video\"\n"},{"location":"examples/3d_indoor_mapping/","title":"3D Indoor mapping","text":"import webbrowser\n\nfrom pymaplibregl import Layer, LayerType, Map, MapOptions\nfrom pymaplibregl.basemaps import background\nfrom pymaplibregl.sources import GeoJSONSource, RasterTileSource\n\nTEMP_FILE = \"/tmp/pymaplibregl_temp.html\"\nFLOORPLAN_SOURCE_ID = \"floorplan\"\n\nraster_source = RasterTileSource(\n tiles=[\"https://tile.openstreetmap.org/{z}/{x}/{y}.png\"],\n tile_size=256,\n min_zoom=0,\n max_zoom=19,\n)\n\nraster_layer = Layer(type=LayerType.RASTER, source=raster_source)\n\nfloorplan_source = GeoJSONSource(\n data=\"https://maplibre.org/maplibre-gl-js/docs/assets/indoor-3d-map.geojson\"\n)\n\nfloorplan_layer = Layer(\n type=LayerType.FILL_EXTRUSION,\n id=\"floorplan\",\n source=FLOORPLAN_SOURCE_ID,\n paint={\n \"fill-extrusion-color\": [\"get\", \"color\"],\n \"fill-extrusion-height\": [\"get\", \"height\"],\n \"fill-extrusion-base\": [\"get\", \"base_height\"],\n \"fill-extrusion-opacity\": 0.5,\n },\n)\n\nmap_options = MapOptions(\n style=background(\"yellow\"),\n center=(-87.61694, 41.86625),\n zoom=17,\n pitch=40,\n bearing=20,\n antialias=True,\n)\n\n\ndef create_map():\n m = Map(map_options)\n m.add_layer(raster_layer)\n m.add_source(FLOORPLAN_SOURCE_ID, floorplan_source)\n m.add_layer(floorplan_layer)\n return m\n\n\nif __name__ == \"__main__\":\n m = create_map()\n with open(TEMP_FILE, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(TEMP_FILE)\n Run example: poetry run python docs/examples/3d_indoor_mapping/app.py\n"},{"location":"examples/airports/","title":"Airport markers","text":"import pandas as pd\nfrom pymaplibregl import (\n Layer,\n LayerType,\n Map,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom pymaplibregl.basemaps import Carto\nfrom pymaplibregl.controls import Marker, MarkerOptions, Popup, PopupOptions\nfrom pymaplibregl.sources import GeoJSONSource\nfrom pymaplibregl.utils import GeometryType, df_to_geojson\nfrom shiny import App, ui\n\nBOUNDS = (-8.92242886, 43.30508298, 13.76496714, 59.87668996)\n\nairports_data = pd.read_json(\n \"https://github.com/visgl/deck.gl-data/raw/master/examples/line/airports.json\"\n)\n\n\ndef get_color(airport_type: str) -> str:\n color = \"darkblue\"\n if airport_type == \"mid\":\n color = \"darkred\"\n elif airport_type == \"major\":\n color = \"darkgreen\"\n\n return color\n\n\ngeojson = df_to_geojson(\n airports_data,\n \"coordinates\",\n GeometryType.POINT,\n properties=[\"type\", \"name\", \"abbrev\"],\n)\n\nairport_circles = Layer(\n type=LayerType.CIRCLE,\n source=GeoJSONSource(data=geojson),\n paint={\n \"circle-color\": [\n \"match\",\n [\"get\", \"type\"],\n \"mid\",\n \"darkred\",\n \"major\",\n \"darkgreen\",\n \"darkblue\",\n ],\n \"circle_radius\": 10,\n \"circle-opacity\": 0.3,\n },\n)\n\nmap_options = MapOptions(\n style=Carto.POSITRON,\n bounds=BOUNDS,\n fit_bounds_options={\"padding\": 20},\n hash=True,\n)\n\npopup_options = PopupOptions(close_button=False)\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Airports\"),\n output_maplibregl(\"maplibre\", height=600),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n async def maplibre():\n m = Map(map_options)\n for _, r in airports_data.iterrows():\n marker = Marker(\n lng_lat=r[\"coordinates\"],\n options=MarkerOptions(color=get_color(r[\"type\"])),\n popup=Popup(\n text=r[\"name\"],\n options=popup_options,\n ),\n )\n m.add_marker(marker)\n m.add_layer(airport_circles)\n return m\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n app.run()\n Run example: poetry run uvicorn docs.examples.airports.app:app --reload\n"},{"location":"examples/custom_basemap/","title":"Custom basemap","text":"import webbrowser\n\nfrom pymaplibregl import Layer, LayerType, Map, MapOptions\nfrom pymaplibregl.basemaps import construct_basemap_style\nfrom pymaplibregl.sources import GeoJSONSource\n\nTEMP_FILE = \"/tmp/pymaplibregl_temp.html\"\n\nbg_layer = Layer(\n type=LayerType.BACKGROUND,\n id=\"background\",\n source=None,\n paint={\"background-color\": \"darkblue\", \"background-opacity\": 0.8},\n)\n\ncountries_source = GeoJSONSource(\n data=\"https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_110m_admin_0_countries.geojson\"\n)\n\nlines_layer = Layer(\n type=LayerType.LINE,\n source=\"countries\",\n paint={\"line-color\": \"white\", \"line-width\": 1.5},\n)\n\npolygons_layer = Layer(\n type=LayerType.FILL,\n source=\"countries\",\n paint={\"fill-color\": \"darkred\", \"fill-opacity\": 0.8},\n)\n\ncustom_basemap = construct_basemap_style(\n layers=[bg_layer, polygons_layer, lines_layer],\n sources={\"countries\": countries_source},\n)\n\n\nmap_options = MapOptions(\n style=custom_basemap,\n center=(0, 0),\n zoom=2,\n)\n\n\ndef create_map():\n m = Map(map_options)\n m.add_layer(\n Layer(\n type=LayerType.CIRCLE,\n id=\"earthquakes\",\n source=GeoJSONSource(\n data=\"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n ),\n paint={\"circle-color\": \"yellow\", \"circle-radius\": 5},\n )\n )\n m.add_popup(\"earthquakes\", \"mag\")\n return m\n\n\nif __name__ == \"__main__\":\n m = create_map()\n with open(TEMP_FILE, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(TEMP_FILE)\n Run example: poetry run python docs/examples/custom_basemap/app.py\n"},{"location":"examples/earthquake_clusters/","title":"Earthquake clusters","text":"from pymaplibregl import (\n Layer,\n LayerType,\n Map,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom pymaplibregl.basemaps import Carto\nfrom pymaplibregl.sources import GeoJSONSource\nfrom shiny import App, reactive, ui\n\nEARTHQUAKE_SOURCE = \"earthquakes\"\nEARTHQUAKE_CIRCLES = \"earthquake-circles\"\nEARTHQUAKE_CLUSTERS = \"earthquake-clusters\"\nEARTHQUAKE_LABELS = \"earthquake-labels\"\n\nCENTER = (-118.0931, 33.78615)\n\nearthquakes_source = GeoJSONSource(\n data=\"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\",\n cluster=True,\n cluster_radius=50,\n cluster_min_points=2,\n cluster_max_zoom=14,\n cluster_properties={\n \"maxMag\": [\"max\", [\"get\", \"mag\"]],\n \"minMag\": [\"min\", [\"get\", \"mag\"]],\n },\n)\n\nearthquake_circles = Layer(\n type=LayerType.CIRCLE,\n id=EARTHQUAKE_CIRCLES,\n source=EARTHQUAKE_SOURCE,\n paint={\"circle-color\": \"darkblue\"},\n filter=[\"!\", [\"has\", \"point_count\"]],\n)\n\nearthquake_clusters = Layer(\n type=LayerType.CIRCLE,\n id=EARTHQUAKE_CLUSTERS,\n source=EARTHQUAKE_SOURCE,\n filter=[\"has\", \"point_count\"],\n paint={\n \"circle-color\": [\n \"step\",\n [\"get\", \"point_count\"],\n \"#51bbd6\",\n 100,\n \"#f1f075\",\n 750,\n \"#f28cb1\",\n ],\n \"circle-radius\": [\"step\", [\"get\", \"point_count\"], 20, 100, 30, 750, 40],\n },\n)\n\nearthquake_labels = Layer(\n type=LayerType.SYMBOL,\n id=\"text\",\n source=EARTHQUAKE_SOURCE,\n filter=[\"has\", \"point_count\"],\n layout={\n \"text-field\": [\"get\", \"point_count_abbreviated\"],\n \"text-size\": 12,\n },\n)\n\nmap_options = MapOptions(style=Carto.POSITRON, center=CENTER, zoom=3, hash=True)\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Earthquakes Cluster\"),\n output_maplibregl(\"maplibre\", height=500),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n async def maplibre():\n m = Map(map_options)\n m.add_source(EARTHQUAKE_SOURCE, earthquakes_source)\n m.add_layer(earthquake_clusters)\n m.add_layer(earthquake_circles)\n m.add_popup(EARTHQUAKE_CLUSTERS, \"maxMag\")\n m.add_layer(earthquake_labels)\n return m\n\n @reactive.Effect\n @reactive.event(input.maplibre)\n async def result():\n print(f\"result: {input.maplibre()}\")\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n app.run()\n Run example: poetry run uvicorn docs.examples.earthquake_clusters.app:app --reload\n"},{"location":"examples/every_person_in_manhattan/","title":"Every person in manhattan","text":"import json\n\nimport pandas as pd\nimport shapely\nfrom pymaplibregl import (\n Layer,\n LayerType,\n Map,\n MapContext,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom pymaplibregl.basemaps import Carto\nfrom pymaplibregl.sources import GeoJSONSource\nfrom pymaplibregl.utils import df_to_geojson\nfrom shiny import App, reactive, ui\n\nMALE_COLOR = \"rgb(0, 128, 255)\"\nFEMALE_COLOR = \"rgb(255, 0, 128)\"\nLAYER_ID = \"every-person-in-manhattan-circles\"\nCIRCLE_RADIUS = 2\n\npoint_data = pd.read_json(\n \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/scatterplot/manhattan.json\"\n)\n\npoint_data.columns = [\"lng\", \"lat\", \"sex\"]\n\nevery_person_in_manhattan_source = GeoJSONSource(\n data=df_to_geojson(point_data, properties=[\"sex\"]),\n)\n\nbbox = shapely.bounds(\n shapely.from_geojson(json.dumps(every_person_in_manhattan_source.data))\n)\n\nevery_person_in_manhattan_circles = Layer(\n type=LayerType.CIRCLE,\n id=LAYER_ID,\n source=every_person_in_manhattan_source,\n paint={\n \"circle-color\": [\"match\", [\"get\", \"sex\"], 1, MALE_COLOR, FEMALE_COLOR],\n \"circle-radius\": CIRCLE_RADIUS,\n },\n)\n\nmap_options = MapOptions(\n style=Carto.POSITRON,\n bounds=tuple(bbox),\n fit_bounds_options={\"padding\": 20},\n)\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Every Person in Manhattan\"),\n output_maplibregl(\"maplibre\", height=600),\n ui.input_slider(\"radius\", \"Radius\", value=CIRCLE_RADIUS, min=1, max=5),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n async def maplibre():\n m = Map(map_options)\n m.add_layer(every_person_in_manhattan_circles)\n return m\n\n @reactive.Effect\n @reactive.event(input.radius, ignore_init=True)\n async def radius():\n async with MapContext(\"maplibre\") as m:\n m.set_paint_property(LAYER_ID, \"circle-radius\", input.radius())\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n app.run()\n Run example: poetry run uvicorn docs.examples.every_person_in_manhattan.app:app --reload\n"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"py-maplibregl","text":"py-maplibregl provides Python bindings for maplibre-gl-js. It integrates seamlessly into py-shiny."},{"location":"#installation","title":"Installation","text":"# Stable\npip install git+https://github.com/eodaGmbH/py-maplibregl\n\n# Dev\npip install git+https://github.com/eodaGmbH/py-maplibregl@dev\n"},{"location":"#basic-usage","title":"Basic usage","text":""},{"location":"#standalone","title":"Standalone","text":"import webbrowser\n\nfrom pymaplibregl import Layer, LayerType, Map, MapOptions\nfrom pymaplibregl.sources import GeoJSONSource\n\nvancouver_blocks = GeoJSONSource(\n data=\"https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/geojson/vancouver-blocks.json\",\n)\n\nmap_options = MapOptions(\n center=(-123.1256, 49.24658),\n zoom=12,\n hash=True,\n pitch=35,\n)\n\nm = Map(map_options)\nm.add_layer(\n Layer(\n type=LayerType.LINE,\n source=vancouver_blocks,\n paint={\"line-color\": \"white\"},\n )\n)\n\ntemp_file = \"/tmp/pymaplibregl.html\"\n\nwith open(temp_file, \"w\") as f:\n f.write(m.to_html(style=\"height: 800px;\"))\n\nwebbrowser.open(temp_file)\n"},{"location":"#shiny-integration","title":"Shiny integration","text":"from pymaplibregl import Map, MapContext, output_maplibregl, render_maplibregl\nfrom pymaplibregl.controls import Marker\nfrom shiny import App, reactive, ui\n\napp_ui = ui.page_fluid(\n output_maplibregl(\"maplibre\", height=600),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre():\n m = Map()\n return m\n\n @reactive.Effect\n @reactive.event(input.maplibre)\n async def coords():\n async with MapContext(\"maplibre\") as m:\n print(input.maplibre())\n m.add_marker(Marker(lng_lat=input.maplibre()[\"coords\"].values()))\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n app.run()\n"},{"location":"jupyter/","title":"Jupyter","text":"Use MapWidget in your Juyper Notebook. import ipywidgets as widgets\n\nfrom pymaplibregl import MapOptions, Layer, LayerType\nfrom pymaplibregl.sources import GeoJSONSource\nfrom pymaplibregl.controls import ScaleControl, Marker\nfrom pymaplibregl.ipywidget import MapWidget as Map\n\n# Create a source\nearthquakes = GeoJSONSource(\n data=\"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n)\n\n# Creat a layer\nlayer_id = \"earthquakes\"\n\nearthquake_circles = Layer(\n type=LayerType.CIRCLE,\n id=layer_id,\n source=earthquakes,\n paint={\"circle-color\": \"yellow\"}\n)\n\n# Render map\nm = Map()\nm.add_control(ScaleControl(), position=\"bottom-left\")\nm.add_layer(earthquake_circles)\nm.add_tooltip(layer_id, \"mag\")\nm.add_marker(Marker(lng_lat=(100.507, 13.745)))\nm\n\n# Change radius\nwidgets.interact(\n lambda radius: m.set_paint_property(layer_id, \"circle-radius\", radius),\n radius=5\n)\n\n# Change color\nwidgets.interact(\n lambda color: m.set_paint_property(layer_id, \"circle-color\", color),\n color=[\"green\", \"yellow\", \"orange\", \"red\"]\n)\n\n# Set filter on magnitude\nwidgets.interact(\n lambda mag_min: m.set_filter(layer_id, [\">=\", [\"get\", \"mag\"], mag_min]),\n mag_min=3\n)\n\n# Observe map-on-click event\nfrom IPython.display import clear_output\n\noutput = widgets.Output()\n\ndef log_lng_lat(lng_lat):\n with output:\n clear_output()\n print(lng_lat.new)\n\n\nm.observe(log_lng_lat, names=\"lng_lat\")\noutput\n"},{"location":"layers/","title":"Layers","text":"The paint and layout properties for the layers depend on the type of the layer. They are passed as a dict corresponding to the Layer Style Spec. For example, to set the radius and the color for a circle layer, the paint property looks like this: paint = {\n \"circle-radius\": 5,\n \"circle-color\": \"yellow\"\n}\n The value for any layout property, paint property, or filter may also be specified as an expression. For details see Expressions. For example, if the source of your layer has a color property that contains the color of the feature, you can use the following expression: paint = {\n \"circle-radius\": 5,\n \"circle-color\": [\"get\", \"color\"]\n}\n A more complex expression where the color depends on the type property of the layer's source might look like this: paint={\n \"circle-color\": [\n \"match\",\n [\"get\", \"type\"],\n # darkred if type == \"mid\"\n \"mid\",\n \"darkred\",\n # darkgreen if type == \"major\"\n \"major\",\n \"darkgreen\",\n # else blue\n \"darkblue\",\n ]\n}\n Filter features of a source according to its magnitude property: # Only show features where magnitude >= 5\nfilter = [\">=\", [\"get\", \"magnitude\"], 5]\n"},{"location":"shiny/","title":"Shiny","text":"py-maplibregl integrates seamlessly into py-shiny."},{"location":"shiny/#adding-ui-output","title":"Adding UI output","text":"from shiny import App, ui\nfrom pymaplibregl import output_maplibregl\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"MapLibre\"),\n output_maplibregl(\"maplibre\", height=600)\n)\n\ndef server(input, output, session):\n pass\n\napp = App(app_ui, server)\n"},{"location":"shiny/#adding-server-logic","title":"Adding server logic","text":"from shiny import App, ui\nfrom pymaplibregl import output_maplibregl, render_maplibregl, Map\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"MapLibre\"),\n output_maplibregl(\"maplibre\", height=600)\n)\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre():\n m = Map()\n return m\n\napp = App(app_ui, server)\n"},{"location":"shiny/#reactivity","title":"Reactivity","text":""},{"location":"shiny/#inputs","title":"Inputs","text":"py-maplibregl provides the following reactive inputs: map-on-click event: Sends the coordinates of the location that was clicked on. The name of the input event corresponds to the output id. For output_maplibregl(\"maplibre\") you need to listen to input.maplibre. feature-on-click event: Sends the properties of the feature that was clicked on. The name of the \u00ecnput is made up of the output id + layer + layer id. For output_maplibregl(\"maplibre\") and a layer with id=test you need to listen to input.maplibre_layer_test. "},{"location":"shiny/#updates","title":"Updates","text":"Use MapContext to update your map object."},{"location":"shiny/#example-using-inputs-and-updates","title":"Example using inputs and updates","text":"from pymaplibregl import (\n Layer,\n LayerType,\n Map,\n MapContext,\n output_maplibregl,\n render_maplibregl,\n)\nfrom pymaplibregl.sources import GeoJSONSource\nfrom shiny import App, reactive, render, ui\n\nLAYER_ID = \"earthquakes\"\nCIRCLE_RADIUS = 5\n\napp_ui = ui.page_fluid(\n #\n # Render map\n #\n ui.panel_title(\"MapLibre\"),\n output_maplibregl(\"maplibre\", height=600),\n #\n # Show coords\n #\n ui.div(\"Click on the map to print the coords.\", style=\"padding: 10px;\"),\n ui.output_text_verbatim(\"coords\", placeholder=True),\n #\n # Show props of a feature\n #\n ui.div(\"Click on a feature to print its props.\", style=\"padding: 10px;\"),\n ui.output_text_verbatim(\"props\", placeholder=True),\n #\n # Change radius\n #\n ui.input_slider(\"radius\", \"Radius\", value=CIRCLE_RADIUS, min=1, max=10),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre():\n m = Map(zoom=3)\n m.add_layer(\n Layer(\n type=LayerType.CIRCLE,\n id=LAYER_ID,\n source=GeoJSONSource(\n data=\"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n ),\n paint={\"circle-color\": \"yellow\"},\n )\n )\n return m\n\n @render.text\n def coords():\n return str(input.maplibre())\n\n @render.text\n def props():\n return str(input.maplibre_layer_earthquakes())\n\n @reactive.Effect\n @reactive.event(input.radius)\n async def radius():\n async with MapContext(\"maplibre\") as m:\n m.set_paint_property(LAYER_ID, \"circle-radius\", input.radius())\n\n\napp = App(app_ui, server)\n Run this example: poetry run uvicorn docs.examples.getting_started.reactivity:app --reload\n"},{"location":"api/basemaps/","title":"Basemaps","text":""},{"location":"api/basemaps/#pymaplibregl.basemaps.Carto","title":"pymaplibregl.basemaps.Carto","text":" Bases: Enum Carto basemap styles Attributes: DARK_MATTER \u2013 dark-matter POSITRON \u2013 positron VOYAGER \u2013 voyager POSITRON_NOLABELS \u2013 positron-nolabels DARK_MATTER_NOLABELS \u2013 dark-matter-nolabels VOYAGER_NOLABELS \u2013 voyager-nolabels Examples: >>> from pymaplibregl import Map, MapOptions\n>>> from pymaplibregl.basemaps import Carto\n >>> map = Map(MapOptions(style=Carto.DARK_MATTER))\n Source code in pymaplibregl/basemaps.py class Carto(Enum):\n \"\"\"Carto basemap styles\n\n Attributes:\n DARK_MATTER: dark-matter\n POSITRON: positron\n VOYAGER: voyager\n POSITRON_NOLABELS: positron-nolabels\n DARK_MATTER_NOLABELS: dark-matter-nolabels\n VOYAGER_NOLABELS: voyager-nolabels\n\n Examples:\n >>> from pymaplibregl import Map, MapOptions\n >>> from pymaplibregl.basemaps import Carto\n\n >>> map = Map(MapOptions(style=Carto.DARK_MATTER))\n \"\"\"\n\n DARK_MATTER = \"dark-matter\"\n POSITRON = \"positron\"\n VOYAGER = \"voyager\"\n POSITRON_NOLABELS = \"positron-nolabels\"\n DARK_MATTER_NOLABELS = \"dark-matter-nolabels\"\n VOYAGER_NOLABELS = \"voyager-nolabels\"\n"},{"location":"api/basemaps/#pymaplibregl.basemaps.construct_basemap_style","title":"pymaplibregl.basemaps.construct_basemap_style(name='nice-style', sources={}, layers=[])","text":"Construct a basemap style Parameters: Name Type Description Default name str The name of the basemap style. 'nice-style' sources dict The sources to be used for the basemap style. {} layers list The layers to be used for the basemap style. [] Source code in pymaplibregl/basemaps.py def construct_basemap_style(\n name: str = \"nice-style\", sources: dict = {}, layers: list = []\n) -> dict:\n \"\"\"Construct a basemap style\n\n Args:\n name (str): The name of the basemap style.\n sources (dict): The sources to be used for the basemap style.\n layers (list): The layers to be used for the basemap style.\n \"\"\"\n layers = [\n layer.to_dict() if isinstance(layer, Layer) else layer for layer in layers\n ]\n return {\"name\": name, \"version\": 8, \"sources\": sources, \"layers\": layers}\n"},{"location":"api/controls/","title":"Markers and controls","text":""},{"location":"api/controls/#pymaplibregl.controls.Popup","title":"pymaplibregl.controls.Popup","text":" Bases: BaseModel Popup Attributes: Name Type Description text str The Text of the popup. options PopupOptions | dict Popup options. Source code in pymaplibregl/controls.py class Popup(BaseModel):\n \"\"\"Popup\n\n Attributes:\n text: The Text of the popup.\n options (PopupOptions | dict): Popup options.\n \"\"\"\n\n text: str\n options: Union[PopupOptions, dict] = {}\n"},{"location":"api/controls/#pymaplibregl.controls.PopupOptions","title":"pymaplibregl.controls.PopupOptions","text":" Bases: BaseModel Popup options Source code in pymaplibregl/controls.py class PopupOptions(BaseModel):\n \"\"\"Popup options\"\"\"\n\n anchor: str = None\n close_button: bool = Field(False, serialization_alias=\"closeButton\")\n close_on_click: bool = Field(None, serialization_alias=\"closeOnClick\")\n close_on_move: bool = Field(None, serialization_alias=\"closeOnMove\")\n max_width: int = Field(None, serialization_alias=\"maxWidth\")\n offset: Union[int, list, dict] = None\n"},{"location":"api/controls/#pymaplibregl.controls.Marker","title":"pymaplibregl.controls.Marker","text":" Bases: BaseModel Marker Attributes: Name Type Description lng_lat tuple | list Required. The longitude and latitude of the marker. popup Popup | dict The Popup that is displayed when a user clicks on the marker. options MarkerOptions | dict Marker options. Source code in pymaplibregl/controls.py class Marker(BaseModel):\n \"\"\"Marker\n\n Attributes:\n lng_lat (tuple |list): **Required.** The longitude and latitude of the marker.\n popup (Popup | dict): The Popup that is displayed when a user clicks on the marker.\n options (MarkerOptions | dict): Marker options.\n \"\"\"\n\n lng_lat: Union[tuple, list] = Field(None, serialization_alias=\"lngLat\")\n popup: Union[Popup, dict] = None\n options: Union[MarkerOptions, dict] = {}\n"},{"location":"api/controls/#pymaplibregl.controls.MarkerOptions","title":"pymaplibregl.controls.MarkerOptions","text":" Bases: BaseModel Marker options Source code in pymaplibregl/controls.py class MarkerOptions(BaseModel):\n \"\"\"Marker options\"\"\"\n\n anchor: str = None\n color: str = None\n draggable: bool = None\n offset: Union[tuple, list] = None\n pitch_alignment: str = Field(None, serialization_alias=\"pitchAlignment\")\n rotation: int = None\n rotation_alignment: str = Field(None, serialization_alias=\"rotationAlignment\")\n scale: int = None\n"},{"location":"api/controls/#pymaplibregl.controls.ControlPosition","title":"pymaplibregl.controls.ControlPosition","text":" Bases: Enum Control position Attributes: TOP_LEFT \u2013 top-left TOP_RIGHT \u2013 top-right BOTTOM_LEFT \u2013 bottom-left BOTTOM_RIGHT \u2013 bottom-right Source code in pymaplibregl/controls.py class ControlPosition(Enum):\n \"\"\"Control position\n\n Attributes:\n TOP_LEFT: top-left\n TOP_RIGHT: top-right\n BOTTOM_LEFT: bottom-left\n BOTTOM_RIGHT: bottom-right\n \"\"\"\n\n TOP_LEFT = \"top-left\"\n TOP_RIGHT = \"top-right\"\n BOTTOM_LEFT = \"bottom-left\"\n BOTTOM_RIGHT = \"bottom-right\"\n"},{"location":"api/controls/#pymaplibregl.controls.FullscreenControl","title":"pymaplibregl.controls.FullscreenControl","text":" Bases: Control Fullscreen control Examples: >>> from pymaplibregl import Map\n>>> from pymaplibregl.controls import FullscreenControl, ControlPosition\n >>> map = Map()\n>>> map.add_control(FullscreenControl(), ControlPosition.BOTTOM_LEFT)\n Source code in pymaplibregl/controls.py class FullscreenControl(Control):\n \"\"\"Fullscreen control\n\n Examples:\n >>> from pymaplibregl import Map\n >>> from pymaplibregl.controls import FullscreenControl, ControlPosition\n\n >>> map = Map()\n >>> map.add_control(FullscreenControl(), ControlPosition.BOTTOM_LEFT)\n \"\"\"\n\n # _name: str = ControlType.FULLSCREEN.value\n pass\n"},{"location":"api/layer/","title":"Layer","text":""},{"location":"api/layer/#pymaplibregl.Layer","title":"pymaplibregl.Layer","text":" Bases: BaseModel Layer properties Notes See layers for more details on the paint and layout properties of the layers. Attributes: Name Type Description id str Required. The unique ID of the layer. Defaults to str(uuid4()). type str | LayerType Required. The type of the layer. filter list The filter expression that is applied to the source of the layer. layout dict The layout properties of the layer. max_zoom int The maximum zoom level for the layer. min_zoom int The minimum zoom level for the layer. paint dict The paint properties of the layer. source str | Source The name (unique ID) of a source or a source object to be used for the layer. source_layer str The layer to use from a vector tile source. Examples: >>> from pymaplibregl.layer import Layer, LayerType\n >>> layer = Layer(id=\"test-layer\", type=LayerType.CIRCLE, source=\"test-source\")\n Source code in pymaplibregl/layer.py class Layer(BaseModel):\n \"\"\"Layer properties\n\n Notes:\n See [layers](https://maplibre.org/maplibre-style-spec/layers/) for more details on the\n `paint` and `layout` properties of the layers.\n\n Attributes:\n id (str): **Required.** The unique ID of the layer. Defaults to `str(uuid4())`.\n type (str | LayerType): **Required.** The type of the layer.\n filter (list): The filter expression that is applied to the source of the layer.\n layout (dict): The layout properties of the layer.\n max_zoom (int): The maximum zoom level for the layer.\n min_zoom (int): The minimum zoom level for the layer.\n paint (dict): The paint properties of the layer.\n source (str | Source): The name (unique ID) of a source or a source object to be used for the layer.\n source_layer (str): The layer to use from a vector tile source.\n\n Examples:\n >>> from pymaplibregl.layer import Layer, LayerType\n\n >>> layer = Layer(id=\"test-layer\", type=LayerType.CIRCLE, source=\"test-source\")\n \"\"\"\n\n id: str = Field(default_factory=lambda: str(uuid4()))\n type: LayerType\n filter: list = None\n layout: dict = None\n max_zoom: int = Field(None, serialization_alias=\"maxzoom\")\n metadata: dict = None\n min_zoom: int = Field(None, serialization_alias=\"minzoom\")\n paint: dict = None\n source: Union[str, Source, dict, None] = None\n source_layer: str = Field(None, serialization_alias=\"source-layer\")\n\n @field_validator(\"source\")\n def validate_source(cls, v):\n if isinstance(v, Source):\n return v.to_dict()\n\n return v\n\n @field_validator(\"paint\", \"layout\")\n def fix_paint(cls, v):\n if isinstance(v, dict):\n return fix_keys(v)\n\n return v\n"},{"location":"api/layer/#pymaplibregl.LayerType","title":"pymaplibregl.LayerType","text":" Bases: Enum Rendering type of layer Attributes: CIRCLE \u2013 A filled circle. FILL \u2013 A filled polygon with an optional stroked border. FILL_EXTRUSION \u2013 An extruded polygon. LINE \u2013 A stroked line. SYMBOL \u2013 An icon or a text label. RASTER \u2013 Raster map textures such as satellite imagery. HEATMAP \u2013 A heatmap. HILLSHADE \u2013 A Client-side hillshading visualization based on DEM data. BACKGROUND \u2013 A background color or pattern. Source code in pymaplibregl/layer.py class LayerType(Enum):\n \"\"\"Rendering type of layer\n\n Attributes:\n CIRCLE: A filled circle.\n FILL: A filled polygon with an optional stroked border.\n FILL_EXTRUSION: An extruded polygon.\n LINE: A stroked line.\n SYMBOL: An icon or a text label.\n RASTER: Raster map textures such as satellite imagery.\n HEATMAP: A heatmap.\n HILLSHADE: A Client-side hillshading visualization based on DEM data.\n BACKGROUND: A background color or pattern.\n \"\"\"\n\n CIRCLE = \"circle\"\n FILL = \"fill\"\n FILL_EXTRUSION = \"fill-extrusion\"\n LINE = \"line\"\n SYMBOL = \"symbol\"\n RASTER = \"raster\"\n HEATMAP = \"heatmap\"\n HILLSHADE = \"hillshade\"\n BACKGROUND = \"background\"\n"},{"location":"api/map/","title":"Map","text":""},{"location":"api/map/#pymaplibregl.Map","title":"pymaplibregl.Map","text":" Bases: object Map Parameters: Name Type Description Default map_options MapOptions Map options. MapOptions() **kwargs Keyword arguments that are appended to the MapOptions object. {} Examples: >>> from pymaplibregl.map import Map, MapOptions\n >>> map_options = MapOptions(center=(9.5, 51.31667), zoom=8)\n>>> map = Map(map_options)\n>>> dict(map)\n{'mapOptions': {'center': (9.5, 51.31667), 'style': 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json', 'zoom': 8}, 'calls': []}\n Source code in pymaplibregl/map.py class Map(object):\n \"\"\"Map\n\n Args:\n map_options (MapOptions): Map options.\n **kwargs: Keyword arguments that are appended to the `MapOptions` object.\n\n Examples:\n >>> from pymaplibregl.map import Map, MapOptions\n\n >>> map_options = MapOptions(center=(9.5, 51.31667), zoom=8)\n >>> map = Map(map_options)\n >>> dict(map)\n {'mapOptions': {'center': (9.5, 51.31667), 'style': 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json', 'zoom': 8}, 'calls': []}\n \"\"\"\n\n MESSAGE = \"not implemented yet\"\n\n def __init__(self, map_options: MapOptions = MapOptions(), **kwargs):\n self.map_options = map_options.to_dict() | kwargs\n self._message_queue = []\n\n def __iter__(self):\n for k, v in self.to_dict().items():\n yield k, v\n\n def to_dict(self) -> dict:\n return {\"mapOptions\": self.map_options, \"calls\": self._message_queue}\n\n \"\"\"\n @property\n def sources(self) -> list:\n return [item[\"data\"] for item in self._calls if item[\"name\"] == \"addSource\"]\n\n @property\n def layers(self) -> list:\n return [item[\"data\"] for item in self._calls if item[\"name\"] == \"addLayer\"]\n \"\"\"\n\n # TODO: Rename to add_map_call\n def add_call_(self, func_name: str, params: list) -> None:\n self._message_queue.append(\n {\"name\": \"applyFunc\", \"data\": {\"funcName\": func_name, \"params\": params}}\n )\n\n def add_call(self, method_name: str, *args) -> None:\n \"\"\"Add a method call that is executed on the map instance\n\n Args:\n method_name (str): The name of the map method to be executed.\n *args (any): The arguments to be passed to the map method.\n \"\"\"\n # TODO: Pass as dict? {\"name\": method_name, \"args\": args}\n call = [method_name, args]\n self._message_queue.append(call)\n\n def add_control(\n self,\n control: Control,\n position: [str | ControlPosition] = ControlPosition.TOP_RIGHT,\n ) -> None:\n \"\"\"Add a control to the map\n\n Args:\n control (Control): The control to be added to the map.\n position (str | ControlPosition): The position of the control.\n \"\"\"\n self.add_call(\n \"addControl\",\n control.type,\n control.to_dict(),\n ControlPosition(position).value,\n )\n\n def add_source(self, id: str, source: [Source | dict]) -> None:\n \"\"\"Add a source to the map\"\"\"\n if isinstance(source, Source):\n source = source.to_dict()\n\n self.add_call(\"addSource\", id, source)\n\n def add_layer(self, layer: [Layer | dict]) -> None:\n \"\"\"Add a layer to the map\n\n Args:\n layer (Layer | dict): The Layer to be added to the map.\n \"\"\"\n if isinstance(layer, Layer):\n layer = layer.to_dict()\n\n self.add_call(\"addLayer\", layer)\n\n def add_marker(self, marker: Marker) -> None:\n \"\"\"Add a marker to the map\n\n Args:\n marker (Marker): The marker to be added to the map.\n \"\"\"\n self.add_call(\"addMarker\", marker.to_dict())\n\n def add_popup(self, layer_id: str, prop: str) -> None:\n \"\"\"Add a popup to the map\n\n Args:\n layer_id (str): The layer to which the popup is added.\n prop (str): The property of the source to be displayed.\n \"\"\"\n self.add_call(\"addPopup\", layer_id, prop)\n\n def add_tooltip(self, layer_id: str, prop: str) -> None:\n \"\"\"Add a tooltip to the map\n\n Args:\n layer_id (str): The layer to which the tooltip is added.\n prop (str): The property of the source to be displayed.\n \"\"\"\n self.add_call(\"addTooltip\", layer_id, prop)\n\n def set_filter(self, layer_id: str, filter_: list):\n \"\"\"Update the filter of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n filter_ (list): The filter expression that is applied to the source of the layer.\n \"\"\"\n self.add_call(\"setFilter\", layer_id, filter_)\n\n def set_paint_property(self, layer_id: str, prop: str, value: any) -> None:\n \"\"\"Update the paint property of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n prop (str): The name of the paint property to be updated.\n value (any): The new value of the paint property.\n \"\"\"\n self.add_call(\"setPaintProperty\", layer_id, prop, value)\n\n def set_layout_property(self, layer_id: str, prop: str, value: any) -> None:\n \"\"\"Update a layout property of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n prop (str): The name of the layout property to be updated.\n value (any): The new value of the layout property.\n \"\"\"\n self.add_call(\"setLayoutProperty\", layer_id, prop, value)\n\n def to_html(self, **kwargs) -> str:\n \"\"\"Render to html\n\n Args:\n **kwargs (Any): Additional keyword arguments that are passed to the template.\n Currently, `style` is the only supported keyword argument.\n\n Examples:\n >>> from pymaplibregl import Map\n\n >>> map = Map()\n >>> with open(\"/tmp/map.html\", \"w\") as f:\n ... f.write(map.to_html(style=\"height: 800px;\") # doctest: +SKIP\n \"\"\"\n js_lib = read_internal_file(\"srcjs\", \"index.js\")\n js_snippet = Template(js_template).render(data=json.dumps(self.to_dict()))\n output = Template(html_template).render(\n js=\"\\n\".join([js_lib, js_snippet]), **kwargs\n )\n return output\n"},{"location":"api/map/#pymaplibregl.Map.add_call","title":"add_call(method_name, *args)","text":"Add a method call that is executed on the map instance Parameters: Name Type Description Default method_name str The name of the map method to be executed. required *args any The arguments to be passed to the map method. () Source code in pymaplibregl/map.py def add_call(self, method_name: str, *args) -> None:\n \"\"\"Add a method call that is executed on the map instance\n\n Args:\n method_name (str): The name of the map method to be executed.\n *args (any): The arguments to be passed to the map method.\n \"\"\"\n # TODO: Pass as dict? {\"name\": method_name, \"args\": args}\n call = [method_name, args]\n self._message_queue.append(call)\n"},{"location":"api/map/#pymaplibregl.Map.add_control","title":"add_control(control, position=ControlPosition.TOP_RIGHT)","text":"Add a control to the map Parameters: Name Type Description Default control Control The control to be added to the map. required position str | ControlPosition The position of the control. TOP_RIGHT Source code in pymaplibregl/map.py def add_control(\n self,\n control: Control,\n position: [str | ControlPosition] = ControlPosition.TOP_RIGHT,\n) -> None:\n \"\"\"Add a control to the map\n\n Args:\n control (Control): The control to be added to the map.\n position (str | ControlPosition): The position of the control.\n \"\"\"\n self.add_call(\n \"addControl\",\n control.type,\n control.to_dict(),\n ControlPosition(position).value,\n )\n"},{"location":"api/map/#pymaplibregl.Map.add_layer","title":"add_layer(layer)","text":"Add a layer to the map Parameters: Name Type Description Default layer Layer | dict The Layer to be added to the map. required Source code in pymaplibregl/map.py def add_layer(self, layer: [Layer | dict]) -> None:\n \"\"\"Add a layer to the map\n\n Args:\n layer (Layer | dict): The Layer to be added to the map.\n \"\"\"\n if isinstance(layer, Layer):\n layer = layer.to_dict()\n\n self.add_call(\"addLayer\", layer)\n"},{"location":"api/map/#pymaplibregl.Map.add_marker","title":"add_marker(marker)","text":"Add a marker to the map Parameters: Name Type Description Default marker Marker The marker to be added to the map. required Source code in pymaplibregl/map.py def add_marker(self, marker: Marker) -> None:\n \"\"\"Add a marker to the map\n\n Args:\n marker (Marker): The marker to be added to the map.\n \"\"\"\n self.add_call(\"addMarker\", marker.to_dict())\n"},{"location":"api/map/#pymaplibregl.Map.add_popup","title":"add_popup(layer_id, prop)","text":"Add a popup to the map Parameters: Name Type Description Default layer_id str The layer to which the popup is added. required prop str The property of the source to be displayed. required Source code in pymaplibregl/map.py def add_popup(self, layer_id: str, prop: str) -> None:\n \"\"\"Add a popup to the map\n\n Args:\n layer_id (str): The layer to which the popup is added.\n prop (str): The property of the source to be displayed.\n \"\"\"\n self.add_call(\"addPopup\", layer_id, prop)\n"},{"location":"api/map/#pymaplibregl.Map.add_source","title":"add_source(id, source)","text":"Add a source to the map Source code in pymaplibregl/map.py def add_source(self, id: str, source: [Source | dict]) -> None:\n \"\"\"Add a source to the map\"\"\"\n if isinstance(source, Source):\n source = source.to_dict()\n\n self.add_call(\"addSource\", id, source)\n"},{"location":"api/map/#pymaplibregl.Map.add_tooltip","title":"add_tooltip(layer_id, prop)","text":"Add a tooltip to the map Parameters: Name Type Description Default layer_id str The layer to which the tooltip is added. required prop str The property of the source to be displayed. required Source code in pymaplibregl/map.py def add_tooltip(self, layer_id: str, prop: str) -> None:\n \"\"\"Add a tooltip to the map\n\n Args:\n layer_id (str): The layer to which the tooltip is added.\n prop (str): The property of the source to be displayed.\n \"\"\"\n self.add_call(\"addTooltip\", layer_id, prop)\n"},{"location":"api/map/#pymaplibregl.Map.set_filter","title":"set_filter(layer_id, filter_)","text":"Update the filter of a layer Parameters: Name Type Description Default layer_id str The name of the layer to be updated. required filter_ list The filter expression that is applied to the source of the layer. required Source code in pymaplibregl/map.py def set_filter(self, layer_id: str, filter_: list):\n \"\"\"Update the filter of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n filter_ (list): The filter expression that is applied to the source of the layer.\n \"\"\"\n self.add_call(\"setFilter\", layer_id, filter_)\n"},{"location":"api/map/#pymaplibregl.Map.set_layout_property","title":"set_layout_property(layer_id, prop, value)","text":"Update a layout property of a layer Parameters: Name Type Description Default layer_id str The name of the layer to be updated. required prop str The name of the layout property to be updated. required value any The new value of the layout property. required Source code in pymaplibregl/map.py def set_layout_property(self, layer_id: str, prop: str, value: any) -> None:\n \"\"\"Update a layout property of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n prop (str): The name of the layout property to be updated.\n value (any): The new value of the layout property.\n \"\"\"\n self.add_call(\"setLayoutProperty\", layer_id, prop, value)\n"},{"location":"api/map/#pymaplibregl.Map.set_paint_property","title":"set_paint_property(layer_id, prop, value)","text":"Update the paint property of a layer Parameters: Name Type Description Default layer_id str The name of the layer to be updated. required prop str The name of the paint property to be updated. required value any The new value of the paint property. required Source code in pymaplibregl/map.py def set_paint_property(self, layer_id: str, prop: str, value: any) -> None:\n \"\"\"Update the paint property of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n prop (str): The name of the paint property to be updated.\n value (any): The new value of the paint property.\n \"\"\"\n self.add_call(\"setPaintProperty\", layer_id, prop, value)\n"},{"location":"api/map/#pymaplibregl.Map.to_html","title":"to_html(**kwargs)","text":"Render to html Parameters: Name Type Description Default **kwargs Any Additional keyword arguments that are passed to the template. Currently, style is the only supported keyword argument. {} Examples: >>> from pymaplibregl import Map\n >>> map = Map()\n>>> with open(\"/tmp/map.html\", \"w\") as f:\n... f.write(map.to_html(style=\"height: 800px;\")\n Source code in pymaplibregl/map.py def to_html(self, **kwargs) -> str:\n \"\"\"Render to html\n\n Args:\n **kwargs (Any): Additional keyword arguments that are passed to the template.\n Currently, `style` is the only supported keyword argument.\n\n Examples:\n >>> from pymaplibregl import Map\n\n >>> map = Map()\n >>> with open(\"/tmp/map.html\", \"w\") as f:\n ... f.write(map.to_html(style=\"height: 800px;\") # doctest: +SKIP\n \"\"\"\n js_lib = read_internal_file(\"srcjs\", \"index.js\")\n js_snippet = Template(js_template).render(data=json.dumps(self.to_dict()))\n output = Template(html_template).render(\n js=\"\\n\".join([js_lib, js_snippet]), **kwargs\n )\n return output\n"},{"location":"api/map/#pymaplibregl.MapOptions","title":"pymaplibregl.MapOptions","text":" Bases: BaseModel Map options Note See mapOptions for more details. Source code in pymaplibregl/map.py class MapOptions(BaseModel):\n \"\"\"Map options\n\n Note:\n See [mapOptions](https://maplibre.org/maplibre-gl-js/docs/API/types/maplibregl.MapOptions/) for more details.\n \"\"\"\n\n model_config = ConfigDict(\n validate_assignment=True, extra=\"forbid\", use_enum_values=False\n )\n antialias: bool = None\n attribution_control: bool = Field(None, serialization_alias=\"attributionControl\")\n bearing: int = None\n bearing_snap: int = Field(None, serialization_alias=\"bearingSnap\")\n bounds: tuple = None\n box_zoom: bool = Field(None, serialization_alias=\"boxZoom\")\n center: tuple = None\n click_tolerance: int = Field(None, serialization_alias=\"clickTolerance\")\n custom_attribution: bool = Field(None, serialization_alias=\"customAttribution\")\n double_click_zoom: bool = Field(None, serialization_alias=\"doubleClickZoom\")\n fade_duration: int = Field(None, serialization_alias=\"fadeDuration\")\n fit_bounds_options: dict = Field(None, serialization_alias=\"fitBoundsOptions\")\n hash: Union[bool, str] = None\n interactive: bool = None\n keyword: bool = None\n max_bounds: tuple = Field(None, serialization_alias=\"maxBounds\")\n max_pitch: int = Field(None, serialization_alias=\"maxPitch\")\n max_zoom: int = Field(None, serialization_alias=\"maxZoom\")\n min_pitch: int = Field(None, serialization_alias=\"minPitch\")\n min_zoom: int = Field(None, serialization_alias=\"minZoom\")\n pitch: int = None\n scroll_zoom: bool = Field(None, serialization_alias=\"scrollZoom\")\n style: Union[str, Carto, dict] = construct_carto_basemap_url(Carto.DARK_MATTER)\n zoom: int = None\n\n @field_validator(\"style\")\n def validate_style(cls, v):\n if isinstance(v, Carto):\n return construct_carto_basemap_url(v)\n\n return v\n"},{"location":"api/map/#pymaplibregl.ipywidget.MapWidget","title":"pymaplibregl.ipywidget.MapWidget","text":" Bases: AnyWidget, Map Source code in pymaplibregl/ipywidget.py class MapWidget(AnyWidget, Map):\n _esm = join(Path(__file__).parent, \"srcjs\", \"ipywidget.js\")\n _css = join(Path(__file__).parent, \"srcjs\", \"maplibre-gl.css\")\n _rendered = traitlets.Bool(False, config=True).tag(sync=True)\n map_options = traitlets.Dict().tag(sync=True)\n height = traitlets.Union([traitlets.Int(), traitlets.Unicode()]).tag(sync=True)\n lng_lat = traitlets.Dict().tag(sync=True)\n\n def __init__(self, map_options=MapOptions(), **kwargs) -> None:\n # self.map_options = map_options.to_dict()\n # self._message_queue = []\n # super().__init__(**kwargs)\n AnyWidget.__init__(self, **kwargs)\n Map.__init__(self, map_options, **kwargs)\n\n @traitlets.default(\"height\")\n def _default_height(self):\n return \"400px\"\n\n @traitlets.validate(\"height\")\n def _validate_height(self, proposal):\n height = proposal[\"value\"]\n if isinstance(height, int):\n return f\"{height}px\"\n\n return height\n\n @traitlets.observe(\"_rendered\")\n def _on_rendered(self, change):\n self.send({\"calls\": self._message_queue, \"msg\": \"init\"})\n self._message_queue = []\n\n def add_call(self, method_name: str, *args) -> None:\n call = [method_name, args]\n if not self._rendered:\n self._message_queue.append(call)\n return\n\n self.send({\"calls\": [call], \"msg\": \"custom call\"})\n"},{"location":"api/map/#pymaplibregl.ipywidget.MapWidget.add_control","title":"add_control(control, position=ControlPosition.TOP_RIGHT)","text":"Add a control to the map Parameters: Name Type Description Default control Control The control to be added to the map. required position str | ControlPosition The position of the control. TOP_RIGHT Source code in pymaplibregl/map.py def add_control(\n self,\n control: Control,\n position: [str | ControlPosition] = ControlPosition.TOP_RIGHT,\n) -> None:\n \"\"\"Add a control to the map\n\n Args:\n control (Control): The control to be added to the map.\n position (str | ControlPosition): The position of the control.\n \"\"\"\n self.add_call(\n \"addControl\",\n control.type,\n control.to_dict(),\n ControlPosition(position).value,\n )\n"},{"location":"api/map/#pymaplibregl.ipywidget.MapWidget.add_layer","title":"add_layer(layer)","text":"Add a layer to the map Parameters: Name Type Description Default layer Layer | dict The Layer to be added to the map. required Source code in pymaplibregl/map.py def add_layer(self, layer: [Layer | dict]) -> None:\n \"\"\"Add a layer to the map\n\n Args:\n layer (Layer | dict): The Layer to be added to the map.\n \"\"\"\n if isinstance(layer, Layer):\n layer = layer.to_dict()\n\n self.add_call(\"addLayer\", layer)\n"},{"location":"api/map/#pymaplibregl.ipywidget.MapWidget.add_marker","title":"add_marker(marker)","text":"Add a marker to the map Parameters: Name Type Description Default marker Marker The marker to be added to the map. required Source code in pymaplibregl/map.py def add_marker(self, marker: Marker) -> None:\n \"\"\"Add a marker to the map\n\n Args:\n marker (Marker): The marker to be added to the map.\n \"\"\"\n self.add_call(\"addMarker\", marker.to_dict())\n"},{"location":"api/map/#pymaplibregl.ipywidget.MapWidget.add_popup","title":"add_popup(layer_id, prop)","text":"Add a popup to the map Parameters: Name Type Description Default layer_id str The layer to which the popup is added. required prop str The property of the source to be displayed. required Source code in pymaplibregl/map.py def add_popup(self, layer_id: str, prop: str) -> None:\n \"\"\"Add a popup to the map\n\n Args:\n layer_id (str): The layer to which the popup is added.\n prop (str): The property of the source to be displayed.\n \"\"\"\n self.add_call(\"addPopup\", layer_id, prop)\n"},{"location":"api/map/#pymaplibregl.ipywidget.MapWidget.add_source","title":"add_source(id, source)","text":"Add a source to the map Source code in pymaplibregl/map.py def add_source(self, id: str, source: [Source | dict]) -> None:\n \"\"\"Add a source to the map\"\"\"\n if isinstance(source, Source):\n source = source.to_dict()\n\n self.add_call(\"addSource\", id, source)\n"},{"location":"api/map/#pymaplibregl.ipywidget.MapWidget.add_tooltip","title":"add_tooltip(layer_id, prop)","text":"Add a tooltip to the map Parameters: Name Type Description Default layer_id str The layer to which the tooltip is added. required prop str The property of the source to be displayed. required Source code in pymaplibregl/map.py def add_tooltip(self, layer_id: str, prop: str) -> None:\n \"\"\"Add a tooltip to the map\n\n Args:\n layer_id (str): The layer to which the tooltip is added.\n prop (str): The property of the source to be displayed.\n \"\"\"\n self.add_call(\"addTooltip\", layer_id, prop)\n"},{"location":"api/map/#pymaplibregl.ipywidget.MapWidget.set_filter","title":"set_filter(layer_id, filter_)","text":"Update the filter of a layer Parameters: Name Type Description Default layer_id str The name of the layer to be updated. required filter_ list The filter expression that is applied to the source of the layer. required Source code in pymaplibregl/map.py def set_filter(self, layer_id: str, filter_: list):\n \"\"\"Update the filter of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n filter_ (list): The filter expression that is applied to the source of the layer.\n \"\"\"\n self.add_call(\"setFilter\", layer_id, filter_)\n"},{"location":"api/map/#pymaplibregl.ipywidget.MapWidget.set_layout_property","title":"set_layout_property(layer_id, prop, value)","text":"Update a layout property of a layer Parameters: Name Type Description Default layer_id str The name of the layer to be updated. required prop str The name of the layout property to be updated. required value any The new value of the layout property. required Source code in pymaplibregl/map.py def set_layout_property(self, layer_id: str, prop: str, value: any) -> None:\n \"\"\"Update a layout property of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n prop (str): The name of the layout property to be updated.\n value (any): The new value of the layout property.\n \"\"\"\n self.add_call(\"setLayoutProperty\", layer_id, prop, value)\n"},{"location":"api/map/#pymaplibregl.ipywidget.MapWidget.set_paint_property","title":"set_paint_property(layer_id, prop, value)","text":"Update the paint property of a layer Parameters: Name Type Description Default layer_id str The name of the layer to be updated. required prop str The name of the paint property to be updated. required value any The new value of the paint property. required Source code in pymaplibregl/map.py def set_paint_property(self, layer_id: str, prop: str, value: any) -> None:\n \"\"\"Update the paint property of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n prop (str): The name of the paint property to be updated.\n value (any): The new value of the paint property.\n \"\"\"\n self.add_call(\"setPaintProperty\", layer_id, prop, value)\n"},{"location":"api/map/#pymaplibregl.ipywidget.MapWidget.to_html","title":"to_html(**kwargs)","text":"Render to html Parameters: Name Type Description Default **kwargs Any Additional keyword arguments that are passed to the template. Currently, style is the only supported keyword argument. {} Examples: >>> from pymaplibregl import Map\n >>> map = Map()\n>>> with open(\"/tmp/map.html\", \"w\") as f:\n... f.write(map.to_html(style=\"height: 800px;\")\n Source code in pymaplibregl/map.py def to_html(self, **kwargs) -> str:\n \"\"\"Render to html\n\n Args:\n **kwargs (Any): Additional keyword arguments that are passed to the template.\n Currently, `style` is the only supported keyword argument.\n\n Examples:\n >>> from pymaplibregl import Map\n\n >>> map = Map()\n >>> with open(\"/tmp/map.html\", \"w\") as f:\n ... f.write(map.to_html(style=\"height: 800px;\") # doctest: +SKIP\n \"\"\"\n js_lib = read_internal_file(\"srcjs\", \"index.js\")\n js_snippet = Template(js_template).render(data=json.dumps(self.to_dict()))\n output = Template(html_template).render(\n js=\"\\n\".join([js_lib, js_snippet]), **kwargs\n )\n return output\n"},{"location":"api/sources/","title":"Sources","text":""},{"location":"api/sources/#pymaplibregl.sources","title":"pymaplibregl.sources","text":""},{"location":"api/sources/#pymaplibregl.sources.GeoJSONSource","title":"GeoJSONSource","text":" Bases: Source GeoJSON Source Examples: >>> from pymaplibregl.sources import GeoJSONSource\n >>> source = GeoJSONSource(data=\"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\")\n Source code in pymaplibregl/sources.py class GeoJSONSource(Source):\n \"\"\"GeoJSON Source\n\n Examples:\n >>> from pymaplibregl.sources import GeoJSONSource\n\n >>> source = GeoJSONSource(data=\"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\")\n \"\"\"\n\n data: Union[str, dict]\n attribution: str = None\n buffer: int = None\n cluster: bool = None\n cluster_max_zoom: int = Field(None, serialization_alias=\"clusterMaxZoom\")\n cluster_min_points: int = Field(None, serialization_alias=\"clusterMinPoints\")\n cluster_properties: dict = Field(None, serialization_alias=\"clusterProperties\")\n cluster_radius: int = Field(None, serialization_alias=\"clusterRadius\")\n filter: list = None\n generate_id: bool = Field(None, serialization_alias=\"generateId\")\n line_metrics: bool = Field(None, serialization_alias=\"lineMetrics\")\n maxzoom: int = None\n promote_id: Union[str, dict] = Field(None, serialization_alias=\"promoteId\")\n tolerance: float = None\n\n @computed_field\n @property\n def type(self) -> str:\n return SourceType.GEOJSON.value\n"},{"location":"api/sources/#pymaplibregl.sources.RasterTileSource","title":"RasterTileSource","text":" Bases: Source Raster tile source Examples: >>> from pymaplibregl.sources import RasterTileSource\n>>> raster_source = RasterTileSource(\n... tiles=[\"https://tile.openstreetmap.org/{z}/{x}/{y}.png\"],\n... tile_size=256,\n... min_zoom=0,\n... max_zoom=19,\n... )\n Source code in pymaplibregl/sources.py class RasterTileSource(Source):\n \"\"\"Raster tile source\n\n Examples:\n >>> from pymaplibregl.sources import RasterTileSource\n >>> raster_source = RasterTileSource(\n ... tiles=[\"https://tile.openstreetmap.org/{z}/{x}/{y}.png\"],\n ... tile_size=256,\n ... min_zoom=0,\n ... max_zoom=19,\n ... )\n \"\"\"\n\n attribution: str = None\n bounds: tuple = None\n max_zoom: int = Field(None, serialization_alias=\"maxzoom\")\n min_zoom: int = Field(None, serialization_alias=\"minzoom\")\n scheme: str = None\n tile_size: int = Field(None, serialization_alias=\"tileSize\")\n tiles: Union[tuple, list] = None\n url: str = None\n volatile: bool = None\n\n @computed_field\n @property\n def type(self) -> str:\n return SourceType.RASTER.value\n"},{"location":"api/sources/#pymaplibregl.sources.SourceType","title":"SourceType","text":" Bases: Enum Source types Source code in pymaplibregl/sources.py class SourceType(Enum):\n \"\"\"Source types\"\"\"\n\n RASTER = \"raster\"\n VECTOR = \"vector\"\n RASTER_DEM = \"raster-dem\"\n GEOJSON = \"geojson\"\n IMAGE = \"image\"\n VIDEO = \"video\"\n"},{"location":"examples/3d_indoor_mapping/","title":"3D Indoor mapping","text":"import webbrowser\n\nfrom pymaplibregl import Layer, LayerType, Map, MapOptions\nfrom pymaplibregl.basemaps import background\nfrom pymaplibregl.sources import GeoJSONSource, RasterTileSource\n\nTEMP_FILE = \"/tmp/pymaplibregl_temp.html\"\nFLOORPLAN_SOURCE_ID = \"floorplan\"\n\nraster_source = RasterTileSource(\n tiles=[\"https://tile.openstreetmap.org/{z}/{x}/{y}.png\"],\n tile_size=256,\n min_zoom=0,\n max_zoom=19,\n)\n\nraster_layer = Layer(type=LayerType.RASTER, source=raster_source)\n\nfloorplan_source = GeoJSONSource(\n data=\"https://maplibre.org/maplibre-gl-js/docs/assets/indoor-3d-map.geojson\"\n)\n\nfloorplan_layer = Layer(\n type=LayerType.FILL_EXTRUSION,\n id=\"floorplan\",\n source=FLOORPLAN_SOURCE_ID,\n paint={\n \"fill-extrusion-color\": [\"get\", \"color\"],\n \"fill-extrusion-height\": [\"get\", \"height\"],\n \"fill-extrusion-base\": [\"get\", \"base_height\"],\n \"fill-extrusion-opacity\": 0.5,\n },\n)\n\nmap_options = MapOptions(\n style=background(\"yellow\"),\n center=(-87.61694, 41.86625),\n zoom=17,\n pitch=40,\n bearing=20,\n antialias=True,\n)\n\n\ndef create_map():\n m = Map(map_options)\n m.add_layer(raster_layer)\n m.add_source(FLOORPLAN_SOURCE_ID, floorplan_source)\n m.add_layer(floorplan_layer)\n return m\n\n\nif __name__ == \"__main__\":\n m = create_map()\n with open(TEMP_FILE, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(TEMP_FILE)\n Run example: poetry run python docs/examples/3d_indoor_mapping/app.py\n"},{"location":"examples/airports/","title":"Airport markers","text":"import pandas as pd\nfrom pymaplibregl import (\n Layer,\n LayerType,\n Map,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom pymaplibregl.basemaps import Carto\nfrom pymaplibregl.controls import Marker, MarkerOptions, Popup, PopupOptions\nfrom pymaplibregl.sources import GeoJSONSource\nfrom pymaplibregl.utils import GeometryType, df_to_geojson\nfrom shiny import App, ui\n\nBOUNDS = (-8.92242886, 43.30508298, 13.76496714, 59.87668996)\n\nairports_data = pd.read_json(\n \"https://github.com/visgl/deck.gl-data/raw/master/examples/line/airports.json\"\n)\n\n\ndef get_color(airport_type: str) -> str:\n color = \"darkblue\"\n if airport_type == \"mid\":\n color = \"darkred\"\n elif airport_type == \"major\":\n color = \"darkgreen\"\n\n return color\n\n\ngeojson = df_to_geojson(\n airports_data,\n \"coordinates\",\n GeometryType.POINT,\n properties=[\"type\", \"name\", \"abbrev\"],\n)\n\nairport_circles = Layer(\n type=LayerType.CIRCLE,\n source=GeoJSONSource(data=geojson),\n paint={\n \"circle-color\": [\n \"match\",\n [\"get\", \"type\"],\n \"mid\",\n \"darkred\",\n \"major\",\n \"darkgreen\",\n \"darkblue\",\n ],\n \"circle_radius\": 10,\n \"circle-opacity\": 0.3,\n },\n)\n\nmap_options = MapOptions(\n style=Carto.POSITRON,\n bounds=BOUNDS,\n fit_bounds_options={\"padding\": 20},\n hash=True,\n)\n\npopup_options = PopupOptions(close_button=False)\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Airports\"),\n output_maplibregl(\"maplibre\", height=600),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n async def maplibre():\n m = Map(map_options)\n for _, r in airports_data.iterrows():\n marker = Marker(\n lng_lat=r[\"coordinates\"],\n options=MarkerOptions(color=get_color(r[\"type\"])),\n popup=Popup(\n text=r[\"name\"],\n options=popup_options,\n ),\n )\n m.add_marker(marker)\n m.add_layer(airport_circles)\n return m\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n app.run()\n Run example: poetry run uvicorn docs.examples.airports.app:app --reload\n"},{"location":"examples/custom_basemap/","title":"Custom basemap","text":"import webbrowser\n\nfrom pymaplibregl import Layer, LayerType, Map, MapOptions\nfrom pymaplibregl.basemaps import construct_basemap_style\nfrom pymaplibregl.sources import GeoJSONSource\n\nTEMP_FILE = \"/tmp/pymaplibregl_temp.html\"\n\nbg_layer = Layer(\n type=LayerType.BACKGROUND,\n id=\"background\",\n source=None,\n paint={\"background-color\": \"darkblue\", \"background-opacity\": 0.8},\n)\n\ncountries_source = GeoJSONSource(\n data=\"https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_110m_admin_0_countries.geojson\"\n)\n\nlines_layer = Layer(\n type=LayerType.LINE,\n source=\"countries\",\n paint={\"line-color\": \"white\", \"line-width\": 1.5},\n)\n\npolygons_layer = Layer(\n type=LayerType.FILL,\n source=\"countries\",\n paint={\"fill-color\": \"darkred\", \"fill-opacity\": 0.8},\n)\n\ncustom_basemap = construct_basemap_style(\n layers=[bg_layer, polygons_layer, lines_layer],\n sources={\"countries\": countries_source},\n)\n\n\nmap_options = MapOptions(\n style=custom_basemap,\n center=(0, 0),\n zoom=2,\n)\n\n\ndef create_map():\n m = Map(map_options)\n m.add_layer(\n Layer(\n type=LayerType.CIRCLE,\n id=\"earthquakes\",\n source=GeoJSONSource(\n data=\"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n ),\n paint={\"circle-color\": \"yellow\", \"circle-radius\": 5},\n )\n )\n m.add_popup(\"earthquakes\", \"mag\")\n return m\n\n\nif __name__ == \"__main__\":\n m = create_map()\n with open(TEMP_FILE, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(TEMP_FILE)\n Run example: poetry run python docs/examples/custom_basemap/app.py\n"},{"location":"examples/earthquake_clusters/","title":"Earthquake clusters","text":"from pymaplibregl import (\n Layer,\n LayerType,\n Map,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom pymaplibregl.basemaps import Carto\nfrom pymaplibregl.sources import GeoJSONSource\nfrom shiny import App, reactive, ui\n\nEARTHQUAKE_SOURCE = \"earthquakes\"\nEARTHQUAKE_CIRCLES = \"earthquake-circles\"\nEARTHQUAKE_CLUSTERS = \"earthquake-clusters\"\nEARTHQUAKE_LABELS = \"earthquake-labels\"\n\nCENTER = (-118.0931, 33.78615)\n\nearthquakes_source = GeoJSONSource(\n data=\"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\",\n cluster=True,\n cluster_radius=50,\n cluster_min_points=2,\n cluster_max_zoom=14,\n cluster_properties={\n \"maxMag\": [\"max\", [\"get\", \"mag\"]],\n \"minMag\": [\"min\", [\"get\", \"mag\"]],\n },\n)\n\nearthquake_circles = Layer(\n type=LayerType.CIRCLE,\n id=EARTHQUAKE_CIRCLES,\n source=EARTHQUAKE_SOURCE,\n paint={\"circle-color\": \"darkblue\"},\n filter=[\"!\", [\"has\", \"point_count\"]],\n)\n\nearthquake_clusters = Layer(\n type=LayerType.CIRCLE,\n id=EARTHQUAKE_CLUSTERS,\n source=EARTHQUAKE_SOURCE,\n filter=[\"has\", \"point_count\"],\n paint={\n \"circle-color\": [\n \"step\",\n [\"get\", \"point_count\"],\n \"#51bbd6\",\n 100,\n \"#f1f075\",\n 750,\n \"#f28cb1\",\n ],\n \"circle-radius\": [\"step\", [\"get\", \"point_count\"], 20, 100, 30, 750, 40],\n },\n)\n\nearthquake_labels = Layer(\n type=LayerType.SYMBOL,\n id=\"text\",\n source=EARTHQUAKE_SOURCE,\n filter=[\"has\", \"point_count\"],\n layout={\n \"text-field\": [\"get\", \"point_count_abbreviated\"],\n \"text-size\": 12,\n },\n)\n\nmap_options = MapOptions(style=Carto.POSITRON, center=CENTER, zoom=3, hash=True)\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Earthquakes Cluster\"),\n output_maplibregl(\"maplibre\", height=500),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre():\n m = Map(map_options)\n m.add_source(EARTHQUAKE_SOURCE, earthquakes_source)\n m.add_layer(earthquake_clusters)\n m.add_layer(earthquake_circles)\n m.add_tooltip(EARTHQUAKE_CLUSTERS, \"maxMag\")\n m.add_layer(earthquake_labels)\n return m\n\n @reactive.Effect\n @reactive.event(input.maplibre)\n async def result():\n print(f\"result: {input.maplibre()}\")\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n app.run()\n Run example: poetry run uvicorn docs.examples.earthquake_clusters.app:app --reload\n"},{"location":"examples/every_person_in_manhattan/","title":"Every person in manhattan","text":"import json\n\nimport pandas as pd\nimport shapely\nfrom pymaplibregl import (\n Layer,\n LayerType,\n Map,\n MapContext,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom pymaplibregl.basemaps import Carto\nfrom pymaplibregl.controls import ScaleControl\nfrom pymaplibregl.sources import GeoJSONSource\nfrom pymaplibregl.utils import df_to_geojson\nfrom shiny import App, reactive, ui\n\nMALE_COLOR = \"rgb(0, 128, 255)\"\nFEMALE_COLOR = \"rgb(255, 0, 128)\"\nLAYER_ID = \"every-person-in-manhattan-circles\"\nCIRCLE_RADIUS = 2\n\npoint_data = pd.read_json(\n \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/scatterplot/manhattan.json\"\n)\n\npoint_data.columns = [\"lng\", \"lat\", \"sex\"]\n\nevery_person_in_manhattan_source = GeoJSONSource(\n data=df_to_geojson(point_data, properties=[\"sex\"]),\n)\n\nbbox = shapely.bounds(\n shapely.from_geojson(json.dumps(every_person_in_manhattan_source.data))\n)\n\nevery_person_in_manhattan_circles = Layer(\n type=LayerType.CIRCLE,\n id=LAYER_ID,\n source=every_person_in_manhattan_source,\n paint={\n \"circle-color\": [\"match\", [\"get\", \"sex\"], 1, MALE_COLOR, FEMALE_COLOR],\n \"circle-radius\": CIRCLE_RADIUS,\n },\n)\n\nmap_options = MapOptions(\n style=Carto.POSITRON,\n bounds=tuple(bbox),\n fit_bounds_options={\"padding\": 20},\n)\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Every Person in Manhattan\"),\n output_maplibregl(\"maplibre\", height=600),\n ui.input_slider(\"radius\", \"Radius\", value=CIRCLE_RADIUS, min=1, max=5),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre():\n m = Map(map_options)\n m.add_control(ScaleControl(), position=\"bottom-left\")\n m.add_layer(every_person_in_manhattan_circles)\n return m\n\n @reactive.Effect\n @reactive.event(input.radius, ignore_init=True)\n async def radius():\n async with MapContext(\"maplibre\") as m:\n m.set_paint_property(LAYER_ID, \"circle-radius\", input.radius())\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n app.run()\n Run example: poetry run uvicorn docs.examples.every_person_in_manhattan.app:app --reload\n"},{"location":"examples/vancouver_blocks/","title":"Vancouver property value","text":"from pymaplibregl import (\n Layer,\n LayerType,\n Map,\n MapContext,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom pymaplibregl.basemaps import Carto\nfrom pymaplibregl.controls import ScaleControl\nfrom pymaplibregl.sources import GeoJSONSource\nfrom shiny import App, reactive, ui\n\nSOURCE_ID = \"vancouver-blocks\"\nLAYER_ID_LINES = \"vancouver-blocks-lines\"\nLAYER_ID_FILL = \"vancouver-blocks-fill-extrusion\"\nMAX_FILTER_VALUE = 1000000\n\nvancouver_blocks_source = GeoJSONSource(\n data=\"https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/geojson/vancouver-blocks.json\"\n)\n\nvancouver_blocks_lines = Layer(\n type=LayerType.LINE,\n id=LAYER_ID_LINES,\n source=SOURCE_ID,\n paint={\n \"line-color\": \"white\",\n \"line-width\": 2,\n },\n)\n\nvancouver_blocks_fill = Layer(\n type=LayerType.FILL_EXTRUSION,\n id=LAYER_ID_FILL,\n source=SOURCE_ID,\n paint={\n \"fill-extrusion-color\": {\n \"property\": \"valuePerSqm\",\n \"stops\": [\n [0, \"grey\"],\n [1000, \"yellow\"],\n [5000, \"orange\"],\n [10000, \"red\"],\n [50000, \"darkred\"],\n ],\n },\n \"fill-extrusion-height\": [\"*\", 10, [\"sqrt\", [\"get\", \"valuePerSqm\"]]],\n \"fill-extrusion-opacity\": 0.9,\n },\n)\n\nmap_options = MapOptions(\n style=Carto.DARK_MATTER,\n center=(-123.13, 49.254),\n zoom=11,\n pitch=45,\n bearing=0,\n)\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Vancouver Property Value\"),\n ui.div(\n \"Height of polygons - average property value per square meter of lot\",\n style=\"padding: 10px;\",\n ),\n output_maplibregl(\"maplibre\", height=700),\n ui.input_select(\n \"filter\",\n \"max property value per square meter\",\n choices=[0, 1000, 5000, 10000, 50000, 100000, MAX_FILTER_VALUE],\n selected=MAX_FILTER_VALUE,\n ),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre():\n m = Map(map_options)\n m.add_control(ScaleControl(), position=\"bottom-left\")\n m.add_source(SOURCE_ID, vancouver_blocks_source)\n m.add_layer(vancouver_blocks_lines)\n m.add_layer(vancouver_blocks_fill)\n m.add_tooltip(LAYER_ID_FILL, \"valuePerSqm\")\n return m\n\n @reactive.Effect\n @reactive.event(input.filter)\n async def filter():\n async with MapContext(\"maplibre\") as m:\n filter_ = [\"<=\", [\"get\", \"valuePerSqm\"], int(input.filter())]\n m.set_filter(LAYER_ID_FILL, filter_)\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n app.run()\n Run example: poetry run uvicorn docs.examples.vancouver_blocks.app:app --reload\n"}]} \ No newline at end of file diff --git a/shiny/index.html b/shiny/index.html new file mode 100644 index 00000000..ac52508a --- /dev/null +++ b/shiny/index.html @@ -0,0 +1,1122 @@ + + + + + + + + + + + + + + + + + + + + + + + Shiny - py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + + + + + + + + + + + + + + + + + + + + + + + + + + + py-maplibregl + + + + + + Shiny + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Initializing search + + + + + + + + + + + + + + + + + py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + + + Get started + + + + + + + + + + + + + + + + + + API Documentation + + + + + + + + + + + + + + + + + + Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + py-maplibregl + + + + + + + + + + py-maplibregl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get started + + + + + + + + + + Get started + + + + + + + + + + + + + + + Welcome to py-maplibregl + + + + + + + + + + + + + + + + + + + + + Layers + + + + + + + + + + + + + + + + + + + + + + + + + + + + Shiny + + + + + + + + + + + Shiny + + + + + + + + + + + + + + + Table of contents + + + + + + + Adding UI output + + + + + + + + + Adding server logic + + + + + + + + + Reactivity + + + + + + + + + + Inputs + + + + + + + + + Updates + + + + + + + + + Example using inputs and updates + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Jupyter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + API Documentation + + + + + + + + + + API Documentation + + + + + + + + + + + + + + + Map + + + + + + + + + + + + + + + + + + + + + Layer + + + + + + + + + + + + + + + + + + + + + Sources + + + + + + + + + + + + + + + + + + + + + Basemaps + + + + + + + + + + + + + + + + + + + + + Markers and controls + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Examples + + + + + + + + + + Examples + + + + + + + + + + + + + + + Every person in manhattan + + + + + + + + + + + + + + + + + + + + + Vancouver property value + + + + + + + + + + + + + + + + + + + + + Earthquake clusters + + + + + + + + + + + + + + + + + + + + + Airport markers + + + + + + + + + + + + + + + + + + + + + 3D Indoor mapping + + + + + + + + + + + + + + + + + + + + + Custom basemap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Table of contents + + + + + + + Adding UI output + + + + + + + + + Adding server logic + + + + + + + + + Reactivity + + + + + + + + + + Inputs + + + + + + + + + Updates + + + + + + + + + Example using inputs and updates + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Shiny + +py-maplibregl integrates seamlessly into py-shiny. +Adding UI output +from shiny import App, ui +from pymaplibregl import output_maplibregl + +app_ui = ui.page_fluid( + ui.panel_title("MapLibre"), + output_maplibregl("maplibre", height=600) +) + +def server(input, output, session): + pass + +app = App(app_ui, server) + +Adding server logic +from shiny import App, ui +from pymaplibregl import output_maplibregl, render_maplibregl, Map + +app_ui = ui.page_fluid( + ui.panel_title("MapLibre"), + output_maplibregl("maplibre", height=600) +) + +def server(input, output, session): + @render_maplibregl + def maplibre(): + m = Map() + return m + +app = App(app_ui, server) + +Reactivity +Inputs +py-maplibregl provides the following reactive inputs: + +map-on-click event: Sends the coordinates of the location that was clicked on. The name of the input event corresponds to the output id. + For output_maplibregl("maplibre") you need to listen to input.maplibre. +feature-on-click event: Sends the properties of the feature that was clicked on. The name of the ìnput is made up of the output id + layer + layer id. + For output_maplibregl("maplibre") and a layer with id=test you need to listen to input.maplibre_layer_test. + +Updates +Use MapContext to update your map object. +Example using inputs and updates +from pymaplibregl import ( + Layer, + LayerType, + Map, + MapContext, + output_maplibregl, + render_maplibregl, +) +from pymaplibregl.sources import GeoJSONSource +from shiny import App, reactive, render, ui + +LAYER_ID = "earthquakes" +CIRCLE_RADIUS = 5 + +app_ui = ui.page_fluid( + # + # Render map + # + ui.panel_title("MapLibre"), + output_maplibregl("maplibre", height=600), + # + # Show coords + # + ui.div("Click on the map to print the coords.", style="padding: 10px;"), + ui.output_text_verbatim("coords", placeholder=True), + # + # Show props of a feature + # + ui.div("Click on a feature to print its props.", style="padding: 10px;"), + ui.output_text_verbatim("props", placeholder=True), + # + # Change radius + # + ui.input_slider("radius", "Radius", value=CIRCLE_RADIUS, min=1, max=10), +) + + +def server(input, output, session): + @render_maplibregl + def maplibre(): + m = Map(zoom=3) + m.add_layer( + Layer( + type=LayerType.CIRCLE, + id=LAYER_ID, + source=GeoJSONSource( + data="https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson" + ), + paint={"circle-color": "yellow"}, + ) + ) + return m + + @render.text + def coords(): + return str(input.maplibre()) + + @render.text + def props(): + return str(input.maplibre_layer_earthquakes()) + + @reactive.Effect + @reactive.event(input.radius) + async def radius(): + async with MapContext("maplibre") as m: + m.set_paint_property(LAYER_ID, "circle-radius", input.radius()) + + +app = App(app_ui, server) + +Run this example: +poetry run uvicorn docs.examples.getting_started.reactivity:app --reload + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index 96f27352..426fc52e 100644 Binary files a/sitemap.xml.gz and b/sitemap.xml.gz differ
+ + + + + + + + Vancouver property value + +from pymaplibregl import ( + Layer, + LayerType, + Map, + MapContext, + MapOptions, + output_maplibregl, + render_maplibregl, +) +from pymaplibregl.basemaps import Carto +from pymaplibregl.controls import ScaleControl +from pymaplibregl.sources import GeoJSONSource +from shiny import App, reactive, ui + +SOURCE_ID = "vancouver-blocks" +LAYER_ID_LINES = "vancouver-blocks-lines" +LAYER_ID_FILL = "vancouver-blocks-fill-extrusion" +MAX_FILTER_VALUE = 1000000 + +vancouver_blocks_source = GeoJSONSource( + data="https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/geojson/vancouver-blocks.json" +) + +vancouver_blocks_lines = Layer( + type=LayerType.LINE, + id=LAYER_ID_LINES, + source=SOURCE_ID, + paint={ + "line-color": "white", + "line-width": 2, + }, +) + +vancouver_blocks_fill = Layer( + type=LayerType.FILL_EXTRUSION, + id=LAYER_ID_FILL, + source=SOURCE_ID, + paint={ + "fill-extrusion-color": { + "property": "valuePerSqm", + "stops": [ + [0, "grey"], + [1000, "yellow"], + [5000, "orange"], + [10000, "red"], + [50000, "darkred"], + ], + }, + "fill-extrusion-height": ["*", 10, ["sqrt", ["get", "valuePerSqm"]]], + "fill-extrusion-opacity": 0.9, + }, +) + +map_options = MapOptions( + style=Carto.DARK_MATTER, + center=(-123.13, 49.254), + zoom=11, + pitch=45, + bearing=0, +) + +app_ui = ui.page_fluid( + ui.panel_title("Vancouver Property Value"), + ui.div( + "Height of polygons - average property value per square meter of lot", + style="padding: 10px;", + ), + output_maplibregl("maplibre", height=700), + ui.input_select( + "filter", + "max property value per square meter", + choices=[0, 1000, 5000, 10000, 50000, 100000, MAX_FILTER_VALUE], + selected=MAX_FILTER_VALUE, + ), +) + + +def server(input, output, session): + @render_maplibregl + def maplibre(): + m = Map(map_options) + m.add_control(ScaleControl(), position="bottom-left") + m.add_source(SOURCE_ID, vancouver_blocks_source) + m.add_layer(vancouver_blocks_lines) + m.add_layer(vancouver_blocks_fill) + m.add_tooltip(LAYER_ID_FILL, "valuePerSqm") + return m + + @reactive.Effect + @reactive.event(input.filter) + async def filter(): + async with MapContext("maplibre") as m: + filter_ = ["<=", ["get", "valuePerSqm"], int(input.filter())] + m.set_filter(LAYER_ID_FILL, filter_) + + +app = App(app_ui, server) + +if __name__ == "__main__": + app.run() + +Run example: +poetry run uvicorn docs.examples.vancouver_blocks.app:app --reload + + + + + + + + + + + + + + +
+ + + + + + + + Jupyter + +Use MapWidget in your Juyper Notebook. +import ipywidgets as widgets + +from pymaplibregl import MapOptions, Layer, LayerType +from pymaplibregl.sources import GeoJSONSource +from pymaplibregl.controls import ScaleControl, Marker +from pymaplibregl.ipywidget import MapWidget as Map + +# Create a source +earthquakes = GeoJSONSource( + data="https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson" +) + +# Creat a layer +layer_id = "earthquakes" + +earthquake_circles = Layer( + type=LayerType.CIRCLE, + id=layer_id, + source=earthquakes, + paint={"circle-color": "yellow"} +) + +# Render map +m = Map() +m.add_control(ScaleControl(), position="bottom-left") +m.add_layer(earthquake_circles) +m.add_tooltip(layer_id, "mag") +m.add_marker(Marker(lng_lat=(100.507, 13.745))) +m + +# Change radius +widgets.interact( + lambda radius: m.set_paint_property(layer_id, "circle-radius", radius), + radius=5 +) + +# Change color +widgets.interact( + lambda color: m.set_paint_property(layer_id, "circle-color", color), + color=["green", "yellow", "orange", "red"] +) + +# Set filter on magnitude +widgets.interact( + lambda mag_min: m.set_filter(layer_id, [">=", ["get", "mag"], mag_min]), + mag_min=3 +) + +# Observe map-on-click event +from IPython.display import clear_output + +output = widgets.Output() + +def log_lng_lat(lng_lat): + with output: + clear_output() + print(lng_lat.new) + + +m.observe(log_lng_lat, names="lng_lat") +output + + + + + + + + + + + + + + +
+ + + + + + + + Layers + +The paint and layout properties for the layers depend on the type of the layer. +They are passed as a dict corresponding to the Layer Style Spec. +For example, to set the radius and the color for a circle layer, the paint property looks like this: +paint = { + "circle-radius": 5, + "circle-color": "yellow" +} + +The value for any layout property, paint property, or filter may also be specified as an expression. +For details see Expressions. +For example, if the source of your layer has a color property that contains the color of the feature, +you can use the following expression: +paint = { + "circle-radius": 5, + "circle-color": ["get", "color"] +} + +A more complex expression where the color depends on the type property of the layer's source might look like this: +paint={ + "circle-color": [ + "match", + ["get", "type"], + # darkred if type == "mid" + "mid", + "darkred", + # darkgreen if type == "major" + "major", + "darkgreen", + # else blue + "darkblue", + ] +} + +Filter features of a source according to its magnitude property: +# Only show features where magnitude >= 5 +filter = [">=", ["get", "magnitude"], 5] + + + + + + + + + + + + + + +
+ + + + + + + + Shiny + +py-maplibregl integrates seamlessly into py-shiny. +Adding UI output +from shiny import App, ui +from pymaplibregl import output_maplibregl + +app_ui = ui.page_fluid( + ui.panel_title("MapLibre"), + output_maplibregl("maplibre", height=600) +) + +def server(input, output, session): + pass + +app = App(app_ui, server) + +Adding server logic +from shiny import App, ui +from pymaplibregl import output_maplibregl, render_maplibregl, Map + +app_ui = ui.page_fluid( + ui.panel_title("MapLibre"), + output_maplibregl("maplibre", height=600) +) + +def server(input, output, session): + @render_maplibregl + def maplibre(): + m = Map() + return m + +app = App(app_ui, server) + +Reactivity +Inputs +py-maplibregl provides the following reactive inputs: + +map-on-click event: Sends the coordinates of the location that was clicked on. The name of the input event corresponds to the output id. + For output_maplibregl("maplibre") you need to listen to input.maplibre. +feature-on-click event: Sends the properties of the feature that was clicked on. The name of the ìnput is made up of the output id + layer + layer id. + For output_maplibregl("maplibre") and a layer with id=test you need to listen to input.maplibre_layer_test. + +Updates +Use MapContext to update your map object. +Example using inputs and updates +from pymaplibregl import ( + Layer, + LayerType, + Map, + MapContext, + output_maplibregl, + render_maplibregl, +) +from pymaplibregl.sources import GeoJSONSource +from shiny import App, reactive, render, ui + +LAYER_ID = "earthquakes" +CIRCLE_RADIUS = 5 + +app_ui = ui.page_fluid( + # + # Render map + # + ui.panel_title("MapLibre"), + output_maplibregl("maplibre", height=600), + # + # Show coords + # + ui.div("Click on the map to print the coords.", style="padding: 10px;"), + ui.output_text_verbatim("coords", placeholder=True), + # + # Show props of a feature + # + ui.div("Click on a feature to print its props.", style="padding: 10px;"), + ui.output_text_verbatim("props", placeholder=True), + # + # Change radius + # + ui.input_slider("radius", "Radius", value=CIRCLE_RADIUS, min=1, max=10), +) + + +def server(input, output, session): + @render_maplibregl + def maplibre(): + m = Map(zoom=3) + m.add_layer( + Layer( + type=LayerType.CIRCLE, + id=LAYER_ID, + source=GeoJSONSource( + data="https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson" + ), + paint={"circle-color": "yellow"}, + ) + ) + return m + + @render.text + def coords(): + return str(input.maplibre()) + + @render.text + def props(): + return str(input.maplibre_layer_earthquakes()) + + @reactive.Effect + @reactive.event(input.radius) + async def radius(): + async with MapContext("maplibre") as m: + m.set_paint_property(LAYER_ID, "circle-radius", input.radius()) + + +app = App(app_ui, server) + +Run this example: +poetry run uvicorn docs.examples.getting_started.reactivity:app --reload + + + + + + + + + + + + + + +