From 187936475356a020499f030a2fab5e7952558248 Mon Sep 17 00:00:00 2001
From: Stefan Kuethe MapLibre for Python provides Python bindings for MapLibre GL JS. It integrates seamlessly into Shiny for Python and Jupyter. Add Add Add Add expression helpers Add support for Add Support Add more parameters to Add Add Shiny Rename Ipywidget Deck.GL layers can be added to the map with They are defined as a dictionary, where classes got the Here is an example corresponding to the Deck.GL GridLayer API Example: The Code above will generate the following JavaScript code: See also: Use The For example, to set the radius and the color for a circle layer, the The value for any For example, if the source of your layer has a A more complex expression where the color depends on the Filter features of a source according to its Use MapLibre for Python provides the following reactive inputs: Use Run this example: In Shiny Express the Use Bases: Carto basemap styles Attributes: dark-matter positron voyager positron-nolabels dark-matter-nolabels voyager-nolabels Examples: Construct a basemap style Parameters: The name of the basemap style. The sources to be used for the basemap style. The layers to be used for the basemap style. Bases: Popup Attributes: The Text of the popup. Popup options. Bases: Popup options Bases: Marker Attributes: Required. The longitude and latitude of the marker. The Popup that is displayed when a user clicks on the marker. Marker options. Bases: Marker options Bases: Control position Attributes: top-left top-right bottom-left bottom-right Bases: Fullscreen control Examples: Bases: Scale control Bases: Navigation control Bases: Geolocate control Bases: InfoBox control Attributes: Content (HTML or plain text) to be displayed in the info box. Optional inline style declaration of the control. Bases: Layer switcher control Attributes: A list of layer ids to be shown in the layer switcher control. The theme of the layer switcher control. Optional inline style declaration of the control. Bases: Layer properties See layers for more details on the Attributes: Required. The unique ID of the layer. Defaults to Required. The type of the layer. A filter expression that is applied to the source of the layer. The layout properties for the layer. The maximum zoom level for the layer. The minimum zoom level for the layer. The paint properties for the layer. The name (unique ID) of a source, a source object or a GeoDataFrame to be used for the layer. The layer to use from a vector tile source. Examples: Bases: Rendering type of layer Attributes: A filled circle. A filled polygon with an optional stroked border. An extruded polygon. A stroked line. An icon or a text label. Raster map textures such as satellite imagery. A heatmap. A Client-side hillshading visualization based on DEM data. A background color or pattern. Bases: Map Parameters: Map options. Sources to be added to the map. Keys are source IDs. Layers to be added to the map. Controls to be added to the map. Keyword arguments that are appended to the Examples: Add a method call that is executed on the map instance Parameters: The name of the map method to be executed. The arguments to be passed to the map method. Add a control to the map Parameters: The control to be added to the map. The position of the control. Add Deck.GL layers to the layer stack Parameters: A list of dictionaries containing the Deck.GL layers to be added. Either a single mustache template string applied to all layers or a dictionary where keys are layer ids and values are mustache template strings. Add a layer to the map Parameters: The Layer to be added to the map. The ID of an existing layer to insert the new layer before, resulting in the new layer appearing visually beneath the existing layer. If Add MapboxDraw controls to the map See MapboxDraw API Reference for available options. Parameters: MapboxDraw options. The position of the MapboxDraw controls. A GeoJSON Feature, FeatureCollection or Geometry to be added to the draw layer. Add a marker to the map Parameters: The marker to be added to the map. Add a popup to the map Parameters: The layer to which the popup is added. The property of the source to be displayed. If A mustache template. If supplied, Add a source to the map Parameters: The unique ID of the source. The source to be added to the map. Add a tooltip to the map Parameters: The layer to which the tooltip is added. The property of the source to be displayed. If A mustache template. If supplied, Examples: Pan and zoom the map to contain its visible area within the specified geographical bounds Save the map to an HTML file Update the data of a GeoJSON source Parameters: The name of the source to be updated. The data of the source. Update Deck.GL layers Parameters: A list of dictionaries containing the Deck.GL layers to be updated. New layers will be added. Missing layers will be removed. Must be set to keep tooltip even if it did not change. Update the filter of a layer Parameters: The name of the layer to be updated. The filter expression that is applied to the source of the layer. Update a layout property of a layer Parameters: The name of the layer to be updated. The name of the layout property to be updated. The new value of the layout property. Update the paint property of a layer Parameters: The name of the layer to be updated. The name of the paint property to be updated. The new value of the paint property. Update the visibility of a layer Parameters: The name of the layer to be updated. Whether the layer is visible or not. Render to html Parameters: The Title of the HTML document. Additional keyword arguments that are passed to the template. Currently, Examples: Bases: Map options See MapOptions for more details. Bases: MapContext Use this class to update a See Parameters: The id of the map to be updated. A Shiny session. If Bases: MapWidget Use this class to display and update maps in Jupyter Notebooks. See Examples: Bases: MapboxDraw controls Bases: MapboxDraw Options Bases: GeoJSON Source Examples: Bases: Raster tile source Examples: Bases: Source types Bases: Vector tile source Examples: Run example: Run example: Run example: Run example: Run example: Run example: Run example: Run example: Add a data layer below the labels of the basemap. Run example: Run example: Run example: Run example: Run example: Run example: Run example: Run example: MapLibre for Python provides Python bindings for MapLibre GL JS. It integrates seamlessly into Shiny for Python and Jupyter. Add Add Add Add expression helpers Add support for Add Support Add more parameters to Add Add Shiny Rename Ipywidget Deck.GL layers can be added to the map with They are defined as a dictionary, where classes got the Here is an example corresponding to the Deck.GL GridLayer API Example: The Code above will generate the following JavaScript code: See also: Use The For example, to set the radius and the color for a circle layer, the The value for any For example, if the source of your layer has a A more complex expression where the color depends on the Filter features of a source according to its Use MapLibre for Python provides the following reactive inputs: Use Run this example: In Shiny Express the Use Bases: Carto basemap styles Attributes: dark-matter positron voyager positron-nolabels dark-matter-nolabels voyager-nolabels Examples: Construct a basemap style Parameters: The name of the basemap style. The sources to be used for the basemap style. The layers to be used for the basemap style. Bases: Popup Attributes: The Text of the popup. Popup options. Bases: Popup options Bases: Marker Attributes: Required. The longitude and latitude of the marker. The Popup that is displayed when a user clicks on the marker. Marker options. Bases: Marker options Bases: Control position Attributes: top-left top-right bottom-left bottom-right Bases: Fullscreen control Examples: Bases: Scale control Bases: Navigation control Bases: Geolocate control Bases: InfoBox control Attributes: Content (HTML or plain text) to be displayed in the info box. Optional inline style declaration of the control. Bases: Layer switcher control Attributes: A list of layer ids to be shown in the layer switcher control. The theme of the layer switcher control. Optional inline style declaration of the control. Bases: Layer properties See layers for more details on the Attributes: Required. The unique ID of the layer. Defaults to Required. The type of the layer. A filter expression that is applied to the source of the layer. The layout properties for the layer. The maximum zoom level for the layer. The minimum zoom level for the layer. The paint properties for the layer. The name (unique ID) of a source, a source object or a GeoDataFrame to be used for the layer. The layer to use from a vector tile source. Examples: Bases: Rendering type of layer Attributes: A filled circle. A filled polygon with an optional stroked border. An extruded polygon. A stroked line. An icon or a text label. Raster map textures such as satellite imagery. A heatmap. A Client-side hillshading visualization based on DEM data. A background color or pattern. Bases: Map Parameters: Map options. Sources to be added to the map. Keys are source IDs. Layers to be added to the map. Controls to be added to the map. Keyword arguments that are appended to the Examples: Add a method call that is executed on the map instance Parameters: The name of the map method to be executed. The arguments to be passed to the map method. Add a control to the map Parameters: The control to be added to the map. The position of the control. Add Deck.GL layers to the layer stack Parameters: A list of dictionaries containing the Deck.GL layers to be added. Either a single mustache template string applied to all layers or a dictionary where keys are layer ids and values are mustache template strings. Add a layer to the map Parameters: The Layer to be added to the map. The ID of an existing layer to insert the new layer before, resulting in the new layer appearing visually beneath the existing layer. If Add MapboxDraw controls to the map See MapboxDraw API Reference for available options. Parameters: MapboxDraw options. The position of the MapboxDraw controls. A GeoJSON Feature, FeatureCollection or Geometry to be added to the draw layer. Add a marker to the map Parameters: The marker to be added to the map. Add a popup to the map Parameters: The layer to which the popup is added. The property of the source to be displayed. If A mustache template. If supplied, Add a source to the map Parameters: The unique ID of the source. The source to be added to the map. Add a tooltip to the map Parameters: The layer to which the tooltip is added. The property of the source to be displayed. If A mustache template. If supplied, Examples: Pan and zoom the map to contain its visible area within the specified geographical bounds Save the map to an HTML file Update the data of a GeoJSON source Parameters: The name of the source to be updated. The data of the source. Update Deck.GL layers Parameters: A list of dictionaries containing the Deck.GL layers to be updated. New layers will be added. Missing layers will be removed. Must be set to keep tooltip even if it did not change. Update the filter of a layer Parameters: The name of the layer to be updated. The filter expression that is applied to the source of the layer. Update a layout property of a layer Parameters: The name of the layer to be updated. The name of the layout property to be updated. The new value of the layout property. Update the paint property of a layer Parameters: The name of the layer to be updated. The name of the paint property to be updated. The new value of the paint property. Update the visibility of a layer Parameters: The name of the layer to be updated. Whether the layer is visible or not. Render to html Parameters: The Title of the HTML document. Additional keyword arguments that are passed to the template. Currently, Examples: Bases: Map options See MapOptions for more details. Bases: MapContext Use this class to update a See Parameters: The id of the map to be updated. A Shiny session. If Bases: MapWidget Use this class to display and update maps in Jupyter Notebooks. See Examples: Bases: MapboxDraw controls Bases: MapboxDraw Options Bases: GeoJSON Source Examples: Bases: Raster tile source Examples: Bases: Source types Bases: Vector tile source Examples: Run example: Run example: Run example: Run example: Run example: Run example: Run example: Run example: Add a data layer below the labels of the basemap. Run example: Run example: Run example: Run example: Run example: Run example: Run example: Run example:
"},{"location":"#basic-usage","title":"Basic usage","text":""},{"location":"#standalone","title":"Standalone","text":"# Stable\npip install maplibre\n\npip install \"maplibre[all]\"\n\n# Dev\npip install git+https://github.com/eoda-dev/py-maplibregl@dev\n
"},{"location":"#shiny-integration","title":"Shiny integration","text":"from maplibre import Layer, LayerType, Map, MapOptions\nfrom maplibre.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\nm.save(preview=True)\n
"},{"location":"#jupyter-widget","title":"Jupyter widget","text":"from maplibre import Map, MapContext, output_maplibregl, render_maplibregl\nfrom maplibre.controls import Marker\nfrom shiny import App, reactive, ui\n\napp_ui = ui.page_fluid(\n output_maplibregl(\"maplibre_map\", height=600),\n ui.div(\"Click on map to set a marker\"),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre_map():\n return Map()\n\n @reactive.Effect\n @reactive.event(input.maplibre_map_clicked)\n async def coords():\n async with MapContext(\"maplibre_map\") as m:\n input_value = input.maplibre_map_clicked()\n print(input_value)\n lng_lat = tuple(input_value[\"coords\"].values())\n marker = Marker(lng_lat=lng_lat)\n m.add_marker(marker)\n m.add_call(\"flyTo\", {\"center\": lng_lat})\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n app.run()\n
"},{"location":"changelog/","title":"Changelog for MapLibre for Python","text":""},{"location":"changelog/#maplibre-v027","title":"maplibre v0.2.7","text":"from maplibre.ipywidget import MapWidget as Map\n\nm = Map()\nm\n
"},{"location":"changelog/#maplibre-v026","title":"maplibre v0.2.6","text":"basemaps.MapTiler
maplibre.__future__
Map.fit_bounds
maplibre.expressions
:interpolate
step_expr
quantile_expr
match_expr
color_step_expr
color_quantile_expr
color_match_expr
filter_expr
range_filter
pydeck.Layer
forMap.add_deck_layers
and Map.set_deck_layers
sources.SimpleFeatures
for geopandas.GeoDataFrame
sources geopandas.GeoDataFrame
as source inLayer
andMap.add_source
Map
class for simpler map initialization:layers
: listsources
: dictcontrols
: listposition
attribute to Control
classessources.VectorTileSource
(Martenz)input.{output_id}_view_state
dict containing {\"center\", \"zoom\", \"bounds\", \"pitch\", \"bearing\"}
input.{output_id}
to input.{output_id}_clicked
input.{output_id}_layer_{layer_id}
to input.{output_id}_feature_clicked
returning layer_id
Map.view_state
dict containing {\"center\", \"zoom\", \"bounds\", \"pitch\", \"bearing\"}
(#89)Map.center
, Map.zoom
, Map.bounds
"},{"location":"changelog/#maplibre-v025","title":"maplibre v0.2.5","text":"maplibre.utils
to save map and display it in the browserstreamlit.components.v1.iframe
component
"},{"location":"changelog/#maplibre-v024","title":"maplibre v0.2.4","text":"LayerSwitcherControl
(#69)InfoBoxControl
(#74)
"},{"location":"changelog/#maplibre-v023","title":"maplibre v0.2.3","text":"MapboxDraw
plugin (#59)MapboxDraw
:<output_id>.draw_features_selected
MapboxDraw
:Map.draw_features_selected
(list)Map.draw_feature_collection_all
(dict)
"},{"location":"changelog/#maplibre-v022","title":"maplibre v0.2.2","text":"Map.center
Map.bounds
Map.zoom
Map.lat_lng
> Map.clicked
(rename)MapOptions.zoom: int
> Union[int, float]
MapOptions.bearing: int
> Union[int, float]
MapOptions.pitch: int
> Union[int, float]
"},{"location":"changelog/#maplibre-v021","title":"maplibre v0.2.1","text":"
"},{"location":"changelog/#maplibre-v020","title":"maplibre v0.2.0","text":"
"},{"location":"changelog/#maplibre-v016","title":"maplibre v0.1.6","text":"
"},{"location":"changelog/#maplibre-v015","title":"maplibre v0.1.5","text":"before_id
parameter to add_layer
method (#45, #47)
"},{"location":"changelog/#maplibre-v014","title":"maplibre v0.1.4","text":"shiny>=0.7.0
"},{"location":"changelog/#maplibre-v013","title":"maplibre v0.1.3","text":"anywidget>=0.9.0
(#36)
"},{"location":"changelog/#maplibre-v012","title":"maplibre v0.1.2","text":"prop = None
(#26)
"},{"location":"changelog/#maplibre-v011","title":"maplibre v0.1.1","text":"Map.set_data
Map.set_visibility
ipywidget.MapWidget
in __init__
and skip tests for MapWidget
, because it causes a core dumped
error, see anywidget issuerequests
dependency
"},{"location":"deckgl/","title":"Deck.GL Layers","text":"Map.add_deck_layers
.@@type
prefix and getter props the @@=
prefix. They are inserted into the layer stack of the maplibre context. Therefore, you can also pass a beforeId
prop.grid_layer = {\n \"@@type\": \"GridLayer\", # JS: new GridLayer\n \"id\": \"my-awsome-grid-layer\",\n \"data\": \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/sf-bike-parking.json\",\n \"extruded\": True,\n \"getPosition\": \"@@=COORDINATES\", # JS: d => d.COORDINATES\n \"getColorWeight\": \"@@=SPACES\", # JS: d => d.SPACES\n \"getElevationWeight\": \"@@=SPACES\", # JS: d => d.SPACES\n \"elevationScale\": 4,\n \"cellSize\": 200,\n \"pickable\": True,\n \"beforeId\": \"first-labels-layer\" # optional\n }\n
const gridLayer = new GridLayer({\n id: 'GridLayer',\n data: 'https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/sf-bike-parking.json',\n extruded: true,\n getPosition: d => d.COORDINATES,\n getColorWeight: d => d.SPACES,\n getElevationWeight: d => d.SPACES,\n elevationScale: 4,\n cellSize: 200,\n pickable: true\n});\n
"},{"location":"jupyter/","title":"Jupyter","text":"MapWidget
in your Jupyter Notebook:
"},{"location":"layers/","title":"Layers","text":"import ipywidgets as widgets\n\nfrom maplibre import Layer, LayerType\nfrom maplibre.sources import GeoJSONSource\nfrom maplibre.controls import ScaleControl, Marker\nfrom maplibre.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# Create 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\n_ = widgets.interact(\n lambda radius: m.set_paint_property(layer_id, \"circle-radius\", radius),\n radius=(1, 8, 1)\n)\n\n# Change color\n_ = widgets.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\n_ = widgets.interact(\n lambda mag_min: m.set_filter(layer_id, [\">=\", [\"get\", \"mag\"], mag_min]),\n mag_min=(1, 8, 1)\n)\n
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.paint
property looks like this:paint = {\n \"circle-radius\": 5,\n \"circle-color\": \"yellow\"\n}\n
layout
property, paint
property, or filter
may also be specified as an expression. For details see Expressions.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
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
magnitude
property:
"},{"location":"shiny/","title":"Shiny","text":""},{"location":"shiny/#input-and-output","title":"Input and output","text":"# Only show features where magnitude >= 5\nfilter = [\">=\", [\"get\", \"magnitude\"], 5]\n
output_maplibregl
in the UI and render_maplibregl
in the server section of your Shiny for Python app:
"},{"location":"shiny/#reactivity","title":"Reactivity","text":""},{"location":"shiny/#input-events","title":"Input events","text":"from shiny import App, ui\nfrom maplibre 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\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre():\n m = Map()\n return m\n\n\napp = App(app_ui, server)\n
"},{"location":"shiny/#map-updates","title":"Map updates","text":"input.{output_id}_clicked
: Sends coordinates of the clicked location on the map.input.{output_id}_feature_clicked
: Sends the properties of the clicked feature and its layer id.input.{output_id}_view_state
: Sends the current view state. Fired when the view state is changed.MapContext
to update your Map
object.import json\n\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapContext,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import GeoJSONSource\nfrom shiny import App, reactive, render, ui\n\nLAYER_ID = \"earthquakes\"\nCIRCLE_RADIUS = 5\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"MapLibre for Python\"),\n output_maplibregl(\"mapgl\", height=600),\n ui.div(\"Click on the map to print the coords.\", style=\"padding: 10px;\"),\n ui.output_text_verbatim(\"coords\", placeholder=True),\n ui.div(\"Click on a feature to print its props.\", style=\"padding: 10px;\"),\n ui.output_text_verbatim(\"props\", placeholder=True),\n ui.div(\"Move map or zoom to update view state.\", style=\"padding: 10px;\"),\n ui.output_text_verbatim(\"view_state\", placeholder=True),\n ui.input_slider(\"radius\", \"Radius\", value=CIRCLE_RADIUS, min=1, max=10),\n)\n\ncircle_layer = 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\ndef server(input, output, session):\n @render_maplibregl\n def mapgl():\n m = Map(zoom=3, pitch=40)\n m.add_control(NavigationControl())\n m.add_layer(circle_layer)\n return m\n\n @render.text\n def coords():\n return str(input.mapgl_clicked())\n\n @render.text\n def view_state():\n return json.dumps(input.mapgl_view_state(), indent=2)\n\n @render.text\n def props():\n return str(input.mapgl_feature_clicked())\n\n @reactive.Effect\n @reactive.event(input.radius)\n async def radius():\n async with MapContext(\"mapgl\") as m:\n m.set_paint_property(LAYER_ID, \"circle-radius\", input.radius())\n\n\napp = App(app_ui, server)\n
"},{"location":"shiny_express/","title":"Shiny Express","text":"poetry run uvicorn docs.examples.getting_started.reactivity:app --reload\n
output_id
corresponds to the name of the render function. For the example below the output_id
is mapgl
, so that you have to listen to input.mapgl_clicked
to get the map clicked event.
"},{"location":"streamlit/","title":"Streamlit","text":"import json\n\nfrom shiny.express import input, render, ui\n\nfrom maplibre import Map, MapOptions, render_maplibregl\n\nui.h1(\"My awesome MapLibre map\")\n\n\n@render_maplibregl\ndef mapgl():\n return Map(MapOptions(zoom=3, pitch=40))\n\n\nui.div(\"Click on map to show coords.\")\n\n\n@render.code\ndef coords():\n return str(input.mapgl_clicked())\n\n\nui.div(\"Move map to change view state.\")\n\n\n@render.code\ndef view_state():\n return json.dumps(input.mapgl_view_state(), indent=2)\n
maplibre.streamlit.st_maplibre
to add a MapLibre map to your Streamlit app:
"},{"location":"api/basemaps/","title":"Basemaps","text":""},{"location":"api/basemaps/#maplibre.basemaps.Carto","title":"import streamlit as st\nfrom maplibre import Map, MapOptions\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl\nfrom maplibre.streamlit import st_maplibre\n\n\ndef create_layer(cell_size: int = 200) -> dict:\n return {\n \"@@type\": \"GridLayer\",\n \"id\": \"GridLayer\",\n \"data\": \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/sf-bike-parking.json\",\n \"extruded\": True,\n \"getPosition\": \"@@=COORDINATES\",\n \"getColorWeight\": \"@@=SPACES\",\n \"getElevationWeight\": \"@@=SPACES\",\n \"elevationScale\": 4,\n \"cellSize\": cell_size,\n \"pickable\": True,\n }\n\n\nmap_options = MapOptions(\n style=Carto.POSITRON,\n center=(-122.4, 37.74),\n zoom=12,\n hash=True,\n pitch=40,\n)\n\n\nst.title(\"SF Bike Parking\")\n\ncell_size = st.slider(\"cell size\", 100, 600, value=200, step=5)\n\nm = Map(map_options)\nm.add_control(NavigationControl())\nm.add_deck_layers([create_layer(cell_size)], tooltip=\"Number of points: {{ count }}\")\n\nst_maplibre(m)\n
maplibre.basemaps.Carto
","text":"Enum
DARK_MATTER
\u2013 POSITRON
\u2013 VOYAGER
\u2013 POSITRON_NOLABELS
\u2013 DARK_MATTER_NOLABELS
\u2013 VOYAGER_NOLABELS
\u2013 >>> from maplibre import Map, MapOptions\n>>> from maplibre.basemaps import Carto\n
Source code in >>> m = Map(MapOptions(style=Carto.DARK_MATTER))\n
maplibre/basemaps.py
"},{"location":"api/basemaps/#maplibre.basemaps.construct_basemap_style","title":"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 maplibre import Map, MapOptions\n >>> from maplibre.basemaps import Carto\n\n >>> m = 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
maplibre.basemaps.construct_basemap_style(name='nice-style', sources={}, layers=[])
","text":"name
str
'nice-style'
sources
dict
{}
layers
list
[]
Source code in maplibre/basemaps.py
"},{"location":"api/controls/","title":"Markers and controls","text":""},{"location":"api/controls/#maplibre.controls.Popup","title":"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
maplibre.controls.Popup
","text":"MapLibreBaseModel
text
str
options
PopupOptions | dict
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.PopupOptions","title":"class Popup(MapLibreBaseModel):\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
maplibre.controls.PopupOptions
","text":"MapLibreBaseModel
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.Marker","title":"class PopupOptions(MapLibreBaseModel):\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
maplibre.controls.Marker
","text":"MapLibreBaseModel
lng_lat
tuple | list
popup
Popup | dict
options
MarkerOptions | dict
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.MarkerOptions","title":"class Marker(MapLibreBaseModel):\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
maplibre.controls.MarkerOptions
","text":"MapLibreBaseModel
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.ControlPosition","title":"class MarkerOptions(MapLibreBaseModel):\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
maplibre.controls.ControlPosition
","text":"Enum
Source code in TOP_LEFT
\u2013 TOP_RIGHT
\u2013 BOTTOM_LEFT
\u2013 BOTTOM_RIGHT
\u2013 maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.FullscreenControl","title":"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
maplibre.controls.FullscreenControl
","text":"Control
>>> from maplibre import Map\n>>> from maplibre.controls import FullscreenControl, ControlPosition\n
Source code in >>> m = Map()\n>>> m.add_control(FullscreenControl(), ControlPosition.BOTTOM_LEFT)\n
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.ScaleControl","title":"class FullscreenControl(Control):\n \"\"\"Fullscreen control\n\n Examples:\n >>> from maplibre import Map\n >>> from maplibre.controls import FullscreenControl, ControlPosition\n\n >>> m = Map()\n >>> m.add_control(FullscreenControl(), ControlPosition.BOTTOM_LEFT)\n \"\"\"\n\n # _name: str = ControlType.FULLSCREEN.value\n pass\n
maplibre.controls.ScaleControl
","text":"Control
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.NavigationControl","title":"class ScaleControl(Control):\n \"\"\"Scale control\"\"\"\n\n max_width: int = Field(None, serialization_alias=\"maxWidth\")\n unit: Literal[\"imperial\", \"metric\", \"nautical\"] = \"metric\"\n
maplibre.controls.NavigationControl
","text":"Control
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.GeolocateControl","title":"class NavigationControl(Control):\n \"\"\"Navigation control\"\"\"\n\n # _name: str = ControlType.NAVIGATION.value\n show_compass: bool = Field(True, serialization_alias=\"showCompass\")\n show_zoom: bool = Field(True, serialization_alias=\"showZoom\")\n visualize_pitch: bool = Field(False, serialization_alias=\"visualizePitch\")\n
maplibre.controls.GeolocateControl
","text":"Control
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.InfoBoxControl","title":"class GeolocateControl(Control):\n \"\"\"Geolocate control\"\"\"\n\n # _name: str = ControlType.GEOLOCATE.value\n position_options: dict = Field(None, serialization_alias=\"positionOptions\")\n show_accuracy_circle: bool = Field(True, serialization_alias=\"showAccuracyCircle\")\n show_user_heading: bool = Field(False, serialization_alias=\"showUserHeading\")\n show_user_location: bool = Field(True, serialization_alias=\"showUserLocation\")\n track_user_location: bool = Field(False, serialization_alias=\"trackUserLocation\")\n
maplibre.controls.InfoBoxControl
","text":"Control
content
str
css_text
str
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.LayerSwitcherControl","title":"class InfoBoxControl(Control):\n \"\"\"InfoBox control\n\n Attributes:\n content (str): Content (HTML or plain text) to be displayed in the info box.\n css_text (str): Optional inline style declaration of the control.\n \"\"\"\n\n content: str\n css_text: str = Field(None, serialization_alias=\"cssText\")\n
maplibre.controls.LayerSwitcherControl
","text":"Control
layer_ids
list
theme
Literal['default', 'simple']
css_text
str
maplibre/controls.py
"},{"location":"api/layer/","title":"Layer","text":""},{"location":"api/layer/#maplibre.Layer","title":"class LayerSwitcherControl(Control):\n \"\"\"Layer switcher control\n\n Attributes:\n layer_ids (list): A list of layer ids to be shown in the layer switcher control.\n theme (Literal[\"default\", \"simple\"]): The theme of the layer switcher control.\n css_text (str): Optional inline style declaration of the control.\n \"\"\"\n\n layer_ids: list = Field([], serialization_alias=\"layerIds\")\n theme: Literal[\"default\", \"simple\"] = \"default\"\n css_text: str = Field(None, serialization_alias=\"cssText\")\n
maplibre.Layer
","text":"MapLibreBaseModel
paint
and layout
properties of the layers.id
str
str(uuid4())
.type
str | LayerType
filter
list
layout
dict
max_zoom
int
min_zoom
int
paint
dict
source
str | Source | GeoDataFrame
source_layer
str
>>> from maplibre.layer import Layer, LayerType\n
Source code in >>> layer = Layer(id=\"test-layer\", type=LayerType.CIRCLE, source=\"test-source\")\n
maplibre/layer.py
"},{"location":"api/layer/#maplibre.LayerType","title":"class Layer(MapLibreBaseModel):\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): A filter expression that is applied to the source of the layer.\n layout (dict): The layout properties for 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 for the layer.\n source (str | Source | GeoDataFrame): The name (unique ID) of a source, a source object or a GeoDataFrame\n to be used for the layer.\n source_layer (str): The layer to use from a vector tile source.\n\n Examples:\n >>> from maplibre.layer import Layer, LayerType\n\n >>> layer = Layer(id=\"test-layer\", type=LayerType.CIRCLE, source=\"test-source\")\n \"\"\"\n\n id: Optional[str] = Field(default_factory=lambda: str(uuid4()))\n type: LayerType\n filter: Optional[list] = None\n layout: Optional[dict] = None\n max_zoom: Optional[int] = Field(None, serialization_alias=\"maxzoom\")\n metadata: Optional[dict] = None\n min_zoom: Optional[int] = Field(None, serialization_alias=\"minzoom\")\n paint: Optional[dict] = None\n source: Union[str, Source, dict, GeoDataFrame, None] = None\n source_layer: Optional[str] = Field(None, serialization_alias=\"source-layer\")\n\n # TODO: Use model_post_init and set bounds if source is a GeoDataFrame\n @field_validator(\"source\")\n def validate_source(cls, v):\n if GeoDataFrame is not None and isinstance(v, GeoDataFrame):\n return SimpleFeatures(v).to_source().to_dict()\n\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\n @property\n def bounds(self) -> tuple | None:\n try:\n bounds = get_bounds(self.source[\"data\"])\n except Exception as e:\n # print(e)\n bounds = None\n\n return bounds\n\n def set_paint_props(self, **props) -> Layer:\n if self.paint is None:\n self.paint = dict()\n\n self.paint = self.paint | fix_keys(props)\n return self\n\n def set_layout_props(self, **props) -> Layer:\n if self.layout is None:\n self.layout = dict()\n\n self.paint = self.paint | fix_keys(props)\n return self\n
maplibre.LayerType
","text":"Enum
Source code in CIRCLE
\u2013 FILL
\u2013 FILL_EXTRUSION
\u2013 LINE
\u2013 SYMBOL
\u2013 RASTER
\u2013 HEATMAP
\u2013 HILLSHADE
\u2013 BACKGROUND
\u2013 maplibre/layer.py
"},{"location":"api/map/","title":"Map","text":""},{"location":"api/map/#maplibre.Map","title":"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
maplibre.Map
","text":"object
map_options
MapOptions
MapOptions()
sources
dict
None
layers
list
None
controls
list
None
**kwargs
MapOptions
object.{}
Source code in >>> from maplibre.map import Map, MapOptions\n>>> map_options = MapOptions(center=(9.5, 51.31667), zoom=8)\n>>> m = Map(map_options)\n>>> dict(m)\n{'mapOptions': {'center': (9.5, 51.31667), 'style': 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json', 'zoom': 8}, 'calls': []}\n
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_call","title":"class Map(object):\n \"\"\"Map\n\n Args:\n map_options (MapOptions): Map options.\n sources (dict): Sources to be added to the map. Keys are source IDs.\n layers (list): Layers to be added to the map.\n controls (list): Controls to be added to the map.\n **kwargs: Keyword arguments that are appended to the `MapOptions` object.\n\n Examples:\n >>> from maplibre.map import Map, MapOptions\n >>> map_options = MapOptions(center=(9.5, 51.31667), zoom=8)\n >>> m = Map(map_options)\n >>> dict(m)\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__(\n self,\n map_options: MapOptions = MapOptions(),\n sources: dict = None,\n layers: list = None,\n controls: list = None,\n **kwargs,\n ):\n self.map_options = (\n map_options.to_dict() | kwargs\n ) # MapOptions(**kwargs).to_dict() # need to fix MapWidget, because height is passed as kwarg\n self._message_queue = []\n self.add_layers(layers, sources)\n if controls:\n for control in controls:\n self.add_control(control)\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 \"\"\"\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\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] = None,\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 position = position or control.position\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 | GeoDataFrame]) -> None:\n \"\"\"Add a source to the map\n\n Args:\n id (str): The unique ID of the source.\n source (Source | dict | GeoDataFrame): The source to be added to the map.\n \"\"\"\n if GeoDataFrame is not None and isinstance(source, GeoDataFrame):\n source = SimpleFeatures(source).to_source()\n\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], before_id: str = None) -> None:\n \"\"\"Add a layer to the map\n\n Args:\n layer (Layer | dict): The Layer to be added to the map.\n before_id (str): The ID of an existing layer to insert the new layer before,\n resulting in the new layer appearing visually beneath the existing layer.\n If `None`, the new layer will appear above all other layers.\n \"\"\"\n if isinstance(layer, Layer):\n layer = layer.to_dict()\n\n self.add_call(\"addLayer\", layer, before_id)\n\n def add_layers(self, layers: list = None, sources: dict = None):\n layers = layers or []\n sources = sources or dict()\n for source_id, source in sources.items():\n self.add_source(source_id, source)\n\n for layer in layers:\n self.add_layer(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, template: str = None) -> 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. If `None`, all properties are displayed.\n template (str): A mustache template. If supplied, `prop` is ignored.\n \"\"\"\n self.add_call(\"addPopup\", layer_id, prop, template)\n\n def add_tooltip(\n self, layer_id: str, prop: str = None, template: str = None\n ) -> 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. If `None`, all properties are displayed.\n template (str): A mustache template. If supplied, `prop` is ignored.\n\n Examples:\n >>> m = Map()\n >>> # ...\n >>> m.add_tooltip(\"test-layer\", template=\"Name: {{ name }}\")\n \"\"\"\n self.add_call(\"addTooltip\", layer_id, prop, template)\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 set_data(self, source_id: str, data: dict | GeoDataFrame) -> None:\n \"\"\"Update the data of a GeoJSON source\n\n Args:\n source_id (str): The name of the source to be updated.\n data (dict): The data of the source.\n \"\"\"\n if isinstance(data, GeoDataFrame):\n data = SimpleFeatures(data).to_source().data\n\n self.add_call(\"setSourceData\", source_id, data)\n\n def set_visibility(self, layer_id: str, visible: bool = True) -> None:\n \"\"\"Update the visibility of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n visible (bool): Whether the layer is visible or not.\n \"\"\"\n value = \"visible\" if visible else \"none\"\n self.add_call(\"setLayoutProperty\", layer_id, \"visibility\", value)\n\n def fit_bounds(\n self,\n bounds: tuple | list = None,\n data: GeoDataFrame = None,\n animate=False,\n **kwargs,\n ) -> None:\n \"\"\"Pan and zoom the map to contain its visible area within the specified geographical bounds\"\"\"\n kwargs[\"animate\"] = animate\n if data is not None:\n bounds = tuple(data.total_bounds)\n\n self.add_call(\"fitBounds\", bounds, kwargs)\n\n def to_html(self, title: str = \"My Awesome Map\", **kwargs) -> str:\n \"\"\"Render to html\n\n Args:\n title (str): The Title of the HTML document.\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 maplibre import Map\n >>> m = Map()\n >>> with open(\"/tmp/map.html\", \"w\") as f:\n ... f.write(m.to_html(style=\"height: 800px;\") # doctest: +SKIP\n \"\"\"\n js_lib = read_internal_file(\"srcjs\", \"pywidget.js\")\n js_snippet = Template(js_template).render(data=json.dumps(self.to_dict()))\n css = read_internal_file(\"srcjs\", \"pywidget.css\")\n headers = [f\"<style>{css}</style>\"]\n\n # Deck.GL headers\n add_deckgl_headers = \"addDeckOverlay\" in [\n item[0] for item in self._message_queue\n ]\n # TODO: Set version in constants\n deckgl_headers = (\n [\n # '<script src=\"https://unpkg.com/h3-js\"></script>',\n '<script src=\"https://unpkg.com/h3-js@4.1.0/dist/h3-js.umd.js\"></script>',\n '<script src=\"https://unpkg.com/deck.gl@9.0.16/dist.min.js\"></script>',\n '<script src=\"https://unpkg.com/@deck.gl/json@9.0.16/dist.min.js\"></script>',\n ]\n if add_deckgl_headers\n else []\n )\n\n # Mapbox Draw headers\n add_mapbox_draw_headers = \"addMapboxDraw\" in [\n item[0] for item in self._message_queue\n ]\n # TODO: Set version in constants\n mapbox_draw_headers = (\n [\n # \"<script src='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.js'></script>\",\n # \"<link rel='stylesheet' href='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.css' type='text/css' />\",\n \"<script src='https://www.unpkg.com/@mapbox/mapbox-gl-draw@1.4.3/dist/mapbox-gl-draw.js'></script>\",\n \"<link rel='stylesheet' href='https://www.unpkg.com/@mapbox/mapbox-gl-draw@1.4.3/dist/mapbox-gl-draw.css' type='text/css' />\",\n ]\n if add_mapbox_draw_headers\n else []\n )\n\n output = Template(html_template).render(\n js=\"\\n\".join([js_lib, js_snippet]),\n title=title,\n headers=headers + deckgl_headers + mapbox_draw_headers,\n **kwargs,\n )\n return output\n\n def save(self, filename: str = None, preview=True, **kwargs):\n \"\"\"Save the map to an HTML file\"\"\"\n return save_map(self, filename, preview, **kwargs)\n\n # -------------------------\n # Plugins\n # -------------------------\n def add_deck_layers(\n self, layers: list[dict | \"pydeck.Layer\"], tooltip: str | dict = None\n ) -> None:\n \"\"\"Add Deck.GL layers to the layer stack\n\n Args:\n layers (list[dict | \"pydeck.Layer\"]): A list of dictionaries containing the Deck.GL layers to be added.\n tooltip (str | dict): Either a single mustache template string applied to all layers\n or a dictionary where keys are layer ids and values are mustache template strings.\n \"\"\"\n layers = parse_deck_layers(layers)\n self.add_call(\"addDeckOverlay\", layers, tooltip)\n\n def set_deck_layers(\n self, layers: list[dict | \"pydeck.Layer\"], tooltip: str | dict = None\n ) -> None:\n \"\"\"Update Deck.GL layers\n\n Args:\n layers (list[dict | \"pydeck.Layer\"]): A list of dictionaries containing the Deck.GL layers to be updated.\n New layers will be added. Missing layers will be removed.\n tooltip (str | dict): Must be set to keep tooltip even if it did not change.\n \"\"\"\n layers = parse_deck_layers(layers)\n self.add_call(\"setDeckLayers\", layers, tooltip)\n\n def add_mapbox_draw(\n self,\n options: dict | MapboxDrawOptions = None,\n position: str | ControlPosition = ControlPosition.TOP_LEFT,\n geojson: dict = None,\n ) -> None:\n \"\"\"Add MapboxDraw controls to the map\n\n Note:\n See [MapboxDraw API Reference](https://github.com/mapbox/mapbox-gl-draw/blob/main/docs/API.md)\n for available options.\n\n Args:\n options (dict | MapboxDrawOptions): MapboxDraw options.\n position (str | ControlPosition): The position of the MapboxDraw controls.\n geojson (dict): A GeoJSON Feature, FeatureCollection or Geometry to be added to the draw layer.\n \"\"\"\n if isinstance(options, MapboxDrawOptions):\n options = options.to_dict()\n\n self.add_call(\n \"addMapboxDraw\", options or {}, ControlPosition(position).value, geojson\n )\n
add_call(method_name, *args)
","text":"method_name
str
*args
any
()
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_control","title":"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
add_control(control, position=None)
","text":"control
Control
position
str | ControlPosition
None
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_deck_layers","title":"def add_control(\n self,\n control: Control,\n position: [str | ControlPosition] = None,\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 position = position or control.position\n self.add_call(\n \"addControl\",\n control.type,\n control.to_dict(),\n ControlPosition(position).value,\n )\n
add_deck_layers(layers, tooltip=None)
","text":"layers
list[dict | 'pydeck.Layer']
tooltip
str | dict
None
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_layer","title":"def add_deck_layers(\n self, layers: list[dict | \"pydeck.Layer\"], tooltip: str | dict = None\n) -> None:\n \"\"\"Add Deck.GL layers to the layer stack\n\n Args:\n layers (list[dict | \"pydeck.Layer\"]): A list of dictionaries containing the Deck.GL layers to be added.\n tooltip (str | dict): Either a single mustache template string applied to all layers\n or a dictionary where keys are layer ids and values are mustache template strings.\n \"\"\"\n layers = parse_deck_layers(layers)\n self.add_call(\"addDeckOverlay\", layers, tooltip)\n
add_layer(layer, before_id=None)
","text":"layer
Layer | dict
before_id
str
None
, the new layer will appear above all other layers.None
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_mapbox_draw","title":"def add_layer(self, layer: [Layer | dict], before_id: str = None) -> None:\n \"\"\"Add a layer to the map\n\n Args:\n layer (Layer | dict): The Layer to be added to the map.\n before_id (str): The ID of an existing layer to insert the new layer before,\n resulting in the new layer appearing visually beneath the existing layer.\n If `None`, the new layer will appear above all other layers.\n \"\"\"\n if isinstance(layer, Layer):\n layer = layer.to_dict()\n\n self.add_call(\"addLayer\", layer, before_id)\n
add_mapbox_draw(options=None, position=ControlPosition.TOP_LEFT, geojson=None)
","text":"options
dict | MapboxDrawOptions
None
position
str | ControlPosition
TOP_LEFT
geojson
dict
None
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_marker","title":"def add_mapbox_draw(\n self,\n options: dict | MapboxDrawOptions = None,\n position: str | ControlPosition = ControlPosition.TOP_LEFT,\n geojson: dict = None,\n) -> None:\n \"\"\"Add MapboxDraw controls to the map\n\n Note:\n See [MapboxDraw API Reference](https://github.com/mapbox/mapbox-gl-draw/blob/main/docs/API.md)\n for available options.\n\n Args:\n options (dict | MapboxDrawOptions): MapboxDraw options.\n position (str | ControlPosition): The position of the MapboxDraw controls.\n geojson (dict): A GeoJSON Feature, FeatureCollection or Geometry to be added to the draw layer.\n \"\"\"\n if isinstance(options, MapboxDrawOptions):\n options = options.to_dict()\n\n self.add_call(\n \"addMapboxDraw\", options or {}, ControlPosition(position).value, geojson\n )\n
add_marker(marker)
","text":"marker
Marker
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_popup","title":"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
add_popup(layer_id, prop=None, template=None)
","text":"layer_id
str
prop
str
None
, all properties are displayed.None
template
str
prop
is ignored.None
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_source","title":"def add_popup(self, layer_id: str, prop: str = None, template: str = None) -> 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. If `None`, all properties are displayed.\n template (str): A mustache template. If supplied, `prop` is ignored.\n \"\"\"\n self.add_call(\"addPopup\", layer_id, prop, template)\n
add_source(id, source)
","text":"id
str
source
Source | dict | GeoDataFrame
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_tooltip","title":"def add_source(self, id: str, source: [Source | dict | GeoDataFrame]) -> None:\n \"\"\"Add a source to the map\n\n Args:\n id (str): The unique ID of the source.\n source (Source | dict | GeoDataFrame): The source to be added to the map.\n \"\"\"\n if GeoDataFrame is not None and isinstance(source, GeoDataFrame):\n source = SimpleFeatures(source).to_source()\n\n if isinstance(source, Source):\n source = source.to_dict()\n\n self.add_call(\"addSource\", id, source)\n
add_tooltip(layer_id, prop=None, template=None)
","text":"layer_id
str
prop
str
None
, all properties are displayed.None
template
str
prop
is ignored.None
Source code in >>> m = Map()\n>>> # ...\n>>> m.add_tooltip(\"test-layer\", template=\"Name: {{ name }}\")\n
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.fit_bounds","title":"def add_tooltip(\n self, layer_id: str, prop: str = None, template: str = None\n) -> 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. If `None`, all properties are displayed.\n template (str): A mustache template. If supplied, `prop` is ignored.\n\n Examples:\n >>> m = Map()\n >>> # ...\n >>> m.add_tooltip(\"test-layer\", template=\"Name: {{ name }}\")\n \"\"\"\n self.add_call(\"addTooltip\", layer_id, prop, template)\n
fit_bounds(bounds=None, data=None, animate=False, **kwargs)
","text":"maplibre/map.py
"},{"location":"api/map/#maplibre.Map.save","title":"def fit_bounds(\n self,\n bounds: tuple | list = None,\n data: GeoDataFrame = None,\n animate=False,\n **kwargs,\n) -> None:\n \"\"\"Pan and zoom the map to contain its visible area within the specified geographical bounds\"\"\"\n kwargs[\"animate\"] = animate\n if data is not None:\n bounds = tuple(data.total_bounds)\n\n self.add_call(\"fitBounds\", bounds, kwargs)\n
save(filename=None, preview=True, **kwargs)
","text":"maplibre/map.py
"},{"location":"api/map/#maplibre.Map.set_data","title":"def save(self, filename: str = None, preview=True, **kwargs):\n \"\"\"Save the map to an HTML file\"\"\"\n return save_map(self, filename, preview, **kwargs)\n
set_data(source_id, data)
","text":"source_id
str
data
dict
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.set_deck_layers","title":"def set_data(self, source_id: str, data: dict | GeoDataFrame) -> None:\n \"\"\"Update the data of a GeoJSON source\n\n Args:\n source_id (str): The name of the source to be updated.\n data (dict): The data of the source.\n \"\"\"\n if isinstance(data, GeoDataFrame):\n data = SimpleFeatures(data).to_source().data\n\n self.add_call(\"setSourceData\", source_id, data)\n
set_deck_layers(layers, tooltip=None)
","text":"layers
list[dict | 'pydeck.Layer']
tooltip
str | dict
None
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.set_filter","title":"def set_deck_layers(\n self, layers: list[dict | \"pydeck.Layer\"], tooltip: str | dict = None\n) -> None:\n \"\"\"Update Deck.GL layers\n\n Args:\n layers (list[dict | \"pydeck.Layer\"]): A list of dictionaries containing the Deck.GL layers to be updated.\n New layers will be added. Missing layers will be removed.\n tooltip (str | dict): Must be set to keep tooltip even if it did not change.\n \"\"\"\n layers = parse_deck_layers(layers)\n self.add_call(\"setDeckLayers\", layers, tooltip)\n
set_filter(layer_id, filter_)
","text":"layer_id
str
filter_
list
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.set_layout_property","title":"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
set_layout_property(layer_id, prop, value)
","text":"layer_id
str
prop
str
value
any
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.set_paint_property","title":"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
set_paint_property(layer_id, prop, value)
","text":"layer_id
str
prop
str
value
any
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.set_visibility","title":"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
set_visibility(layer_id, visible=True)
","text":"layer_id
str
visible
bool
True
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.to_html","title":"def set_visibility(self, layer_id: str, visible: bool = True) -> None:\n \"\"\"Update the visibility of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n visible (bool): Whether the layer is visible or not.\n \"\"\"\n value = \"visible\" if visible else \"none\"\n self.add_call(\"setLayoutProperty\", layer_id, \"visibility\", value)\n
to_html(title='My Awesome Map', **kwargs)
","text":"title
str
'My Awesome Map'
**kwargs
Any
style
is the only supported keyword argument.{}
Source code in >>> from maplibre import Map\n>>> m = Map()\n>>> with open(\"/tmp/map.html\", \"w\") as f:\n... f.write(m.to_html(style=\"height: 800px;\")\n
maplibre/map.py
"},{"location":"api/map/#maplibre.MapOptions","title":"def to_html(self, title: str = \"My Awesome Map\", **kwargs) -> str:\n \"\"\"Render to html\n\n Args:\n title (str): The Title of the HTML document.\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 maplibre import Map\n >>> m = Map()\n >>> with open(\"/tmp/map.html\", \"w\") as f:\n ... f.write(m.to_html(style=\"height: 800px;\") # doctest: +SKIP\n \"\"\"\n js_lib = read_internal_file(\"srcjs\", \"pywidget.js\")\n js_snippet = Template(js_template).render(data=json.dumps(self.to_dict()))\n css = read_internal_file(\"srcjs\", \"pywidget.css\")\n headers = [f\"<style>{css}</style>\"]\n\n # Deck.GL headers\n add_deckgl_headers = \"addDeckOverlay\" in [\n item[0] for item in self._message_queue\n ]\n # TODO: Set version in constants\n deckgl_headers = (\n [\n # '<script src=\"https://unpkg.com/h3-js\"></script>',\n '<script src=\"https://unpkg.com/h3-js@4.1.0/dist/h3-js.umd.js\"></script>',\n '<script src=\"https://unpkg.com/deck.gl@9.0.16/dist.min.js\"></script>',\n '<script src=\"https://unpkg.com/@deck.gl/json@9.0.16/dist.min.js\"></script>',\n ]\n if add_deckgl_headers\n else []\n )\n\n # Mapbox Draw headers\n add_mapbox_draw_headers = \"addMapboxDraw\" in [\n item[0] for item in self._message_queue\n ]\n # TODO: Set version in constants\n mapbox_draw_headers = (\n [\n # \"<script src='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.js'></script>\",\n # \"<link rel='stylesheet' href='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.css' type='text/css' />\",\n \"<script src='https://www.unpkg.com/@mapbox/mapbox-gl-draw@1.4.3/dist/mapbox-gl-draw.js'></script>\",\n \"<link rel='stylesheet' href='https://www.unpkg.com/@mapbox/mapbox-gl-draw@1.4.3/dist/mapbox-gl-draw.css' type='text/css' />\",\n ]\n if add_mapbox_draw_headers\n else []\n )\n\n output = Template(html_template).render(\n js=\"\\n\".join([js_lib, js_snippet]),\n title=title,\n headers=headers + deckgl_headers + mapbox_draw_headers,\n **kwargs,\n )\n return output\n
maplibre.MapOptions
","text":"MapLibreBaseModel
maplibre/map.py
"},{"location":"api/map/#maplibre.MapContext","title":"class MapOptions(MapLibreBaseModel):\n \"\"\"Map options\n\n Note:\n See [MapOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/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: Union[int, float] = 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: Union[int, float] = None\n scroll_zoom: bool = Field(None, serialization_alias=\"scrollZoom\")\n style: Union[str, Carto, MapTiler, dict] = construct_carto_basemap_url(\n Carto.DARK_MATTER\n )\n zoom: Union[int, float] = 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 if isinstance(v, MapTiler):\n return construct_maptiler_basemap_url(v)\n\n return v\n
maplibre.MapContext
","text":"Map
Map
instance in a Shiny app. Must be used inside an async function.maplibre.Map
for available methods.id
string
session
Session
None
, the active session is used.None
Source code in maplibre/mapcontext.py
"},{"location":"api/map/#maplibre.ipywidget.MapWidget","title":"class MapContext(Map):\n \"\"\"MapContext\n\n Use this class to update a `Map` instance in a Shiny app.\n Must be used inside an async function.\n\n See `maplibre.Map` for available methods.\n\n Args:\n id (string): The id of the map to be updated.\n session (Session): A Shiny session.\n If `None`, the active session is used.\n \"\"\"\n\n def __init__(self, id: str, session: Session = None) -> None:\n self.id = id\n self._session = require_active_session(session)\n self.map_options = {}\n self._message_queue = []\n\n async def __aenter__(self):\n return self\n\n async def __aexit__(self, exc_type, exc_val, exc_tb):\n await self.render()\n\n async def render(self):\n await self._session.send_custom_message(\n f\"pymaplibregl-{self.id}\", {\"id\": self.id, \"calls\": self._message_queue}\n )\n
maplibre.ipywidget.MapWidget
","text":"AnyWidget
, Map
maplibre.Map
for available methods.
Source code in >>> from maplibre import MapOptions\n>>> from maplibre.ipywidget import MapWidget as Map\n>>> m = Map(MapOptions(center=(-123.13, 49.254), zoom=11, pitch=45))\n>>> m\n
maplibre/ipywidget.py
"},{"location":"api/map/#maplibre.plugins","title":"class MapWidget(AnyWidget, Map):\n \"\"\"MapWidget\n\n Use this class to display and update maps in Jupyter Notebooks.\n\n See `maplibre.Map` for available methods.\n\n Examples:\n >>> from maplibre import MapOptions\n >>> from maplibre.ipywidget import MapWidget as Map\n >>> m = Map(MapOptions(center=(-123.13, 49.254), zoom=11, pitch=45))\n >>> m # doctest: +SKIP\n \"\"\"\n\n _esm = join(Path(__file__).parent, \"srcjs\", \"ipywidget.js\")\n # _css = join(Path(__file__).parent, \"srcjs\", \"maplibre-gl.css\")\n _css = join(Path(__file__).parent, \"srcjs\", \"ipywidget.css\")\n _use_message_queue = True\n # _rendered = traitlets.Bool(False, config=True).tag(sync=True)\n _rendered = traitlets.Bool(False).tag(config=True).tag(sync=True)\n map_options = traitlets.Dict().tag(sync=True)\n calls = traitlets.List().tag(sync=True)\n height = traitlets.Union([traitlets.Int(), traitlets.Unicode()]).tag(sync=True)\n\n # Interactions Map\n clicked = traitlets.Dict().tag(sync=True)\n view_state = traitlets.Dict().tag(sync=True)\n\n # Interactions MapboxDraw plugin\n draw_features_selected = traitlets.List().tag(sync=True)\n draw_feature_collection_all = traitlets.Dict().tag(sync=True)\n\n def __init__(\n self,\n map_options=MapOptions(),\n sources: dict = None,\n layers: list = None,\n controls: list = None,\n height: int | str = 400,\n **kwargs,\n ) -> None:\n self.calls = []\n AnyWidget.__init__(self, height=height, **kwargs)\n Map.__init__(self, map_options, sources, layers, controls, **kwargs)\n\n \"\"\"\n @traitlets.default(\"height\")\n def _default_height(self):\n return \"400px\"\n \"\"\"\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 use_message_queue(self, value: bool = True) -> None:\n self._use_message_queue = value\n\n def add_call(self, method_name: str, *args) -> None:\n call = [method_name, args]\n if not self._rendered:\n if not self._use_message_queue:\n self.calls = self.calls + [call]\n return\n\n self._message_queue.append(call)\n return\n\n self.send({\"calls\": [call], \"msg\": \"custom call\"})\n
maplibre.plugins
","text":""},{"location":"api/map/#maplibre.plugins.MapboxDrawControls","title":"MapboxDrawControls
","text":"MapLibreBaseModel
maplibre/plugins.py
"},{"location":"api/map/#maplibre.plugins.MapboxDrawOptions","title":"class MapboxDrawControls(MapLibreBaseModel):\n \"\"\"MapboxDraw controls\"\"\"\n\n point: bool = False\n line_string: bool = False\n polygon: bool = False\n trash: bool = False\n combine_features: bool = False\n uncombine_features: bool = False\n
MapboxDrawOptions
","text":"MapLibreBaseModel
maplibre/plugins.py
"},{"location":"api/sources/","title":"Sources","text":""},{"location":"api/sources/#maplibre.sources","title":"class MapboxDrawOptions(MapLibreBaseModel):\n \"\"\"MapboxDraw Options\"\"\"\n\n display_controls_default: bool = Field(\n True, serialization_alias=\"displayControlsDefault\"\n )\n controls: MapboxDrawControls = None\n box_select: bool = Field(True, serialization_alias=\"boxSelect\")\n
maplibre.sources
","text":""},{"location":"api/sources/#maplibre.sources.GeoJSONSource","title":"GeoJSONSource
","text":"Source
>>> from maplibre.sources import GeoJSONSource\n
Source code in >>> geojson = \"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n>>> source = GeoJSONSource(data=geojson)\n
maplibre/sources.py
"},{"location":"api/sources/#maplibre.sources.RasterTileSource","title":"class GeoJSONSource(Source):\n \"\"\"GeoJSON Source\n\n Examples:\n >>> from maplibre.sources import GeoJSONSource\n\n >>> geojson = \"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n >>> source = GeoJSONSource(data=geojson)\n \"\"\"\n\n data: Union[str, dict]\n attribution: Optional[str] = None\n buffer: Optional[int] = None\n cluster: Optional[bool] = None\n cluster_max_zoom: Optional[int] = Field(None, serialization_alias=\"clusterMaxZoom\")\n cluster_min_points: Optional[int] = Field(\n None, serialization_alias=\"clusterMinPoints\"\n )\n cluster_properties: Optional[dict] = Field(\n None, serialization_alias=\"clusterProperties\"\n )\n cluster_radius: Optional[int] = Field(None, serialization_alias=\"clusterRadius\")\n filter: Optional[list] = None\n generate_id: Optional[bool] = Field(None, serialization_alias=\"generateId\")\n line_metrics: Optional[bool] = Field(None, serialization_alias=\"lineMetrics\")\n min_zoom: Optional[int] = Field(None, serialization_alias=\"minzoom\")\n max_zoom: Optional[int] = Field(None, serialization_alias=\"maxzoom\")\n promote_id: Union[str, dict, None] = Field(None, serialization_alias=\"promoteId\")\n tolerance: Optional[float] = None\n\n @computed_field\n @property\n def type(self) -> str:\n return SourceType.GEOJSON.value\n
RasterTileSource
","text":"Source
>>> from maplibre.sources import RasterTileSource\n
Source code in >>> raster_tile_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
maplibre/sources.py
"},{"location":"api/sources/#maplibre.sources.SourceType","title":"class RasterTileSource(Source):\n \"\"\"Raster tile source\n\n Examples:\n >>> from maplibre.sources import RasterTileSource\n\n >>> raster_tile_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
SourceType
","text":"Enum
maplibre/sources.py
"},{"location":"api/sources/#maplibre.sources.VectorTileSource","title":"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
VectorTileSource
","text":"Source
>>> from maplibre.sources import VectorTileSource\n>>> from maplibre import LayerType, Layer\n
>>> vector_tile_source = VectorTileSource(\n... tiles=[\"https://demotiles.maplibre.org/tiles/{z}/{x}/{y}.pbf\"],\n... min_zoom=0,\n... max_zoom=6,\n... )\n
Source code in >>> layer = Layer(\n... type=LayerType.LINE,\n... id=\"countries\",\n... source=vector_tile_source,\n... source_layer=\"countries\",\n... paint={\"fill-color\": \"lightgreen\", \"fill-outline-color\": \"black\"},\n... )\n
maplibre/sources.py
"},{"location":"examples/3d_indoor_mapping/","title":"3D Indoor Mapping","text":"class VectorTileSource(Source):\n \"\"\"Vector tile source\n\n Examples:\n >>> from maplibre.sources import VectorTileSource\n >>> from maplibre import LayerType, Layer\n\n >>> vector_tile_source = VectorTileSource(\n ... tiles=[\"https://demotiles.maplibre.org/tiles/{z}/{x}/{y}.pbf\"],\n ... min_zoom=0,\n ... max_zoom=6,\n ... )\n\n >>> layer = Layer(\n ... type=LayerType.LINE,\n ... id=\"countries\",\n ... source=vector_tile_source,\n ... source_layer=\"countries\",\n ... paint={\"fill-color\": \"lightgreen\", \"fill-outline-color\": \"black\"},\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 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.VECTOR.value\n
import sys\nimport webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions\nfrom maplibre.basemaps import background\nfrom maplibre.sources import GeoJSONSource, RasterTileSource\n\nfile_name = \"/tmp/pymaplibregl_temp.html\"\n\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 if len(sys.argv) == 2:\n file_name = sys.argv[1]\n\n with open(file_name, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(file_name)\n
"},{"location":"examples/airports/","title":"Airport Markers","text":"poetry run python docs/examples/3d_indoor_mapping/app.py\n
import sys\n\nimport pandas as pd\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import (\n Marker,\n MarkerOptions,\n NavigationControl,\n Popup,\n PopupOptions,\n)\nfrom maplibre.sources import GeoJSONSource\nfrom maplibre.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\n\ndef create_map() -> Map:\n m = Map(map_options)\n m.add_control(NavigationControl())\n m.add_layer(airport_circles)\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 return m\n\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 def maplibre():\n return create_map()\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n if len(sys.argv) == 2:\n with open(sys.argv[1], \"w\") as f:\n f.write(create_map().to_html())\n else:\n app.run()\n
"},{"location":"examples/custom_basemap/","title":"Custom basemap","text":"poetry run uvicorn docs.examples.airports.app:app --reload\n
import webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions\nfrom maplibre.basemaps import construct_basemap_style\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import GeoJSONSource\n\nfile_name = \"docs/examples/custom_basemap/app.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_control(NavigationControl())\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(file_name, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(file_name)\n
"},{"location":"examples/deckgl_layer/","title":"Deck.GL Layer","text":"poetry run python docs/examples/custom_basemap/app.py\n
# Shiny Express App\n\nimport json\n\nfrom maplibre import Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl\nfrom maplibre.ui import use_deckgl\n\n# from shiny import reactive\nfrom shiny.express import input, render, ui\n\nm = Map(\n MapOptions(\n style=Carto.POSITRON,\n center=(-122.4, 37.74),\n zoom=12,\n hash=True,\n pitch=40,\n )\n)\nm.add_control(NavigationControl())\n\ndeck_grid_layer = {\n \"@@type\": \"GridLayer\",\n \"id\": \"GridLayer\",\n \"data\": \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/sf-bike-parking.json\",\n \"extruded\": True,\n \"getPosition\": \"@@=COORDINATES\",\n \"getColorWeight\": \"@@=SPACES\",\n \"getElevationWeight\": \"@@=SPACES\",\n \"elevationScale\": 4,\n \"cellSize\": 200,\n \"pickable\": True,\n}\n\nm.add_deck_layers([deck_grid_layer], tooltip=\"Number of points: {{ count }}\")\n\n# Shiny Express\nuse_deckgl()\n\n\n@render_maplibregl\ndef render_map():\n return m\n\n\n@render.code\ndef picking_object():\n obj = input.render_map_layer_GridLayer()\n print(obj)\n return json.dumps(obj[\"points\"], indent=2) if obj else \"Pick a feature!\"\n\n\nif __name__ == \"__main__\":\n with open(\"docs/examples/deckgl_layer/app.html\", \"w\") as f:\n f.write(m.to_html())\n
"},{"location":"examples/deckgl_multiple_layers/","title":"Multiple Deck.GL Layers","text":"# Run Shiny app\nshiny run docs/examples/deckgl_layer/app.py\n
# Shiny Express App\n\nimport requests as req\nfrom maplibre import Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl\nfrom maplibre.ui import use_deckgl\nfrom shiny.express import input, render, ui\n\ndata = req.get(\n \"https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson\"\n).json()\n\nm = Map(\n MapOptions(\n style=Carto.POSITRON,\n center=(0.45, 51.47),\n zoom=4,\n hash=True,\n pitch=30,\n )\n)\nm.add_control(NavigationControl())\n\ndeck_geojson_layer = {\n \"@@type\": \"GeoJsonLayer\",\n \"id\": \"airports\",\n \"data\": data,\n \"filled\": True,\n \"pointRadiusMinPixels\": 2,\n \"pointRadiusScale\": 2000,\n \"getPointRadius\": \"@@=11 - properties.scalerank\",\n \"getFillColor\": [200, 0, 80, 180],\n \"autoHighlight\": True,\n \"pickable\": True,\n}\n\ndeck_arc_layer = {\n \"@@type\": \"ArcLayer\",\n \"id\": \"arcs\",\n \"data\": [\n feature\n for feature in data[\"features\"]\n if feature[\"properties\"][\"scalerank\"] < 4\n ],\n \"getSourcePosition\": [-0.4531566, 51.4709959], # London\n \"getTargetPosition\": \"@@=geometry.coordinates\",\n \"getSourceColor\": [0, 128, 200],\n \"getTargetColor\": [200, 0, 80],\n \"getWidth\": 2,\n \"pickable\": True,\n}\n\nm.add_deck_layers(\n [deck_geojson_layer, deck_arc_layer],\n tooltip={\n \"airports\": \"{{ &properties.name }}\",\n \"arcs\": \"gps_code: {{ properties.gps_code }}\",\n },\n)\n\n# Shiny Express\nuse_deckgl()\n\n\n@render_maplibregl\ndef render_map():\n return m\n\n\nif __name__ == \"__main__\":\n with open(\"docs/examples/deckgl_multiple_layers/app.html\", \"w\") as f:\n f.write(m.to_html())\n
"},{"location":"examples/earthquake_clusters/","title":"Earthquake Clusters","text":"# Run Shiny app\npoetry run shiny run docs/examples/deckgl_multiple_layers/app.py\n
import sys\n\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl\nfrom maplibre.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\n\ndef create_map() -> Map:\n m = Map(map_options)\n m.add_control(NavigationControl())\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\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 return create_map()\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 if len(sys.argv) == 2:\n file_name = sys.argv[1]\n with open(file_name, \"w\") as f:\n f.write(create_map().to_html())\n else:\n app.run()\n
"},{"location":"examples/every_person_in_manhattan/","title":"Every Person in Manhattan","text":"poetry run uvicorn docs.examples.earthquake_clusters.app:app --reload\n
import json\nimport sys\n\nimport pandas as pd\nimport shapely\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapContext,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl, ScaleControl\nfrom maplibre.sources import GeoJSONSource\nfrom maplibre.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 hash=True,\n)\n\n\ndef create_map() -> Map:\n m = Map(map_options)\n m.add_control(NavigationControl())\n m.add_control(ScaleControl(), position=\"bottom-left\")\n m.add_layer(every_person_in_manhattan_circles)\n return m\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 return create_map()\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 if len(sys.argv) == 2:\n file_name = sys.argv[1]\n with open(file_name, \"w\") as f:\n f.write(create_map().to_html())\n else:\n app.run()\n
"},{"location":"examples/geopandas/","title":"GeoPandas","text":"poetry run uvicorn docs.examples.every_person_in_manhattan.app:app --reload\n
import sys\nimport webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import GeoJSONSource\nfrom maplibre.utils import geopandas_to_geojson\n\nimport geopandas as gpd\n\nfile_name = \"/tmp/pymaplibregl_temp.html\"\nLAYER_ID = \"wilderness\"\n\ndf_geo = gpd.read_file(\n \"zip+https://github.com/Toblerity/Fiona/files/11151652/coutwildrnp.zip\"\n)\n\nwilderness_source = GeoJSONSource(data=geopandas_to_geojson(df_geo))\n\nwilderness_layer = Layer(\n type=LayerType.FILL,\n id=LAYER_ID,\n source=wilderness_source,\n paint={\"fill-color\": \"darkred\", \"fill-opacity\": 0.5},\n)\n\nmap_options = MapOptions(bounds=df_geo.total_bounds)\n\n\ndef create_map():\n m = Map(map_options)\n m.add_control(NavigationControl())\n m.add_layer(wilderness_layer)\n m.add_tooltip(LAYER_ID, \"NAME\")\n return m\n\n\nif __name__ == \"__main__\":\n m = create_map()\n if len(sys.argv) == 2:\n file_name = sys.argv[1]\n\n with open(file_name, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(file_name)\n
"},{"location":"examples/layer_order/","title":"Layer Order","text":"poetry run python docs/examples/geopandas/app.py\n
# Shiny Express App\n\nimport requests as req\nfrom maplibre import Layer, LayerType, Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import Carto, construct_carto_basemap_url\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import GeoJSONSource\nfrom shiny.express import input, render, ui\n\nstyle = req.get(construct_carto_basemap_url(Carto.VOYAGER)).json()\n\n\nsymbol_ids = [layer[\"id\"] for layer in style[\"layers\"] if layer[\"type\"] == \"symbol\"]\n# print(symbol_ids)\n\nurban_areas = GeoJSONSource(\n data=\"https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_urban_areas.geojson\"\n)\n\nm = Map(\n MapOptions(\n style=style,\n center=(-89.928, 35.204),\n # center=(-88.13734351262877, 35.137451890638886),\n zoom=9,\n hash=True,\n )\n)\nm.add_control(NavigationControl())\nm.add_layer(\n Layer(\n id=\"urban-areas-fill\",\n type=LayerType.FILL,\n source=urban_areas,\n paint={\"fill-color\": \"pink\", \"fill-opacity\": 1.0},\n ),\n before_id=symbol_ids[0],\n)\nfor symbol_id in symbol_ids:\n m.set_paint_property(symbol_id, \"text-color\", \"purple\")\n\n\n@render_maplibregl\ndef render_map():\n return m\n\n\nif __name__ == \"__main__\":\n with open(\"docs/examples/layer_order/app.html\", \"w\") as f:\n f.write(m.to_html())\n
"},{"location":"examples/layer_switcher/","title":"Layer Switcher","text":"poetry run shiny run docs/examples/layer_order/app.py\n
# Example taken from here: https://maplibre.org/maplibre-gl-js/docs/examples/pmtiles/\n\nimport webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import construct_basemap_style\nfrom maplibre.controls import (\n ControlPosition,\n InfoBoxControl,\n LayerSwitcherControl,\n NavigationControl,\n)\nfrom shiny.express import input, render, ui\n\nPMTILES_URL = \"https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles\"\n\npmtiles_source = {\n \"type\": \"vector\",\n \"url\": f\"pmtiles://{PMTILES_URL}\",\n \"attribution\": '\u00a9 <a href=\"https://openstreetmap.org\">OpenStreetMap</a>',\n}\n\ncustom_basemap = construct_basemap_style(\n sources={\"pmtiles\": pmtiles_source},\n layers=[\n Layer(\n id=\"buildings\",\n source=\"pmtiles\",\n source_layer=\"landuse\",\n type=LayerType.FILL,\n paint={\"fill-color\": \"red\"},\n layout={\"visibility\": \"none\"},\n ),\n Layer(\n id=\"roads\",\n source=\"pmtiles\",\n source_layer=\"roads\",\n type=LayerType.LINE,\n paint={\"line-color\": \"black\"},\n ),\n Layer(\n id=\"mask\",\n source=\"pmtiles\",\n source_layer=\"mask\",\n type=LayerType.FILL,\n paint={\"fill-color\": \"yellow\"},\n layout={\"visibility\": \"none\"},\n ),\n ],\n)\n\n\nmap_options = MapOptions(\n style=custom_basemap,\n # hash=True,\n # bounds=(11.154026, 43.7270125, 11.3289395, 43.8325455),\n center=(11.2415, 43.7798),\n zoom=12.5,\n)\n\n\ndef create_map():\n m = Map(map_options)\n m.add_control(NavigationControl())\n m.add_control(\n InfoBoxControl(\n content=\"Toggle layers of PMTiles source\",\n css_text=\"padding: 10px; background-color: yellow; color: steelblue; font-weight: bold;\",\n ),\n ControlPosition.TOP_LEFT,\n )\n m.add_control(\n LayerSwitcherControl(\n layer_ids=[\"buildings\", \"roads\", \"mask\"],\n css_text=\"padding: 5px; border: 1px solid darkgrey; border-radius: 4px;\",\n ),\n position=ControlPosition.TOP_LEFT,\n )\n return m\n\n\n@render_maplibregl\ndef render_map():\n return create_map()\n\n\nif __name__ == \"__main__\":\n file_name = \"docs/examples/layer_switcher/app.html\"\n\n m = create_map()\n with open(file_name, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(file_name)\n
"},{"location":"examples/mapbox_draw_plugin/","title":"Mapbox Draw Plugin","text":"shiny run docs/examples/layer_switcher/app.py\n
# Shiny Express App\n\nimport json\nimport webbrowser\n\nfrom maplibre import Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import ControlPosition, NavigationControl, ScaleControl\nfrom maplibre.plugins import MapboxDrawControls, MapboxDrawOptions\nfrom maplibre.ui import use_mapboxgl_draw\n\n# from shiny import reactive\nfrom shiny.express import input, render, ui\n\ngeojson_feature = {\n \"id\": \"xyz\",\n \"type\": \"Feature\",\n \"properties\": {},\n \"geometry\": {\n \"coordinates\": [\n [\n [-122.4523683552298, 37.775540942000546],\n [-122.41910082339776, 37.75932501909665],\n [-122.43487191413453, 37.72543546737114],\n [-122.46053073611722, 37.729612763886834],\n [-122.4523683552298, 37.775540942000546],\n ]\n ],\n \"type\": \"Polygon\",\n },\n}\n\nm = Map(\n MapOptions(\n style=Carto.POSITRON,\n center=(-122.4, 37.74),\n zoom=12,\n hash=True,\n pitch=40,\n )\n)\nm.add_control(NavigationControl())\nm.add_control(ScaleControl(), ControlPosition.BOTTOM_LEFT)\n\n# Optional: only activate a given set of controls\ndraw_options = MapboxDrawOptions(\n display_controls_default=False,\n controls=MapboxDrawControls(polygon=True, line_string=True, trash=True),\n)\n# Use options from above\n# m.add_mapbox_draw(draw_options, geojson=geojson_feature)\n\n# If no options are passed, all controls are activated by default\nm.add_mapbox_draw(geojson=geojson_feature)\n\n# Shiny Express\nuse_mapboxgl_draw()\n\n\n@render_maplibregl\ndef maplibre():\n return m\n\n\n@render.code\ndef selected_features():\n obj = input.maplibre_draw_features_selected()\n print(obj)\n return json.dumps(obj[\"features\"], indent=2) if obj else \"Pick some features!\"\n\n\nif __name__ == \"__main__\":\n filename = \"docs/examples/mapbox_draw_plugin/app.html\"\n with open(filename, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(filename)\n
"},{"location":"examples/pmtiles/","title":"PMTiles","text":"shiny run docs/examples/mapbox_draw_plugin/app.py\n
# Example taken from here: https://maplibre.org/maplibre-gl-js/docs/examples/pmtiles/\n\nimport webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import construct_basemap_style\nfrom maplibre.controls import NavigationControl\nfrom shiny.express import input, render, ui\n\nPMTILES_URL = \"https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles\"\n\npmtiles_source = {\n \"type\": \"vector\",\n \"url\": f\"pmtiles://{PMTILES_URL}\",\n \"attribution\": '\u00a9 <a href=\"https://openstreetmap.org\">OpenStreetMap</a>',\n}\n\ncustom_basemap = construct_basemap_style(\n sources={\"pmtiles\": pmtiles_source},\n layers=[\n Layer(\n id=\"buildings\",\n source=\"pmtiles\",\n source_layer=\"landuse\",\n type=LayerType.FILL,\n paint={\"fill-color\": \"steelblue\"},\n ),\n Layer(\n id=\"roads\",\n source=\"pmtiles\",\n source_layer=\"roads\",\n type=LayerType.LINE,\n paint={\"line-color\": \"black\"},\n ),\n Layer(\n id=\"mask\",\n source=\"pmtiles\",\n source_layer=\"mask\",\n type=LayerType.FILL,\n paint={\"fill-color\": \"white\"},\n ),\n ],\n)\n\n\nmap_options = MapOptions(\n style=custom_basemap,\n bounds=(11.154026, 43.7270125, 11.3289395, 43.8325455),\n)\n\n\ndef create_map():\n m = Map(map_options)\n m.add_control(NavigationControl())\n return m\n\n\n@render_maplibregl\ndef render_map():\n return create_map()\n\n\nif __name__ == \"__main__\":\n file_name = \"docs/examples/pmtiles/app.html\"\n\n m = create_map()\n with open(file_name, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(file_name)\n
"},{"location":"examples/road_safety/","title":"H3 Grid UK Road Safety","text":"shiny run docs/examples/pmtiles/app.py\n
import sys\nimport webbrowser\n\nimport h3\nimport pandas as pd\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapContext,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import GeoJSONSource\nfrom maplibre.utils import df_to_geojson\nfrom shiny import App, reactive, ui\n\nRESOLUTION = 7\nCOLORS = (\n \"lightblue\",\n \"turquoise\",\n \"lightgreen\",\n \"yellow\",\n \"orange\",\n \"darkred\",\n)\n\nroad_safety = pd.read_csv(\n \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv\"\n).dropna()\n\n\ndef create_h3_grid(res=RESOLUTION) -> dict:\n road_safety[\"h3\"] = road_safety.apply(\n lambda x: h3.geo_to_h3(x[\"lat\"], x[\"lng\"], resolution=res), axis=1\n )\n df = road_safety.groupby(\"h3\").h3.agg(\"count\").to_frame(\"count\").reset_index()\n df[\"hexagon\"] = df.apply(\n lambda x: [h3.h3_to_geo_boundary(x[\"h3\"], geo_json=True)], axis=1\n )\n df[\"color\"] = pd.cut(\n df[\"count\"],\n bins=len(COLORS),\n labels=COLORS,\n )\n return df_to_geojson(\n df, \"hexagon\", geometry_type=\"Polygon\", properties=[\"count\", \"color\"]\n )\n\n\nsource = GeoJSONSource(data=create_h3_grid())\n\nmap_options = MapOptions(\n center=(-1.415727, 52.232395),\n zoom=7,\n pitch=40,\n bearing=-27,\n)\n\nh3_layer = Layer(\n id=\"road-safety\",\n type=LayerType.FILL_EXTRUSION,\n source=source,\n paint={\n \"fill-extrusion-color\": [\"get\", \"color\"],\n \"fill-extrusion-opacity\": 0.7,\n \"fill-extrusion-height\": [\"*\", 100, [\"get\", \"count\"]],\n },\n)\n\n\ndef create_map() -> Map:\n m = Map(map_options)\n m.add_control(NavigationControl())\n m.add_layer(h3_layer)\n m.add_tooltip(\"road-safety\", \"count\")\n return m\n\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Road safety in UK\"),\n output_maplibregl(\"mapylibre\", height=700),\n ui.input_slider(\"res\", \"Resolution\", min=4, max=8, step=1, value=RESOLUTION),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def mapylibre():\n return create_map()\n\n @reactive.Effect\n @reactive.event(input.res, ignore_init=True)\n async def resolution():\n async with MapContext(\"mapylibre\") as m:\n with ui.Progress() as p:\n p.set(message=\"H3 calculation in progress\")\n m.set_data(\"road-safety\", create_h3_grid(input.res()))\n p.set(1, message=\"Calculation finished\")\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n filename = sys.argv[1] if len(sys.argv) == 2 else \"/tmp/road_safety.html\"\n with open(filename, \"w\") as f:\n m = create_map()\n f.write(m.to_html(style=\"height: 700px;\"))\n\n webbrowser.open(filename)\n
"},{"location":"examples/vancouver_blocks/","title":"Vancouver Property Value","text":"poetry run uvicorn docs.examples.road_safety.app:app --reload\n
import sys\n\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapContext,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl, ScaleControl\nfrom maplibre.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, \"darkred\"],\n [50000, \"lightblue\"],\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\n\ndef create_map() -> Map:\n m = Map(map_options)\n m.add_control(NavigationControl())\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\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=600),\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 ui.input_checkbox_group(\n \"layers\",\n \"Layers\",\n choices=[LAYER_ID_FILL, LAYER_ID_LINES],\n selected=[LAYER_ID_FILL, LAYER_ID_LINES],\n ),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre():\n m = create_map()\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 @reactive.Effect\n @reactive.event(input.layers)\n async def layers():\n visible_layers = input.layers()\n async with MapContext(\"maplibre\") as m:\n for layer in [LAYER_ID_FILL, LAYER_ID_LINES]:\n m.set_visibility(layer, layer in visible_layers)\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n if len(sys.argv) == 2:\n file_name = sys.argv[1]\n m = create_map()\n with open(file_name, \"w\") as f:\n f.write(m.to_html())\n else:\n app.run()\n
"},{"location":"examples/vector_tiles/","title":"Vector Tiles","text":"poetry run uvicorn docs.examples.vancouver_blocks.app:app --reload\n
# Example taken from here:\n# https://maplibre.org/maplibre-gl-js/docs/API/classes/VectorTileSource/\n# https://maplibre.org/maplibre-style-spec/sources/\n\nimport webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import VectorTileSource\nfrom shiny.express import input, render, ui\n\n# Get layer ids and pbf url from here\nVECTOR_TILES_URL = \"https://demotiles.maplibre.org/tiles/tiles.json\"\nLAYER_ID = \"countries\"\n\nvector_source = VectorTileSource(\n url=VECTOR_TILES_URL,\n # tiles=[\"https://demotiles.maplibre.org/tiles/{z}/{x}/{y}.pbf\"],\n min_zoom=0,\n max_zoom=6,\n)\n\nvector_layer = Layer(\n type=LayerType.FILL,\n id=LAYER_ID,\n source=vector_source,\n paint={\"fill-color\": \"lightgreen\", \"fill-outline-color\": \"black\"},\n source_layer=\"countries\",\n)\n\n\ndef create_map():\n m = Map(MapOptions(style=Carto.POSITRON, center=(11, 42), zoom=3, hash=True))\n m.add_control(NavigationControl())\n m.add_layer(vector_layer)\n m.add_tooltip(LAYER_ID)\n return m\n\n\n@render_maplibregl\ndef render_map():\n return create_map()\n\n\nif __name__ == \"__main__\":\n file_name = \"docs/examples/vector_tiles/app.html\"\n\n m = create_map()\n with open(file_name, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(file_name)\n
"},{"location":"examples/where_is_the_iss/","title":"Where is the ISS","text":"shiny run docs/examples/vector_tiles/app.py\n
import requests\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapContext,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import GeoJSONSource\nfrom shiny import App, reactive, ui\n\nMAX_FEATURES = 30\nSOURCE_ID_ISS_POSITION = \"iss_position\"\nSOURCE_ID_ISS_LAST_POSITIONS = \"iss-last-positions\"\n\n\ndef where_is_the_iss() -> tuple:\n r = requests.get(\"https://api.wheretheiss.at/v1/satellites/25544\").json()\n return (r[\"longitude\"], r[\"latitude\"])\n\n\ndef create_feature(lng_lat: tuple) -> dict:\n return {\n \"type\": \"Feature\",\n \"geometry\": {\n \"type\": \"Point\",\n \"coordinates\": lng_lat,\n },\n \"properties\": {\"coords\": \", \".join(map(str, lng_lat))},\n }\n\n\nlng_lat = where_is_the_iss()\nfeature = create_feature(where_is_the_iss())\nfeature_collection = {\"type\": \"FeatureCollection\", \"features\": [feature]}\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Where is the ISS\"),\n ui.div(\"Click on Update to get the current position of the ISS.\"),\n ui.div(\n \"The yellow dots show the positions before. Hover the blue dot to display the coordinates.\"\n ),\n output_maplibregl(\"mapylibre\", height=600),\n ui.input_action_button(\"update\", \"Update\"),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def mapylibre():\n m = Map(MapOptions(center=lng_lat, zoom=3))\n m.add_control(NavigationControl())\n m.set_paint_property(\"water\", \"fill-color\", \"darkblue\")\n m.add_source(\n SOURCE_ID_ISS_LAST_POSITIONS, GeoJSONSource(data=feature_collection)\n )\n m.add_layer(\n Layer(\n type=LayerType.CIRCLE,\n source=SOURCE_ID_ISS_LAST_POSITIONS,\n paint={\"circle-color\": \"yellow\", \"circle-radius\": 5},\n ),\n )\n m.add_source(SOURCE_ID_ISS_POSITION, GeoJSONSource(data=feature))\n m.add_layer(\n Layer(\n type=LayerType.CIRCLE,\n id=\"iss-position\",\n source=SOURCE_ID_ISS_POSITION,\n paint={\"circle-color\": \"lightblue\", \"circle-radius\": 7},\n )\n )\n m.add_tooltip(\"iss-position\", \"coords\")\n return m\n\n @reactive.Effect\n @reactive.event(input.update)\n async def update():\n print(\"Fetching new position\")\n lng_lat = where_is_the_iss()\n print(lng_lat)\n if len(feature_collection[\"features\"]) == MAX_FEATURES:\n feature_collection[\"features\"] = []\n\n async with MapContext(\"mapylibre\") as m:\n feature = create_feature(lng_lat)\n m.set_data(SOURCE_ID_ISS_POSITION, feature)\n feature_collection[\"features\"].append(feature)\n m.set_data(SOURCE_ID_ISS_LAST_POSITIONS, feature_collection)\n m.add_call(\"flyTo\", {\"center\": lng_lat, \"speed\": 0.5})\n\n\napp = App(app_ui, server)\n
"},{"location":"examples/wms/","title":"WMS","text":"poetry run uvicorn docs.examples.where_is_the_iss.app:app --reload\n
"}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"MapLibre for Python","text":"import webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import RasterTileSource\n\nSOURCE_ID = \"wms-test-source\"\nLAYER_ID = \"wms-test-layer\"\n\nwms_source = RasterTileSource(\n tiles=[\n \"https://img.nj.gov/imagerywms/Natural2015?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.1&request=GetMap&srs=EPSG:3857&transparent=true&width=256&height=256&layers=Natural2015\"\n ],\n tile_size=256,\n)\nwms_layer = Layer(type=LayerType.RASTER, source=SOURCE_ID, id=LAYER_ID)\n\nmap_options = MapOptions(zoom=8, center=(-74.5447, 40.6892))\n\nm = Map(map_options=map_options)\nm.add_control(NavigationControl())\nm.add_source(SOURCE_ID, wms_source)\nm.add_layer(wms_layer)\n\nfilename = \"docs/examples/wms/app.html\"\n\nwith open(filename, \"w\") as f:\n f.write(m.to_html(style=\"height: 800px;\"))\n\nwebbrowser.open(filename)\n
"},{"location":"#basic-usage","title":"Basic usage","text":""},{"location":"#standalone","title":"Standalone","text":"# Stable\npip install maplibre\n\npip install \"maplibre[all]\"\n\n# Dev\npip install git+https://github.com/eoda-dev/py-maplibregl@dev\n
"},{"location":"#shiny-integration","title":"Shiny integration","text":"from maplibre import Layer, LayerType, Map, MapOptions\nfrom maplibre.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\nm.save(preview=True)\n
"},{"location":"#jupyter-widget","title":"Jupyter widget","text":"from maplibre import Map, MapContext, output_maplibregl, render_maplibregl\nfrom maplibre.controls import Marker\nfrom shiny import App, reactive, ui\n\napp_ui = ui.page_fluid(\n output_maplibregl(\"maplibre_map\", height=600),\n ui.div(\"Click on map to set a marker\"),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre_map():\n return Map()\n\n @reactive.Effect\n @reactive.event(input.maplibre_map_clicked)\n async def coords():\n async with MapContext(\"maplibre_map\") as m:\n input_value = input.maplibre_map_clicked()\n print(input_value)\n lng_lat = tuple(input_value[\"coords\"].values())\n marker = Marker(lng_lat=lng_lat)\n m.add_marker(marker)\n m.add_call(\"flyTo\", {\"center\": lng_lat})\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n app.run()\n
"},{"location":"changelog/","title":"Changelog for MapLibre for Python","text":""},{"location":"changelog/#maplibre-v027","title":"maplibre v0.2.7","text":"from maplibre.ipywidget import MapWidget as Map\n\nm = Map()\nm\n
"},{"location":"changelog/#maplibre-v026","title":"maplibre v0.2.6","text":"basemaps.MapTiler
maplibre.__future__
Map.fit_bounds
maplibre.expressions
:interpolate
step_expr
quantile_expr
match_expr
color_step_expr
color_quantile_expr
color_match_expr
filter_expr
range_filter
pydeck.Layer
forMap.add_deck_layers
and Map.set_deck_layers
sources.SimpleFeatures
for geopandas.GeoDataFrame
sources geopandas.GeoDataFrame
as source inLayer
andMap.add_source
Map
class for simpler map initialization:layers
: listsources
: dictcontrols
: listposition
attribute to Control
classessources.VectorTileSource
(Martenz)input.{output_id}_view_state
dict containing {\"center\", \"zoom\", \"bounds\", \"pitch\", \"bearing\"}
input.{output_id}
to input.{output_id}_clicked
input.{output_id}_layer_{layer_id}
to input.{output_id}_feature_clicked
returning layer_id
Map.view_state
dict containing {\"center\", \"zoom\", \"bounds\", \"pitch\", \"bearing\"}
(#89)Map.center
, Map.zoom
, Map.bounds
"},{"location":"changelog/#maplibre-v025","title":"maplibre v0.2.5","text":"maplibre.utils
to save map and display it in the browserstreamlit.components.v1.iframe
component
"},{"location":"changelog/#maplibre-v024","title":"maplibre v0.2.4","text":"LayerSwitcherControl
(#69)InfoBoxControl
(#74)
"},{"location":"changelog/#maplibre-v023","title":"maplibre v0.2.3","text":"MapboxDraw
plugin (#59)MapboxDraw
:<output_id>.draw_features_selected
MapboxDraw
:Map.draw_features_selected
(list)Map.draw_feature_collection_all
(dict)
"},{"location":"changelog/#maplibre-v022","title":"maplibre v0.2.2","text":"Map.center
Map.bounds
Map.zoom
Map.lat_lng
> Map.clicked
(rename)MapOptions.zoom: int
> Union[int, float]
MapOptions.bearing: int
> Union[int, float]
MapOptions.pitch: int
> Union[int, float]
"},{"location":"changelog/#maplibre-v021","title":"maplibre v0.2.1","text":"
"},{"location":"changelog/#maplibre-v020","title":"maplibre v0.2.0","text":"
"},{"location":"changelog/#maplibre-v016","title":"maplibre v0.1.6","text":"
"},{"location":"changelog/#maplibre-v015","title":"maplibre v0.1.5","text":"before_id
parameter to add_layer
method (#45, #47)
"},{"location":"changelog/#maplibre-v014","title":"maplibre v0.1.4","text":"shiny>=0.7.0
"},{"location":"changelog/#maplibre-v013","title":"maplibre v0.1.3","text":"anywidget>=0.9.0
(#36)
"},{"location":"changelog/#maplibre-v012","title":"maplibre v0.1.2","text":"prop = None
(#26)
"},{"location":"changelog/#maplibre-v011","title":"maplibre v0.1.1","text":"Map.set_data
Map.set_visibility
ipywidget.MapWidget
in __init__
and skip tests for MapWidget
, because it causes a core dumped
error, see anywidget issuerequests
dependency
"},{"location":"deckgl/","title":"Deck.GL Layers","text":"Map.add_deck_layers
.@@type
prefix and getter props the @@=
prefix. They are inserted into the layer stack of the maplibre context. Therefore, you can also pass a beforeId
prop.grid_layer = {\n \"@@type\": \"GridLayer\", # JS: new GridLayer\n \"id\": \"my-awsome-grid-layer\",\n \"data\": \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/sf-bike-parking.json\",\n \"extruded\": True,\n \"getPosition\": \"@@=COORDINATES\", # JS: d => d.COORDINATES\n \"getColorWeight\": \"@@=SPACES\", # JS: d => d.SPACES\n \"getElevationWeight\": \"@@=SPACES\", # JS: d => d.SPACES\n \"elevationScale\": 4,\n \"cellSize\": 200,\n \"pickable\": True,\n \"beforeId\": \"first-labels-layer\" # optional\n }\n
const gridLayer = new GridLayer({\n id: 'GridLayer',\n data: 'https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/sf-bike-parking.json',\n extruded: true,\n getPosition: d => d.COORDINATES,\n getColorWeight: d => d.SPACES,\n getElevationWeight: d => d.SPACES,\n elevationScale: 4,\n cellSize: 200,\n pickable: true\n});\n
"},{"location":"jupyter/","title":"Jupyter","text":"MapWidget
in your Jupyter Notebook:
"},{"location":"layers/","title":"Layers","text":"import ipywidgets as widgets\n\nfrom maplibre import Layer, LayerType\nfrom maplibre.sources import GeoJSONSource\nfrom maplibre.controls import ScaleControl, Marker\nfrom maplibre.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# Create 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\n_ = widgets.interact(\n lambda radius: m.set_paint_property(layer_id, \"circle-radius\", radius),\n radius=(1, 8, 1)\n)\n\n# Change color\n_ = widgets.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\n_ = widgets.interact(\n lambda mag_min: m.set_filter(layer_id, [\">=\", [\"get\", \"mag\"], mag_min]),\n mag_min=(1, 8, 1)\n)\n
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.paint
property looks like this:paint = {\n \"circle-radius\": 5,\n \"circle-color\": \"yellow\"\n}\n
layout
property, paint
property, or filter
may also be specified as an expression. For details see Expressions.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
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
magnitude
property:
"},{"location":"shiny/","title":"Shiny","text":""},{"location":"shiny/#input-and-output","title":"Input and output","text":"# Only show features where magnitude >= 5\nfilter = [\">=\", [\"get\", \"magnitude\"], 5]\n
output_maplibregl
in the UI and render_maplibregl
in the server section of your Shiny for Python app:
"},{"location":"shiny/#reactivity","title":"Reactivity","text":""},{"location":"shiny/#input-events","title":"Input events","text":"from shiny import App, ui\nfrom maplibre 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\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre():\n m = Map()\n return m\n\n\napp = App(app_ui, server)\n
"},{"location":"shiny/#map-updates","title":"Map updates","text":"input.{output_id}_clicked
: Sends coordinates of the clicked location on the map.input.{output_id}_feature_clicked
: Sends the properties of the clicked feature and its layer id.input.{output_id}_view_state
: Sends the current view state. Fired when the view state is changed.MapContext
to update your Map
object.import json\n\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapContext,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import GeoJSONSource\nfrom shiny import App, reactive, render, ui\n\nLAYER_ID = \"earthquakes\"\nCIRCLE_RADIUS = 5\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"MapLibre for Python\"),\n output_maplibregl(\"mapgl\", height=600),\n ui.div(\"Click on the map to print the coords.\", style=\"padding: 10px;\"),\n ui.output_text_verbatim(\"coords\", placeholder=True),\n ui.div(\"Click on a feature to print its props.\", style=\"padding: 10px;\"),\n ui.output_text_verbatim(\"props\", placeholder=True),\n ui.div(\"Move map or zoom to update view state.\", style=\"padding: 10px;\"),\n ui.output_text_verbatim(\"view_state\", placeholder=True),\n ui.input_slider(\"radius\", \"Radius\", value=CIRCLE_RADIUS, min=1, max=10),\n)\n\ncircle_layer = 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\ndef server(input, output, session):\n @render_maplibregl\n def mapgl():\n m = Map(zoom=3, pitch=40)\n m.add_control(NavigationControl())\n m.add_layer(circle_layer)\n return m\n\n @render.text\n def coords():\n return str(input.mapgl_clicked())\n\n @render.text\n def view_state():\n return json.dumps(input.mapgl_view_state(), indent=2)\n\n @render.text\n def props():\n return str(input.mapgl_feature_clicked())\n\n @reactive.Effect\n @reactive.event(input.radius)\n async def radius():\n async with MapContext(\"mapgl\") as m:\n m.set_paint_property(LAYER_ID, \"circle-radius\", input.radius())\n\n\napp = App(app_ui, server)\n
"},{"location":"shiny_express/","title":"Shiny Express","text":"poetry run uvicorn docs.examples.getting_started.reactivity:app --reload\n
output_id
corresponds to the name of the render function. For the example below the output_id
is mapgl
, so that you have to listen to input.mapgl_clicked
to get the map clicked event.
"},{"location":"streamlit/","title":"Streamlit","text":"import json\n\nfrom shiny import reactive\nfrom shiny.express import input, render, ui\n\nfrom maplibre import Map, MapContext, MapOptions, render_maplibregl\nfrom maplibre.controls import Marker\n\nui.h1(\"My awesome MapLibre map\")\n\n\n@render_maplibregl\ndef mapgl():\n return Map(MapOptions(zoom=3, pitch=40))\n\n\nui.div(\"Click on map to show coords.\")\n\n\n@render.code\ndef coords():\n return str(input.mapgl_clicked())\n\n\nui.div(\"Move map to change view state.\")\n\n\n@render.code\ndef view_state():\n return json.dumps(input.mapgl_view_state(), indent=2)\n\n\n@reactive.Effect\n@reactive.event(input.mapgl_clicked)\nasync def set_marker():\n async with MapContext(\"mapgl\") as m:\n m.add_marker(Marker(lng_lat=input.mapgl_clicked()[\"coords\"].values()))\n
maplibre.streamlit.st_maplibre
to add a MapLibre map to your Streamlit app:
"},{"location":"api/basemaps/","title":"Basemaps","text":""},{"location":"api/basemaps/#maplibre.basemaps.Carto","title":"import streamlit as st\nfrom maplibre import Map, MapOptions\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl\nfrom maplibre.streamlit import st_maplibre\n\n\ndef create_layer(cell_size: int = 200) -> dict:\n return {\n \"@@type\": \"GridLayer\",\n \"id\": \"GridLayer\",\n \"data\": \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/sf-bike-parking.json\",\n \"extruded\": True,\n \"getPosition\": \"@@=COORDINATES\",\n \"getColorWeight\": \"@@=SPACES\",\n \"getElevationWeight\": \"@@=SPACES\",\n \"elevationScale\": 4,\n \"cellSize\": cell_size,\n \"pickable\": True,\n }\n\n\nmap_options = MapOptions(\n style=Carto.POSITRON,\n center=(-122.4, 37.74),\n zoom=12,\n hash=True,\n pitch=40,\n)\n\n\nst.title(\"SF Bike Parking\")\n\ncell_size = st.slider(\"cell size\", 100, 600, value=200, step=5)\n\nm = Map(map_options)\nm.add_control(NavigationControl())\nm.add_deck_layers([create_layer(cell_size)], tooltip=\"Number of points: {{ count }}\")\n\nst_maplibre(m)\n
maplibre.basemaps.Carto
","text":"Enum
DARK_MATTER
\u2013 POSITRON
\u2013 VOYAGER
\u2013 POSITRON_NOLABELS
\u2013 DARK_MATTER_NOLABELS
\u2013 VOYAGER_NOLABELS
\u2013 >>> from maplibre import Map, MapOptions\n>>> from maplibre.basemaps import Carto\n
Source code in >>> m = Map(MapOptions(style=Carto.DARK_MATTER))\n
maplibre/basemaps.py
"},{"location":"api/basemaps/#maplibre.basemaps.construct_basemap_style","title":"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 maplibre import Map, MapOptions\n >>> from maplibre.basemaps import Carto\n\n >>> m = 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
maplibre.basemaps.construct_basemap_style(name='nice-style', sources={}, layers=[])
","text":"name
str
'nice-style'
sources
dict
{}
layers
list
[]
Source code in maplibre/basemaps.py
"},{"location":"api/controls/","title":"Markers and controls","text":""},{"location":"api/controls/#maplibre.controls.Popup","title":"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
maplibre.controls.Popup
","text":"MapLibreBaseModel
text
str
options
PopupOptions | dict
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.PopupOptions","title":"class Popup(MapLibreBaseModel):\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
maplibre.controls.PopupOptions
","text":"MapLibreBaseModel
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.Marker","title":"class PopupOptions(MapLibreBaseModel):\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
maplibre.controls.Marker
","text":"MapLibreBaseModel
lng_lat
tuple | list
popup
Popup | dict
options
MarkerOptions | dict
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.MarkerOptions","title":"class Marker(MapLibreBaseModel):\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
maplibre.controls.MarkerOptions
","text":"MapLibreBaseModel
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.ControlPosition","title":"class MarkerOptions(MapLibreBaseModel):\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
maplibre.controls.ControlPosition
","text":"Enum
Source code in TOP_LEFT
\u2013 TOP_RIGHT
\u2013 BOTTOM_LEFT
\u2013 BOTTOM_RIGHT
\u2013 maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.FullscreenControl","title":"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
maplibre.controls.FullscreenControl
","text":"Control
>>> from maplibre import Map\n>>> from maplibre.controls import FullscreenControl, ControlPosition\n
Source code in >>> m = Map()\n>>> m.add_control(FullscreenControl(), ControlPosition.BOTTOM_LEFT)\n
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.ScaleControl","title":"class FullscreenControl(Control):\n \"\"\"Fullscreen control\n\n Examples:\n >>> from maplibre import Map\n >>> from maplibre.controls import FullscreenControl, ControlPosition\n\n >>> m = Map()\n >>> m.add_control(FullscreenControl(), ControlPosition.BOTTOM_LEFT)\n \"\"\"\n\n # _name: str = ControlType.FULLSCREEN.value\n pass\n
maplibre.controls.ScaleControl
","text":"Control
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.NavigationControl","title":"class ScaleControl(Control):\n \"\"\"Scale control\"\"\"\n\n max_width: int = Field(None, serialization_alias=\"maxWidth\")\n unit: Literal[\"imperial\", \"metric\", \"nautical\"] = \"metric\"\n
maplibre.controls.NavigationControl
","text":"Control
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.GeolocateControl","title":"class NavigationControl(Control):\n \"\"\"Navigation control\"\"\"\n\n # _name: str = ControlType.NAVIGATION.value\n show_compass: bool = Field(True, serialization_alias=\"showCompass\")\n show_zoom: bool = Field(True, serialization_alias=\"showZoom\")\n visualize_pitch: bool = Field(False, serialization_alias=\"visualizePitch\")\n
maplibre.controls.GeolocateControl
","text":"Control
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.InfoBoxControl","title":"class GeolocateControl(Control):\n \"\"\"Geolocate control\"\"\"\n\n # _name: str = ControlType.GEOLOCATE.value\n position_options: dict = Field(None, serialization_alias=\"positionOptions\")\n show_accuracy_circle: bool = Field(True, serialization_alias=\"showAccuracyCircle\")\n show_user_heading: bool = Field(False, serialization_alias=\"showUserHeading\")\n show_user_location: bool = Field(True, serialization_alias=\"showUserLocation\")\n track_user_location: bool = Field(False, serialization_alias=\"trackUserLocation\")\n
maplibre.controls.InfoBoxControl
","text":"Control
content
str
css_text
str
maplibre/controls.py
"},{"location":"api/controls/#maplibre.controls.LayerSwitcherControl","title":"class InfoBoxControl(Control):\n \"\"\"InfoBox control\n\n Attributes:\n content (str): Content (HTML or plain text) to be displayed in the info box.\n css_text (str): Optional inline style declaration of the control.\n \"\"\"\n\n content: str\n css_text: str = Field(None, serialization_alias=\"cssText\")\n
maplibre.controls.LayerSwitcherControl
","text":"Control
layer_ids
list
theme
Literal['default', 'simple']
css_text
str
maplibre/controls.py
"},{"location":"api/layer/","title":"Layer","text":""},{"location":"api/layer/#maplibre.Layer","title":"class LayerSwitcherControl(Control):\n \"\"\"Layer switcher control\n\n Attributes:\n layer_ids (list): A list of layer ids to be shown in the layer switcher control.\n theme (Literal[\"default\", \"simple\"]): The theme of the layer switcher control.\n css_text (str): Optional inline style declaration of the control.\n \"\"\"\n\n layer_ids: list = Field([], serialization_alias=\"layerIds\")\n theme: Literal[\"default\", \"simple\"] = \"default\"\n css_text: str = Field(None, serialization_alias=\"cssText\")\n
maplibre.Layer
","text":"MapLibreBaseModel
paint
and layout
properties of the layers.id
str
str(uuid4())
.type
str | LayerType
filter
list
layout
dict
max_zoom
int
min_zoom
int
paint
dict
source
str | Source | GeoDataFrame
source_layer
str
>>> from maplibre.layer import Layer, LayerType\n
Source code in >>> layer = Layer(id=\"test-layer\", type=LayerType.CIRCLE, source=\"test-source\")\n
maplibre/layer.py
"},{"location":"api/layer/#maplibre.LayerType","title":"class Layer(MapLibreBaseModel):\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): A filter expression that is applied to the source of the layer.\n layout (dict): The layout properties for 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 for the layer.\n source (str | Source | GeoDataFrame): The name (unique ID) of a source, a source object or a GeoDataFrame\n to be used for the layer.\n source_layer (str): The layer to use from a vector tile source.\n\n Examples:\n >>> from maplibre.layer import Layer, LayerType\n\n >>> layer = Layer(id=\"test-layer\", type=LayerType.CIRCLE, source=\"test-source\")\n \"\"\"\n\n id: Optional[str] = Field(default_factory=lambda: str(uuid4()))\n type: LayerType\n filter: Optional[list] = None\n layout: Optional[dict] = None\n max_zoom: Optional[int] = Field(None, serialization_alias=\"maxzoom\")\n metadata: Optional[dict] = None\n min_zoom: Optional[int] = Field(None, serialization_alias=\"minzoom\")\n paint: Optional[dict] = None\n source: Union[str, Source, dict, GeoDataFrame, None] = None\n source_layer: Optional[str] = Field(None, serialization_alias=\"source-layer\")\n\n # TODO: Use model_post_init and set bounds if source is a GeoDataFrame\n @field_validator(\"source\")\n def validate_source(cls, v):\n if GeoDataFrame is not None and isinstance(v, GeoDataFrame):\n return SimpleFeatures(v).to_source().to_dict()\n\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\n @property\n def bounds(self) -> tuple | None:\n try:\n bounds = get_bounds(self.source[\"data\"])\n except Exception as e:\n # print(e)\n bounds = None\n\n return bounds\n\n def set_paint_props(self, **props) -> Layer:\n if self.paint is None:\n self.paint = dict()\n\n self.paint = self.paint | fix_keys(props)\n return self\n\n def set_layout_props(self, **props) -> Layer:\n if self.layout is None:\n self.layout = dict()\n\n self.paint = self.paint | fix_keys(props)\n return self\n
maplibre.LayerType
","text":"Enum
Source code in CIRCLE
\u2013 FILL
\u2013 FILL_EXTRUSION
\u2013 LINE
\u2013 SYMBOL
\u2013 RASTER
\u2013 HEATMAP
\u2013 HILLSHADE
\u2013 BACKGROUND
\u2013 maplibre/layer.py
"},{"location":"api/map/","title":"Map","text":""},{"location":"api/map/#maplibre.Map","title":"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
maplibre.Map
","text":"object
map_options
MapOptions
MapOptions()
sources
dict
None
layers
list
None
controls
list
None
**kwargs
MapOptions
object.{}
Source code in >>> from maplibre.map import Map, MapOptions\n>>> map_options = MapOptions(center=(9.5, 51.31667), zoom=8)\n>>> m = Map(map_options)\n>>> dict(m)\n{'mapOptions': {'center': (9.5, 51.31667), 'style': 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json', 'zoom': 8}, 'calls': []}\n
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_call","title":"class Map(object):\n \"\"\"Map\n\n Args:\n map_options (MapOptions): Map options.\n sources (dict): Sources to be added to the map. Keys are source IDs.\n layers (list): Layers to be added to the map.\n controls (list): Controls to be added to the map.\n **kwargs: Keyword arguments that are appended to the `MapOptions` object.\n\n Examples:\n >>> from maplibre.map import Map, MapOptions\n >>> map_options = MapOptions(center=(9.5, 51.31667), zoom=8)\n >>> m = Map(map_options)\n >>> dict(m)\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__(\n self,\n map_options: MapOptions = MapOptions(),\n sources: dict = None,\n layers: list = None,\n controls: list = None,\n **kwargs,\n ):\n self.map_options = (\n map_options.to_dict() | kwargs\n ) # MapOptions(**kwargs).to_dict() # need to fix MapWidget, because height is passed as kwarg\n self._message_queue = []\n self.add_layers(layers, sources)\n if controls:\n for control in controls:\n self.add_control(control)\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 \"\"\"\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\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] = None,\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 position = position or control.position\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 | GeoDataFrame]) -> None:\n \"\"\"Add a source to the map\n\n Args:\n id (str): The unique ID of the source.\n source (Source | dict | GeoDataFrame): The source to be added to the map.\n \"\"\"\n if GeoDataFrame is not None and isinstance(source, GeoDataFrame):\n source = SimpleFeatures(source).to_source()\n\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], before_id: str = None) -> None:\n \"\"\"Add a layer to the map\n\n Args:\n layer (Layer | dict): The Layer to be added to the map.\n before_id (str): The ID of an existing layer to insert the new layer before,\n resulting in the new layer appearing visually beneath the existing layer.\n If `None`, the new layer will appear above all other layers.\n \"\"\"\n if isinstance(layer, Layer):\n layer = layer.to_dict()\n\n self.add_call(\"addLayer\", layer, before_id)\n\n def add_layers(self, layers: list = None, sources: dict = None):\n layers = layers or []\n sources = sources or dict()\n for source_id, source in sources.items():\n self.add_source(source_id, source)\n\n for layer in layers:\n self.add_layer(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, template: str = None) -> 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. If `None`, all properties are displayed.\n template (str): A mustache template. If supplied, `prop` is ignored.\n \"\"\"\n self.add_call(\"addPopup\", layer_id, prop, template)\n\n def add_tooltip(\n self, layer_id: str, prop: str = None, template: str = None\n ) -> 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. If `None`, all properties are displayed.\n template (str): A mustache template. If supplied, `prop` is ignored.\n\n Examples:\n >>> m = Map()\n >>> # ...\n >>> m.add_tooltip(\"test-layer\", template=\"Name: {{ name }}\")\n \"\"\"\n self.add_call(\"addTooltip\", layer_id, prop, template)\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 set_data(self, source_id: str, data: dict | GeoDataFrame) -> None:\n \"\"\"Update the data of a GeoJSON source\n\n Args:\n source_id (str): The name of the source to be updated.\n data (dict): The data of the source.\n \"\"\"\n if isinstance(data, GeoDataFrame):\n data = SimpleFeatures(data).to_source().data\n\n self.add_call(\"setSourceData\", source_id, data)\n\n def set_visibility(self, layer_id: str, visible: bool = True) -> None:\n \"\"\"Update the visibility of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n visible (bool): Whether the layer is visible or not.\n \"\"\"\n value = \"visible\" if visible else \"none\"\n self.add_call(\"setLayoutProperty\", layer_id, \"visibility\", value)\n\n def fit_bounds(\n self,\n bounds: tuple | list = None,\n data: GeoDataFrame = None,\n animate=False,\n **kwargs,\n ) -> None:\n \"\"\"Pan and zoom the map to contain its visible area within the specified geographical bounds\"\"\"\n kwargs[\"animate\"] = animate\n if data is not None:\n bounds = tuple(data.total_bounds)\n\n self.add_call(\"fitBounds\", bounds, kwargs)\n\n def to_html(self, title: str = \"My Awesome Map\", **kwargs) -> str:\n \"\"\"Render to html\n\n Args:\n title (str): The Title of the HTML document.\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 maplibre import Map\n >>> m = Map()\n >>> with open(\"/tmp/map.html\", \"w\") as f:\n ... f.write(m.to_html(style=\"height: 800px;\") # doctest: +SKIP\n \"\"\"\n js_lib = read_internal_file(\"srcjs\", \"pywidget.js\")\n js_snippet = Template(js_template).render(data=json.dumps(self.to_dict()))\n css = read_internal_file(\"srcjs\", \"pywidget.css\")\n headers = [f\"<style>{css}</style>\"]\n\n # Deck.GL headers\n add_deckgl_headers = \"addDeckOverlay\" in [\n item[0] for item in self._message_queue\n ]\n # TODO: Set version in constants\n deckgl_headers = (\n [\n # '<script src=\"https://unpkg.com/h3-js\"></script>',\n '<script src=\"https://unpkg.com/h3-js@4.1.0/dist/h3-js.umd.js\"></script>',\n '<script src=\"https://unpkg.com/deck.gl@9.0.16/dist.min.js\"></script>',\n '<script src=\"https://unpkg.com/@deck.gl/json@9.0.16/dist.min.js\"></script>',\n ]\n if add_deckgl_headers\n else []\n )\n\n # Mapbox Draw headers\n add_mapbox_draw_headers = \"addMapboxDraw\" in [\n item[0] for item in self._message_queue\n ]\n # TODO: Set version in constants\n mapbox_draw_headers = (\n [\n # \"<script src='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.js'></script>\",\n # \"<link rel='stylesheet' href='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.css' type='text/css' />\",\n \"<script src='https://www.unpkg.com/@mapbox/mapbox-gl-draw@1.4.3/dist/mapbox-gl-draw.js'></script>\",\n \"<link rel='stylesheet' href='https://www.unpkg.com/@mapbox/mapbox-gl-draw@1.4.3/dist/mapbox-gl-draw.css' type='text/css' />\",\n ]\n if add_mapbox_draw_headers\n else []\n )\n\n output = Template(html_template).render(\n js=\"\\n\".join([js_lib, js_snippet]),\n title=title,\n headers=headers + deckgl_headers + mapbox_draw_headers,\n **kwargs,\n )\n return output\n\n def save(self, filename: str = None, preview=True, **kwargs):\n \"\"\"Save the map to an HTML file\"\"\"\n return save_map(self, filename, preview, **kwargs)\n\n # -------------------------\n # Plugins\n # -------------------------\n def add_deck_layers(\n self, layers: list[dict | \"pydeck.Layer\"], tooltip: str | dict = None\n ) -> None:\n \"\"\"Add Deck.GL layers to the layer stack\n\n Args:\n layers (list[dict | \"pydeck.Layer\"]): A list of dictionaries containing the Deck.GL layers to be added.\n tooltip (str | dict): Either a single mustache template string applied to all layers\n or a dictionary where keys are layer ids and values are mustache template strings.\n \"\"\"\n layers = parse_deck_layers(layers)\n self.add_call(\"addDeckOverlay\", layers, tooltip)\n\n def set_deck_layers(\n self, layers: list[dict | \"pydeck.Layer\"], tooltip: str | dict = None\n ) -> None:\n \"\"\"Update Deck.GL layers\n\n Args:\n layers (list[dict | \"pydeck.Layer\"]): A list of dictionaries containing the Deck.GL layers to be updated.\n New layers will be added. Missing layers will be removed.\n tooltip (str | dict): Must be set to keep tooltip even if it did not change.\n \"\"\"\n layers = parse_deck_layers(layers)\n self.add_call(\"setDeckLayers\", layers, tooltip)\n\n def add_mapbox_draw(\n self,\n options: dict | MapboxDrawOptions = None,\n position: str | ControlPosition = ControlPosition.TOP_LEFT,\n geojson: dict = None,\n ) -> None:\n \"\"\"Add MapboxDraw controls to the map\n\n Note:\n See [MapboxDraw API Reference](https://github.com/mapbox/mapbox-gl-draw/blob/main/docs/API.md)\n for available options.\n\n Args:\n options (dict | MapboxDrawOptions): MapboxDraw options.\n position (str | ControlPosition): The position of the MapboxDraw controls.\n geojson (dict): A GeoJSON Feature, FeatureCollection or Geometry to be added to the draw layer.\n \"\"\"\n if isinstance(options, MapboxDrawOptions):\n options = options.to_dict()\n\n self.add_call(\n \"addMapboxDraw\", options or {}, ControlPosition(position).value, geojson\n )\n
add_call(method_name, *args)
","text":"method_name
str
*args
any
()
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_control","title":"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
add_control(control, position=None)
","text":"control
Control
position
str | ControlPosition
None
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_deck_layers","title":"def add_control(\n self,\n control: Control,\n position: [str | ControlPosition] = None,\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 position = position or control.position\n self.add_call(\n \"addControl\",\n control.type,\n control.to_dict(),\n ControlPosition(position).value,\n )\n
add_deck_layers(layers, tooltip=None)
","text":"layers
list[dict | 'pydeck.Layer']
tooltip
str | dict
None
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_layer","title":"def add_deck_layers(\n self, layers: list[dict | \"pydeck.Layer\"], tooltip: str | dict = None\n) -> None:\n \"\"\"Add Deck.GL layers to the layer stack\n\n Args:\n layers (list[dict | \"pydeck.Layer\"]): A list of dictionaries containing the Deck.GL layers to be added.\n tooltip (str | dict): Either a single mustache template string applied to all layers\n or a dictionary where keys are layer ids and values are mustache template strings.\n \"\"\"\n layers = parse_deck_layers(layers)\n self.add_call(\"addDeckOverlay\", layers, tooltip)\n
add_layer(layer, before_id=None)
","text":"layer
Layer | dict
before_id
str
None
, the new layer will appear above all other layers.None
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_mapbox_draw","title":"def add_layer(self, layer: [Layer | dict], before_id: str = None) -> None:\n \"\"\"Add a layer to the map\n\n Args:\n layer (Layer | dict): The Layer to be added to the map.\n before_id (str): The ID of an existing layer to insert the new layer before,\n resulting in the new layer appearing visually beneath the existing layer.\n If `None`, the new layer will appear above all other layers.\n \"\"\"\n if isinstance(layer, Layer):\n layer = layer.to_dict()\n\n self.add_call(\"addLayer\", layer, before_id)\n
add_mapbox_draw(options=None, position=ControlPosition.TOP_LEFT, geojson=None)
","text":"options
dict | MapboxDrawOptions
None
position
str | ControlPosition
TOP_LEFT
geojson
dict
None
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_marker","title":"def add_mapbox_draw(\n self,\n options: dict | MapboxDrawOptions = None,\n position: str | ControlPosition = ControlPosition.TOP_LEFT,\n geojson: dict = None,\n) -> None:\n \"\"\"Add MapboxDraw controls to the map\n\n Note:\n See [MapboxDraw API Reference](https://github.com/mapbox/mapbox-gl-draw/blob/main/docs/API.md)\n for available options.\n\n Args:\n options (dict | MapboxDrawOptions): MapboxDraw options.\n position (str | ControlPosition): The position of the MapboxDraw controls.\n geojson (dict): A GeoJSON Feature, FeatureCollection or Geometry to be added to the draw layer.\n \"\"\"\n if isinstance(options, MapboxDrawOptions):\n options = options.to_dict()\n\n self.add_call(\n \"addMapboxDraw\", options or {}, ControlPosition(position).value, geojson\n )\n
add_marker(marker)
","text":"marker
Marker
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_popup","title":"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
add_popup(layer_id, prop=None, template=None)
","text":"layer_id
str
prop
str
None
, all properties are displayed.None
template
str
prop
is ignored.None
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_source","title":"def add_popup(self, layer_id: str, prop: str = None, template: str = None) -> 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. If `None`, all properties are displayed.\n template (str): A mustache template. If supplied, `prop` is ignored.\n \"\"\"\n self.add_call(\"addPopup\", layer_id, prop, template)\n
add_source(id, source)
","text":"id
str
source
Source | dict | GeoDataFrame
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.add_tooltip","title":"def add_source(self, id: str, source: [Source | dict | GeoDataFrame]) -> None:\n \"\"\"Add a source to the map\n\n Args:\n id (str): The unique ID of the source.\n source (Source | dict | GeoDataFrame): The source to be added to the map.\n \"\"\"\n if GeoDataFrame is not None and isinstance(source, GeoDataFrame):\n source = SimpleFeatures(source).to_source()\n\n if isinstance(source, Source):\n source = source.to_dict()\n\n self.add_call(\"addSource\", id, source)\n
add_tooltip(layer_id, prop=None, template=None)
","text":"layer_id
str
prop
str
None
, all properties are displayed.None
template
str
prop
is ignored.None
Source code in >>> m = Map()\n>>> # ...\n>>> m.add_tooltip(\"test-layer\", template=\"Name: {{ name }}\")\n
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.fit_bounds","title":"def add_tooltip(\n self, layer_id: str, prop: str = None, template: str = None\n) -> 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. If `None`, all properties are displayed.\n template (str): A mustache template. If supplied, `prop` is ignored.\n\n Examples:\n >>> m = Map()\n >>> # ...\n >>> m.add_tooltip(\"test-layer\", template=\"Name: {{ name }}\")\n \"\"\"\n self.add_call(\"addTooltip\", layer_id, prop, template)\n
fit_bounds(bounds=None, data=None, animate=False, **kwargs)
","text":"maplibre/map.py
"},{"location":"api/map/#maplibre.Map.save","title":"def fit_bounds(\n self,\n bounds: tuple | list = None,\n data: GeoDataFrame = None,\n animate=False,\n **kwargs,\n) -> None:\n \"\"\"Pan and zoom the map to contain its visible area within the specified geographical bounds\"\"\"\n kwargs[\"animate\"] = animate\n if data is not None:\n bounds = tuple(data.total_bounds)\n\n self.add_call(\"fitBounds\", bounds, kwargs)\n
save(filename=None, preview=True, **kwargs)
","text":"maplibre/map.py
"},{"location":"api/map/#maplibre.Map.set_data","title":"def save(self, filename: str = None, preview=True, **kwargs):\n \"\"\"Save the map to an HTML file\"\"\"\n return save_map(self, filename, preview, **kwargs)\n
set_data(source_id, data)
","text":"source_id
str
data
dict
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.set_deck_layers","title":"def set_data(self, source_id: str, data: dict | GeoDataFrame) -> None:\n \"\"\"Update the data of a GeoJSON source\n\n Args:\n source_id (str): The name of the source to be updated.\n data (dict): The data of the source.\n \"\"\"\n if isinstance(data, GeoDataFrame):\n data = SimpleFeatures(data).to_source().data\n\n self.add_call(\"setSourceData\", source_id, data)\n
set_deck_layers(layers, tooltip=None)
","text":"layers
list[dict | 'pydeck.Layer']
tooltip
str | dict
None
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.set_filter","title":"def set_deck_layers(\n self, layers: list[dict | \"pydeck.Layer\"], tooltip: str | dict = None\n) -> None:\n \"\"\"Update Deck.GL layers\n\n Args:\n layers (list[dict | \"pydeck.Layer\"]): A list of dictionaries containing the Deck.GL layers to be updated.\n New layers will be added. Missing layers will be removed.\n tooltip (str | dict): Must be set to keep tooltip even if it did not change.\n \"\"\"\n layers = parse_deck_layers(layers)\n self.add_call(\"setDeckLayers\", layers, tooltip)\n
set_filter(layer_id, filter_)
","text":"layer_id
str
filter_
list
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.set_layout_property","title":"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
set_layout_property(layer_id, prop, value)
","text":"layer_id
str
prop
str
value
any
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.set_paint_property","title":"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
set_paint_property(layer_id, prop, value)
","text":"layer_id
str
prop
str
value
any
maplibre/map.py
"},{"location":"api/map/#maplibre.Map.set_visibility","title":"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
set_visibility(layer_id, visible=True)
","text":"layer_id
str
visible
bool
True
Source code in maplibre/map.py
"},{"location":"api/map/#maplibre.Map.to_html","title":"def set_visibility(self, layer_id: str, visible: bool = True) -> None:\n \"\"\"Update the visibility of a layer\n\n Args:\n layer_id (str): The name of the layer to be updated.\n visible (bool): Whether the layer is visible or not.\n \"\"\"\n value = \"visible\" if visible else \"none\"\n self.add_call(\"setLayoutProperty\", layer_id, \"visibility\", value)\n
to_html(title='My Awesome Map', **kwargs)
","text":"title
str
'My Awesome Map'
**kwargs
Any
style
is the only supported keyword argument.{}
Source code in >>> from maplibre import Map\n>>> m = Map()\n>>> with open(\"/tmp/map.html\", \"w\") as f:\n... f.write(m.to_html(style=\"height: 800px;\")\n
maplibre/map.py
"},{"location":"api/map/#maplibre.MapOptions","title":"def to_html(self, title: str = \"My Awesome Map\", **kwargs) -> str:\n \"\"\"Render to html\n\n Args:\n title (str): The Title of the HTML document.\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 maplibre import Map\n >>> m = Map()\n >>> with open(\"/tmp/map.html\", \"w\") as f:\n ... f.write(m.to_html(style=\"height: 800px;\") # doctest: +SKIP\n \"\"\"\n js_lib = read_internal_file(\"srcjs\", \"pywidget.js\")\n js_snippet = Template(js_template).render(data=json.dumps(self.to_dict()))\n css = read_internal_file(\"srcjs\", \"pywidget.css\")\n headers = [f\"<style>{css}</style>\"]\n\n # Deck.GL headers\n add_deckgl_headers = \"addDeckOverlay\" in [\n item[0] for item in self._message_queue\n ]\n # TODO: Set version in constants\n deckgl_headers = (\n [\n # '<script src=\"https://unpkg.com/h3-js\"></script>',\n '<script src=\"https://unpkg.com/h3-js@4.1.0/dist/h3-js.umd.js\"></script>',\n '<script src=\"https://unpkg.com/deck.gl@9.0.16/dist.min.js\"></script>',\n '<script src=\"https://unpkg.com/@deck.gl/json@9.0.16/dist.min.js\"></script>',\n ]\n if add_deckgl_headers\n else []\n )\n\n # Mapbox Draw headers\n add_mapbox_draw_headers = \"addMapboxDraw\" in [\n item[0] for item in self._message_queue\n ]\n # TODO: Set version in constants\n mapbox_draw_headers = (\n [\n # \"<script src='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.js'></script>\",\n # \"<link rel='stylesheet' href='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.css' type='text/css' />\",\n \"<script src='https://www.unpkg.com/@mapbox/mapbox-gl-draw@1.4.3/dist/mapbox-gl-draw.js'></script>\",\n \"<link rel='stylesheet' href='https://www.unpkg.com/@mapbox/mapbox-gl-draw@1.4.3/dist/mapbox-gl-draw.css' type='text/css' />\",\n ]\n if add_mapbox_draw_headers\n else []\n )\n\n output = Template(html_template).render(\n js=\"\\n\".join([js_lib, js_snippet]),\n title=title,\n headers=headers + deckgl_headers + mapbox_draw_headers,\n **kwargs,\n )\n return output\n
maplibre.MapOptions
","text":"MapLibreBaseModel
maplibre/map.py
"},{"location":"api/map/#maplibre.MapContext","title":"class MapOptions(MapLibreBaseModel):\n \"\"\"Map options\n\n Note:\n See [MapOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/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: Union[int, float] = 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: Union[int, float] = None\n scroll_zoom: bool = Field(None, serialization_alias=\"scrollZoom\")\n style: Union[str, Carto, MapTiler, dict] = construct_carto_basemap_url(\n Carto.DARK_MATTER\n )\n zoom: Union[int, float] = 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 if isinstance(v, MapTiler):\n return construct_maptiler_basemap_url(v)\n\n return v\n
maplibre.MapContext
","text":"Map
Map
instance in a Shiny app. Must be used inside an async function.maplibre.Map
for available methods.id
string
session
Session
None
, the active session is used.None
Source code in maplibre/mapcontext.py
"},{"location":"api/map/#maplibre.ipywidget.MapWidget","title":"class MapContext(Map):\n \"\"\"MapContext\n\n Use this class to update a `Map` instance in a Shiny app.\n Must be used inside an async function.\n\n See `maplibre.Map` for available methods.\n\n Args:\n id (string): The id of the map to be updated.\n session (Session): A Shiny session.\n If `None`, the active session is used.\n \"\"\"\n\n def __init__(self, id: str, session: Session = None) -> None:\n self.id = id\n self._session = require_active_session(session)\n self.map_options = {}\n self._message_queue = []\n\n async def __aenter__(self):\n return self\n\n async def __aexit__(self, exc_type, exc_val, exc_tb):\n await self.render()\n\n async def render(self):\n await self._session.send_custom_message(\n f\"pymaplibregl-{self.id}\", {\"id\": self.id, \"calls\": self._message_queue}\n )\n
maplibre.ipywidget.MapWidget
","text":"AnyWidget
, Map
maplibre.Map
for available methods.
Source code in >>> from maplibre import MapOptions\n>>> from maplibre.ipywidget import MapWidget as Map\n>>> m = Map(MapOptions(center=(-123.13, 49.254), zoom=11, pitch=45))\n>>> m\n
maplibre/ipywidget.py
"},{"location":"api/map/#maplibre.plugins","title":"class MapWidget(AnyWidget, Map):\n \"\"\"MapWidget\n\n Use this class to display and update maps in Jupyter Notebooks.\n\n See `maplibre.Map` for available methods.\n\n Examples:\n >>> from maplibre import MapOptions\n >>> from maplibre.ipywidget import MapWidget as Map\n >>> m = Map(MapOptions(center=(-123.13, 49.254), zoom=11, pitch=45))\n >>> m # doctest: +SKIP\n \"\"\"\n\n _esm = join(Path(__file__).parent, \"srcjs\", \"ipywidget.js\")\n # _css = join(Path(__file__).parent, \"srcjs\", \"maplibre-gl.css\")\n _css = join(Path(__file__).parent, \"srcjs\", \"ipywidget.css\")\n _use_message_queue = True\n # _rendered = traitlets.Bool(False, config=True).tag(sync=True)\n _rendered = traitlets.Bool(False).tag(config=True).tag(sync=True)\n map_options = traitlets.Dict().tag(sync=True)\n calls = traitlets.List().tag(sync=True)\n height = traitlets.Union([traitlets.Int(), traitlets.Unicode()]).tag(sync=True)\n\n # Interactions Map\n clicked = traitlets.Dict().tag(sync=True)\n view_state = traitlets.Dict().tag(sync=True)\n\n # Interactions MapboxDraw plugin\n draw_features_selected = traitlets.List().tag(sync=True)\n draw_feature_collection_all = traitlets.Dict().tag(sync=True)\n\n def __init__(\n self,\n map_options=MapOptions(),\n sources: dict = None,\n layers: list = None,\n controls: list = None,\n height: int | str = 400,\n **kwargs,\n ) -> None:\n self.calls = []\n AnyWidget.__init__(self, height=height, **kwargs)\n Map.__init__(self, map_options, sources, layers, controls, **kwargs)\n\n \"\"\"\n @traitlets.default(\"height\")\n def _default_height(self):\n return \"400px\"\n \"\"\"\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 use_message_queue(self, value: bool = True) -> None:\n self._use_message_queue = value\n\n def add_call(self, method_name: str, *args) -> None:\n call = [method_name, args]\n if not self._rendered:\n if not self._use_message_queue:\n self.calls = self.calls + [call]\n return\n\n self._message_queue.append(call)\n return\n\n self.send({\"calls\": [call], \"msg\": \"custom call\"})\n
maplibre.plugins
","text":""},{"location":"api/map/#maplibre.plugins.MapboxDrawControls","title":"MapboxDrawControls
","text":"MapLibreBaseModel
maplibre/plugins.py
"},{"location":"api/map/#maplibre.plugins.MapboxDrawOptions","title":"class MapboxDrawControls(MapLibreBaseModel):\n \"\"\"MapboxDraw controls\"\"\"\n\n point: bool = False\n line_string: bool = False\n polygon: bool = False\n trash: bool = False\n combine_features: bool = False\n uncombine_features: bool = False\n
MapboxDrawOptions
","text":"MapLibreBaseModel
maplibre/plugins.py
"},{"location":"api/sources/","title":"Sources","text":""},{"location":"api/sources/#maplibre.sources","title":"class MapboxDrawOptions(MapLibreBaseModel):\n \"\"\"MapboxDraw Options\"\"\"\n\n display_controls_default: bool = Field(\n True, serialization_alias=\"displayControlsDefault\"\n )\n controls: MapboxDrawControls = None\n box_select: bool = Field(True, serialization_alias=\"boxSelect\")\n
maplibre.sources
","text":""},{"location":"api/sources/#maplibre.sources.GeoJSONSource","title":"GeoJSONSource
","text":"Source
>>> from maplibre.sources import GeoJSONSource\n
Source code in >>> geojson = \"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n>>> source = GeoJSONSource(data=geojson)\n
maplibre/sources.py
"},{"location":"api/sources/#maplibre.sources.RasterTileSource","title":"class GeoJSONSource(Source):\n \"\"\"GeoJSON Source\n\n Examples:\n >>> from maplibre.sources import GeoJSONSource\n\n >>> geojson = \"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n >>> source = GeoJSONSource(data=geojson)\n \"\"\"\n\n data: Union[str, dict]\n attribution: Optional[str] = None\n buffer: Optional[int] = None\n cluster: Optional[bool] = None\n cluster_max_zoom: Optional[int] = Field(None, serialization_alias=\"clusterMaxZoom\")\n cluster_min_points: Optional[int] = Field(\n None, serialization_alias=\"clusterMinPoints\"\n )\n cluster_properties: Optional[dict] = Field(\n None, serialization_alias=\"clusterProperties\"\n )\n cluster_radius: Optional[int] = Field(None, serialization_alias=\"clusterRadius\")\n filter: Optional[list] = None\n generate_id: Optional[bool] = Field(None, serialization_alias=\"generateId\")\n line_metrics: Optional[bool] = Field(None, serialization_alias=\"lineMetrics\")\n min_zoom: Optional[int] = Field(None, serialization_alias=\"minzoom\")\n max_zoom: Optional[int] = Field(None, serialization_alias=\"maxzoom\")\n promote_id: Union[str, dict, None] = Field(None, serialization_alias=\"promoteId\")\n tolerance: Optional[float] = None\n\n @computed_field\n @property\n def type(self) -> str:\n return SourceType.GEOJSON.value\n
RasterTileSource
","text":"Source
>>> from maplibre.sources import RasterTileSource\n
Source code in >>> raster_tile_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
maplibre/sources.py
"},{"location":"api/sources/#maplibre.sources.SourceType","title":"class RasterTileSource(Source):\n \"\"\"Raster tile source\n\n Examples:\n >>> from maplibre.sources import RasterTileSource\n\n >>> raster_tile_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
SourceType
","text":"Enum
maplibre/sources.py
"},{"location":"api/sources/#maplibre.sources.VectorTileSource","title":"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
VectorTileSource
","text":"Source
>>> from maplibre.sources import VectorTileSource\n>>> from maplibre import LayerType, Layer\n
>>> vector_tile_source = VectorTileSource(\n... tiles=[\"https://demotiles.maplibre.org/tiles/{z}/{x}/{y}.pbf\"],\n... min_zoom=0,\n... max_zoom=6,\n... )\n
Source code in >>> layer = Layer(\n... type=LayerType.LINE,\n... id=\"countries\",\n... source=vector_tile_source,\n... source_layer=\"countries\",\n... paint={\"fill-color\": \"lightgreen\", \"fill-outline-color\": \"black\"},\n... )\n
maplibre/sources.py
"},{"location":"examples/3d_indoor_mapping/","title":"3D Indoor Mapping","text":"class VectorTileSource(Source):\n \"\"\"Vector tile source\n\n Examples:\n >>> from maplibre.sources import VectorTileSource\n >>> from maplibre import LayerType, Layer\n\n >>> vector_tile_source = VectorTileSource(\n ... tiles=[\"https://demotiles.maplibre.org/tiles/{z}/{x}/{y}.pbf\"],\n ... min_zoom=0,\n ... max_zoom=6,\n ... )\n\n >>> layer = Layer(\n ... type=LayerType.LINE,\n ... id=\"countries\",\n ... source=vector_tile_source,\n ... source_layer=\"countries\",\n ... paint={\"fill-color\": \"lightgreen\", \"fill-outline-color\": \"black\"},\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 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.VECTOR.value\n
import sys\nimport webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions\nfrom maplibre.basemaps import background\nfrom maplibre.sources import GeoJSONSource, RasterTileSource\n\nfile_name = \"/tmp/pymaplibregl_temp.html\"\n\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 if len(sys.argv) == 2:\n file_name = sys.argv[1]\n\n with open(file_name, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(file_name)\n
"},{"location":"examples/airports/","title":"Airport Markers","text":"poetry run python docs/examples/3d_indoor_mapping/app.py\n
import sys\n\nimport pandas as pd\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import (\n Marker,\n MarkerOptions,\n NavigationControl,\n Popup,\n PopupOptions,\n)\nfrom maplibre.sources import GeoJSONSource\nfrom maplibre.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\n\ndef create_map() -> Map:\n m = Map(map_options)\n m.add_control(NavigationControl())\n m.add_layer(airport_circles)\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 return m\n\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 def maplibre():\n return create_map()\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n if len(sys.argv) == 2:\n with open(sys.argv[1], \"w\") as f:\n f.write(create_map().to_html())\n else:\n app.run()\n
"},{"location":"examples/custom_basemap/","title":"Custom basemap","text":"poetry run uvicorn docs.examples.airports.app:app --reload\n
import webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions\nfrom maplibre.basemaps import construct_basemap_style\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import GeoJSONSource\n\nfile_name = \"docs/examples/custom_basemap/app.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_control(NavigationControl())\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(file_name, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(file_name)\n
"},{"location":"examples/deckgl_layer/","title":"Deck.GL Layer","text":"poetry run python docs/examples/custom_basemap/app.py\n
# Shiny Express App\n\nimport json\n\nfrom maplibre import Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl\nfrom maplibre.ui import use_deckgl\n\n# from shiny import reactive\nfrom shiny.express import input, render, ui\n\nm = Map(\n MapOptions(\n style=Carto.POSITRON,\n center=(-122.4, 37.74),\n zoom=12,\n hash=True,\n pitch=40,\n )\n)\nm.add_control(NavigationControl())\n\ndeck_grid_layer = {\n \"@@type\": \"GridLayer\",\n \"id\": \"GridLayer\",\n \"data\": \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/sf-bike-parking.json\",\n \"extruded\": True,\n \"getPosition\": \"@@=COORDINATES\",\n \"getColorWeight\": \"@@=SPACES\",\n \"getElevationWeight\": \"@@=SPACES\",\n \"elevationScale\": 4,\n \"cellSize\": 200,\n \"pickable\": True,\n}\n\nm.add_deck_layers([deck_grid_layer], tooltip=\"Number of points: {{ count }}\")\n\n# Shiny Express\nuse_deckgl()\n\n\n@render_maplibregl\ndef render_map():\n return m\n\n\n@render.code\ndef picking_object():\n obj = input.render_map_layer_GridLayer()\n print(obj)\n return json.dumps(obj[\"points\"], indent=2) if obj else \"Pick a feature!\"\n\n\nif __name__ == \"__main__\":\n with open(\"docs/examples/deckgl_layer/app.html\", \"w\") as f:\n f.write(m.to_html())\n
"},{"location":"examples/deckgl_multiple_layers/","title":"Multiple Deck.GL Layers","text":"# Run Shiny app\nshiny run docs/examples/deckgl_layer/app.py\n
# Shiny Express App\n\nimport requests as req\nfrom maplibre import Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl\nfrom maplibre.ui import use_deckgl\nfrom shiny.express import input, render, ui\n\ndata = req.get(\n \"https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson\"\n).json()\n\nm = Map(\n MapOptions(\n style=Carto.POSITRON,\n center=(0.45, 51.47),\n zoom=4,\n hash=True,\n pitch=30,\n )\n)\nm.add_control(NavigationControl())\n\ndeck_geojson_layer = {\n \"@@type\": \"GeoJsonLayer\",\n \"id\": \"airports\",\n \"data\": data,\n \"filled\": True,\n \"pointRadiusMinPixels\": 2,\n \"pointRadiusScale\": 2000,\n \"getPointRadius\": \"@@=11 - properties.scalerank\",\n \"getFillColor\": [200, 0, 80, 180],\n \"autoHighlight\": True,\n \"pickable\": True,\n}\n\ndeck_arc_layer = {\n \"@@type\": \"ArcLayer\",\n \"id\": \"arcs\",\n \"data\": [\n feature\n for feature in data[\"features\"]\n if feature[\"properties\"][\"scalerank\"] < 4\n ],\n \"getSourcePosition\": [-0.4531566, 51.4709959], # London\n \"getTargetPosition\": \"@@=geometry.coordinates\",\n \"getSourceColor\": [0, 128, 200],\n \"getTargetColor\": [200, 0, 80],\n \"getWidth\": 2,\n \"pickable\": True,\n}\n\nm.add_deck_layers(\n [deck_geojson_layer, deck_arc_layer],\n tooltip={\n \"airports\": \"{{ &properties.name }}\",\n \"arcs\": \"gps_code: {{ properties.gps_code }}\",\n },\n)\n\n# Shiny Express\nuse_deckgl()\n\n\n@render_maplibregl\ndef render_map():\n return m\n\n\nif __name__ == \"__main__\":\n with open(\"docs/examples/deckgl_multiple_layers/app.html\", \"w\") as f:\n f.write(m.to_html())\n
"},{"location":"examples/earthquake_clusters/","title":"Earthquake Clusters","text":"# Run Shiny app\npoetry run shiny run docs/examples/deckgl_multiple_layers/app.py\n
import sys\n\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl\nfrom maplibre.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\n\ndef create_map() -> Map:\n m = Map(map_options)\n m.add_control(NavigationControl())\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\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 return create_map()\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 if len(sys.argv) == 2:\n file_name = sys.argv[1]\n with open(file_name, \"w\") as f:\n f.write(create_map().to_html())\n else:\n app.run()\n
"},{"location":"examples/every_person_in_manhattan/","title":"Every Person in Manhattan","text":"poetry run uvicorn docs.examples.earthquake_clusters.app:app --reload\n
import json\nimport sys\n\nimport pandas as pd\nimport shapely\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapContext,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl, ScaleControl\nfrom maplibre.sources import GeoJSONSource\nfrom maplibre.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 hash=True,\n)\n\n\ndef create_map() -> Map:\n m = Map(map_options)\n m.add_control(NavigationControl())\n m.add_control(ScaleControl(), position=\"bottom-left\")\n m.add_layer(every_person_in_manhattan_circles)\n return m\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 return create_map()\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 if len(sys.argv) == 2:\n file_name = sys.argv[1]\n with open(file_name, \"w\") as f:\n f.write(create_map().to_html())\n else:\n app.run()\n
"},{"location":"examples/geopandas/","title":"GeoPandas","text":"poetry run uvicorn docs.examples.every_person_in_manhattan.app:app --reload\n
import sys\nimport webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import GeoJSONSource\nfrom maplibre.utils import geopandas_to_geojson\n\nimport geopandas as gpd\n\nfile_name = \"/tmp/pymaplibregl_temp.html\"\nLAYER_ID = \"wilderness\"\n\ndf_geo = gpd.read_file(\n \"zip+https://github.com/Toblerity/Fiona/files/11151652/coutwildrnp.zip\"\n)\n\nwilderness_source = GeoJSONSource(data=geopandas_to_geojson(df_geo))\n\nwilderness_layer = Layer(\n type=LayerType.FILL,\n id=LAYER_ID,\n source=wilderness_source,\n paint={\"fill-color\": \"darkred\", \"fill-opacity\": 0.5},\n)\n\nmap_options = MapOptions(bounds=df_geo.total_bounds)\n\n\ndef create_map():\n m = Map(map_options)\n m.add_control(NavigationControl())\n m.add_layer(wilderness_layer)\n m.add_tooltip(LAYER_ID, \"NAME\")\n return m\n\n\nif __name__ == \"__main__\":\n m = create_map()\n if len(sys.argv) == 2:\n file_name = sys.argv[1]\n\n with open(file_name, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(file_name)\n
"},{"location":"examples/layer_order/","title":"Layer Order","text":"poetry run python docs/examples/geopandas/app.py\n
# Shiny Express App\n\nimport requests as req\nfrom maplibre import Layer, LayerType, Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import Carto, construct_carto_basemap_url\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import GeoJSONSource\nfrom shiny.express import input, render, ui\n\nstyle = req.get(construct_carto_basemap_url(Carto.VOYAGER)).json()\n\n\nsymbol_ids = [layer[\"id\"] for layer in style[\"layers\"] if layer[\"type\"] == \"symbol\"]\n# print(symbol_ids)\n\nurban_areas = GeoJSONSource(\n data=\"https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_urban_areas.geojson\"\n)\n\nm = Map(\n MapOptions(\n style=style,\n center=(-89.928, 35.204),\n # center=(-88.13734351262877, 35.137451890638886),\n zoom=9,\n hash=True,\n )\n)\nm.add_control(NavigationControl())\nm.add_layer(\n Layer(\n id=\"urban-areas-fill\",\n type=LayerType.FILL,\n source=urban_areas,\n paint={\"fill-color\": \"pink\", \"fill-opacity\": 1.0},\n ),\n before_id=symbol_ids[0],\n)\nfor symbol_id in symbol_ids:\n m.set_paint_property(symbol_id, \"text-color\", \"purple\")\n\n\n@render_maplibregl\ndef render_map():\n return m\n\n\nif __name__ == \"__main__\":\n with open(\"docs/examples/layer_order/app.html\", \"w\") as f:\n f.write(m.to_html())\n
"},{"location":"examples/layer_switcher/","title":"Layer Switcher","text":"poetry run shiny run docs/examples/layer_order/app.py\n
# Example taken from here: https://maplibre.org/maplibre-gl-js/docs/examples/pmtiles/\n\nimport webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import construct_basemap_style\nfrom maplibre.controls import (\n ControlPosition,\n InfoBoxControl,\n LayerSwitcherControl,\n NavigationControl,\n)\nfrom shiny.express import input, render, ui\n\nPMTILES_URL = \"https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles\"\n\npmtiles_source = {\n \"type\": \"vector\",\n \"url\": f\"pmtiles://{PMTILES_URL}\",\n \"attribution\": '\u00a9 <a href=\"https://openstreetmap.org\">OpenStreetMap</a>',\n}\n\ncustom_basemap = construct_basemap_style(\n sources={\"pmtiles\": pmtiles_source},\n layers=[\n Layer(\n id=\"buildings\",\n source=\"pmtiles\",\n source_layer=\"landuse\",\n type=LayerType.FILL,\n paint={\"fill-color\": \"red\"},\n layout={\"visibility\": \"none\"},\n ),\n Layer(\n id=\"roads\",\n source=\"pmtiles\",\n source_layer=\"roads\",\n type=LayerType.LINE,\n paint={\"line-color\": \"black\"},\n ),\n Layer(\n id=\"mask\",\n source=\"pmtiles\",\n source_layer=\"mask\",\n type=LayerType.FILL,\n paint={\"fill-color\": \"yellow\"},\n layout={\"visibility\": \"none\"},\n ),\n ],\n)\n\n\nmap_options = MapOptions(\n style=custom_basemap,\n # hash=True,\n # bounds=(11.154026, 43.7270125, 11.3289395, 43.8325455),\n center=(11.2415, 43.7798),\n zoom=12.5,\n)\n\n\ndef create_map():\n m = Map(map_options)\n m.add_control(NavigationControl())\n m.add_control(\n InfoBoxControl(\n content=\"Toggle layers of PMTiles source\",\n css_text=\"padding: 10px; background-color: yellow; color: steelblue; font-weight: bold;\",\n ),\n ControlPosition.TOP_LEFT,\n )\n m.add_control(\n LayerSwitcherControl(\n layer_ids=[\"buildings\", \"roads\", \"mask\"],\n css_text=\"padding: 5px; border: 1px solid darkgrey; border-radius: 4px;\",\n ),\n position=ControlPosition.TOP_LEFT,\n )\n return m\n\n\n@render_maplibregl\ndef render_map():\n return create_map()\n\n\nif __name__ == \"__main__\":\n file_name = \"docs/examples/layer_switcher/app.html\"\n\n m = create_map()\n with open(file_name, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(file_name)\n
"},{"location":"examples/mapbox_draw_plugin/","title":"Mapbox Draw Plugin","text":"shiny run docs/examples/layer_switcher/app.py\n
# Shiny Express App\n\nimport json\nimport webbrowser\n\nfrom maplibre import Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import ControlPosition, NavigationControl, ScaleControl\nfrom maplibre.plugins import MapboxDrawControls, MapboxDrawOptions\nfrom maplibre.ui import use_mapboxgl_draw\n\n# from shiny import reactive\nfrom shiny.express import input, render, ui\n\ngeojson_feature = {\n \"id\": \"xyz\",\n \"type\": \"Feature\",\n \"properties\": {},\n \"geometry\": {\n \"coordinates\": [\n [\n [-122.4523683552298, 37.775540942000546],\n [-122.41910082339776, 37.75932501909665],\n [-122.43487191413453, 37.72543546737114],\n [-122.46053073611722, 37.729612763886834],\n [-122.4523683552298, 37.775540942000546],\n ]\n ],\n \"type\": \"Polygon\",\n },\n}\n\nm = Map(\n MapOptions(\n style=Carto.POSITRON,\n center=(-122.4, 37.74),\n zoom=12,\n hash=True,\n pitch=40,\n )\n)\nm.add_control(NavigationControl())\nm.add_control(ScaleControl(), ControlPosition.BOTTOM_LEFT)\n\n# Optional: only activate a given set of controls\ndraw_options = MapboxDrawOptions(\n display_controls_default=False,\n controls=MapboxDrawControls(polygon=True, line_string=True, trash=True),\n)\n# Use options from above\n# m.add_mapbox_draw(draw_options, geojson=geojson_feature)\n\n# If no options are passed, all controls are activated by default\nm.add_mapbox_draw(geojson=geojson_feature)\n\n# Shiny Express\nuse_mapboxgl_draw()\n\n\n@render_maplibregl\ndef maplibre():\n return m\n\n\n@render.code\ndef selected_features():\n obj = input.maplibre_draw_features_selected()\n print(obj)\n return json.dumps(obj[\"features\"], indent=2) if obj else \"Pick some features!\"\n\n\nif __name__ == \"__main__\":\n filename = \"docs/examples/mapbox_draw_plugin/app.html\"\n with open(filename, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(filename)\n
"},{"location":"examples/pmtiles/","title":"PMTiles","text":"shiny run docs/examples/mapbox_draw_plugin/app.py\n
# Example taken from here: https://maplibre.org/maplibre-gl-js/docs/examples/pmtiles/\n\nimport webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import construct_basemap_style\nfrom maplibre.controls import NavigationControl\nfrom shiny.express import input, render, ui\n\nPMTILES_URL = \"https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles\"\n\npmtiles_source = {\n \"type\": \"vector\",\n \"url\": f\"pmtiles://{PMTILES_URL}\",\n \"attribution\": '\u00a9 <a href=\"https://openstreetmap.org\">OpenStreetMap</a>',\n}\n\ncustom_basemap = construct_basemap_style(\n sources={\"pmtiles\": pmtiles_source},\n layers=[\n Layer(\n id=\"buildings\",\n source=\"pmtiles\",\n source_layer=\"landuse\",\n type=LayerType.FILL,\n paint={\"fill-color\": \"steelblue\"},\n ),\n Layer(\n id=\"roads\",\n source=\"pmtiles\",\n source_layer=\"roads\",\n type=LayerType.LINE,\n paint={\"line-color\": \"black\"},\n ),\n Layer(\n id=\"mask\",\n source=\"pmtiles\",\n source_layer=\"mask\",\n type=LayerType.FILL,\n paint={\"fill-color\": \"white\"},\n ),\n ],\n)\n\n\nmap_options = MapOptions(\n style=custom_basemap,\n bounds=(11.154026, 43.7270125, 11.3289395, 43.8325455),\n)\n\n\ndef create_map():\n m = Map(map_options)\n m.add_control(NavigationControl())\n return m\n\n\n@render_maplibregl\ndef render_map():\n return create_map()\n\n\nif __name__ == \"__main__\":\n file_name = \"docs/examples/pmtiles/app.html\"\n\n m = create_map()\n with open(file_name, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(file_name)\n
"},{"location":"examples/road_safety/","title":"H3 Grid UK Road Safety","text":"shiny run docs/examples/pmtiles/app.py\n
import sys\nimport webbrowser\n\nimport h3\nimport pandas as pd\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapContext,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import GeoJSONSource\nfrom maplibre.utils import df_to_geojson\nfrom shiny import App, reactive, ui\n\nRESOLUTION = 7\nCOLORS = (\n \"lightblue\",\n \"turquoise\",\n \"lightgreen\",\n \"yellow\",\n \"orange\",\n \"darkred\",\n)\n\nroad_safety = pd.read_csv(\n \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv\"\n).dropna()\n\n\ndef create_h3_grid(res=RESOLUTION) -> dict:\n road_safety[\"h3\"] = road_safety.apply(\n lambda x: h3.geo_to_h3(x[\"lat\"], x[\"lng\"], resolution=res), axis=1\n )\n df = road_safety.groupby(\"h3\").h3.agg(\"count\").to_frame(\"count\").reset_index()\n df[\"hexagon\"] = df.apply(\n lambda x: [h3.h3_to_geo_boundary(x[\"h3\"], geo_json=True)], axis=1\n )\n df[\"color\"] = pd.cut(\n df[\"count\"],\n bins=len(COLORS),\n labels=COLORS,\n )\n return df_to_geojson(\n df, \"hexagon\", geometry_type=\"Polygon\", properties=[\"count\", \"color\"]\n )\n\n\nsource = GeoJSONSource(data=create_h3_grid())\n\nmap_options = MapOptions(\n center=(-1.415727, 52.232395),\n zoom=7,\n pitch=40,\n bearing=-27,\n)\n\nh3_layer = Layer(\n id=\"road-safety\",\n type=LayerType.FILL_EXTRUSION,\n source=source,\n paint={\n \"fill-extrusion-color\": [\"get\", \"color\"],\n \"fill-extrusion-opacity\": 0.7,\n \"fill-extrusion-height\": [\"*\", 100, [\"get\", \"count\"]],\n },\n)\n\n\ndef create_map() -> Map:\n m = Map(map_options)\n m.add_control(NavigationControl())\n m.add_layer(h3_layer)\n m.add_tooltip(\"road-safety\", \"count\")\n return m\n\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Road safety in UK\"),\n output_maplibregl(\"mapylibre\", height=700),\n ui.input_slider(\"res\", \"Resolution\", min=4, max=8, step=1, value=RESOLUTION),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def mapylibre():\n return create_map()\n\n @reactive.Effect\n @reactive.event(input.res, ignore_init=True)\n async def resolution():\n async with MapContext(\"mapylibre\") as m:\n with ui.Progress() as p:\n p.set(message=\"H3 calculation in progress\")\n m.set_data(\"road-safety\", create_h3_grid(input.res()))\n p.set(1, message=\"Calculation finished\")\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n filename = sys.argv[1] if len(sys.argv) == 2 else \"/tmp/road_safety.html\"\n with open(filename, \"w\") as f:\n m = create_map()\n f.write(m.to_html(style=\"height: 700px;\"))\n\n webbrowser.open(filename)\n
"},{"location":"examples/vancouver_blocks/","title":"Vancouver Property Value","text":"poetry run uvicorn docs.examples.road_safety.app:app --reload\n
import sys\n\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapContext,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl, ScaleControl\nfrom maplibre.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, \"darkred\"],\n [50000, \"lightblue\"],\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\n\ndef create_map() -> Map:\n m = Map(map_options)\n m.add_control(NavigationControl())\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\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=600),\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 ui.input_checkbox_group(\n \"layers\",\n \"Layers\",\n choices=[LAYER_ID_FILL, LAYER_ID_LINES],\n selected=[LAYER_ID_FILL, LAYER_ID_LINES],\n ),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def maplibre():\n m = create_map()\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 @reactive.Effect\n @reactive.event(input.layers)\n async def layers():\n visible_layers = input.layers()\n async with MapContext(\"maplibre\") as m:\n for layer in [LAYER_ID_FILL, LAYER_ID_LINES]:\n m.set_visibility(layer, layer in visible_layers)\n\n\napp = App(app_ui, server)\n\nif __name__ == \"__main__\":\n if len(sys.argv) == 2:\n file_name = sys.argv[1]\n m = create_map()\n with open(file_name, \"w\") as f:\n f.write(m.to_html())\n else:\n app.run()\n
"},{"location":"examples/vector_tiles/","title":"Vector Tiles","text":"poetry run uvicorn docs.examples.vancouver_blocks.app:app --reload\n
# Example taken from here:\n# https://maplibre.org/maplibre-gl-js/docs/API/classes/VectorTileSource/\n# https://maplibre.org/maplibre-style-spec/sources/\n\nimport webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions, render_maplibregl\nfrom maplibre.basemaps import Carto\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import VectorTileSource\nfrom shiny.express import input, render, ui\n\n# Get layer ids and pbf url from here\nVECTOR_TILES_URL = \"https://demotiles.maplibre.org/tiles/tiles.json\"\nLAYER_ID = \"countries\"\n\nvector_source = VectorTileSource(\n url=VECTOR_TILES_URL,\n # tiles=[\"https://demotiles.maplibre.org/tiles/{z}/{x}/{y}.pbf\"],\n min_zoom=0,\n max_zoom=6,\n)\n\nvector_layer = Layer(\n type=LayerType.FILL,\n id=LAYER_ID,\n source=vector_source,\n paint={\"fill-color\": \"lightgreen\", \"fill-outline-color\": \"black\"},\n source_layer=\"countries\",\n)\n\n\ndef create_map():\n m = Map(MapOptions(style=Carto.POSITRON, center=(11, 42), zoom=3, hash=True))\n m.add_control(NavigationControl())\n m.add_layer(vector_layer)\n m.add_tooltip(LAYER_ID)\n return m\n\n\n@render_maplibregl\ndef render_map():\n return create_map()\n\n\nif __name__ == \"__main__\":\n file_name = \"docs/examples/vector_tiles/app.html\"\n\n m = create_map()\n with open(file_name, \"w\") as f:\n f.write(m.to_html())\n\n webbrowser.open(file_name)\n
"},{"location":"examples/where_is_the_iss/","title":"Where is the ISS","text":"shiny run docs/examples/vector_tiles/app.py\n
import requests\nfrom maplibre import (\n Layer,\n LayerType,\n Map,\n MapContext,\n MapOptions,\n output_maplibregl,\n render_maplibregl,\n)\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import GeoJSONSource\nfrom shiny import App, reactive, ui\n\nMAX_FEATURES = 30\nSOURCE_ID_ISS_POSITION = \"iss_position\"\nSOURCE_ID_ISS_LAST_POSITIONS = \"iss-last-positions\"\n\n\ndef where_is_the_iss() -> tuple:\n r = requests.get(\"https://api.wheretheiss.at/v1/satellites/25544\").json()\n return (r[\"longitude\"], r[\"latitude\"])\n\n\ndef create_feature(lng_lat: tuple) -> dict:\n return {\n \"type\": \"Feature\",\n \"geometry\": {\n \"type\": \"Point\",\n \"coordinates\": lng_lat,\n },\n \"properties\": {\"coords\": \", \".join(map(str, lng_lat))},\n }\n\n\nlng_lat = where_is_the_iss()\nfeature = create_feature(where_is_the_iss())\nfeature_collection = {\"type\": \"FeatureCollection\", \"features\": [feature]}\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Where is the ISS\"),\n ui.div(\"Click on Update to get the current position of the ISS.\"),\n ui.div(\n \"The yellow dots show the positions before. Hover the blue dot to display the coordinates.\"\n ),\n output_maplibregl(\"mapylibre\", height=600),\n ui.input_action_button(\"update\", \"Update\"),\n)\n\n\ndef server(input, output, session):\n @render_maplibregl\n def mapylibre():\n m = Map(MapOptions(center=lng_lat, zoom=3))\n m.add_control(NavigationControl())\n m.set_paint_property(\"water\", \"fill-color\", \"darkblue\")\n m.add_source(\n SOURCE_ID_ISS_LAST_POSITIONS, GeoJSONSource(data=feature_collection)\n )\n m.add_layer(\n Layer(\n type=LayerType.CIRCLE,\n source=SOURCE_ID_ISS_LAST_POSITIONS,\n paint={\"circle-color\": \"yellow\", \"circle-radius\": 5},\n ),\n )\n m.add_source(SOURCE_ID_ISS_POSITION, GeoJSONSource(data=feature))\n m.add_layer(\n Layer(\n type=LayerType.CIRCLE,\n id=\"iss-position\",\n source=SOURCE_ID_ISS_POSITION,\n paint={\"circle-color\": \"lightblue\", \"circle-radius\": 7},\n )\n )\n m.add_tooltip(\"iss-position\", \"coords\")\n return m\n\n @reactive.Effect\n @reactive.event(input.update)\n async def update():\n print(\"Fetching new position\")\n lng_lat = where_is_the_iss()\n print(lng_lat)\n if len(feature_collection[\"features\"]) == MAX_FEATURES:\n feature_collection[\"features\"] = []\n\n async with MapContext(\"mapylibre\") as m:\n feature = create_feature(lng_lat)\n m.set_data(SOURCE_ID_ISS_POSITION, feature)\n feature_collection[\"features\"].append(feature)\n m.set_data(SOURCE_ID_ISS_LAST_POSITIONS, feature_collection)\n m.add_call(\"flyTo\", {\"center\": lng_lat, \"speed\": 0.5})\n\n\napp = App(app_ui, server)\n
"},{"location":"examples/wms/","title":"WMS","text":"poetry run uvicorn docs.examples.where_is_the_iss.app:app --reload\n
"}]}
\ No newline at end of file
diff --git a/shiny_express/index.html b/shiny_express/index.html
index 6e95257..e939dec 100644
--- a/shiny_express/index.html
+++ b/shiny_express/index.html
@@ -1104,32 +1104,41 @@ import webbrowser\n\nfrom maplibre import Layer, LayerType, Map, MapOptions\nfrom maplibre.controls import NavigationControl\nfrom maplibre.sources import RasterTileSource\n\nSOURCE_ID = \"wms-test-source\"\nLAYER_ID = \"wms-test-layer\"\n\nwms_source = RasterTileSource(\n tiles=[\n \"https://img.nj.gov/imagerywms/Natural2015?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.1&request=GetMap&srs=EPSG:3857&transparent=true&width=256&height=256&layers=Natural2015\"\n ],\n tile_size=256,\n)\nwms_layer = Layer(type=LayerType.RASTER, source=SOURCE_ID, id=LAYER_ID)\n\nmap_options = MapOptions(zoom=8, center=(-74.5447, 40.6892))\n\nm = Map(map_options=map_options)\nm.add_control(NavigationControl())\nm.add_source(SOURCE_ID, wms_source)\nm.add_layer(wms_layer)\n\nfilename = \"docs/examples/wms/app.html\"\n\nwith open(filename, \"w\") as f:\n f.write(m.to_html(style=\"height: 800px;\"))\n\nwebbrowser.open(filename)\n
Shiny Express
For the example below the output_id
is mapgl
, so that you have to listen to input.mapgl_clicked
to get the map clicked event.
import json
-from shiny.express import input, render, ui
-
-from maplibre import Map, MapOptions, render_maplibregl
-
-ui.h1("My awesome MapLibre map")
+from shiny import reactive
+from shiny.express import input, render, ui
+
+from maplibre import Map, MapContext, MapOptions, render_maplibregl
+from maplibre.controls import Marker
-
-@render_maplibregl
-def mapgl():
- return Map(MapOptions(zoom=3, pitch=40))
-
-
-ui.div("Click on map to show coords.")
+ui.h1("My awesome MapLibre map")
+
+
+@render_maplibregl
+def mapgl():
+ return Map(MapOptions(zoom=3, pitch=40))
+
-
-@render.code
-def coords():
- return str(input.mapgl_clicked())
-
-
-ui.div("Move map to change view state.")
+ui.div("Click on map to show coords.")
+
+
+@render.code
+def coords():
+ return str(input.mapgl_clicked())
+
-
-@render.code
-def view_state():
- return json.dumps(input.mapgl_view_state(), indent=2)
+ui.div("Move map to change view state.")
+
+
+@render.code
+def view_state():
+ return json.dumps(input.mapgl_view_state(), indent=2)
+
+
+@reactive.Effect
+@reactive.event(input.mapgl_clicked)
+async def set_marker():
+ async with MapContext("mapgl") as m:
+ m.add_marker(Marker(lng_lat=input.mapgl_clicked()["coords"].values()))