Shortcuts

Source code for geodesic.mapping.base

import ipyleaflet
import geodesic
import numpy as np
from shapely.geometry import shape
from shapely.ops import transform

DEFAULT_BASEMAP = ipyleaflet.basemaps.CartoDB.DarkMatter

_color_cycle = [
    "#428BA9",
    "#FF902B",
    "#5FAD56",
    "#966B9D",
    "#DF2935",
]


def _get_color(i: int) -> str:
    """returns the color corresponding to the given index, cyclic on the _color_cycle."""
    return _color_cycle[i % len(_color_cycle)]


[docs]class Map(ipyleaflet.Map): """Light wrapper on top of an ipyleaflet.Map A basic map with some basic initialization. """ def __init__(self, basemap=DEFAULT_BASEMAP, zoom=3, center=(0.0, 0.0), **kwargs): super().__init__(basemap=basemap, zoom=zoom, center=center, **kwargs) self._fc_layers = [] self.add_control(ipyleaflet.LayersControl())
[docs] def add_feature_collection( self, layer_name: str, feature_collection: geodesic.FeatureCollection, on_click: callable = None, style_callback: callable = None, **kwargs, ) -> None: """add a feature colleciton to the map. Adds a geodesic.FeatureCollection to the map as a GeoJSON layer. Args: layer_name: display name of the layer feature_collection: the `geodesic.FeatureCollection` to add to the map on_click: a callback function that will be called when a feature is selected. style_callback: a function that will be called on each feature to return the style. Can be used to style each feature based on its properties. **kwargs: additional kwargs passed to the layer constructor. """ index = len(self._fc_layers) add_layer = True current_layer = None for i, layer in enumerate(self._fc_layers): if layer.name == layer_name: index = i current_layer = layer add_layer = False break color = _get_color(index) if "style" not in kwargs: kwargs["style"] = dict(opacity=1.0, fillOpacity=0.5, color=color, fillColor=color) if "hover_style" not in kwargs: kwargs["hover_style"] = dict(fillOpacity=1.0) if current_layer is None: current_layer = ipyleaflet.GeoJSON( name=layer_name, data=dict(feature_collection), **kwargs ) else: current_layer.data = dict(feature_collection) if on_click is not None: current_layer.on_click(on_click) current_layer.style_callback = style_callback if add_layer: self._fc_layers.append(current_layer) self.add_layer(current_layer) else: self._fc_layers[index] = current_layer
[docs]class BBoxSelector(Map): """select a geometry/aoi on the a interactive webmap Lets a user draw a geometry on the map. This geometry will be accessible as this object's `geometry` parameter and the bounding rectangle corners as `bbox`. Note: Does not handle geometries that cross the datetime. Args: set_geometry_on: a list of objects such as a `geodesic.Feature`, a `geodesic.tesseract.Job`, or a `geodesic.entanglement.Object`. When a draw action is performed, the drawn geometry is set on all objects in this list. """ def __init__(self, set_geometry_on=[], **kwargs): super().__init__(**kwargs) self.draw_control = ipyleaflet.DrawControl() self.draw_control.rectangle = dict( shapeOptions=dict(fillColor="#428BA9", color="#428BA9", fillOpacity=0.15) ) self.draw_control.polygon = dict( shapeOptions=dict(fillColor="#428BA9", color="#428BA9", fillOpacity=0.15) ) self.draw_control.circle = dict( shapeOptions=dict(fillColor="#428BA9", color="#428BA9", fillOpacity=0.15) ) self.set_geometry_on = set_geometry_on self.geometry = None self.draw_control.on_draw(self._bbox_callback) self.add_control(self.draw_control) def _bbox_callback(self, target, action, geo_json): geometry = geo_json["geometry"] # If it's a circle, parse that into a polygon so we can use it if "radius" in geo_json["properties"]["style"]: cx, cy = geometry["coordinates"] radius = geo_json["properties"]["style"]["radius"] / ( 1852.0 * 60.0 ) # rough conversion from m to deg angles = np.linspace(0.0, 2.0 * np.pi, 25) cos = np.cos(angles) sin = np.sin(angles) x = (cx + radius * cos).tolist() y = (cy + radius * sin).tolist() coordinates = [[c for c in zip(x, y)]] geometry = {"type": "Polygon", "coordinates": coordinates} def xform(x, y, z=None) -> tuple: while x < -180: x += 360 while x > 180: x -= 360 return x, y self.geometry = shape(geometry) self.geometry = transform(xform, self.geometry) self.action = action for obj in self.set_geometry_on: obj.geometry = self.geometry target.data = [geo_json] @property def bbox(self): """bbox for the geometry drawn on the map""" if self.geometry is None: return None return self.geometry.bounds

Docs

Developer documentation for Seer AI APIs

View Docs

Tutorials

Get in-depth tutorials for beginners and advanced developers

View Tutorials

Resources

Find development resources and get your questions answered

View Resources