def __init__(self, position: str = "bottomleft", attr_name: str = "style", kind: str = "stroke", orientation: str = "horizontal", transparent: bool = False, a_map: Map = None, layer: Layer = None, place_control: bool = True): def updated(change): """Called after each single-letter edit of the JSON in the textarea. """ if change["type"] != "change": return value = change["owner"].value if not is_valid_json(value): return else: layer.style = json.loads(value) def close(button): a_map.remove_control(wc) layout = Layout(width="28px", height="28px", padding="0px 0px 0px 4px") btn = Button(tooltip="Close", icon="close", layout=layout) btn.on_click(close) ta = Textarea(value=json.dumps(getattr(layer, attr_name), indent=2)) ta.layout.width = "200px" ta.observe(updated) header = HBox([HTML(f"<i>{attr_name} (JSON)</i>"), btn]) ui = VBox([header, ta]) wc = WidgetControl(widget=ui, position=position, transparent_bg=True) a_map.add_control(wc)
class LeafletMap: def __init__(self, bounds: tuple): self.layer = None self._leaflet_map = Map(layers=(basemap_to_tiles( basemaps.OpenStreetMap.BlackAndWhite), ), name="Leaflet Map", center=center(bounds), zoom=12, scroll_wheel_zoom=True) self._leaflet_map.add_control(FullScreenControl()) @property def map(self): return self._leaflet_map def update(self, layer: Layer): self.layer = layer self._remove_layers() self._update_layers() def _remove_layers(self): for layer in self._leaflet_map.layers: if isinstance(layer, TileLayer): continue self._leaflet_map.remove_layer(layer) def _update_layers(self): if self.layer.empty: return self._leaflet_map.add_layer(self.layer.layer)
def polygon_map(area, source): from ipyleaflet import Map, DrawControl center, zoom = centroid(area, source) m = Map(center=center, zoom=zoom) draw_control = DrawControl() draw_control.polygon = { "shapeOptions": { "fillColor": "#6be5c3", "color": "#6be5c3", "fillOpacity": 1.0 }, "drawError": { "color": "#dd253b", "message": "Oups!" }, "allowIntersection": False } polygon_map.feature_collection = { 'type': 'FeatureCollection', 'features': [] } def handle_draw(self, action, geo_json): """Do something with the GeoJSON when it's drawn on the map""" polygon_map.feature_collection['features'].append(geo_json) draw_control.on_draw(handle_draw) m.add_control(draw_control) return m
def show_map(selected_stats, year): control = WidgetControl(widget=districtbox, position='topright', min_width = 250, max_width=500) # load selected stats into choro_data_all choro_data_all, unit = choro_data_complete[selected_stats], units[selected_stats] # for geo plot extract chosen year and assign to choro_data choro_data = choro_data_all[choro_data_all['year']==year] choro_data = dict(choro_data.drop(columns=['year', 'name']).to_dict('split')['data']) # initialize bar chart with Frankfurt vs Offenbach update_figure('06412', selected_stats, choro_data_all, year) update_figure('06413', selected_stats, choro_data_all, year) # initialize districtbox loading_name, loading_values = id_to_name['06413'], choro_data['06413'] districtbox.value = f'<center><p><b>{loading_name}</b>:</p> {loading_values:g} {unit} {norm_unit}</center>' # set y-axis label fig.update_layout(yaxis_title=f'{stat_dict[selected_stats]} [{unit} {norm_unit}]', yaxis={'range':[0,max(choro_data_all[selected_stats])]}) # define chropleth layer for basic geo plotting layer = Choropleth(geo_data=geo_data,choro_data=choro_data,colormap=cm, style={'fillOpacity': 0.65, 'dashArray': '0, 0', 'weight':1}) # define GeoJSON layer for click and hover event interactions geo_json = GeoJSON(data=geo_data, style={'opacity': 0, 'dashArray': '9', 'fillOpacity': .0, 'weight': 1}, hover_style={'color': 'blue', 'dashArray': '0', 'fillOpacity': 0.7}) # on hover, the districtbox is updated to show properties of the hovered district def update_districtbox(feature, **kwargs): feature['value'] = choro_data[feature['id']] districtbox.value = f'<center><p><b>{id_to_name[feature["id"]]}</b>:</p> {feature["value"]:g} {unit} {norm_unit}</center>' # this function is called upon a click events and triggers figure update with the arguments passed from the map def update_fig_on_click(feature, **kwags): update_figure(feature['id'], selected_stats, choro_data_all, year) geo_json.on_hover(update_districtbox) geo_json.on_click(update_fig_on_click) # add layers and controls; set layout parameters m = Map(basemap=basemaps.OpenStreetMap.Mapnik, center=(50.5,9), zoom=8) m.add_layer(layer) m.add_layer(geo_json) m.add_control(control) m.layout.width = '40%' m.layout.height = '700px' # custom made legend using min/max normalization min_value, max_value = min(choro_data.values()), max(choro_data.values()) legend = LegendControl( {f"{min_value:g} {unit} {norm_unit}": cm(0), #hier f"{min_value+0.5*(max_value-min_value):g} {unit} {norm_unit}": cm(.5), f"{max_value:g} {unit} {norm_unit}": cm(1)}, name= f"{stat_dict[selected_stats]} ({year})", position="bottomleft") m.add_control(legend) return HBox([m, fig], layout=Layout(width='85%'))
def draw_interactive_map(): """ Draws interactive map to be able to draw/define a region of interest """ wms_drillholes = WMSLayer( url='http://geo.loop-gis.org/geoserver/loop/wms?', layers='loop:collar_4326', format='image/png', transparent=True, attribution='Drilhole collar from GSWA', name='drillhole collars' ) wms_geol = WMSLayer( url='http://geo.loop-gis.org/geoserver/loop/wms?', layers='loop:2_5m_interpgeop15_4326', format='image/png', transparent=True, opacity=0.4, attribution='Geology data from GSWA', name='geology' ) m =Map(basemap=basemaps.OpenTopoMap, center=(-29,116.5), zoom=8,scroll_wheel_zoom=True) m.add_layer(wms_geol) m.add_layer(wms_drillholes) m.add_control(LayersControl()) dc = DrawControl(rectangle={'shapeOptions': {'color': '#0000FF'}}) m.add_control(dc) m
def plotHeatmap(locations: [tuple], heatmapName: str, worldMap: lf.Map = None, center: tuple = (0, 0), **kwargs) -> lf.Map: ''' Plot the given lat lon locations as a heatmap layer on a world map object @center: the center coordinate when creating the world map object @locations: list of latitude & longitude pair @worldMap: ipyleaflet Map object. If this is specified, the new heatmap will be addded to this object. Else a new Map object will be created @heatmapName: name of the heatmap layer Returns: a newly created Map object or the passed in worldMap object. ''' # Create map if it's not passed in to the function if (worldMap is None): baseMap = lf.basemaps.CartoDB.DarkMatter # lf.basemaps.Esri.WorldTopoMap worldMap = lf.Map(basemap=baseMap, center=center, zoom=10) worldMap.add_control(lf.FullScreenControl()) worldMap.add_control(lf.LayersControl(position='topright')) # Remove existing heatmap layer that has the same name removeLayerByType(worldMap, heatmapName, lf.Heatmap) # Add the heatmap layer to the world map object heatmap = lf.Heatmap(locations=locations, radius=20, name=heatmapName, **kwargs) worldMap.add_layer(heatmap) return worldMap
class Grass2Leaflet(object): def __init__(self, grassimg): self.grassimg = grassimg self.draw_control = None self.zoom = 15 self.center = self.centermap() self.m = Map(default_tiles=TileLayer(opacity=1.0), center=self.center, zoom=self.zoom) def centermap(self): centerlat = [] centerlon = [] for i in self.grassimg: centerlat.append(self.grassimg[i]['C'][0]) centerlon.append(self.grassimg[i]['C'][1]) center = (sum(centerlat) / float(len(centerlat)), sum(centerlon) / float(len(centerlon))) return center def imgoverlays(self): self.leafletimg = OrderedDict() for i in self.grassimg: layer = ImageOverlay(url=self.grassimg[i]['raster'], bounds=(self.grassimg[i]['LL'], self.grassimg[i]['UR'])) self.leafletimg[i] = layer def render(self, draw_control=None): self.imgoverlays() self.dc = None options = ['None'] self.m.add_layer(self.leafletimg[list(self.grassimg.keys())[-1]]) if len(self.grassimg) >= 2: self.maplist = widgets.Dropdown( options=options + list(self.grassimg.keys()), value=list(self.grassimg.keys())[-1], description='Select Layer:', ) self.maplist.observe(self.on_value_change, names='value') display(self.maplist) if draw_control: self.dc = DrawControl() self.dc.on_draw(handle_draw) self.m.add_control(self.dc) display(self.m) return {'map': self.m, 'drawer': self.dc} def on_value_change(self, layername): self.m.clear_layers() self.m.add_layer(TileLayer(opacity=1.0)) if self.maplist.value != 'None': self.m.add_layer(self.leafletimg[layername['new']]) def main(self): self.imgoverlays() self.render()
def ipyleaflet_contourmap( center, datapoints=None, contourmap=None, isolines=[0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1], lineopacity=1.0, colormap=linear.viridis, fillopacity=0.7, legend_title='Legend', m=None, zoom=11, width='600px', height='400px'): if m is None: m = Map(center=center, zoom=zoom) m.layout.width = width m.layout.height = height cs = contourmap colors = [ colormap(i / (len(cs.levels) - 1)) for i in range(len(cs.levels) - 1) ] allsegs = cs.allsegs allkinds = cs.allkinds for clev in range(len(cs.allsegs)): kinds = None if allkinds is None else allkinds[clev] segs = split_contours(allsegs[clev], kinds) polygons = Polygon( locations=[p.tolist() for p in segs], # locations=segs[14].tolist(), color=colors[clev], weight=2, opacity=lineopacity, fill_color=colors[clev], fill_opacity=fillopacity) m.add_layer(polygons) if datapoints is not None: m = ipyleaflet_scatterplot_per_class(datapoints[0], datapoints[1], proportion=1.0, m=m) legend_colors = {} for i in reversed(range(len(isolines) - 1)): legend_colors["{:0.1f}-{:0.1f}".format( isolines[i], isolines[i + 1])] = colormap(i / (len(isolines) - 1)) legend = LegendControl(legend_colors, name=legend_title, position="topright") m.add_control(legend) return m
def __init__(self, description: str = "Basemap", position: str = "topright", a_map: Map = None): options = list(yield_basemap_dicts()) options = [opt["name"] for opt in options] current_basemap_name = [ l for l in a_map.layers if type(l) == TileLayer ][0].name start_value = current_basemap_name if current_basemap_name in options else options[ 0] dropdown = Dropdown(description=description, options=options, value=start_value, layout=Layout(width="250px")) close_btn = Button( icon="times", button_style="info", tooltip="Close the basemap widget", layout=Layout(width="32px"), ) self.widget = HBox([dropdown, close_btn]) def switch(basemap_name): if len(a_map.layers) == 1: a_map.layers = tuple([TileLayer(**get_basemap(basemap_name))]) else: old_basemap = [ l for l in a_map.layers if type(l) == TileLayer ][0] a_map.substitute_layer(old_basemap, TileLayer(**get_basemap(basemap_name))) def on_click(change): basemap_name = change["new"] switch(basemap_name) dropdown.observe(on_click, "value") def close_click(change): if a_map.basemap_ctrl is not None and a_map.basemap_ctrl in a_map.controls: a_map.remove_control(a_map.basemap_ctrl) self.widget.close() close_btn.on_click(close_click) self.widget_control = WidgetControl(widget=self.widget, position="topright") a_map.add_control(self.widget_control) a_map.basemap_ctrl = self.widget_control switch(dropdown.value)
def run(): global m,dc,center center = list(reversed(poly.centroid().coordinates().getInfo())) m = Map(center=center, zoom=11, layout={'height':'400px'}) osm = basemap_to_tiles(basemaps.OpenStreetMap.HOT) mb = TileLayer(url="https://api.mapbox.com/styles/v1/mapbox/satellite-streets-v9/tiles/256/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWNhbnR5IiwiYSI6ImNpcjRsMmJxazAwM3hoeW05aDA1cmNkNzMifQ.d2UbIugbQFk2lnU8uHwCsQ") sm_control = SplitMapControl(left_layer=osm,right_layer=mb) m.add_control(dc) m.add_control(sm_control) display(m) display(box)
def display_da(da, cm): """ Description: Display a colored xarray.DataArray on a map and allow the user to select a point ----- Input: da: xarray.DataArray cm: matplotlib colormap Output: m: map to interact with dc: draw control Usage: View, interact and point a location to be used later on """ # Check inputs assert 'dataarray.DataArray' in str( type(da)), "da must be an xarray.DataArray" # convert DataArray to png64 imgurl = da_to_png64(da, cm) # Display latitude = (da.latitude.values.min(), da.latitude.values.max()) longitude = (da.longitude.values.min(), da.longitude.values.max()) margin = -0.5 zoom_bias = 0 lat_zoom_level = _degree_to_zoom_level(margin=margin, * latitude) + zoom_bias lon_zoom_level = _degree_to_zoom_level(margin=margin, * longitude) + zoom_bias zoom = min(lat_zoom_level, lon_zoom_level) - 1 center = [np.mean(latitude), np.mean(longitude)] m = Map(center=center, zoom=zoom) # http://leaflet-extras.github.io/leaflet-providers/preview/ esri = basemap_to_tiles(basemaps.Esri.WorldImagery) m.add_layer(esri) io = ImageOverlay(name='DataArray', url=imgurl, bounds=[(latitude[0], longitude[0]), (latitude[1], longitude[1])]) m.add_layer(io) dc = DrawControl(circlemarker={'color': 'yellow'}, polygon={}, polyline={}) m.add_control(dc) m.add_control(LayersControl()) return m, dc, io
def flight_map(self, center=None, basemap=None, zoom=8): """Display interactive map of the flight path. (Jupyter notebook only.) Parameters ---------- center: tuple, optional (latitude, longitude) center of the map. The default is the average of the flight's lat/lon bounding box. basemap: str, or list or tuple of str, optional Name of the base map available in ipyleaflet. Default: ``('Esri.WorldImagery', 'OpenTopoMap')``. zoom: int, optional Map zoom level. Default is 8. """ if not display_map: raise RuntimeError('Cannot display map') if basemap is None: basemap = ('Esri.WorldImagery', 'OpenTopoMap') elif isinstance(basemap, str): basemap = (basemap, ) elif not isinstance(basemap, (list, tuple)): raise TypeError('basemap is not a str, list, or tuple') base_layers = list() for layer in basemap: name_parts = layer.split('.') base_layer = basemaps for p in name_parts: base_layer = base_layer[p] if not isinstance(base_layer, dict): raise TypeError('base layer not a dict') base_layers.append(basemap_to_tiles(base_layer)) data = self._flight flight_lat = data['latitude'] flight_lon = data['longitude'] if center is None: center = (flight_lat.mean(), flight_lon.mean()) flight_path = Polyline( locations=[np.column_stack((flight_lat, flight_lon)).tolist()], color='blue', fill=False, name='Flight path') flight_map = Map(center=center, zoom=int(zoom)) for _ in base_layers: flight_map.add_layer(_) flight_map.add_layer(flight_path) flight_map.add_control(FullScreenControl()) flight_map.add_control(LayersControl()) display(flight_map)
def area(): """ Provide map and options to choose area of interest """ center = [65.73, -50.71] zoom = 4 m = Map(center=center, zoom=zoom) global dc, start, end, file, lon_l, lat_l, lon_r, lat_r # Pick date start = widgets.DatePicker(disabled=False) end = widgets.DatePicker(disabled=False) # Select from map dc = DrawControl(rectangle={'shapeOptions': { 'color': '#0000FF' }}, polyline={}, polygon={}, circlemarker={}) m.add_control(dc) # Shapefile file = widgets.FileUpload(accept='.shp', multiple=False) # Bounding box lon_l = widgets.FloatText(description="lon") lat_l = widgets.FloatText(description="lat") lon_r = widgets.FloatText(description="lon") lat_r = widgets.FloatText(description="lat") return (AppLayout(header=VBox([ HTML("<h1>Select area (time and space)</h1>"), HBox([Label("Start Date:"), start, Label("End Date:"), end]) ]), center=m, right_sidebar=VBox([ HTML("<h3>or upload shapefile<h3>"), file, HTML("<h3> <h3>"), HTML("<h3>or bounding box<h3>"), Label("Bottom-left corner"), lon_l, lat_l, Label("Upper-right corner"), lon_r, lat_r ])))
def draw_map(): """ Description: Create an empty map to be used to draw a polygon or rectangle ----- Input: None Output: m: empty map ti interact with dc: draw control Usage: Draw a polygon or a rectangle """ # Location center = [47, 8] zoom = 7 m = Map(center=center, zoom=zoom) # Layers # http://leaflet-extras.github.io/leaflet-providers/preview/ esri = basemap_to_tiles(basemaps.Esri.WorldImagery) m.add_layer(esri) terrain = basemap_to_tiles(basemaps.Stamen.Terrain) m.add_layer(terrain) mapnik = basemap_to_tiles(basemaps.OpenStreetMap.Mapnik) m.add_layer(mapnik) m.add_control(LayersControl()) # Controls dc = DrawControl(rectangle={'shapeOptions': {'color': '#0000FF'}}, polygon={'shapeOptions': {'color': '#0000FF'}}, marker={}, polyline={}, circle={}, circlemarker={} ) m.add_control(dc) return m, dc
def get_image_container_zoom(): image_container = Map(center = config["center"], min_zoom=config["min_zoom"], zoom=config["min_zoom"], dragging=True, zoom_control=True, box_zoom=True, double_click_zoom=True, bounce_at_zoom_limits=False, layers=[LocalTileLayer(path='../classes/white.png')], layout=dict(width=config["size"], height=config["size"]), crs=projections.Simple) button = widgets.Button( disabled=False, button_style='', icon='arrows-alt', layout= widgets.Layout(width='35px', height='30px') ) def function(b): center_image_on_map(image_container) button.on_click(function) recenter_control = WidgetControl(widget = button, position = 'topleft') image_container.add_control(recenter_control) return image_container
class openeoMap: def __init__(self, center, zoom): self.map = Map(center=center, zoom=zoom, scroll_wheel_zoom=True, interpolation='nearest') self.bbox = [] self.point_coords = [] self.figure = None self.figure_widget = None feature_collection = {'type': 'FeatureCollection', 'features': []} draw = DrawControl( circlemarker={}, polyline={}, polygon={}, marker={"shapeOptions": { "original": {}, "editing": {}, }}, rectangle={"shapeOptions": { "original": {}, "editing": {}, }}) self.map.add_control(draw) def handle_draw(target, action, geo_json): feature_collection['features'] = [] feature_collection['features'].append(geo_json) if feature_collection['features'][0]['geometry'][ 'type'] == 'Point': self.point_coords = feature_collection['features'][0][ 'geometry']['coordinates'] else: coords = feature_collection['features'][0]['geometry'][ 'coordinates'][0] polygon = shapely.geometry.Polygon(coords) self.bbox = polygon.bounds layers_control = LayersControl(position='topright') self.map.add_control(layers_control) self.map.add_control(FullScreenControl()) self.map.add_layer(basemap_to_tiles(basemaps.Esri.WorldImagery)) draw.on_draw(handle_draw) def getBbox(self): if (len(self.bbox) == 0): mapBox = self.map.bounds return [mapBox[0][1], mapBox[0][0], mapBox[1][1], mapBox[1][0]] else: return self.bbox
def rasters_on_map(rasters_list, out_dir, overlay_names_list, geojson_data=None): """ displays a raster on a ipyleaflet map :param rasters_list: rasters to display (rasterio image) :param out_dir: path to the output directory (preview writing) :param overlay_names_list: name of the overlays for the map """ # - get bounding box raster = rasters_list[0] epsg4326 = {'init': 'EPSG:4326'} bounds = transform_bounds(raster.crs, epsg4326, *raster.bounds) center = [(bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2] # - get centered map m = Map(center=(center[-1], center[0]), zoom=10) # - plot quicklook for raster, overlay_name in zip(rasters_list, overlay_names_list): bounds = transform_bounds(raster.crs, epsg4326, *raster.bounds) quicklook_url = os.path.join( out_dir, "PREVIEW_{}.JPG".format(datetime.datetime.now())) write_quicklook(raster, quicklook_url) quicklook = ImageOverlay(url=quicklook_url, bounds=((bounds[1], bounds[0]), (bounds[3], bounds[2])), name=overlay_name) m.add_layer(quicklook) m.add_control(LayersControl()) m.add_control(FullScreenControl()) # - add geojson data if geojson_data is not None: geo_json = GeoJSON(data=geojson_data, style={ 'color': 'green', 'opacity': 1, 'weight': 1.9, 'dashArray': '9', 'fillOpacity': 0.1 }) m.add_layer(geo_json) # - add draw control dc = DrawControl() m.add_control(dc) return m, dc
def run_valuation_app(): """ Description of function to come """ # Suppress warnings warnings.filterwarnings('ignore') # Update plotting functionality through rcParams mpl.rcParams.update({'figure.autolayout': True}) #Start the datacube dc = datacube.Datacube(app='dem') # Set the parameters to load the backgroun map # center specifies where the background map view should focus on # zoom specifies how zoomed in the background map should be loadeddata_center = [-33.419474, 149.577299] loadeddata_zoom = 12 # define the background map studyarea_map = Map(center=loadeddata_center, zoom=loadeddata_zoom, basemap=basemaps.OpenStreetMap.Mapnik) # define the drawing controls studyarea_drawctrl = DrawControl( polygon={"shapeOptions": { "fillOpacity": 0 }}, marker={}, circle={}, circlemarker={}, polyline={}, ) # add drawing controls and data bound geometry to the map studyarea_map.add_control(studyarea_drawctrl) #studyarea_map.add_layer(GeoJSON(data=geom_obj)) # Index to count drawn polygons polygon_number = 0 # Define widgets to interact with instruction = widgets.Output(layout={'border': '1px solid black'}) with instruction: print("Draw a polygon within the red box to estimate " "the number of pixels in the polygon.") info = widgets.Output(layout={'border': '1px solid black'}) with info: print("Plot status:") fig_display = widgets.Output(layout=widgets.Layout( width="50%", # proportion of horizontal space taken by plot )) with fig_display: plt.ioff() fig, ax = plt.subplots(figsize=(8, 6)) colour_list = plt.rcParams['axes.prop_cycle'].by_key()['color'] # Function to execute each time something is drawn on the map def handle_draw(self, action, geo_json): nonlocal polygon_number # Execute behaviour based on what the user draws if geo_json['geometry']['type'] == 'Polygon': # Convert the drawn geometry to pixel coordinates geom_selectedarea_flat, geom_selectedarea = transform_from_wgs_poly( geo_json['geometry'], EPSGa=3577 # hard-coded to be same as case-study data ) geom_envelope = geom_selectedarea_flat.GetEnvelope() minX, maxX, minY, maxY = geom_envelope # Insert dc.load for dem and dlcdnsw x_range = (minX, maxX) y_range = (minY, maxY) inputcrs = "EPSG:3577" dem_res = (-5, 5) # dlcd_res is unused as the same res must be used when loading # multiple products (to support the cross count process). The # smallest cell size is used as this will provide the greatest # accuracy. dlcd_res = (-100, 100) # unused slope_cat = get_slope_raster(dc, x_range, y_range, inputcrs, dem_res, geom_selectedarea) dlcd = get_dlcd_raster(dc, x_range, y_range, inputcrs, dem_res, geom_selectedarea) stacked = xr.merge([dlcd, slope_cat]) cross_counts = unique_counts(stacked) slope_cat_count = slope_cat.to_dataframe( ).slope_category.value_counts().rename('counts').to_frame() slope_cat_count.index.name = 'index' slope_cat_table = pd.read_csv('slope_cat.csv') slope_coverage = pd.merge(slope_cat_count, slope_cat_table, how="left", left_on=['index'], right_on=['id']) # Compute the total number of pixels in the masked data set pix_dlcd = dlcd.count().compute().item() # Convert dlcd to pandas and get value counts for each class pd_dlcd = dlcd.to_dataframe() pd_dlcd_classcount = pd_dlcd.dlcd.value_counts().reset_index( name='counts') # Convert slope_cat to pandas and get value counts for each category # pd_slope_cat_count = slope_cat.to_dataframe().band1.value_counts() # Load DLCD land cover look-up table dlcd_lookup = pd.read_csv("dlcd.csv") # Join dlcd counts against landcover look up table pd_dlcd_coverage = pd.merge(pd_dlcd_classcount, dlcd_lookup, how="left", left_on=['index'], right_on=['id']) # Format the counts table to keep necessary items pd_dlcd_coverage['area(km^2)'] = pd_dlcd_coverage['counts'] * ( dem_res[1] / 1000.)**2 pd_dlcd_coverage['percentage_area'] = pd_dlcd_coverage[ 'counts'] / pd_dlcd_coverage['counts'].sum() * 100 pd_dlcd_output = pd_dlcd_coverage[[ 'Name', 'area(km^2)', 'percentage_area' ]] # manipulate cross counts into format suitable for presentation as # a table pd_cross_counts = cross_counts.to_dataframe() pd_cross_counts.sort_values(by='count', ascending=False, inplace=True) # join DLCD lookup table for DLCD class names pd_cross_counts = pd.merge(pd_cross_counts, dlcd_lookup, how='left', left_on=['dlcd'], right_on=['id']) pd_cross_counts = pd_cross_counts.rename(columns={ 'dlcd': 'dlcd_id', 'Name': 'DLCD' }) # join slope category definition table for slope class names pd_cross_counts = pd.merge(pd_cross_counts, slope_cat_table, how='left', left_on=['slope_category'], right_on=['id']) pd_cross_counts['slope'] = (pd_cross_counts[[ 'label', 'range' ]].apply(lambda x: '{} {}'.format(x[0], x[1]), axis=1)) # Format the counts table to keep necessary items pd_cross_counts['area(km^2)'] = (pd_cross_counts['count'] * (dem_res[1] / 1000.)**2) pd_cross_counts['percentage_area'] = ( pd_cross_counts['count'] / pd_cross_counts['count'].sum() * 100) pd_cross_counts_output = (pd_cross_counts[[ 'DLCD', 'slope', 'area(km^2)', 'percentage_area' ]]) # display(pd_cross_counts) colour = colour_list[polygon_number % len(colour_list)] # Add a layer to the map to make the most recently drawn polygon # the same colour as the line on the plot studyarea_map.add_layer( GeoJSON(data=geo_json, style={ 'color': colour, 'opacity': 1, 'weight': 4.5, 'fillOpacity': 0.0 })) # Make the DLDC Summary plot ax.clear() pd_dlcd_output.plot.bar(x='Name', y='percentage_area', rot=45, ax=ax, legend=False, color=colour) ax.set_xlabel("Land Cover Class") ax.set_ylabel("Percentage Coverage Of Polygon") # refresh display fig_display.clear_output( wait=True) # wait=True reduces flicker effect with fig_display: display(fig) info.clear_output(wait=True) # wait=True reduces flicker effect with info: # use to_string function to avoid truncation of results print(pd_cross_counts_output.to_string()) # Iterate the polygon number before drawing another polygon polygon_number = polygon_number + 1 else: info.clear_output(wait=True) with info: print("Plot status: this drawing tool is not currently " "supported. Please use the polygon tool.") # call to say activate handle_draw function on draw studyarea_drawctrl.on_draw(handle_draw) with fig_display: # TODO: update with user friendly something display(widgets.HTML("")) # Construct UI: # +-----------------------+ # | instruction | # +-----------+-----------+ # | map | # | | # +-----------+-----------+ # | info | # +-----------------------+ ui = widgets.VBox( [instruction, widgets.HBox([studyarea_map, fig_display]), info]) display(ui)
def plotLeaflet(geoJson: dict, idToValue: dict, worldMap: lf.Map = None, includeEmpty: bool = True, labelFormat: str = "Id={0} - Value={1}", mapArgs: dict = {}, heatmapArgs: dict = {}) -> lf.Map: ''' Plot the choropleth on the map using the ipyleaflet library @idToValue: a dictionary containing mappings of ids to their associated values @worldMap: ipyleaflet Map object. If this is specified, the new heatmap will be addded to this object. Else a new Map object will be created @includeEmpty: true if we want to display the regions that have value 0. False otherwise @labelFormat: the string format of the text that is displayed when the mouse hovers over a polygon. The format must contain exactly 2 placeholders. Returns: map object ''' updatedIdToValue = __syncIdToValueDict(geoJson, idToValue) # If we don't display empty regions, we need to # create a new geo JSON that does NOT contain the # ids that have 0 value if (not includeEmpty): origGeoJson = geoJson geoJson = {"type": "FeatureCollection", "features": []} for idValue, value in updatedIdToValue.items(): if (value > 0): feature = getFeatureById(origGeoJson, idValue) geoJson["features"].append(feature) # Create the world map object if not specified if (worldMap is None): #basemap=lf.basemaps.CartoDB.DarkMatter, center=center, zoom=10 worldMap = lf.Map(**mapArgs) worldMap.add_control(lf.FullScreenControl()) worldMap.add_control(lf.LayersControl(position="topright")) # Default heatmap arguments minVal, maxVal = min(updatedIdToValue.values()), max( updatedIdToValue.values()) defaultHeatmapArgs = { "key_on": "id", "border_color": "black", "value_min": minVal, "value_max": maxVal, "style": { 'fillOpacity': 0.8, 'dashArray': '5, 5' }, "hover_style": { 'fillColor': 'purple', 'dashArray': '0', 'fillOpacity': 0.5 }, "name": "Choropleth", "colormap": linear.OrRd_06 } # Make a copy of the heatmapArgs, because we would add the default arguments # to this dict if the default arguments are not specified by the caller. Making # a copy prevents modifying the passed in dict object heatmapArgs = dict(heatmapArgs) for k, v in defaultHeatmapArgs.items(): if (k not in heatmapArgs): heatmapArgs[k] = v # Create the choropleth layer choroplethLayer = lf.Choropleth(geo_data=geoJson, choro_data=updatedIdToValue, **heatmapArgs) # Create a label widget to display the currently hovered polygon id & # the value associated with that id labelWidget = widgets.Label(value="") widgetControl = lf.WidgetControl(widget=labelWidget, position="bottomright") worldMap.add_control(widgetControl) def mouseout(*args, **kwargs): ''' Set the label value to empty string when the mouse exits a region ''' labelWidget.value = "" def hover(*args, **kwargs): ''' Set the label to the id & its associated value ''' idValue = kwargs["id"] labelWidget.value = labelFormat.format(idValue, updatedIdToValue[idValue]) # Register callbacks choroplethLayer.on_mouseout(mouseout) choroplethLayer.on_hover(hover) # Remove existing choropleth layer that has the same name choroplethName = heatmapArgs["name"] if ("name" in heatmapArgs) else "" removeLayerByType(worldMap, choroplethName, lf.Choropleth) worldMap.add_layer(choroplethLayer) return worldMap
reqPassing = urllib2.Request( "http://api.open-notify.org/iss-pass.json?lat=48.634566&lon=8.09760") responsePassing = urllib2.urlopen(reqPassing) fetchPassing = json.loads(responsePassing.read()) passTime = int(fetchPassing['request']['datetime']) passTimeCounts = fetchPassing['request']['passes'] for i in range(passTimeCounts): riseTime = int(fetchPassing['response'][i]['risetime']) print( "ISS Overflight " + str(i + 1) + ": " + datetime.utcfromtimestamp(passTime).strftime('%Y-%m-%d %H:%M:%S')) i = +1 m = Map(basemap=basemaps.Esri.WorldImagery, center=(lat, long), zoom=2, scroll_wheel_zoom=True) m.add_layer( Marker( location=(lat, long), title="ISS", icon=Icon(icon_url= "https://img.icons8.com/fluent/48/000000/gps-device.png", icon_size=[20, 20]))) m.add_control(FullScreenControl()) m.add_control(ScaleControl(position='bottomleft')) m.save('current state.html', title="Space Radar") driver.refresh() time.sleep(30.0)
def run_miningrehab_app(ds): """ Plots an interactive map of the mining case-study area and allows the user to draw polygons. This returns plots of the fractional cover value of bare soil, green vegetation and brown vegetation in the polygon area. Last modified: January 2020 inputs ds - data set containing masked Fractional Cover data from Landsat 8 """ # Suppress warnings warnings.filterwarnings("ignore") # Update plotting functionality through rcParams mpl.rcParams.update({"figure.autolayout": True}) # Define the bounding box that will be overlayed on the interactive map # The bounds are hard-coded to match those from the loaded data geom_obj = { "type": "Feature", "properties": { "style": { "stroke": True, "color": "red", "weight": 4, "opacity": 0.8, "fill": True, "fillColor": False, "fillOpacity": 0, "showArea": True, "clickable": True, } }, "geometry": { "type": "Polygon", "coordinates": [[ [116.630731, -34.434517], [116.630731, -34.426512], [116.648123, -34.426512], [116.648123, -34.434517], [116.630731, -34.434517], ]], }, } # Create a map geometry from the geom_obj dictionary # center specifies where the background map view should focus on # zoom specifies how zoomed in the background map should be loadeddata_geometry = ogr.CreateGeometryFromJson(str(geom_obj["geometry"])) loadeddata_center = [ loadeddata_geometry.Centroid().GetY(), loadeddata_geometry.Centroid().GetX(), ] loadeddata_zoom = 15 # define the study area map studyarea_map = Map( layout=widgets.Layout(width="480px", height="600px"), center=loadeddata_center, zoom=loadeddata_zoom, basemap=basemaps.Esri.WorldImagery, ) # define the drawing controls studyarea_drawctrl = DrawControl( polygon={"shapeOptions": { "fillOpacity": 0 }}, marker={}, circle={}, circlemarker={}, polyline={}, ) # add drawing controls and data bound geometry to the map studyarea_map.add_control(studyarea_drawctrl) studyarea_map.add_layer(GeoJSON(data=geom_obj)) # Index to count drawn polygons polygon_number = 0 # Define widgets to interact with instruction = widgets.Output(layout={"border": "1px solid black"}) with instruction: print("Draw a polygon within the red box to view plots of " "the fractional cover values of bare, green and " "non-green cover for the area over time.") info = widgets.Output(layout={"border": "1px solid black"}) with info: print("Plot status:") fig_display = widgets.Output(layout=widgets.Layout( width="50%" # proportion of horizontal space taken by plot )) with fig_display: plt.ioff() fig, ax = plt.subplots(3, 1, figsize=(9, 9)) for axis in ax: axis.set_ylim([0, 1]) colour_list = plt.rcParams["axes.prop_cycle"].by_key()["color"] # Function to execute each time something is drawn on the map def handle_draw(self, action, geo_json): nonlocal polygon_number # info.clear_output(wait=True) # wait=True reduces flicker effect # with info: # print("Plot status: entered handle draw") # Execute behaviour based on what the user draws if geo_json["geometry"]["type"] == "Polygon": # Convert the drawn geometry to pixel coordinates geom_selectedarea = transform_geojson_wgs_to_epsg( geo_json, EPSG=3577 # hard-coded to be same as case-study data ) # Construct a mask to only select pixels within the drawn polygon mask = rasterio.features.geometry_mask( [geom_selectedarea for geoms in [geom_selectedarea]], out_shape=ds.geobox.shape, transform=ds.geobox.affine, all_touched=False, invert=True, ) masked_ds = ds.where(mask) masked_ds_mean = masked_ds.mean(dim=["x", "y"], skipna=True) colour = colour_list[polygon_number % len(colour_list)] # Add a layer to the map to make the most recently drawn polygon # the same colour as the line on the plot studyarea_map.add_layer( GeoJSON( data=geo_json, style={ "color": colour, "opacity": 1, "weight": 4.5, "fillOpacity": 0.0, }, )) # Add Fractional cover plots to app masked_ds_mean.BS.interpolate_na( dim="time", method="nearest").plot.line("-", ax=ax[0]) masked_ds_mean.PV.interpolate_na( dim="time", method="nearest").plot.line("-", ax=ax[1]) masked_ds_mean.NPV.interpolate_na( dim="time", method="nearest").plot.line("-", ax=ax[2]) # reset titles back to custom ax[0].set_ylabel("Bare cover") ax[1].set_ylabel("Green cover") ax[2].set_ylabel("Non-green cover") # refresh display fig_display.clear_output( wait=True) # wait=True reduces flicker effect with fig_display: display(fig) # Update plot info info.clear_output(wait=True) # wait=True reduces flicker effect with info: print("Plot status: polygon added to plot") # Iterate the polygon number before drawing another polygon polygon_number = polygon_number + 1 else: info.clear_output(wait=True) with info: print("Plot status: this drawing tool is not currently " "supported. Please use the polygon tool.") # call to say activate handle_draw function on draw studyarea_drawctrl.on_draw(handle_draw) with fig_display: # TODO: update with user friendly something display(widgets.HTML("")) # Construct UI: # +-----------------------+ # | instruction | # +-----------+-----------+ # | map | plot | # | | | # +-----------+-----------+ # | info | # +-----------------------+ ui = widgets.VBox( [instruction, widgets.HBox([studyarea_map, fig_display]), info]) display(ui)
class App(): """ """ settings = {"enabled_grid": "B"} def __init__(self, session=None): self.session = session self.use_grid = self.settings["enabled_grid"] # generate map grid polygon layers self.grid_layers = LayerGroup() self.grid_dict = {} for feat in above_grid["features"]: level = feat["properties"]["grid_level"] if level == self.use_grid: Cell_object = Cell(feat) #Cell_object.layer.on_click() grid_id = Cell_object.id self.grid_dict[grid_id] = Cell_object self.grid_layers.add_layer(self.grid_dict[grid_id].layer) # make an attribute that will hold selected layer self.selected_layer = LayerGroup() self.map = Map(layers=( esri, self.grid_layers, self.selected_layer, ), center=(65, -100), zoom=3, width="auto", height="auto", scroll_wheel_zoom=True) # map draw controls self.draw_control = DrawControl() self.draw_control.polyline = {} self.draw_control.circle = {} self.draw_control.circlemarker = {} self.draw_control.remove = False self.draw_control.edit = False self.draw_control.polygon = {**draw_style} self.draw_control.rectangle = {**draw_style} self.draw_control.on_draw(self.update_selected_cells) self.map.add_control(self.draw_control) # output display self.output = Output(layout=Layout(width="auto", height="auto")) # make the widget layout self.ui = VBox( [ #header, #HBox([instruct, geojson_text]), self.map, self.output ], layout=Layout(width="auto")) # display ui display(self.ui) def update_selected_cells(self, *args, **kwargs): """ """ # clear all draw and selection layers self.draw_control.clear() # -------------------------------------------------------------------- # update active cells and make a big merged polgyon for selection # make shapely geom from geojson drawn_json = kwargs["geo_json"] shapely_geom = shape(drawn_json["geometry"]) cells = self.grid_dict # iterate over cells and collect intersecting cells on = [] for id, cell in cells.items(): if shapely_geom.intersects(cell.shape): on.append(cell.shape) # this is blatant abuse of try/except; fix it try: # get the union of all of the cells that are toggled on union = cascaded_union(on) centroid = union.centroid # make layer that represents selected cells and add to selected_layer self.selected_layer.clear_layers() x, y = union.exterior.coords.xy self.selected_layer.add_layer(Polygon(locations=list(zip(y, x)))) self.map.center = (centroid.y, centroid.x) # -------------------------------------------------------------- # find all CMR collections that intersect with merged cells geom selected = [] for index, collection in above_results_df.iterrows(): box = collection.boxes shapely_box = CMR_box_to_Shapely_box(box[0]) # intersect: use shapely_geom if strictly using drawn poly intersect_bool = shapely_box.intersects(union) if intersect_bool: selected.append(index) self.coll = above_results_df.iloc[selected] self.tab = qgrid.show_grid( self.coll[["dataset_id", "time_start", "time_end", "boxes"]], grid_options={ 'forceFitColumns': False, 'minColumnWidth': "0", 'maxColumnWidth': "400" }, show_toolbar=False) self.output.clear_output() with self.output: display(self.tab) #display(self.coll[[ # "dataset_id", "time_start", "time_end", "boxes"]]) except: pass
def sel_params_form(processing_parameters: ProcessingParameters, identifier='identifier', name='name', mock=False): debug_view = get_debug_view() fetch_inputs_func = fetch_inputs if mock: @debug_view.capture(clear_output=True) def fetch_inputs_mock(input_request: InputRequest, message_func) -> ProcessingRequest: debug_view.value = '' time.sleep(2) input_identifiers = { input_type: [f'iid-{i}' for i in range(10)] for input_type in input_request.input_types } processing_request_data = input_request.as_dict() processing_request_data.update( dict(inputIdentifiers=input_identifiers)) return ProcessingRequest(processing_request_data) fetch_inputs_func = fetch_inputs_mock form_item_layout = widgets.Layout( display='flex', flex_flow='row', justify_content='space-between', ) var_checks_layout = widgets.Layout( display='flex', flex_flow='row', justify_content='center', ) variable_names = [] for variable_id in processing_parameters.variables.ids: variable_names.append( processing_parameters.variables.get(variable_id).name) forward_model_names = [] for model_id in processing_parameters.forward_models.ids: forward_model_names.append( processing_parameters.forward_models.get(model_id).name) variable_boxes_dict = _get_checkboxes_dict( processing_parameters.variables.ids, variable_names) forward_model_boxes_dict = _get_checkboxes_dict( processing_parameters.forward_models.ids, forward_model_names) request_validation = widgets.HTML( value=html_element('h3', att=dict(style='color:red'), value='No variable or forward model selected')) non_disabled_forward_models = [] available_forward_models_per_type = {} forward_models_per_variable = {} forward_model_select_buttons = {} for fm_id in processing_parameters.forward_models.ids: non_disabled_forward_models.append(fm_id) fm = processing_parameters.forward_models.get(fm_id) if not fm.input_type in available_forward_models_per_type: available_forward_models_per_type[fm.input_type] = [] available_forward_models_per_type[fm.input_type].append(fm_id) for variable in fm.variables: if not variable in forward_models_per_variable: forward_models_per_variable[variable] = [] forward_models_per_variable[variable].append(fm_id) selected_forward_models = [] selected_variables = [] selected_forward_model_per_type = {} for it in processing_parameters.input_types.ids: selected_forward_model_per_type[it] = None def _fm_variables(fm_id: str): return processing_parameters.forward_models.get(fm_id).variables def _fm_input_type(fm_id: str): return processing_parameters.forward_models.get(fm_id).input_type def _recommend(id: str): if id in processing_parameters.variables.ids: _recommend_box(variable_boxes_dict[id]) elif id in processing_parameters.forward_models.ids: if id not in non_disabled_forward_models: non_disabled_forward_models.append(id) _recommend_box(forward_model_boxes_dict[id]) def _recommend_box(box: LabeledCheckbox): box.enabled = True box.color = "green" box.font_weight = "bold" def _disable(id: str): if id in processing_parameters.variables.ids: _disable_box(variable_boxes_dict[id]) elif id in processing_parameters.forward_models.ids: if id in non_disabled_forward_models: non_disabled_forward_models.remove(id) _disable_box(forward_model_boxes_dict[id]) def _disable_box(box: LabeledCheckbox): box.enabled = False box.font_weight = "normal" def _display_normally(id: str): if id in processing_parameters.variables.ids: _display_normally_box(variable_boxes_dict[id]) elif id in processing_parameters.forward_models.ids: if id not in non_disabled_forward_models: non_disabled_forward_models.append(id) _display_normally_box(forward_model_boxes_dict[id]) def _display_normally_box(box: LabeledCheckbox): box.enabled = True box.color = "black" box.font_weight = "bold" def _request_status() -> str: if len(selected_variables) == 0 and len(selected_forward_models) == 0: return 'No variable or forward model selected' elif len(selected_variables) == 0: return 'No variable selected' elif len(selected_forward_models) == 0: return 'No forward model selected' else: for selected_variable in selected_variables: forward_model_available = False for variable_fm in forward_models_per_variable[ selected_variable]: if variable_fm in selected_forward_models: forward_model_available = True break if not forward_model_available: return f"Variable '{selected_variable}' cannot be derived with any of the selected forward models." for selected_forward_model in selected_forward_models: at_least_one_variable_selected = False for variable in processing_parameters.forward_models.get( selected_forward_model).variables: if variable in selected_variables: at_least_one_variable_selected = True break if not at_least_one_variable_selected: return f"Selection is valid, " \ f"but no variable is selected for forward model '{selected_forward_model}'." return 'Selection is valid' def _validate_selection(): color = 'red' request_status = _request_status() if request_status.startswith('Selection is valid'): if request_status == 'Selection is valid': color = 'green' else: color = 'orange' request_status = _format_request_status(request_status) request_validation.value = html_element( 'h3', att=dict(style=f'color:{color}'), value=request_status) def _format_request_status(request_status: str) -> str: if not request_status.startswith('Selection is valid'): return request_status forward_model_lines = [] for forward_model_id in selected_forward_models: fm_selected_variables = [] fm_variables = processing_parameters.forward_models.get( forward_model_id).variables for fm_variable in fm_variables: if fm_variable in selected_variables: fm_selected_variables.append(f"'{fm_variable}'") if len(fm_selected_variables) > 0: fm_selected_variables = ', '.join(fm_selected_variables) forward_model_lines.append( f"With model '{forward_model_id}': Compute {fm_selected_variables}" ) else: forward_model_lines.append( f"Model '{forward_model_id}' " f"is selected, but does not compute any variables") forward_model_lines = '<br>'.join(forward_model_lines) message = f"{request_status}:<br>{forward_model_lines}" return message def _handle_variable_selection(change: dict): if change['name'] is not '_property_lock': return variable_id = change['owner'].label_text if change['new']['selected']: selected_variables.append(variable_id) else: selected_variables.remove(variable_id) _update_forward_models_after_variable_change(variable_id, True) _validate_selection() def _update_forward_models_after_variable_change( variable_id: str, examine_secondary_models: bool = False): already_examined_types = [] for potential_forward_model in forward_models_per_variable[ variable_id]: fm_type = _fm_input_type(potential_forward_model) if (selected_forward_model_per_type[fm_type] ) is not None or fm_type in already_examined_types: continue _validate_forward_models_of_type(fm_type) _validate_variables_of_forward_models_of_type(fm_type) if examine_secondary_models: _validate_forward_models_of_variables_of_forward_models_of_type( fm_type) already_examined_types.append(fm_type) def _validate_forward_models_of_type(fm_type: str): for fm_of_same_type in available_forward_models_per_type[fm_type]: if selected_forward_model_per_type[fm_type] == fm_of_same_type: _recommend(fm_of_same_type) continue if selected_forward_model_per_type[fm_type] is not None: _disable(fm_of_same_type) continue fm_of_same_type_variables = _fm_variables(fm_of_same_type) at_least_one_variable_selected = False for fm_of_same_type_variable in fm_of_same_type_variables: if fm_of_same_type_variable in selected_variables: afms_for_st_variable = _available_forward_models_for_variable( fm_of_same_type_variable) if len(afms_for_st_variable) == 1 and _fm_input_type( afms_for_st_variable[0]) == fm_type: _recommend(fm_of_same_type) for other_fm_of_same_type in available_forward_models_per_type[ fm_type]: if other_fm_of_same_type != fm_of_same_type: _disable(other_fm_of_same_type) return at_least_one_variable_selected = True if at_least_one_variable_selected: _recommend(fm_of_same_type) else: _display_normally(fm_of_same_type) def _validate_variables_of_forward_models_of_type(fm_type: str): for fm_of_same_type in available_forward_models_per_type[fm_type]: fm_of_same_type_variables = _fm_variables(fm_of_same_type) for fm_of_same_type_variable in fm_of_same_type_variables: _validate_variable(fm_of_same_type_variable) def _validate_forward_models_of_variables_of_forward_models_of_type( fm_type: str): for fm_of_same_type in available_forward_models_per_type[fm_type]: fm_of_same_type_variables = _fm_variables(fm_of_same_type) for fm_of_same_type_variable in fm_of_same_type_variables: afms_for_same_type_variable = _available_forward_models_for_variable( fm_of_same_type_variable) if _fm_input_type(afms_for_same_type_variable[0]) != fm_type: _validate_forward_models_of_type( _fm_input_type(afms_for_same_type_variable[0])) _validate_variables_of_forward_models_of_type( _fm_input_type(afms_for_same_type_variable[0])) def _available_forward_models_for_variable(variable_id: str) -> List[str]: available_forward_models_for_variable = [] for model_id in forward_models_per_variable[variable_id]: if model_id in non_disabled_forward_models: available_forward_models_for_variable.append(model_id) return available_forward_models_for_variable def _validate_variable(variable: str): if variable in selected_variables: _recommend(variable) return available_forward_models_for_variable = _available_forward_models_for_variable( variable) if len(available_forward_models_for_variable) == 0: _disable(variable) return for available_forward_model_for_variable in available_forward_models_for_variable: if available_forward_model_for_variable in selected_forward_models: _recommend(variable) return _display_normally(variable) @debug_view.capture(clear_output=True) def _handle_forward_model_selection(change: dict): if change['name'] is not '_property_lock': return if 'selected' not in change['new']: return selected_fm_id = change['owner'].label_text selected_fm_it = _fm_input_type(selected_fm_id) if change['new']['selected']: selected_forward_models.append(selected_fm_id) selected_forward_model_per_type[selected_fm_it] = selected_fm_id forward_model_select_buttons[selected_fm_id].disabled = False else: selected_forward_models.remove(selected_fm_id) selected_forward_model_per_type[selected_fm_it] = None forward_model_select_buttons[selected_fm_id].disabled = True _validate_forward_models_of_type(selected_fm_it) _validate_variables_of_forward_models_of_type(selected_fm_it) _validate_selection() _update_preprocessing_states() _setup_user_priors() def _clear_variable_selection(b): for variable_id in variable_boxes_dict: if variable_id in selected_variables: selected_variables.remove(variable_id) variable_boxes_dict[variable_id].selected = False _validate_variable(variable_id) _update_forward_models_after_variable_change(variable_id) _validate_selection() def _clear_forward_model_selection(b): affected_input_types = [] for forward_model_id in forward_model_boxes_dict: if forward_model_id in selected_forward_models: selected_forward_models.remove(forward_model_id) forward_model_type = _fm_input_type(forward_model_id) selected_forward_model_per_type[forward_model_type] = None if forward_model_type not in affected_input_types: affected_input_types.append(forward_model_type) forward_model_boxes_dict[forward_model_id].selected = False for input_type in affected_input_types: _validate_forward_models_of_type(input_type) _validate_variables_of_forward_models_of_type(input_type) _update_preprocessing_states() _validate_selection() _setup_user_priors() def _select_all_variables_for_forward_model(forward_model_id: str): fm_variables = _fm_variables(forward_model_id) for variable_id in fm_variables: if variable_id not in selected_variables: selected_variables.append(variable_id) variable_boxes_dict[variable_id].selected = True _update_forward_models_after_variable_change(variable_id) _validate_selection() # noinspection PyTypeChecker variables_box = _wrap_variable_checkboxes_in_widget( variable_boxes_dict.values(), 4, _handle_variable_selection) clear_variable_selection_button = widgets.Button( description="Clear Variable Selection", layout=widgets.Layout(left='60%', width='35%')) clear_variable_selection_button.on_click(_clear_variable_selection) forward_model_variables = {} for fm_id in processing_parameters.forward_models.ids: forward_model_variables[ fm_id] = processing_parameters.forward_models.get(fm_id).variables forward_model_select_buttons[fm_id] = _get_select_button( _select_all_variables_for_forward_model, fm_id) # noinspection PyTypeChecker forward_models_box = _wrap_forward_model_checkboxes_in_widget( forward_model_boxes_dict.values(), forward_model_select_buttons, _handle_forward_model_selection, forward_model_variables) clear_model_selection_button = widgets.Button( description="Clear Forward Model Selection", layout=widgets.Layout(left='60%', width='35%')) clear_model_selection_button.on_click(_clear_forward_model_selection) user_priors_box = widgets.Box(children=[], layout=widgets.Layout(overflow='hidden', display='flex')) user_priors_component = widgets.VBox(children=[ widgets.HTML( value=html_element('h2', value='User Priors')), user_priors_box ]) user_priors_dict = {} def _handle_user_prior_change(user_prior_dict): for user_prior in user_prior_dict: user_priors_dict[user_prior] = user_prior_dict[user_prior] @debug_view.capture(clear_output=True) def _setup_user_priors(): possible_user_priors = [] s2_output_variables = [] if selected_forward_model_per_type['Sentinel-2'] is not None: selected_forward_model = \ processing_parameters.forward_models.get(selected_forward_model_per_type['Sentinel-2']) for prior in selected_forward_model.requiredPriors: if prior not in possible_user_priors: possible_user_priors.append(prior) s2_output_variables = selected_forward_model.variables if selected_forward_model_per_type['Sentinel-1'] is not None: selected_forward_model = \ processing_parameters.forward_models.get(selected_forward_model_per_type['Sentinel-1']) for prior in selected_forward_model.requiredPriors: if prior not in possible_user_priors and prior not in s2_output_variables: possible_user_priors.append(prior) user_prior_components = [] for possible_user_prior_id in possible_user_priors: prior = processing_parameters.variables.get(possible_user_prior_id) if not prior.may_be_user_prior: continue mu = None unc = None if possible_user_prior_id in user_priors_dict: if 'mu' in user_priors_dict[possible_user_prior_id]: mu = user_priors_dict[possible_user_prior_id]['mu'] if 'unc' in user_priors_dict[possible_user_prior_id]: unc = user_priors_dict[possible_user_prior_id]['unc'] user_prior_components.append( user_prior_component(prior.id, prior.unit, _handle_user_prior_change, mu, unc)) user_priors_box.children = [ _wrap_user_priors_in_widget(user_prior_components) ] @debug_view.capture(clear_output=True) def _must_preprocess(it: str) -> bool: must_preprocess = it in selected_forward_model_per_type and selected_forward_model_per_type[ it] is not None if not must_preprocess: for post_processor_name in post_processor_checkbox_dict: if post_processor_checkbox_dict[post_processor_name].selected: post_processor = processing_parameters.post_processors.get( post_processor_name) if it in post_processor.input_types: must_preprocess = True break return must_preprocess def _update_preprocessing_states(): preprocess_s1_temporal_filter.disabled = not _must_preprocess( 'Sentinel-1') preprocess_s2_only_roi_checkbox.enabled = _must_preprocess( 'Sentinel-2') preprocess_s1_temporal_filter = widgets.BoundedIntText(value=5, min=2, max=15, step=1, disabled=True) preprocess_s2_only_roi_checkbox = LabeledCheckbox( selected=False, label_text='Only preprocess Region of Interest', tooltip='Only preprocess Region of Interest', enabled=False, layout=widgets.Layout(display='flex', width='30%')) global _NUM_REQUESTS _NUM_REQUESTS += 1 request_name = widgets.Text(name) python_var_name = widgets.Text(identifier) start_date = widgets.DatePicker( value=datetime.datetime(year=2018, month=5, day=10)) end_date = widgets.DatePicker( value=datetime.datetime(year=2018, month=5, day=15)) time_steps = Spinner(value=5, min=1) time_steps_unit = widgets.Dropdown(options=['days', 'weeks'], value='days', disabled=False) map_background_layer = basemap_to_tiles(basemaps.OpenStreetMap.Mapnik) geometry_layer = GeoJSON() leaflet_map = Map(layers=(map_background_layer, geometry_layer), center=[52., 10.], zoom=4) draw_control = DrawControl() draw_control.polyline = {} draw_control.polygon = {} draw_control.circlemarker = {} draw_control.rectangle = {'shapeOptions': {}} draw_control.edit = False draw_control.remove = False @debug_view.capture(clear_output=True) def _handle_draw(self, action, geo_json): self.clear() leaflet_map.remove_layer(leaflet_map.layers[1]) geometry_layer = GeoJSON(data=geo_json['geometry']) leaflet_map.add_layer(geometry_layer) roi_shape = shape(leaflet_map.layers[1].data) roi_area.value = roi_shape.wkt roi_validation.value = html_element( 'h3', att=dict(style=f'color:green'), value='Region of Interest defined.') draw_control.on_draw(_handle_draw) leaflet_map.add_control(draw_control) roi_area = widgets.Textarea( layout=widgets.Layout(flex='1 10 90%', align_items='stretch')) roi_map_button = widgets.Button(description="Map region", layout=widgets.Layout(flex='0 1 10%')) def _update_roi_status_for_error(message: str): roi_data = leaflet_map.layers[1].data if not roi_data: roi_validation.value = html_element('h3', att=dict(style=f'color:red'), value=message) return roi_validation.value = html_element( 'h3', att=dict(style=f'color:orange'), value=f'{message} Keep previously defined Region of Interest.') selected_indicators = [] indicator_check_boxes = [] for indicator_id in processing_parameters.indicators.ids: indicator = processing_parameters.indicators.get(indicator_id) indicator_check_box = LabeledCheckbox(selected=False, label_text=indicator_id, tooltip=indicator.description, enabled=True) indicator_check_boxes.append(indicator_check_box) @debug_view.capture(clear_output=True) def _handle_indicator_selection(change: dict): if change['name'] is not '_property_lock' or not 'selected' in change[ 'new']: return indicator_id = change['owner'].label_text if change['new']['selected']: selected_indicators.append(indicator_id) else: selected_indicators.remove(indicator_id) for inner_post_processor_name in post_processor_checkbox_dict: inner_post_processor = processing_parameters.post_processors.get( inner_post_processor_name) post_processor_selected = False for post_processor_indicator in inner_post_processor.indicators: if post_processor_indicator in selected_indicators: post_processor_selected = True break if post_processor_checkbox_dict[ inner_post_processor_name].selected != post_processor_selected: post_processor_checkbox_dict[ inner_post_processor_name].selected = post_processor_selected _update_preprocessing_states() indicators_box = _wrap_variable_checkboxes_in_widget( indicator_check_boxes, 3, _handle_indicator_selection) post_processor_checkbox_dict = {} post_processor_checkboxes = [] for post_processor_name in processing_parameters.post_processors.names: post_processor = processing_parameters.post_processors.get( post_processor_name) post_processor_checkbox = LabeledCheckbox( selected=False, label_text=post_processor_name, tooltip=post_processor.description, enabled=False) post_processor_checkboxes.append(post_processor_checkbox) post_processor_checkbox_dict[ post_processor_name] = post_processor_checkbox post_processors_box = _wrap_variable_checkboxes_in_widget( post_processor_checkboxes, 2, None) @debug_view.capture(clear_output=True) def _handle_roi_map_button_clicked(*args, **kwargs): try: geom = loads(roi_area.value) if type(geom) is not Polygon: _update_roi_status_for_error( 'User-provided Region of Interest is not of type Polygon.') return geojson_feature = geojson.Feature(geometry=geom, properties={}) draw_control.clear() leaflet_map.remove_layer(leaflet_map.layers[1]) geometry_layer = GeoJSON(data=geojson_feature['geometry']) leaflet_map.add_layer(geometry_layer) center_lon, center_lat = geom.centroid.coords.xy leaflet_map.center = [center_lat[0], center_lon[0]] @debug_view.capture(clear_output=False) def _adjust_zoom_level(event): if event['name'] == 'bounds' and leaflet_map.zoom < 18: southwest, northeast = leaflet_map.bounds map_bounds = Polygon([(southwest[1], southwest[0]), (southwest[1], northeast[0]), (northeast[1], northeast[0]), (northeast[1], southwest[0]), (southwest[1], southwest[0])]) if map_bounds.covers(geom): leaflet_map.zoom = leaflet_map.zoom + 1 elif leaflet_map.zoom > 1: leaflet_map.zoom = leaflet_map.zoom - 1 leaflet_map.unobserve(_adjust_zoom_level) leaflet_map.zoom = 1 leaflet_map.observe(_adjust_zoom_level) if geom.is_valid: roi_validation.value = html_element( 'h3', att=dict(style=f'color:green'), value='Region of Interest defined.') else: roi_validation.value = html_element( 'h3', att=dict(style=f'color:orange'), value='User-provided Region of Interest is invalid.') except WKTReadingError: _update_roi_status_for_error( 'User-provided Region of Interest cannot be read.') roi_map_button.on_click(_handle_roi_map_button_clicked) spatial_resolution = Spinner(value=100, min=1, step=1) roi_validation = widgets.HTML( value=html_element('h3', att=dict(style='color:red'), value='No region of interest defined')) info = InfoComponent() def new_input_request(): request_status = _request_status() if request_status != 'Selection is valid': info.output_error(request_status) return input_types = [] for input_type in selected_forward_model_per_type: if selected_forward_model_per_type[input_type] is not None: input_types.append(input_type) roi_data = leaflet_map.layers[1].data if not roi_data: info.output_error('Error: No Region of Interest specified') return roi = shape(roi_data) if not roi.is_valid: info.output_error('Error: Region of Interest is invalid') return request_models = [] required_priors = [] for model_id in selected_forward_models: request_model = processing_parameters.forward_models.get(model_id) request_variables = [] for variable_id in request_model.variables: if variable_id in selected_variables: request_variables.append(variable_id) request_model_dict = dict( name=model_id, type=request_model.type, modelDataType=request_model.input_type, requiredPriors=request_model.requiredPriors, outputParameters=request_variables) for required_model_prior in request_model.requiredPriors: if not required_model_prior in required_priors: required_priors.append(required_model_prior) request_models.append(request_model_dict) user_priors_for_request_list = [] for user_prior in user_priors_dict: if user_prior in required_priors: user_priors_for_request_dict = {'name': user_prior} if 'mu' in user_priors_dict: user_priors_for_request_dict['mu'] = user_priors_dict['mu'] if 'unc' in user_priors_dict: user_priors_for_request_dict['unc'] = user_priors_dict[ 'unc'] user_priors_for_request_list.append( user_priors_for_request_dict) temporalFilter = None if not preprocess_s1_temporal_filter.disabled: temporalFilter = preprocess_s1_temporal_filter.value computeOnlyRoi = None if preprocess_s2_only_roi_checkbox.enabled: computeOnlyRoi = preprocess_s2_only_roi_checkbox.selected postProcessors = [] if len(selected_indicators) > 0: postProcessors = [] for post_processor_name in processing_parameters.post_processors.names: post_processor = processing_parameters.post_processors.get( post_processor_name) selected_pp_indicators = [] for indicator in post_processor.indicators: if indicator in selected_indicators: selected_pp_indicators.append(indicator) if len(selected_pp_indicators) > 0: post_processor_dict = dict( name=post_processor_name, type=post_processor.type, inputTypes=post_processor.input_types, indicatorNames=selected_pp_indicators, variableNames=selected_variables) postProcessors.append(post_processor_dict) return InputRequest( dict(name=request_name.value, timeRange=[ datetime.datetime.strftime(start_date.value, "%Y-%m-%d"), datetime.datetime.strftime(end_date.value, "%Y-%m-%d") ], timeStep=time_steps.value, timeStepUnit=time_steps_unit.value, roi=f"{roi.wkt}", spatialResolution=spatial_resolution.value, inputTypes=input_types, forwardModels=request_models, userPriors=user_priors_for_request_list, s1TemporalFilter=temporalFilter, s2ComputeRoi=computeOnlyRoi, postProcessors=postProcessors)) # noinspection PyUnusedLocal @debug_view.capture(clear_output=True) def handle_new_button_clicked(*args, **kwargs): req_var_name = python_var_name.value or 'req' if req_var_name and not req_var_name.isidentifier(): info.output_error( f'Error: invalid Python identifier: {req_var_name}') return inputs_request = new_input_request() if inputs_request is None: return info.output_message('Fetching results...') processing_request = fetch_inputs_func(inputs_request, info.message_func) if processing_request is None: return input_identifiers = processing_request.inputs data_rows = [] for input_type, input_ids in input_identifiers.as_dict().items(): data_rows.append([input_type, len(input_ids)]) result_html = html_table( data_rows, header_row=['Input Type', 'Number of inputs found']) # insert shall variable_id whose value is processing_request # users can later call the GUI with that object to edit it if req_var_name: shell = IPython.get_ipython() shell.push({req_var_name: processing_request}, interactive=True) var_name_html = html_element( 'p', value=f'Note: a new processing request has been ' f'stored in variable <code>{req_var_name}</code>.') result_html = html_element('div', value=result_html + var_name_html) info.output_html(result_html) # noinspection PyUnusedLocal @debug_view.capture(clear_output=True) def handle_submit_button_clicked(*args, **kwargs): req_var_name = python_var_name.value or 'job' if req_var_name and not req_var_name.isidentifier(): info.output_error( f'Error: invalid Python identifier: {req_var_name}') return inputs_request = new_input_request() info.output_message('Submitting processing request...') job = submit_processing_request(inputs_request, message_func=info.message_func, mock=mock) if job is not None: shell = IPython.get_ipython() shell.push({req_var_name: job}, interactive=True) result_html = html_element( 'p', value=f'Note: a new job is currently being executed and is ' f'stored in variable_id <code>{req_var_name}</code>.') info.output_html(result_html) # TODO: make GUI form look nice new_button = widgets.Button(description="New Request", icon="search") new_button.on_click(handle_new_button_clicked) submit_button = widgets.Button(description="Submit Request", icon="upload") submit_button.on_click(handle_submit_button_clicked) form_items = [ widgets.Box( [widgets.HTML(value=html_element('h2', value='Output Variables'))], layout=form_item_layout), widgets.Box([variables_box], layout=var_checks_layout), widgets.Box([clear_variable_selection_button], layout=form_item_layout), widgets.Box( [widgets.HTML(value=html_element('h2', value='Forward Models'))], layout=form_item_layout), widgets.Box([forward_models_box], layout=var_checks_layout), widgets.Box([clear_model_selection_button], layout=form_item_layout), widgets.Box([request_validation], layout=form_item_layout), widgets.Box([ widgets.HTML( value=html_element('h2', value='Sentinel-1 Pre-Processing')) ], layout=form_item_layout), widgets.Box([ widgets.Label(value='Temporal Filter'), preprocess_s1_temporal_filter ], layout=form_item_layout), widgets.Box([ widgets.HTML( value=html_element('h2', value='Sentinel-2 Pre-Processing')) ], layout=form_item_layout), preprocess_s2_only_roi_checkbox, widgets.Box([user_priors_component], layout=form_item_layout), widgets.Box([ widgets.HTML( value=html_element('h2', value='Time Period of Interest')) ], layout=form_item_layout), widgets.Box([widgets.Label(value='Start date'), start_date], layout=form_item_layout), widgets.Box([widgets.Label(value='End date'), end_date], layout=form_item_layout), widgets.Box([ widgets.Label(value='Time steps'), widgets.Box([time_steps, time_steps_unit]) ], layout=form_item_layout), widgets.Box([ widgets.HTML(value=html_element('h2', value='Region of Interest')) ], layout=form_item_layout), widgets.Box([roi_area, roi_map_button], layout=form_item_layout), widgets.Box([leaflet_map], layout=form_item_layout), widgets.Box( [widgets.Label(value='Resolution (m)'), spatial_resolution], layout=form_item_layout), widgets.Box([roi_validation], layout=form_item_layout), widgets.Box( [widgets.HTML(value=html_element('h2', value='Post-Processing'))], layout=form_item_layout), widgets.Label(value='Indicators', layout=form_item_layout), widgets.Box([indicators_box], layout=var_checks_layout), widgets.Label(value='Post Processors', layout=form_item_layout), widgets.Box([post_processors_box], layout=var_checks_layout), widgets.Box([widgets.Label(value='Request/job name'), request_name], layout=form_item_layout), widgets.Box( [widgets.Label(value='Python identifier'), python_var_name], layout=form_item_layout), widgets.Box([ widgets.Label(value=''), widgets.Box([new_button, submit_button]) ], layout=form_item_layout), widgets.Box([info.as_widget()], layout=form_item_layout) ] form = widgets.Box(form_items, layout=widgets.Layout(display='flex', flex_flow='column', border='solid 1px lightgray', align_items='stretch', width='100%')) return form
control.rectangle['shapeOptions'].update({ 'color': '#ffffff', 'weight': 4, 'opacity': 0.5, 'stroke': True }) # remove default polyline and circlemarker control.polyline = {} control.circlemarker = {} # specify clear function control.on_draw(rid) # add draw control chart.add_control(control) # force a rectange onto the map force(south, north, west, east) # display chart chart # ### Setting the Date Range # Set the date range below. Leaving the beginning date blank will default to Earth Day 1995. Leaving the ending date blank will default to today's date. # In[103]: designate('setting date range', 'settings')
def clickablemap(center=[48.790153, 2.327395], zoom=13, layout=ipywidgets.Layout(width='100%', height='500px')): # look at: http://leaflet.github.io/Leaflet.draw/docs/examples/basic.html import json from ipyleaflet import (Map, Rectangle, Polygon, TileLayer, ImageOverlay, DrawControl, GeoJSON) #%matplotlib inline # %matplotlib notebook # google tileserver # https://stackoverflow.com/questions/9394190/leaflet-map-api-with-google-satellite-layer mosaicsTilesURL = 'https://mt1.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}' # Hybrid: s,h; Satellite: s; Streets: m; Terrain: p; # Map Settings # Define colors colors = {'blue': "#009da5"} # Define initial map center lat/long #center = [48.790153, 2.327395] # Define initial map zoom level #zoom = 13 # Create the map m = Map(center=center, zoom=zoom, scroll_wheel_zoom=True, layout=layout) # using custom basemap m.clear_layers() m.add_layer(TileLayer(url=mosaicsTilesURL)) # Define the draw tool type options polygon = {'shapeOptions': {'color': colors['blue']}} rectangle = {'shapeOptions': {'color': colors['blue']}} ## Create the draw controls ## @see https://github.com/ellisonbg/ipyleaflet/blob/master/ipyleaflet/leaflet.py#L293 #dc = DrawControl( # polygon = polygon, # rectangle = rectangle #) dc = DrawControl( polygon={'shapeOptions': { 'color': '#0000FF' }}, polyline={'shapeOptions': { 'color': '#0000FF' }}, circle={'shapeOptions': { 'color': '#0000FF' }}, rectangle={'shapeOptions': { 'color': '#0000FF' }}, ) # Initialize an action counter variable m.actionCount = 0 m.AOIs = [] # Register the draw controls handler def handle_draw(self, action, geo_json): # Increment the action counter #global actionCount m.actionCount += 1 # Remove the `style` property from the GeoJSON geo_json['properties'] = {} # Convert geo_json output to a string and prettify (indent & replace ' with ") geojsonStr = json.dumps(geo_json, indent=2).replace("'", '"') m.AOIs.append(json.loads(geojsonStr)) # Attach the draw handler to the draw controls `on_draw` event dc.on_draw(handle_draw) m.add_control(dc) # add a custom function to create and add a Rectangle layer # (LESS USEFUL THAN add_geojson) def add_rect(*args, **kwargs): r = Rectangle(*args, **kwargs) return m.add_layer(r) m.add_rectangle = add_rect # add a custom function to create and add a Polygon layer def add_geojson(*args, **kwargs): # ugly workaround to call without data=aoi if 'data' not in kwargs: kwargs['data'] = args[0] args2 = [i for i in args[1:-1]] else: args2 = args r = GeoJSON(*args2, **kwargs) return m.add_layer(r) m.add_GeoJSON = add_geojson # Display return m
# display map jakarta_heatmap # In[19] from ipyleaflet import Map, FullScreenControl # create map full_screen_map = Map(zoom=1) # create control control = FullScreenControl() # add control to map full_screen_map.add_control(control) # display map full_screen_map # In[20] import ipyleaflet from ipyleaflet import DrawControl # create map draw_control_map = ipyleaflet.Map(zoom=1) # create control draw_control = DrawControl()
def show_datasets( dss, mode='leaflet', dst=None, layer_name='Datasets', style={}, simplify=True, tolerance=0.001, # ~100m at equator **kw): """ Display dataset footprints on a Leaflet map. :param mode: leaflet|geojson, geojson only works in JupyterLab, leave it as default :param dst: leaflet map to "show" datasets on, default -- create new one :param layer_name: name to give to the layer :param style: GeoJSON style dictionary - weight - color/fillColor - opacity/fillOpacity - full list of options here: https://leafletjs.com/reference-1.5.0.html#path-option :param simplify: simplify geometries before adding them to map :param tolerance: tolerance in degrees for geometry simplification, default 0.001 ~ 111 meters at equator **kw: Arguments to pass to leaflet.Map(..) constructor """ if mode not in ('leaflet', 'geojson'): raise ValueError('Invalid value for mode, expected: leaflet|geojson') polygons, bbox = dss_to_geojson(dss, bbox=True, simplify=simplify, tolerance=tolerance) if mode == 'geojson': from IPython.display import GeoJSON return GeoJSON(polygons) if mode == 'leaflet': from ipyleaflet import Map, GeoJSON, FullScreenControl, LayersControl if dst is None: center = kw.pop('center', None) zoom = kw.pop('zoom', None) if center is None: center = (bbox.bottom + bbox.top) * 0.5, (bbox.right + bbox.left) * 0.5 if zoom is None: zoom = zoom_from_bbox(bbox) height = kw.pop('height', '600px') width = kw.pop('width', None) m = Map(center=center, zoom=zoom, **kw) m.layout.height = height m.layout.width = width m.add_control(FullScreenControl()) m.add_control(LayersControl()) else: m = dst gg = GeoJSON(data={ 'type': 'FeatureCollection', 'features': polygons }, style=style, hover_style={'color': 'tomato'}, name=layer_name) m.add_layer(gg) if dst is None: return m else: return gg
def mk_map_region_selector(height='600px', **kwargs): from ipyleaflet import Map, WidgetControl, FullScreenControl, DrawControl from ipywidgets.widgets import Layout, Button, HTML from types import SimpleNamespace state = SimpleNamespace(selection=None, bounds=None, done=False) btn_done = Button(description='done', layout=Layout(width='5em')) btn_done.style.button_color = 'green' btn_done.disabled = True html_info = HTML( layout=Layout(flex='1 0 20em', width='20em', height='3em')) def update_info(txt): html_info.value = '<pre style="color:grey">' + txt + '</pre>' m = Map(**kwargs) if len(kwargs) else Map(zoom=2) m.scroll_wheel_zoom = True m.layout.height = height widgets = [ WidgetControl(widget=btn_done, position='topright'), WidgetControl(widget=html_info, position='bottomleft'), ] for w in widgets: m.add_control(w) draw = DrawControl() draw.circle = {} draw.polyline = {} draw.circlemarker = {} shape_opts = { "fillColor": "#fca45d", "color": "#000000", "fillOpacity": 0.1 } draw.rectangle = {"shapeOptions": shape_opts} poly_opts = {"shapeOptions": dict(**shape_opts)} poly_opts["shapeOptions"]["original"] = dict(**shape_opts) poly_opts["shapeOptions"]["editing"] = dict(**shape_opts) draw.polygon = poly_opts draw.edit = True draw.remove = True m.add_control(draw) m.add_control(FullScreenControl()) def on_done(btn): state.done = True btn_done.disabled = True m.remove_control(draw) for w in widgets: m.remove_control(w) def bounds_handler(event): (lat1, lon1), (lat2, lon2) = event['new'] txt = 'lat: [{:.{n}f}, {:.{n}f}]\nlon: [{:.{n}f}, {:.{n}f}]'.format( lat1, lat2, lon1, lon2, n=4) update_info(txt) state.bounds = dict(lat=(lat1, lat2), lon=(lon1, lon2)) def on_draw(event): v = event['new'] action = event['name'] if action == 'last_draw': state.selection = v['geometry'] elif action == 'last_action' and v == 'deleted': state.selection = None btn_done.disabled = state.selection is None draw.observe(on_draw) m.observe(bounds_handler, ('bounds', )) btn_done.on_click(on_done) return m, state
tiffFiles_path = os.path.join(orig_path, "tiffFiles") os.chdir(tiffFiles_path) jsonFile = cityName + ".geojson" geojson_exists = False if (os.path.exists(os.path.join(os.getcwd(), jsonFile))): actionCount += 1 with open(os.path.join(os.getcwd(), jsonFile)) as f: AOIs[actionCount] = json.load(f) print("GEOJSON ALREADY CREATED - MOVE TO NEXT CELL\n") geojson_exists = True else: # Attach the draw handler to the draw controls `on_draw` event print("Draw area of interest on map and a geojson will be generated\n") os.chdir(orig_path) dc.on_draw(handle_draw) m.add_control(dc) geojson_exists = False m # # Querying the Planet API. # * First we'll grab our geojson area of interest (AOI) and use it to construct a query. # * We'll then build a search to search that area looking for PSScene3Band # * We have lots of products: RapidEye, PlanetScope (PS) 3 and 4 band, LandSat, and Sentinel are all possible. # * Once we have our query, we'll do the search. We will then iterate over the results, slurp up the data, and put them in a pandas data frame for easy sorting. # * We'll print the first few so we're sure it works. # In[73]: import datetime os.chdir(orig_path) print(AOIs[1])
def show_m(): multipoly = [] multycent = [] geom = spatial_utils.transform_geometry(info_data) poly = geom['geom'][0]['coordinates'][0] # poly = spatial_utils.swap_xy(geom['coordinates'][0])[0] multipoly.append(poly) centroid = spatial_utils.centroid(poly) multycent.append(centroid) centroid = spatial_utils.centroid(multycent) m = Map(center=centroid, zoom=16, basemap=basemaps.OpenStreetMap.Mapnik) polygon = Polygon(locations=multipoly, name='Parcel polygon', color="yellow", fill_color=None) m.add_layer(polygon) basemap2 = basemap_to_tiles(basemaps.Esri.WorldImagery) poly_text = HTML() poly_text.value = f"""Parcel ID: {pid}<br> Crop name: {crop_name}<br> Area: {area:.2f} sqm<br> Coordinates: {centroid} """ poly_text.placeholder = "HTML" poly_text.description = "" # Popup with a given location on the map: poly_popup = Popup(child=poly_text, close_button=False, auto_close=False, close_on_escape_key=False) m.add_layer(poly_popup) polygon.popup = poly_popup # Popup associated to a layer # Layers control show_poly = Checkbox(value=True, description='Polygon', indent=False, layout=Layout(width='140px')) show_sat = Checkbox(value=False, description='High res basemap', indent=False, layout=Layout(width='140px')) def polygon_changed(b): try: if show_poly.value is True: m.add_layer(polygon) else: m.remove_layer(polygon) except Exception: pass show_poly.observe(polygon_changed) def show_sat_changed(b): try: if show_sat.value is True: m.add_layer(basemap2) else: m.remove_layer(basemap2) except Exception: pass show_sat.observe(show_sat_changed) try: df = raster_utils.create_df(ci_path, pid, ci_band.value) geotiff = normpath( join(ci_path, f"{df['imgs'][0]}.{ci_band.value[0]}.tif")) bounds = raster_utils.bounds(geotiff) images = {} for i, row in df.iterrows(): str_date = str(row['date'].date()).replace('-', '') img_tc = normpath( join(ci_path, f"{('').join(ci_band.value)}_{str_date}.png")) # Create false color image if it does not exist # Merge bands (images path, export image path, bands list) if not isfile(img_tc): imgs_path = normpath(join(ci_path, row['imgs'])) raster_utils.merge_bands(imgs_path, img_tc, ci_band.value) if bool(config.get_value(['set', 'jupyterlab'])) is True: jlab_path = os.getcwd().replace(os.path.expanduser("~"), '') image_path = normpath(join(f'files{jlab_path}', img_tc)) else: image_path = img_tc # print('image_path: ', image_path) images[i] = ImageOverlay(url=image_path, name=str_date, bounds=(bounds)) # Time slider slider = IntSlider(value=1, min=1, max=len(images), step=1, description=str(df['date'][0].date()), continuous_update=False, orientation='horizontal', readout=True, readout_format='d') show_chip = Checkbox(value=True, description='Chip image', indent=False, layout=Layout(width='140px')) def on_ci_band_change(change): pass ci_band.observe(on_ci_band_change, 'value') def show_chip_changed(b): try: if show_chip.value is True: m.add_layer(images[slider.value - 1]) else: m.remove_layer(images[slider.value - 1]) except Exception: pass show_chip.observe(show_chip_changed) # Slider control play = Play( value=1, min=1, max=len(images), step=1, interval=1000, description="Press play", ) def slider_changed(b): if show_chip.value is True: try: m.substitute_layer(images[b['old'] - 1], images[b['new'] - 1]) except Exception: pass slider.description = str(df['date'][slider.value - 1].date()) slider.observe(slider_changed) jslink((play, 'value'), (slider, 'value')) time_box = HBox([slider, play]) time_control = WidgetControl(widget=time_box, position='bottomleft') m.add_control(time_control) m.add_layer(images[0]) map_options = VBox([show_poly, show_chip, show_sat]) except Exception as err: map_options = VBox([show_poly, show_sat]) print(err) layers_control = WidgetControl(widget=map_options, position='topright', max_width=150) m.add_control(layers_control) return m