chartops module¶
Map (Map)
¶
Source code in chartops/chartops.py
class Map(iPyLeafletMap):
def _get_basemap_layers(self) -> List[Layer]:
return [layer for layer in self.layers if layer.base]
def _get_latest_basemap_layer(self) -> Layer:
return self._get_basemap_layers()[-1]
def _create_basemap_tile_layer(self, name: str) -> TileLayer:
tile = basemap_to_tiles(xyz.query_name(name))
tile.base = True
tile.name = name
return tile
def _validate_opacity(self, opacity: float) -> None:
if not isinstance(opacity, (int, float)) or not (0 <= opacity <= 1):
raise TypeError("opacity must be a float between 0 and 1")
def _validate_bounds(
self, bounds: Tuple[Tuple[float, float], Tuple[float, float]]
) -> None:
if (
not isinstance(bounds, tuple)
or len(bounds) != 2
or not all(isinstance(pair, tuple) and len(pair) == 2 for pair in bounds)
or not all(
isinstance(coord, (int, float)) for pair in bounds for coord in pair
)
):
raise TypeError(
"bounds must be a tuple of two (lat, lon) tuples: ((south, west), (north, east))"
)
def _validate_position(self, position: str) -> None:
valid_positions = ["topright", "topleft", "bottomright", "bottomleft"]
if position not in valid_positions:
raise ValueError(
f"Invalid position '{position}'. Valid positions are: {valid_positions}"
)
def add_basemap(self, basemap_name: str, **kwargs) -> None:
"""
Add a basemap to the ipyleaflet map.
Args:
basemap_name (str): Name of the basemap to add. Resolved with xyzservices.
**kwargs (dict): Extra kwargs to pass to basemap_to_tiles.
Returns:
None
"""
basemap_tiles = self._create_basemap_tile_layer(basemap_name)
self.add(basemap_tiles)
def add_layer_control(self, position: str = "topright") -> None:
"""
Add a layer control to the map.
Args:
position (str, optional): Position of the layer control. Valid positions are "topright", "topleft", "bottomright", "bottomleft". Default is "topright".
Returns:
None
Raises:
ValueError: If the position is not valid.
"""
self._validate_position(position)
self.add(LayersControl(position=position))
def add_vector(self, filepath: Union[Path, str], name: str = "", **kwargs) -> None:
"""
Add a vector layer to the map.
Args:
filepath (Path or str): Path to the vector dataset or URL to a remote file.
name (str): Name of the layer. Defaults to ''..
**kwargs (dict): Additional styling options for the layer. Valid options include:
- color: str (default: 'blue')
- weight: int (default: 2)
- fillOpacity: float (default: 0.1)
Returns:
None
Raises:
FileNotFoundError: If the local filepath does not exist.
ValueError: If the vector data cannot be read or converted to GeoJSON, or if styling options are invalid.
"""
if isinstance(filepath, Path) and not filepath.exists():
raise FileNotFoundError(f"File not found: {filepath}")
color = kwargs.get("color", "blue")
if not isinstance(color, str):
raise ValueError(f"color must be a string, got {type(color)}")
weight = kwargs.get("weight", 2)
if not isinstance(weight, int):
raise ValueError(f"weight must be an integer, got {type(weight)}")
fillOpacity = kwargs.get("fillOpacity", 0.1)
self._validate_opacity(fillOpacity)
try:
gdf = gpd.read_file(filepath)
geojson = gdf.__geo_interface__
layer = GeoJSON(
data=geojson,
name=name,
style={"color": color, "weight": weight, "fillOpacity": fillOpacity},
)
self.add(layer)
except Exception as e:
raise ValueError(f"Failed to add vector layer from {filepath}: {e}")
def add_raster(
self,
url: Union[str, Path],
opacity: float,
name: Optional[str] = None,
colormap: Optional[Union[str, dict]] = None,
**kwargs,
) -> None:
"""
Add a raster layer to the map using a local or remote tile source.
Args:
url (str or Path): Path or URL to the raster file.
opacity (float): Opacity of the raster layer. Must be between 0 and 1.
name (str, optional): Name of the layer. Defaults to the stem of the file path.
colormap (str or dict, optional): Colormap to apply to the raster. Can be a colormap name or a dict. Resolved using `common.resolve_colormap`.
**kwargs (dict): Additional keyword arguments passed to the tile layer.
Returns:
None
Raises:
FileNotFoundError: If the local raster file does not exist.
ValueError: If the opacity is not valid or raster layer cannot be added.
"""
from localtileserver import TileClient, get_leaflet_tile_layer
if isinstance(url, Path) and not url.exists():
raise FileNotFoundError(f"Raster file not found: {url}")
self._validate_opacity(opacity)
try:
colormap_arg = common.resolve_colormap(colormap)
except Exception as e:
raise ValueError(f"Failed to resolve colormap: {e}")
try:
client = TileClient(str(url))
self.center = client.center()
self.zoom = client.default_zoom
tile_layer = get_leaflet_tile_layer(
client, colormap=colormap_arg, opacity=opacity, **kwargs
)
tile_layer.name = name or ""
self.add(tile_layer)
except Exception as e:
raise ValueError(f"Failed to add raster layer: {e}")
def add_image(
self,
url: Union[str, Path],
bounds: Tuple[Tuple[float, float], Tuple[float, float]],
opacity: float,
**kwargs,
) -> None:
"""
Add a static image overlay to the map.
Args:
url (str or Path): URL or path to the image to overlay.
bounds (tuple): A tuple of ((south, west), (north, east)) coordinates defining the bounding box of the image.
opacity (float): Opacity of the image overlay. Must be between 0 and 1.
**kwargs (dict): Additional keyword arguments passed to ImageOverlay.
Returns:
None
Raises:
ValueError: If the bounds are not in correct format or opacity is invalid.
FileNotFoundError: If the local image path does not exist.
"""
if isinstance(url, Path) and not url.exists():
raise FileNotFoundError(f"Image file not found: {url}")
self._validate_bounds(bounds)
self._validate_opacity(opacity)
try:
image = ImageOverlay(url=str(url), bounds=bounds, opacity=opacity, **kwargs)
self.add(image)
except Exception as e:
raise ValueError(f"Failed to add image overlay: {e}")
def add_video(
self,
url: Union[str, Path],
bounds: Tuple[Tuple[float, float], Tuple[float, float]],
opacity: float,
**kwargs,
) -> None:
"""
Add a video overlay to the map.
Args:
url (str or Path): URL or path to the video to overlay.
bounds (tuple): A tuple of ((south, west), (north, east)) coordinates defining the bounding box of the video.
opacity (float): Opacity of the video overlay. Must be between 0 and 1.
**kwargs (dict): Additional keyword arguments passed to VideoOverlay.
Returns:
None
Raises:
ValueError: If the bounds are not in correct format or opacity is invalid.
FileNotFoundError: If the local video path does not exist.
"""
if isinstance(url, Path) and not url.exists():
raise FileNotFoundError(f"Video file not found: {url}")
self._validate_bounds(bounds)
self._validate_opacity(opacity)
try:
video = VideoOverlay(url=str(url), bounds=bounds, opacity=opacity, **kwargs)
self.add(video)
except Exception as e:
raise ValueError(f"Failed to add video overlay: {e}")
def add_wms_layer(
self, url: str, layers: str, name: str, format: str, transparent: bool, **kwargs
) -> None:
"""
Add a WMS (Web Map Service) layer to the map.
Args:
url (str): Base URL of the WMS service.
layers (str): Comma-separated list of layer names to request from the service.
name (str): Name of the layer to show in the map.
format (str): Image format for the WMS tiles (e.g., 'image/png').
transparent (bool): Whether the WMS tiles should support transparency.
**kwargs (dict): Additional keyword arguments passed to the WMSLayer.
Returns:
None
Raises:
TypeError: If any of the required parameters are not of the expected type.
ValueError: If the WMS layer cannot be created or added.
"""
if not isinstance(url, str):
raise TypeError(f"url must be a string, got {type(url)}")
if not isinstance(layers, str):
raise TypeError(f"layers must be a string, got {type(layers)}")
if not isinstance(name, str):
raise TypeError(f"name must be a string, got {type(name)}")
if not isinstance(format, str):
raise TypeError(f"format must be a string, got {type(format)}")
if not isinstance(transparent, bool):
raise TypeError(f"transparent must be a boolean, got {type(transparent)}")
try:
wms = WMSLayer(
url=url,
layers=layers,
format=format,
transparent=transparent,
**kwargs,
)
wms.name = name
self.add(wms)
except Exception as e:
raise ValueError(f"Failed to add WMS layer: {e}")
def add_basemap_gui(self, position="topright") -> None:
"""
Add a toggleable dropdown GUI to select and switch basemaps on the map.
A small toggle button is initially displayed at the given position.
When clicked, it reveals a dropdown menu listing available free basemaps.
The user can select a different basemap, which replaces the latest one.
Args:
position (str, optional): Position of the widget control on the map.
Must be one of "topright", "topleft", "bottomright", or "bottomleft".
Default is "topright".
Returns:
None
Raises:
ValueError: If the provided position is not valid.
"""
self._validate_position(position)
basemap_names = common.get_free_basemap_names()
current = self._get_latest_basemap_layer().name
dropdown = widgets.Dropdown(
options=basemap_names,
value=current,
description="Basemap:",
layout=widgets.Layout(height="42px", width="auto"),
)
name_to_tile = {
name: self._create_basemap_tile_layer(name) for name in basemap_names
}
def on_dropdown_change(change):
new = change["new"]
if new != self._get_latest_basemap_layer().name:
self.substitute(self._get_latest_basemap_layer(), name_to_tile[new])
dropdown.observe(on_dropdown_change, names="value")
toggle = widgets.ToggleButton(
value=False,
tooltip="Show/hide basemap GUI",
icon="map",
layout=widgets.Layout(width="42px", height="42px"),
)
btn_control = WidgetControl(widget=toggle, position=position)
dropdown_box = widgets.HBox([dropdown, toggle])
gui_control = WidgetControl(widget=dropdown_box, position=position)
def on_toggle(change):
if change["new"]:
self.remove(btn_control)
self.add(gui_control)
else:
try:
self.remove(gui_control)
except ValueError:
pass
self.add(btn_control)
toggle.observe(on_toggle, names="value")
self.add(btn_control)
add_basemap(self, basemap_name, **kwargs)
¶
Add a basemap to the ipyleaflet map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
basemap_name |
str |
Name of the basemap to add. Resolved with xyzservices. |
required |
**kwargs |
dict |
Extra kwargs to pass to basemap_to_tiles. |
{} |
Returns:
| Type | Description |
|---|---|
None |
None |
Source code in chartops/chartops.py
def add_basemap(self, basemap_name: str, **kwargs) -> None:
"""
Add a basemap to the ipyleaflet map.
Args:
basemap_name (str): Name of the basemap to add. Resolved with xyzservices.
**kwargs (dict): Extra kwargs to pass to basemap_to_tiles.
Returns:
None
"""
basemap_tiles = self._create_basemap_tile_layer(basemap_name)
self.add(basemap_tiles)
add_basemap_gui(self, position='topright')
¶
Add a toggleable dropdown GUI to select and switch basemaps on the map.
A small toggle button is initially displayed at the given position. When clicked, it reveals a dropdown menu listing available free basemaps. The user can select a different basemap, which replaces the latest one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
position |
str |
Position of the widget control on the map. Must be one of "topright", "topleft", "bottomright", or "bottomleft". Default is "topright". |
'topright' |
Returns:
| Type | Description |
|---|---|
None |
None |
Exceptions:
| Type | Description |
|---|---|
ValueError |
If the provided position is not valid. |
Source code in chartops/chartops.py
def add_basemap_gui(self, position="topright") -> None:
"""
Add a toggleable dropdown GUI to select and switch basemaps on the map.
A small toggle button is initially displayed at the given position.
When clicked, it reveals a dropdown menu listing available free basemaps.
The user can select a different basemap, which replaces the latest one.
Args:
position (str, optional): Position of the widget control on the map.
Must be one of "topright", "topleft", "bottomright", or "bottomleft".
Default is "topright".
Returns:
None
Raises:
ValueError: If the provided position is not valid.
"""
self._validate_position(position)
basemap_names = common.get_free_basemap_names()
current = self._get_latest_basemap_layer().name
dropdown = widgets.Dropdown(
options=basemap_names,
value=current,
description="Basemap:",
layout=widgets.Layout(height="42px", width="auto"),
)
name_to_tile = {
name: self._create_basemap_tile_layer(name) for name in basemap_names
}
def on_dropdown_change(change):
new = change["new"]
if new != self._get_latest_basemap_layer().name:
self.substitute(self._get_latest_basemap_layer(), name_to_tile[new])
dropdown.observe(on_dropdown_change, names="value")
toggle = widgets.ToggleButton(
value=False,
tooltip="Show/hide basemap GUI",
icon="map",
layout=widgets.Layout(width="42px", height="42px"),
)
btn_control = WidgetControl(widget=toggle, position=position)
dropdown_box = widgets.HBox([dropdown, toggle])
gui_control = WidgetControl(widget=dropdown_box, position=position)
def on_toggle(change):
if change["new"]:
self.remove(btn_control)
self.add(gui_control)
else:
try:
self.remove(gui_control)
except ValueError:
pass
self.add(btn_control)
toggle.observe(on_toggle, names="value")
self.add(btn_control)
add_image(self, url, bounds, opacity, **kwargs)
¶
Add a static image overlay to the map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url |
str or Path |
URL or path to the image to overlay. |
required |
bounds |
tuple |
A tuple of ((south, west), (north, east)) coordinates defining the bounding box of the image. |
required |
opacity |
float |
Opacity of the image overlay. Must be between 0 and 1. |
required |
**kwargs |
dict |
Additional keyword arguments passed to ImageOverlay. |
{} |
Returns:
| Type | Description |
|---|---|
None |
None |
Exceptions:
| Type | Description |
|---|---|
ValueError |
If the bounds are not in correct format or opacity is invalid. |
FileNotFoundError |
If the local image path does not exist. |
Source code in chartops/chartops.py
def add_image(
self,
url: Union[str, Path],
bounds: Tuple[Tuple[float, float], Tuple[float, float]],
opacity: float,
**kwargs,
) -> None:
"""
Add a static image overlay to the map.
Args:
url (str or Path): URL or path to the image to overlay.
bounds (tuple): A tuple of ((south, west), (north, east)) coordinates defining the bounding box of the image.
opacity (float): Opacity of the image overlay. Must be between 0 and 1.
**kwargs (dict): Additional keyword arguments passed to ImageOverlay.
Returns:
None
Raises:
ValueError: If the bounds are not in correct format or opacity is invalid.
FileNotFoundError: If the local image path does not exist.
"""
if isinstance(url, Path) and not url.exists():
raise FileNotFoundError(f"Image file not found: {url}")
self._validate_bounds(bounds)
self._validate_opacity(opacity)
try:
image = ImageOverlay(url=str(url), bounds=bounds, opacity=opacity, **kwargs)
self.add(image)
except Exception as e:
raise ValueError(f"Failed to add image overlay: {e}")
add_layer_control(self, position='topright')
¶
Add a layer control to the map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
position |
str |
Position of the layer control. Valid positions are "topright", "topleft", "bottomright", "bottomleft". Default is "topright". |
'topright' |
Returns:
| Type | Description |
|---|---|
None |
None |
Exceptions:
| Type | Description |
|---|---|
ValueError |
If the position is not valid. |
Source code in chartops/chartops.py
def add_layer_control(self, position: str = "topright") -> None:
"""
Add a layer control to the map.
Args:
position (str, optional): Position of the layer control. Valid positions are "topright", "topleft", "bottomright", "bottomleft". Default is "topright".
Returns:
None
Raises:
ValueError: If the position is not valid.
"""
self._validate_position(position)
self.add(LayersControl(position=position))
add_raster(self, url, opacity, name=None, colormap=None, **kwargs)
¶
Add a raster layer to the map using a local or remote tile source.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url |
str or Path |
Path or URL to the raster file. |
required |
opacity |
float |
Opacity of the raster layer. Must be between 0 and 1. |
required |
name |
str |
Name of the layer. Defaults to the stem of the file path. |
None |
colormap |
str or dict |
Colormap to apply to the raster. Can be a colormap name or a dict. Resolved using |
None |
**kwargs |
dict |
Additional keyword arguments passed to the tile layer. |
{} |
Returns:
| Type | Description |
|---|---|
None |
None |
Exceptions:
| Type | Description |
|---|---|
FileNotFoundError |
If the local raster file does not exist. |
ValueError |
If the opacity is not valid or raster layer cannot be added. |
Source code in chartops/chartops.py
def add_raster(
self,
url: Union[str, Path],
opacity: float,
name: Optional[str] = None,
colormap: Optional[Union[str, dict]] = None,
**kwargs,
) -> None:
"""
Add a raster layer to the map using a local or remote tile source.
Args:
url (str or Path): Path or URL to the raster file.
opacity (float): Opacity of the raster layer. Must be between 0 and 1.
name (str, optional): Name of the layer. Defaults to the stem of the file path.
colormap (str or dict, optional): Colormap to apply to the raster. Can be a colormap name or a dict. Resolved using `common.resolve_colormap`.
**kwargs (dict): Additional keyword arguments passed to the tile layer.
Returns:
None
Raises:
FileNotFoundError: If the local raster file does not exist.
ValueError: If the opacity is not valid or raster layer cannot be added.
"""
from localtileserver import TileClient, get_leaflet_tile_layer
if isinstance(url, Path) and not url.exists():
raise FileNotFoundError(f"Raster file not found: {url}")
self._validate_opacity(opacity)
try:
colormap_arg = common.resolve_colormap(colormap)
except Exception as e:
raise ValueError(f"Failed to resolve colormap: {e}")
try:
client = TileClient(str(url))
self.center = client.center()
self.zoom = client.default_zoom
tile_layer = get_leaflet_tile_layer(
client, colormap=colormap_arg, opacity=opacity, **kwargs
)
tile_layer.name = name or ""
self.add(tile_layer)
except Exception as e:
raise ValueError(f"Failed to add raster layer: {e}")
add_vector(self, filepath, name='', **kwargs)
¶
Add a vector layer to the map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filepath |
Path or str |
Path to the vector dataset or URL to a remote file. |
required |
name |
str |
Name of the layer. Defaults to ''.. |
'' |
**kwargs |
dict |
Additional styling options for the layer. Valid options include: - color: str (default: 'blue') - weight: int (default: 2) - fillOpacity: float (default: 0.1) |
{} |
Returns:
| Type | Description |
|---|---|
None |
None |
Exceptions:
| Type | Description |
|---|---|
FileNotFoundError |
If the local filepath does not exist. |
ValueError |
If the vector data cannot be read or converted to GeoJSON, or if styling options are invalid. |
Source code in chartops/chartops.py
def add_vector(self, filepath: Union[Path, str], name: str = "", **kwargs) -> None:
"""
Add a vector layer to the map.
Args:
filepath (Path or str): Path to the vector dataset or URL to a remote file.
name (str): Name of the layer. Defaults to ''..
**kwargs (dict): Additional styling options for the layer. Valid options include:
- color: str (default: 'blue')
- weight: int (default: 2)
- fillOpacity: float (default: 0.1)
Returns:
None
Raises:
FileNotFoundError: If the local filepath does not exist.
ValueError: If the vector data cannot be read or converted to GeoJSON, or if styling options are invalid.
"""
if isinstance(filepath, Path) and not filepath.exists():
raise FileNotFoundError(f"File not found: {filepath}")
color = kwargs.get("color", "blue")
if not isinstance(color, str):
raise ValueError(f"color must be a string, got {type(color)}")
weight = kwargs.get("weight", 2)
if not isinstance(weight, int):
raise ValueError(f"weight must be an integer, got {type(weight)}")
fillOpacity = kwargs.get("fillOpacity", 0.1)
self._validate_opacity(fillOpacity)
try:
gdf = gpd.read_file(filepath)
geojson = gdf.__geo_interface__
layer = GeoJSON(
data=geojson,
name=name,
style={"color": color, "weight": weight, "fillOpacity": fillOpacity},
)
self.add(layer)
except Exception as e:
raise ValueError(f"Failed to add vector layer from {filepath}: {e}")
add_video(self, url, bounds, opacity, **kwargs)
¶
Add a video overlay to the map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url |
str or Path |
URL or path to the video to overlay. |
required |
bounds |
tuple |
A tuple of ((south, west), (north, east)) coordinates defining the bounding box of the video. |
required |
opacity |
float |
Opacity of the video overlay. Must be between 0 and 1. |
required |
**kwargs |
dict |
Additional keyword arguments passed to VideoOverlay. |
{} |
Returns:
| Type | Description |
|---|---|
None |
None |
Exceptions:
| Type | Description |
|---|---|
ValueError |
If the bounds are not in correct format or opacity is invalid. |
FileNotFoundError |
If the local video path does not exist. |
Source code in chartops/chartops.py
def add_video(
self,
url: Union[str, Path],
bounds: Tuple[Tuple[float, float], Tuple[float, float]],
opacity: float,
**kwargs,
) -> None:
"""
Add a video overlay to the map.
Args:
url (str or Path): URL or path to the video to overlay.
bounds (tuple): A tuple of ((south, west), (north, east)) coordinates defining the bounding box of the video.
opacity (float): Opacity of the video overlay. Must be between 0 and 1.
**kwargs (dict): Additional keyword arguments passed to VideoOverlay.
Returns:
None
Raises:
ValueError: If the bounds are not in correct format or opacity is invalid.
FileNotFoundError: If the local video path does not exist.
"""
if isinstance(url, Path) and not url.exists():
raise FileNotFoundError(f"Video file not found: {url}")
self._validate_bounds(bounds)
self._validate_opacity(opacity)
try:
video = VideoOverlay(url=str(url), bounds=bounds, opacity=opacity, **kwargs)
self.add(video)
except Exception as e:
raise ValueError(f"Failed to add video overlay: {e}")
add_wms_layer(self, url, layers, name, format, transparent, **kwargs)
¶
Add a WMS (Web Map Service) layer to the map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url |
str |
Base URL of the WMS service. |
required |
layers |
str |
Comma-separated list of layer names to request from the service. |
required |
name |
str |
Name of the layer to show in the map. |
required |
format |
str |
Image format for the WMS tiles (e.g., 'image/png'). |
required |
transparent |
bool |
Whether the WMS tiles should support transparency. |
required |
**kwargs |
dict |
Additional keyword arguments passed to the WMSLayer. |
{} |
Returns:
| Type | Description |
|---|---|
None |
None |
Exceptions:
| Type | Description |
|---|---|
TypeError |
If any of the required parameters are not of the expected type. |
ValueError |
If the WMS layer cannot be created or added. |
Source code in chartops/chartops.py
def add_wms_layer(
self, url: str, layers: str, name: str, format: str, transparent: bool, **kwargs
) -> None:
"""
Add a WMS (Web Map Service) layer to the map.
Args:
url (str): Base URL of the WMS service.
layers (str): Comma-separated list of layer names to request from the service.
name (str): Name of the layer to show in the map.
format (str): Image format for the WMS tiles (e.g., 'image/png').
transparent (bool): Whether the WMS tiles should support transparency.
**kwargs (dict): Additional keyword arguments passed to the WMSLayer.
Returns:
None
Raises:
TypeError: If any of the required parameters are not of the expected type.
ValueError: If the WMS layer cannot be created or added.
"""
if not isinstance(url, str):
raise TypeError(f"url must be a string, got {type(url)}")
if not isinstance(layers, str):
raise TypeError(f"layers must be a string, got {type(layers)}")
if not isinstance(name, str):
raise TypeError(f"name must be a string, got {type(name)}")
if not isinstance(format, str):
raise TypeError(f"format must be a string, got {type(format)}")
if not isinstance(transparent, bool):
raise TypeError(f"transparent must be a boolean, got {type(transparent)}")
try:
wms = WMSLayer(
url=url,
layers=layers,
format=format,
transparent=transparent,
**kwargs,
)
wms.name = name
self.add(wms)
except Exception as e:
raise ValueError(f"Failed to add WMS layer: {e}")