def run(): global m,center # center = list(reversed(poly.centroid().coordinates().getInfo())) center = [51.0,6.4] osm = basemap_to_tiles(basemaps.OpenStreetMap.Mapnik) ews = basemap_to_tiles(basemaps.Esri.WorldStreetMap) ewi = basemap_to_tiles(basemaps.Esri.WorldImagery) dc = DrawControl(polyline={},circlemarker={}) dc.rectangle = {"shapeOptions": {"fillColor": "#0000ff","color": "#0000ff","fillOpacity": 0.05}} dc.polygon = {"shapeOptions": {"fillColor": "#0000ff","color": "#0000ff","fillOpacity": 0.05}} dc.on_draw(handle_draw) lc = LayersControl(position='topright') fs = FullScreenControl(position='topleft') mc = MeasureControl(position='topright',primary_length_unit = 'kilometers') m = Map(center=center, zoom=11, layout={'height':'500px'},layers=(ewi,ews,osm),controls=(mc,dc,lc,fs)) # m = Map(center=center, zoom=11, layout={'height':'500px'},controls=(lc,dc,fs,mc,sm_control)) with w_out: w_out.clear_output() print('Algorithm output') display(m) return box
def run(): global m, dc, center # center = list(reversed(poly.centroid().coordinates().getInfo())) center = [51.0, 6.4] osm = basemap_to_tiles(basemaps.OpenStreetMap.Mapnik) ews = basemap_to_tiles(basemaps.Esri.WorldStreetMap) ewi = basemap_to_tiles(basemaps.Esri.WorldImagery) # mb = TileLayer(url="https://api.mapbox.com/styles/v1/mapbox/satellite-streets-v9/tiles/256/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWNhbnR5IiwiYSI6ImNpcjRsMmJxazAwM3hoeW05aDA1cmNkNzMifQ.d2UbIugbQFk2lnU8uHwCsQ", # attribution = "<a href='https://www.mapbox.com/about/maps/'>Mapbox</a> © <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> <strong><a href='https://www.mapbox.com/map-feedback/' target='_blank'>Improve this map</a></strong>" ) # sm_control = SplitMapControl(left_layer=osm,right_layer=ewi) lc = LayersControl(position='topright') fs = FullScreenControl(position='topleft') mc = MeasureControl(position='topright', primary_length_unit='kilometers') m = Map(center=center, zoom=11, layout={'height': '500px'}, layers=(ewi, ews, osm), controls=(mc, dc, lc, fs)) # m = Map(center=center, zoom=11, layout={'height':'500px'},controls=(lc,dc,fs,mc,sm_control)) with w_out: w_out.clear_output() print('Algorithm output') display(m) return box
def demo_basemaps(location, base_demo): strava = ipl.basemap_to_tiles(ipl.basemaps.Strava.Winter) carto_dark = ipl.basemap_to_tiles(ipl.basemaps.CartoDB.DarkMatter) mapnik = ipl.basemap_to_tiles(ipl.basemaps.OpenStreetMap.Mapnik) black_white = ipl.basemap_to_tiles( ipl.basemaps.OpenStreetMap.BlackAndWhite) osm_hot = ipl.basemap_to_tiles(ipl.basemaps.OpenStreetMap.HOT) esri_image = ipl.basemap_to_tiles(ipl.basemaps.Esri.WorldImagery) esri_topo = ipl.basemap_to_tiles(ipl.basemaps.Esri.WorldTopoMap) esri_world = ipl.basemap_to_tiles(ipl.basemaps.Esri.NatGeoWorldMap) water_color = ipl.basemap_to_tiles(ipl.basemaps.Stamen.Watercolor) layer_demo = [ strava, carto_dark, mapnik, black_white, osm_hot, esri_image, esri_topo, esri_world, water_color ] for show_layer in layer_demo: base_demo.add_layer(show_layer) time.sleep(.95) base_demo.remove_layer(base_demo.layers[0]) time.sleep(1.2) base_demo.add_layer(mapnik) base_demo.add_control(ipl.LayersControl())
def print_geojson(geojson, limit=100): center = None j = json.load(StringIO(geojson)) layer_group = LayerGroup() features = j['features'] if limit is not None: features = features[0:limit] for f in features: location = (f['geometry']['coordinates'][1], f['geometry']['coordinates'][0]) marker = Marker(location=location) marker.popup = HTML(str(f['properties'])) layer_group.add_layer(marker) if not center: center = location if not center: center = (0, 0) m = Map(layers=(basemap_to_tiles(basemaps.OpenStreetMap.Mapnik), ), center=center, zoom=8) m.add_layer(layer_group) return m
def __init__(self, n_days_old_satimg=1): t = datetime.datetime.now() - datetime.timedelta(days=n_days_old_satimg) t_str = t.strftime("%Y-%m-%d") self.m = Map( layers=[ basemap_to_tiles(basemaps.NASAGIBS.ModisTerraTrueColorCR, t_str), ], center=(52.204793, 360.121558), zoom=2, ) self.domain_coords = [] self.polygon = None self.marker_locs = {} self.m.on_interaction(self._handle_map_click) button_reset = Button(description="reset") button_reset.on_click(self._clear_domain) button_save = Button(description="save domain") button_save.on_click(self._save_domain) self.name_textfield = Text(value="domain_name", width=10) self.m.add_control(WidgetControl(widget=button_save, position="bottomright")) self.m.add_control(WidgetControl(widget=button_reset, position="bottomright")) self.m.add_control( WidgetControl(widget=self.name_textfield, position="bottomright") )
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())
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 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 show_stations_on_map(self,list_inc,list_process,list_filters, opt_params): """ Returns an interactive map of source and stations, use only in Jupyter Notebooks. Inputs: | list_inc: list of incidents | list_process: list of processes, one list per incident | list filters: list of filters defined for stations | opt_params: optional parameters (dictionary) Optional parameters: """ records = self._extract_records(list_inc, list_process, list_filters) if not records: LOGGER.warning("There are no records to satisfy the provided" " filters.") return m = Map( basemap=basemap_to_tiles(basemaps.Esri.WorldImagery, "2020-04-08"), center = (Station.pr_source_loc[0],Station.pr_source_loc[1]), zoom = 8, close_popup_on_click=True ) for i in records: if not i[0]: continue lat = i[0].station.lat lon = i[0].station.lon marker = Marker(location=(lat, lon), draggable=False, icon=AwesomeIcon(name="map-pin", marker_color='green', icon_color='darkgreen'), opacity=0.8) m.add_layer(marker) message = HTML() message.value = i[0].station.inc_st_name[list_inc[0]] marker.popup = message m.add_layer(Marker(icon=AwesomeIcon(name="star", marker_color='red', icon_color='darkred'), location=(Station.pr_source_loc[0],Station.pr_source_loc[1]), draggable=False)) return m
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 test_remove_last_layer(self): # init m = sm.SepalMap() # there is just one (the basemap) so not supposed to move res = m.remove_last_layer() self.assertEqual(res, m) self.assertEqual(len(m.layers), 1) # add 1 layer and remove it layer = basemap_to_tiles(basemaps.CartoDB.Positron) m.add_layer(layer) m.remove_last_layer() self.assertEqual(len(m.layers), 1) ####################################################### ## TODO problem dealing with local rasters ## ####################################################### # # add 1 local raster # out_dir = os.path.expanduser('~') # dem = os.path.join(out_dir, 'dem.tif') # # if not os.path.exists(dem): # dem_url = 'https://drive.google.com/file/d/1vRkAWQYsLWCi6vcTMk8vLxoXMFbdMFn8/view?usp=sharing' # geemap.download_from_gdrive(dem_url, 'dem.tif', out_dir, unzip=False) # # # add a raster # m.add_raster(dem, colormap='terrain', layer_name='DEM') # # # remove it # m.remove_last_layer() # # self.assertEqual(len(m.layers), 1) # self.assertEqual(len(m.loaded_rasters), 0) # # # remove the file # os.remove(dem) return
def __init__( self, data_url_prefix='https://raw.githubusercontent.com/yyu/GeoJSON-US/master' ): self.zipcodes = WebDict( url_maker=lambda z: f'{data_url_prefix}/perZIPgeojson/{z[0]}/{z[1]}/{z[2]}/{z}.json', response_processor=json.loads) self.gazetteer = WebTSV(f'{data_url_prefix}/ZIPCodesGazetteer.tsv') self.zipcode_set = set(self.gazetteer.keys()) self.center = [47.621795, -122.334958] self.zoom = 8 self.height = '500px' self.progress_bar_width = '500px' self.area_style = { 'color': '#0000ff', 'weight': .5, 'fillColor': '#000077', 'fillOpacity': 0.2 } self.progress_bar = widgets.IntProgress( bar_style='info', layout=widgets.Layout(width=self.progress_bar_width)) self.label = widgets.Label() self.progress_label = widgets.Label() self.info_box = widgets.HBox([self.progress_label, self.progress_bar]) self.basemap = leaflet.basemaps.OpenMapSurfer.Roads self.basemap['name'] = 'basemap' self.heatmap_data = leaflet.basemaps.Strava.All self.heatmap_data['name'] = 'heatmap' self.heatmap = leaflet.basemap_to_tiles(self.heatmap_data) self.layers_control = leaflet.LayersControl() self.map_layout = widgets.Layout(height=self.height) self.map = None
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
# measure line color measure.completed_color='red' # display map measure_control_map # In[22] import ipyleaflet from ipyleaflet import basemaps, basemap_to_tiles, SplitMapControl # create map split_map = ipyleaflet.Map(zoom=1) # create right and left layers right_layer = basemap_to_tiles(basemaps.Esri.WorldStreetMap) left_layer = basemap_to_tiles(basemaps.NASAGIBS.ViirsEarthAtNight2012) # create control control = SplitMapControl(left_layer=left_layer, right_layer=right_layer) # add control to map split_map.add_control(control) # display map split_map # In[23] from ipyleaflet import Map, Marker import geocoder import ipywidgets
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
def display(self, basemap=False, mapLayout=False, style=False, groupBy=False, colorDict=False, pageTitle='GeoJSON map', outputPath='html/static'): """ Display the dataframe on a map. Markers can be plotted at once, grouped (style='grouped'), or as pie charts (style='pie') grouped by a chosen category (groupBy='COLUMN'). """ if basemap: self.basemap = basemap else: self.basemap = { 'url': 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', 'max_zoom': 16, 'attribution': '<a href="https://carto.com">Carto Light NoLabels</a>', 'name': 'Carto Light' } latList = [ x for x in self.df[self.lat].values if type(x) not in [str, list, dict] ] latMean = sum(latList) / len(latList) lonList = [ x for x in self.df[self.lon].values if type(x) not in [str, list, dict] ] lonMean = sum(lonList) / len(lonList) self.center = [latMean, lonMean] self.zoom = 5 self.displayMap = ipyleaflet.Map(center=self.center, zoom=self.zoom, layers=(ipyleaflet.basemap_to_tiles( self.basemap), )) if mapLayout: self.displayMap.layout = mapLayout if not style: markers = self._generateMarkers() for marker in markers: self.displayMap.add_layer(marker) return self.displayMap elif style == 'grouped': markers = self._generateMarkers() self.markerCluster = ipyleaflet.MarkerCluster(markers=markers) self.displayMap.add_control(ipyleaflet.LayersControl()) self.displayMap.add_layer(self.markerCluster) return self.displayMap elif style == 'pie': if not groupBy: raise KeyError( 'Please add groupBy=COLNAME. You need to specify the column containing the categories for the pie chart.' ) html = self._writeHTML(groupCategory=groupBy, pageTitle=pageTitle, outputPath=outputPath) css = self._writeCSS(groupCategory=groupBy, colorDict=colorDict, outputPath=outputPath) print( 'Your map has been generated at\n\t"/html/static/index.html".\nDue to CORS issues, most browsers will not load the GeoJSON in an Iframe correctly.\nPlease open the map in a seperate browser window.' ) return displayHTML( "<iframe allowfullscreen=”true” mozallowfullscreen=”true” webkitallowfullscreen=”true” height=550px; width=100% src='./html/static/index.html'> <iframe>" )
def __init__(self, basemaps=[], add_google_map=None, **kwargs): """ Initialize Sepal Map. Args: basemap (str): Select one of the Sepal Base Maps available. """ basemap = dict( url='http://c.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', max_zoom=20, attribution= '© <a href="http://www.openstreetmap.org/copyright">\ OpenStreetMap</a> © <a href="http://cartodb.com/attributions">\ CartoDB</a>', name='CartoDB.DarkMatter') basemap = basemap_to_tiles(basemap) if not add_google_map: add_google_map = False super().__init__(**kwargs, add_google_map=add_google_map, basemap=basemap) if basemaps: for basemap in basemaps: self.add_basemap(basemap) self.center = [0, 0] self.zoom = 2 super().clear_controls() self.add_control(ZoomControl(position='topright')) self.add_control(LayersControl(position='topright')) self.add_control(AttributionControl(position='bottomleft')) self.add_control(ScaleControl(position='bottomleft', imperial=False)) # Create output space for raster interaction output_r = widgets.Output(layout={'border': '1px solid black'}) output_control_r = WidgetControl(widget=output_r, position='bottomright') self.add_control(output_control_r) self.loaded_rasters = {} # Define a behavior when ispector checked and map clicked def raster_interaction(**kwargs): if kwargs.get('type') == 'click' and self.inspector_checked: latlon = kwargs.get('coordinates') self.default_style = {'cursor': 'wait'} local_rasters = [ lr.name for lr in self.layers if isinstance(lr, LocalTileLayer) ] if local_rasters: with output_r: output_r.clear_output(wait=True) for lr_name in local_rasters: lr = self.loaded_rasters[lr_name] lat, lon = latlon # Verify if the selected latlon is the image bounds if any([ lat < lr.bottom, lat > lr.top, lon < lr.left, lon > lr.right ]): print('Location out of raster bounds') else: #row in pixel coordinates y = int(((lr.top - lat) / abs(lr.y_res))) #column in pixel coordinates x = int(((lon - lr.left) / abs(lr.x_res))) #get height and width h, w = lr.data.shape value = lr.data[y][x] print(f'{lr_name}') print( f'Lat: {round(lat,4)}, Lon: {round(lon,4)}' ) print(f'x:{x}, y:{y}') print(f'Pixel value: {value}') else: with output_r: output_r.clear_output() self.default_style = {'cursor': 'crosshair'} self.on_interaction(raster_interaction)
from ipyleaflet import Map, basemaps, basemap_to_tiles def foo(p): print(p) m = Map( layers=(basemap_to_tiles(basemaps.NASAGIBS.ModisTerraTrueColorCR, "2017-04-08"), ), center=(52.204793, 360.121558), zoom=4, ) m.on_interaction(foo)
def show(self, **kwargs): """ Generate and return the map object for displaying the map Parameters ----------- None Returns ---------- map:ipyleaflet.Map """ self.map = ipyleaflet.Map( layers=(ipyleaflet.basemap_to_tiles( ipyleaflet.basemaps.CartoDB.Positron),), **kwargs ) choro_layer = ipyleaflet.Choropleth( name=self.dataset, geo_data=self.geo_data, choro_data=self.choro_data[self.selectedAttr][self.selectedYear], colormap=linear.YlOrRd_04, style={ 'opacity': 1, 'weight': 1.9, 'dashArray': '9', 'fillOpacity': 0.5} ) def handle_click(**kwargs): if kwargs['event'] == 'click': clickedFips = kwargs['properties']['GEOID'] clickedName = self.fipsLookUp[clickedFips] dataBox.value = f"{clickedName} : {self.choro_data[self.selectedAttr][self.selectedYear][clickedFips]:,}" self.clickedID = clickedFips choro_layer.on_click(handle_click) # Year select def handle_year_change(change): new_year = str(change.new) choro_layer.choro_data = self.choro_data[self.selectedAttr][new_year] if self.clickedID: clickedName = self.fipsLookUp[self.clickedID] dataBox.value = f"{clickedName} : {self.choro_data[self.selectedAttr][new_year][self.clickedID]:,}" self.selectedYear = new_year yearList = self.availableYearDict[self.selectedAttr] yearListNum = list(map(int, yearList)) minYear = min(yearListNum) maxYear = max(yearListNum) yearSlider, yearWidget = self.yearSlider(minYear, maxYear, maxYear) yearSlider.observe(handle_year_change, 'value') dataBox, dataWidget = self.dataBox() def handle_attr_change(change): new_attr = change.new choro_layer.choro_data = self.choro_data[new_attr][self.selectedYear] if self.clickedID: clickedName = self.fipsLookUp[self.clickedID] dataBox.value = f"{clickedName} : {self.choro_data[new_attr][self.selectedYear][self.clickedID]:,}" self.selectedAttr = new_attr attrDropdown, attrDropdownWidget = self.attrDropdown() attrDropdown.observe(handle_attr_change, "value") # Add to map self.map.add_layer(choro_layer) self.map.add_control(ipyleaflet.LayersControl()) self.map.add_control(ipyleaflet.FullScreenControl()) self.map.add_control(attrDropdownWidget) self.map.add_control(yearWidget) self.map.add_control(dataWidget) return self.map
def on_map_selected(change): m.layers = [ basemap_to_tiles(maps[basemap_selector.value]), weather_maps[heatmap_selector.value] ]
def __init__(self, **kwargs): if "center" not in kwargs: kwargs["center"] = [40, -100] if "zoom" not in kwargs: kwargs["zoom"] = 4 if "scroll_wheel_zoom" not in kwargs: kwargs["scroll_wheel_zoom"] = True super().__init__(**kwargs) if "height" not in kwargs: self.layout.height = "600px" else: self.layout.height = kwargs["height"] self.add_control(FullScreenControl()) self.add_control(LayersControl(position="topright")) self.add_control(DrawControl(position="topleft")) self.add_control(MeasureControl()) self.add_control(ScaleControl(position="bottomleft")) self.toolbar = None # tools = { # "folder-open": { # "name": "open_data", # "tooltip": "Open local vector/raster data" # }, # "map": { # "name": "basemap", # "tooltip": "Change basemap" # }, # "gears": { # "name": "whitebox", # "tooltip": "WhiteboxTools for local geoprocessing" # }, # "filter": { # "name": "query", # "tooltip": "Attribute selection" # }, # } # icons = list(tools.keys()) # tooltips = [item["tooltip"] for item in list(tools.values())] # icon_width = "32px" # icon_height = "32px" # n_cols = 3 # n_rows = math.ceil(len(icons) / n_cols) # toolbar_grid = ipywidgets.GridBox( # children=[ # ipywidgets.ToggleButton( # layout=ipywidgets.Layout( # width="auto", height="auto", padding="0px 0px 0px 4px" # ), # button_style="primary", # icon=icons[i], # tooltip=tooltips[i], # ) # for i in range(len(icons)) # ], # layout=ipywidgets.Layout( # width="107px", # grid_template_columns=(icon_width + " ") * n_cols, # grid_template_rows=(icon_height + " ") * n_rows, # grid_gap="1px 1px", # padding="5px", # ), # ) # self.toolbar = toolbar_grid if "google_map" not in kwargs: layer = TileLayer( url="https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}", attribution="Google", name="Google Maps", ) self.add_layer(layer) else: if kwargs["google_map"] == "ROADMAP": layer = TileLayer( url="https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}", attribution="Google", name="Google Maps", ) self.add_layer(layer) elif kwargs["google_map"] == "HYBRID": layer = TileLayer( url="https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}", attribution="Google", name="Google Satellite") self.add_layer(layer) if "basemap" not in kwargs: layer = basemap_to_tiles(basemaps.OpenStreetMap.Mapnik) self.add_layer(layer) else: layer = basemap_to_tiles(kwargs["basemap"]) self.add_layer(layer) main_toolbar(self)
def add_basemap(m, basemap): bm = ipyleaflet.basemap_to_tiles(basemap) m.add_layer(bm) return
def run_filmstrip_app(output_name, time_range, time_step, tide_range=(0.0, 1.0), resolution=(-30, 30), max_cloud=0.5, ls7_slc_off=False, size_limit=10000): ''' An interactive app that allows the user to select a region from a map, then load Digital Earth Africa Landsat data and combine it using the geometric median ("geomedian") statistic to reveal the median or 'typical' appearance of the landscape for a series of time periods. The results for each time period are combined into a 'filmstrip' plot which visualises how the landscape has changed in appearance across time, with a 'change heatmap' panel highlighting potential areas of greatest change. For coastal applications, the analysis can be customised to select only satellite images obtained during a specific tidal range (e.g. low, average or high tide). Last modified: April 2020 Parameters ---------- output_name : str A name that will be used to name the output filmstrip plot file. time_range : tuple A tuple giving the date range to analyse (e.g. `time_range = ('1988-01-01', '2017-12-31')`). time_step : dict This parameter sets the length of the time periods to compare (e.g. `time_step = {'years': 5}` will generate one filmstrip plot for every five years of data; `time_step = {'months': 18}` will generate one plot for each 18 month period etc. Time periods are counted from the first value given in `time_range`. tide_range : tuple, optional An optional parameter that can be used to generate filmstrip plots based on specific ocean tide conditions. This can be valuable for analysing change consistently along the coast. For example, `tide_range = (0.0, 0.2)` will select only satellite images acquired at the lowest 20% of tides; `tide_range = (0.8, 1.0)` will select images from the highest 20% of tides. The default is `tide_range = (0.0, 1.0)` which will select all images regardless of tide. resolution : tuple, optional The spatial resolution to load data. The default is `resolution = (-30, 30)`, which will load data at 30 m pixel resolution. Increasing this (e.g. to `resolution = (-100, 100)`) can be useful for loading large spatial extents. max_cloud : float, optional This parameter can be used to exclude satellite images with excessive cloud. The default is `0.5`, which will keep all images with less than 50% cloud. ls7_slc_off : bool, optional An optional boolean indicating whether to include data from after the Landsat 7 SLC failure (i.e. SLC-off). Defaults to False, which removes all Landsat 7 observations > May 31 2003. size_limit : int, optional An optional integer (in hectares) specifying the size limit for the data query. Queries larger than this size will receive a warning that he data query is too large (and may therefore result in memory errors). Returns ------- ds_geomedian : xarray Dataset An xarray dataset containing geomedian composites for each timestep in the analysis. ''' ######################## # Select and load data # ######################## # Define centre_coords as a global variable global centre_coords # Test if centre_coords is in the global namespace; # use default value if it isn't if 'centre_coords' not in globals(): centre_coords = (6.587292, 1.532833) # Plot interactive map to select area basemap = basemap_to_tiles(basemaps.Esri.WorldImagery) geopolygon = select_on_a_map(height='600px', layers=(basemap, ), center=centre_coords, zoom=14) # Set centre coords based on most recent selection to re-focus # subsequent data selections centre_coords = geopolygon.centroid.points[0][::-1] # Test size of selected area msq_per_hectare = 10000 area = (geopolygon.to_crs(crs=CRS('epsg:6933')).area / msq_per_hectare) radius = np.round(np.sqrt(size_limit), 1) if area > size_limit: print(f'Warning: Your selected area is {area:.00f} hectares. ' f'Please select an area of less than {size_limit} hectares.' f'\nTo select a smaller area, re-run the cell ' f'above and draw a new polygon.') else: print('Starting analysis...') # Connect to datacube database dc = datacube.Datacube(app='Change_filmstrips') # Configure local dask cluster create_local_dask_cluster() # Obtain native CRS crs = mostcommon_crs(dc=dc, product='ls5_usgs_sr_scene', query={ 'time': '1990', 'geopolygon': geopolygon }) # Create query based on time range, area selected, custom params query = { 'time': time_range, 'geopolygon': geopolygon, 'output_crs': crs, 'resolution': resolution, 'dask_chunks': { 'x': 3000, 'y': 3000 }, 'align': (resolution[1] / 2.0, resolution[1] / 2.0) } # Load data from all three Landsats warnings.filterwarnings("ignore") ds = load_ard(dc=dc, measurements=['red', 'green', 'blue'], products=[ 'ls5_usgs_sr_scene', 'ls7_usgs_sr_scene', 'ls8_usgs_sr_scene' ], min_gooddata=max_cloud, ls7_slc_off=ls7_slc_off, **query) # Optionally calculate tides for each timestep in the satellite # dataset and drop any observations out side this range if tide_range != (0.0, 1.0): ds = tidal_tag(ds=ds, tidepost_lat=None, tidepost_lon=None) min_tide, max_tide = ds.tide_height.quantile(tide_range).values ds = ds.sel(time=(ds.tide_height >= min_tide) & (ds.tide_height <= max_tide)) ds = ds.drop('tide_height') print(f' Keeping {len(ds.time)} observations with tides ' f'between {min_tide:.2f} and {max_tide:.2f} m') # Create time step ranges to generate filmstrips from bins_dt = pd.date_range(start=time_range[0], end=time_range[1], freq=pd.DateOffset(**time_step)) # Bin all satellite observations by timestep. If some observations # fall outside the upper bin, label these with the highest bin labels = bins_dt.astype('str') time_steps = (pd.cut(ds.time.values, bins_dt, labels=labels[:-1]).add_categories( labels[-1]).fillna(labels[-1])) time_steps_var = xr.DataArray(time_steps, [('time', ds.time)], name='timestep') # Resample data temporally into time steps, and compute geomedians ds_geomedian = ( ds.groupby(time_steps_var).apply(lambda ds_subset: xr_geomedian( ds_subset, num_threads= 1, # disable internal threading, dask will run several concurrently eps=0.2 * (1 / 10_000), # 1/5 pixel value resolution nocheck=True)) ) # disable some checks inside geomedian library that use too much ram
class Plot_interface(object): """Class to handle map and plot interaction""" # Declare class attributes pyccd_flag = False pyccd_flag2 = False current_band = '' band_index1 = 4 band_index2 = 4 click_col = '' point_color = ['#43a2ca'] click_df = pd.DataFrame() sample_col = '' sample_df = pd.DataFrame() PyCCDdf = pd.DataFrame() table = pd.DataFrame() band_list = ['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'] year_range = [1986, 2018] doy_range = [1, 365] step = 1 #in years # Create widget controls next_pt = Button(value=False, description='Next point', disabled=False) previous_pt = Button(value=False, description='Previous point', disabled=False) pyccd_button = Button(value=False, description='Run PyCCD 1', disabled=False) pyccd_button2 = Button(value=False, description='Run PyCCD 2', disabled=False) band_selector1 = Dropdown( options=['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'], description='Select band', value=None) band_selector2 = Dropdown( options=['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'], description='Select band', value=None) image_band_1 = Dropdown( options=['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'], description='Red:', value='SWIR1') image_band_2 = Dropdown( options=['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'], description='Green:', value='NIR') image_band_3 = Dropdown( options=['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'], description='Blue:', value='RED') stretch_min = FloatText(value=0, description='Min:', disabled=False) stretch_max = FloatText(value=6000, description='Min:', disabled=False) # Clear layers on map clear_layers = Button(value=False, description='Clear Map', disabled=False) # Color points by DOY color_check = widgets.Checkbox(value=False, description='Color DOY', disabled=False) idBox = widgets.Text(value='0', description='ID:', disabled=False) ylim = widgets.IntRangeSlider(value=[0, 4000], min=0, max=10000, step=500, description='YLim:', disabled=False, continuous_update=False, orientation='horizontal', readout=True, readout_format='d') xlim = widgets.IntRangeSlider(value=[2000, 2018], min=1986, max=2018, step=1, description='XLim:', disabled=False, continuous_update=False, orientation='horizontal', readout=True, readout_format='d') ylim2 = widgets.IntRangeSlider(value=[0, 4000], min=0, max=10000, step=500, description='YLim:', disabled=False, continuous_update=False, orientation='horizontal', readout=True, readout_format='d') xlim2 = widgets.IntRangeSlider(value=[2000, 2018], min=1986, max=2018, step=1, description='XLim:', disabled=False, continuous_update=False, orientation='horizontal', readout=True, readout_format='d') coords_label = Label() pt_message = HTML("Current ID: ") time_label = HTML(value='') selected_label = HTML("ID of selected point") hover_label = HTML("test value") text_brush = HTML(value='Selected year range:') kml_link = HTML(value='KML:') error_label = HTML(value='Load a point') # Create map including streets and satellite and controls m = ipyleaflet.Map(zoom=5, layout={'height': '400px'}, center=(3.3890701010382958, -67.32297252983098), dragging=True, close_popup_on_click=False, basemap=ipyleaflet.basemaps.Esri.WorldStreetMap) streets = ipyleaflet.basemap_to_tiles( ipyleaflet.basemaps.Esri.WorldImagery) m.add_layer(streets) dc = ipyleaflet.DrawControl(marker={'shapeOptions': { 'color': '#ff0000' }}, polygon={}, circle={}, circlemarker={}, polyline={}) # Table widget table_widget = qgrid.show_grid(table, show_toolbar=False) # Set plots # Plot scales. HERE lc1_x = bqplot.DateScale(min=datetime.date(xlim.value[0], 2, 1), max=datetime.date(xlim.value[1], 1, 1)) # DOY scale lc1_x3 = bqplot.LinearScale(min=0, max=365) lc2_y = bqplot.LinearScale(min=ylim.value[0], max=ylim.value[1]) lc1_x2 = bqplot.DateScale(min=datetime.date(xlim.value[0], 2, 1), max=datetime.date(xlim.value[1], 1, 1)) lc2_y2 = bqplot.LinearScale(min=ylim.value[0], max=ylim.value[1]) # Main scatter plot for samples lc2 = bqplot.Scatter(x=[], y=[], scales={ 'x': lc1_x, 'y': lc2_y }, size=[1, 1], interactions={ 'click': 'select', 'hover': 'tooltip' }, selected_style={ 'opacity': 1.0, 'fill': 'DarkOrange', 'stroke': 'Red' }, unselected_style={'opacity': 0.5}, display_legend=True, labels=['Sample point']) # Pyccd model fit lc4 = bqplot.Lines( x=[], y=[], colors=['black'], stroke_width=3, scales={ 'x': lc1_x, 'y': lc2_y }, size=[1, 1], ) # Pyccd model break lc5 = bqplot.Scatter(x=[], y=[], marker='triangle-up', colors=['red'], scales={ 'x': lc1_x, 'y': lc2_y }, size=[1, 1], display_legend=False, labels=['Model Endpoint']) # Scatter plot for clicked points in map lc3 = bqplot.Scatter(x=[], y=[], scales={ 'x': lc1_x2, 'y': lc2_y2 }, size=[1, 1], colors=['gray'], interactions={ 'click': 'select', 'hover': 'tooltip' }, selected_style={ 'opacity': 1.0, 'fill': 'DarkOrange', 'stroke': 'Red' }, unselected_style={'opacity': 0.5}, display_legend=True, labels=['Clicked point']) # Pyccd model fit for clicked point lc6 = bqplot.Lines( x=[], y=[], colors=['black'], stroke_width=3, scales={ 'x': lc1_x2, 'y': lc2_y2 }, size=[1, 1], ) # Pyccd model break for clicked point lc7 = bqplot.Scatter(x=[], y=[], marker='triangle-up', colors=['red'], scales={ 'x': lc1_x2, 'y': lc2_y2 }, size=[1, 1], display_legend=False, labels=['Model Endpoint']) # Scatter for sample DOY lc8 = bqplot.Scatter(x=[], y=[], scales={ 'x': lc1_x3, 'y': lc2_y }, size=[1, 1], interactions={ 'click': 'select', 'hover': 'tooltip' }, selected_style={ 'opacity': 1.0, 'fill': 'DarkOrange', 'stroke': 'Red' }, unselected_style={'opacity': 0.5}, display_legend=True, labels=['Sample point']) # Plot axes. x_ax1 = bqplot.Axis(label='Date', scale=lc1_x, num_ticks=6, tick_format='%Y') x_ax2 = bqplot.Axis(label='Date', scale=lc1_x2, num_ticks=6, tick_format='%Y') x_ax3 = bqplot.Axis(label='DOY', scale=lc1_x3, num_ticks=6) x_ay1 = bqplot.Axis(label='SWIR1', scale=lc2_y, orientation='vertical') x_ay2 = bqplot.Axis(label='SWIR1', scale=lc2_y2, orientation='vertical') # Create a figure for sample points. fig = bqplot.Figure(marks=[lc2, lc4, lc5], axes=[x_ax1, x_ay1], layout={ 'height': '300px', 'width': '100%' }, title="Sample TS") # Create a figure for clicked points. fig2 = bqplot.Figure(marks=[lc3, lc6, lc7], axes=[x_ax2, x_ay2], layout={ 'height': '300px', 'width': '100%' }, title="Clicked TS") # Create a figure for sample DOY. fig3 = bqplot.Figure(marks=[lc8], axes=[x_ax3, x_ay1], layout={ 'height': '300px', 'width': '100%' }, title="Clicked TS") def __init__(self, navigate): Plot_interface.navigate = navigate Plot_interface.band_index1 = 4 Plot_interface.band_index2 = 4 Plot_interface.pyccd_flag = False Plot_interface.pyccd_flag2 = False Plot_interface.table = None # Set up database conn = sqlite3.connect(Plot_interface.navigate.dbPath) Plot_interface.current_id = Plot_interface.navigate.current_id Plot_interface.c = conn.cursor() Plot_interface.minv = 0 Plot_interface.maxv = 6000 Plot_interface.b1 = 'SWIR1' Plot_interface.b2 = 'NIR' Plot_interface.b3 = 'RED' @classmethod def map_point(self): gjson = ipyleaflet.GeoJSON( data=Plot_interface.navigate.fc_df['geometry'][ Plot_interface.current_id], name="Sample point") Plot_interface.m.center = gjson.data['coordinates'][::-1] Plot_interface.m.zoom = 12 Plot_interface.m.add_layer(gjson) kmlstr = ee.FeatureCollection( ee.Geometry.Point(Plot_interface.navigate.fc_df['geometry'][ Plot_interface.current_id]['coordinates'])).getDownloadURL( "kml") Plot_interface.kml_link.value = "<a '_blank' rel='noopener noreferrer' href={}>KML Link</a>".format( kmlstr) @classmethod def get_ts(self): #try: Plot_interface.error_label.value = 'Loading' Plot_interface.current_band = Plot_interface.band_list[ Plot_interface.band_index1] Plot_interface.sample_col = get_full_collection( Plot_interface.navigate.fc_df['geometry'][ Plot_interface.current_id]['coordinates'], Plot_interface.year_range, Plot_interface.doy_range) Plot_interface.sample_df = get_df_full( Plot_interface.sample_col, Plot_interface.navigate.fc_df['geometry'][ Plot_interface.current_id]['coordinates']).dropna() Plot_interface.error_label.value = 'Point loaded!' #except: # Plot_interface.error_label.value = 'Point could not be loaded!' def clear_map(b): Plot_interface.m.clear_layers() Plot_interface.m.add_layer(Plot_interface.streets) Plot_interface.map_point() @classmethod def plot_ts(self): current_band = Plot_interface.band_list[Plot_interface.band_index1] Plot_interface.lc2.x = Plot_interface.sample_df['datetime'] if Plot_interface.color_check.value == False: Plot_interface.lc2.colors = list(Plot_interface.point_color) Plot_interface.lc8.colors = list(Plot_interface.point_color) else: Plot_interface.lc2.colors = list( Plot_interface.sample_df['color'].values) Plot_interface.lc8.colors = list( Plot_interface.sample_df['color'].values) Plot_interface.lc2.y = Plot_interface.sample_df[current_band] Plot_interface.x_ay1.label = current_band Plot_interface.lc4.x = [] Plot_interface.lc4.y = [] Plot_interface.lc5.x = [] Plot_interface.lc5.y = [] Plot_interface.lc8.x = Plot_interface.sample_df['doy'] Plot_interface.lc8.y = Plot_interface.sample_df[current_band] #if pyccd_flag: if Plot_interface.pyccd_flag: Plot_interface.run_pyccd(0) # Go back or forth between sample points def advance(b): # Plot point in map Plot_interface.lc4.x = [] Plot_interface.lc4.y = [] Plot_interface.lc5.x = [] Plot_interface.lc5.y = [] Plot_interface.lc5.display_legend = False Plot_interface.pyccd_flag = False Plot_interface.current_id += 1 Plot_interface.pt_message.value = "Point ID: {}".format( Plot_interface.current_id) Plot_interface.map_point() Plot_interface.get_ts() Plot_interface.plot_ts() Plot_interface.change_table(0) Plot_interface.navigate.valid.value = False Plot_interface.navigate.description = 'Not Saved' def decrease(b): # Plot point in map Plot_interface.lc4.x = [] Plot_interface.lc4.y = [] Plot_interface.lc5.x = [] Plot_interface.lc5.y = [] Plot_interface.lc5.display_legend = False Plot_interface.pyccd_flag = False Plot_interface.current_id -= 1 Plot_interface.pt_message.value = "Point ID: {}".format( Plot_interface.current_id) Plot_interface.map_point() Plot_interface.get_ts() Plot_interface.plot_ts() Plot_interface.change_table(0) Plot_interface.navigate.valid.value = False Plot_interface.navigate.description = 'Not Saved' def change_table(b): # Update the table based on current ID # Get header cursor = Plot_interface.c.execute('select * from measures') names = list(map(lambda x: x[0], cursor.description)) previous_inputs = pd.DataFrame() for i, row in enumerate( Plot_interface.c.execute( "SELECT * FROM measures WHERE id = '%s'" % Plot_interface.current_id)): previous_inputs[i] = row previous_inputs = previous_inputs.T if previous_inputs.shape[0] > 0: previous_inputs.columns = names Plot_interface.table_widget.df = previous_inputs # Functions for changing image stretch def change_image_band1(change): new_band = change['new'] Plot_interface.b1 = new_band def change_image_band2(change): new_band = change['new'] Plot_interface.b2 = new_band def change_image_band3(change): new_band = change['new'] Plot_interface.b3 = new_band # Band selection for sample point def on_band_selection1(change): new_band = change['new'] #global band_index band_index = change['owner'].index Plot_interface.band_index1 = band_index Plot_interface.plot_ts() # Band selection for clicked point def on_band_selection2(change): new_band = change['new'] band_index = change['owner'].index Plot_interface.band_index2 = band_index Plot_interface.lc3.x = Plot_interface.click_df['datetime'] Plot_interface.lc3.y = Plot_interface.click_df[new_band] Plot_interface.x_ay2.label = new_band if Plot_interface.pyccd_flag2: Plot_interface.run_pyccd2(0) def change_yaxis(value): Plot_interface.lc2_y.min = Plot_interface.ylim.value[0] Plot_interface.lc2_y.max = Plot_interface.ylim.value[1] def change_xaxis(value): Plot_interface.lc1_x.min = datetime.date(Plot_interface.xlim.value[0], 2, 1) Plot_interface.lc1_x.max = datetime.date(Plot_interface.xlim.value[1], 2, 1) Plot_interface.year_range = [ Plot_interface.xlim.value[0], Plot_interface.xlim.value[1] ] def change_yaxis2(value): Plot_interface.lc2_y2.min = Plot_interface.ylim2.value[0] Plot_interface.lc2_y2.max = Plot_interface.ylim2.value[1] def change_xaxis2(value): Plot_interface.lc1_x2.min = datetime.date( Plot_interface.xlim2.value[0], 2, 1) Plot_interface.lc1_x2.max = datetime.date( Plot_interface.xlim2.value[1], 2, 1) def hover_event(self, target): Plot_interface.hover_label.value = str(target['data']['x']) # Add layer from clicked point in sample TS figure def click_event(self, target): pt_index = target['data']['index'] current_band = Plot_interface.band_list[Plot_interface.band_index1] image_id = Plot_interface.sample_df['id'].values[pt_index] selected_image = ee.Image( Plot_interface.sample_col.filterMetadata('system:index', 'equals', image_id).first()) tile_url = GetTileLayerUrl( selected_image.visualize(min=Plot_interface.stretch_min.value, max=Plot_interface.stretch_max.value, bands=[ Plot_interface.b1, Plot_interface.b2, Plot_interface.b3 ])) Plot_interface.m.add_layer( ipyleaflet.TileLayer(url=tile_url, name=image_id)) # Add layer from clicked point in clicked TS figure def click_event2(self, target): pt_index = target['data']['index'] current_band = Plot_interface.band_list[Plot_interface.band_index2] #Find clicked image. .values needed to access the nth element of that list instead of indexing by ID image_id = Plot_interface.click_df['id'].values[pt_index] selected_image = ee.Image( Plot_interface.click_col.filterMetadata('system:index', 'equals', image_id).first()) tile_url = GetTileLayerUrl( selected_image.visualize(min=Plot_interface.minv, max=Plot_interface.maxv, bands=[ Plot_interface.b1, Plot_interface.b2, Plot_interface.b3 ])) Plot_interface.m.add_layer( ipyleaflet.TileLayer(url=tile_url, name=image_id)) # Plot TS from clicked point def handle_draw(self, action, geo_json): # Get the selected coordinates from the map's drawing control. current_band = Plot_interface.band_list[Plot_interface.band_index2] coords = geo_json['geometry']['coordinates'] Plot_interface.click_col = get_full_collection( coords, Plot_interface.year_range, Plot_interface.doy_range) Plot_interface.click_df = get_df_full(Plot_interface.click_col, coords).dropna() Plot_interface.lc6.x = [] Plot_interface.lc6.y = [] Plot_interface.lc7.x = [] Plot_interface.lc7.y = [] Plot_interface.lc3.x = Plot_interface.click_df['datetime'] Plot_interface.lc3.y = Plot_interface.click_df[current_band] if Plot_interface.color_check.value == False: Plot_interface.lc3.colors = list(Plot_interface.point_color) else: Plot_interface.lc3.colors = list( Plot_interface.click_df['color'].values) # Plotting pyccd def plot_pyccd(results, band, plotband, dates, yl, ylabel, ts_type): mask = np.array(results['processing_mask']).astype(np.bool_) predicted_values = [] prediction_dates = [] break_dates = [] start_dates = [] for num, result in enumerate(results['change_models']): days = np.arange(result['start_day'], result['end_day'] + 1) prediction_dates.append(days) break_dates.append(result['break_day']) start_dates.append(result['start_day']) intercept = result[list(result.keys())[6 + band]]['intercept'] coef = result[list(result.keys())[6 + band]]['coefficients'] predicted_values.append( intercept + coef[0] * days + coef[1] * np.cos(days * 1 * 2 * np.pi / 365.25) + coef[2] * np.sin(days * 1 * 2 * np.pi / 365.25) + coef[3] * np.cos(days * 2 * 2 * np.pi / 365.25) + coef[4] * np.sin(days * 2 * 2 * np.pi / 365.25) + coef[5] * np.cos(days * 3 * 2 * np.pi / 365.25) + coef[6] * np.sin(days * 3 * 2 * np.pi / 365.25)) num_breaks = len(break_dates) break_y = [plotband[dates == i][0] for i in break_dates] #break_y = [0] * num_breaks break_dates_plot = [ datetime.datetime.fromordinal(i).strftime('%Y-%m-%d %H:%M:%S.%f') for i in break_dates ] plot_dates = np.array( [datetime.datetime.fromordinal(i) for i in (dates)]) # Predicted curves all_dates = [] all_preds = [] for _preddate, _predvalue in zip(prediction_dates, predicted_values): all_dates.append(_preddate) all_preds.append(_predvalue) all_preds = [item for sublist in all_preds for item in sublist] all_dates = [item for sublist in all_dates for item in sublist] date_ord = [ datetime.datetime.fromordinal(i).strftime('%Y-%m-%d %H:%M:%S.%f') for i in all_dates ] _x = np.array(date_ord, dtype='datetime64') _y = all_preds if ts_type == 'sample_ts': Plot_interface.lc4.x = _x Plot_interface.lc4.y = _y Plot_interface.lc5.x = np.array(break_dates_plot, dtype='datetime64') Plot_interface.lc5.y = break_y elif ts_type == 'clicked_ts': Plot_interface.lc6.x = _x Plot_interface.lc6.y = _y Plot_interface.lc7.x = np.array(break_dates_plot, dtype='datetime64') Plot_interface.lc7.y = break_y # Go to a specific sample def go_to_sample(b): # Plot point in map Plot_interface.lc4.x = [] Plot_interface.lc4.y = [] Plot_interface.lc5.x = [] Plot_interface.lc5.y = [] Plot_interface.lc5.display_legend = False Plot_interface.pyccd_flag = False Plot_interface.current_id = int(b.value) Plot_interface.pt_message.value = "Point ID: {}".format( Plot_interface.current_id) Plot_interface.navigate.valid.value = False Plot_interface.navigate.description = 'Not Saved' Plot_interface.map_point() Plot_interface.get_ts() Plot_interface.plot_ts() # Run pyccd def run_pyccd(b): # Run pyCCD on current point Plot_interface.pyccd_flag = True Plot_interface.lc5.display_legend = True dfPyCCD = Plot_interface.sample_df dfPyCCD['pixel_qa'][dfPyCCD['pixel_qa'] > 4] = 0 #TODO: Paramaterize everything params = { 'QA_BITPACKED': False, 'QA_FILL': 255, 'QA_CLEAR': 0, 'QA_WATER': 1, 'QA_SHADOW': 2, 'QA_SNOW': 3, 'QA_CLOUD': 4 } dates = np.array(dfPyCCD['ord_time']) blues = np.array(dfPyCCD['BLUE']) greens = np.array(dfPyCCD['GREEN']) reds = np.array(dfPyCCD['RED']) nirs = np.array(dfPyCCD['NIR']) swir1s = np.array(dfPyCCD['SWIR1']) swir2s = np.array(dfPyCCD['SWIR2']) thermals = np.array(dfPyCCD['THERMAL']) qas = np.array(dfPyCCD['pixel_qa']) results = ccd.detect(dates, blues, greens, reds, nirs, swir1s, swir2s, thermals, qas, params=params) band_names = [ 'Blue SR', 'Green SR', 'Red SR', 'NIR SR', 'SWIR1 SR', 'SWIR2 SR', 'THERMAL' ] plotlabel = band_names[Plot_interface.band_index1] plot_arrays = [blues, greens, reds, nirs, swir1s, swir2s] plotband = plot_arrays[Plot_interface.band_index1] Plot_interface.plot_pyccd(results, Plot_interface.band_index1, plotband, dates, (0, 4000), 'PyCCD Results', 'sample_ts') def run_pyccd2(b): # Run pyCCD on current point Plot_interface.pyccd_flag2 = True # Display the legend Plot_interface.lc7.display_legend = True dfPyCCD = Plot_interface.click_df # First two lines no longer required bc we are removing NA's when we load the TS dfPyCCD['pixel_qa'][dfPyCCD['pixel_qa'] > 4] = 0 #TODO: Paramaterize everything params = { 'QA_BITPACKED': False, 'QA_FILL': 255, 'QA_CLEAR': 0, 'QA_WATER': 1, 'QA_SHADOW': 2, 'QA_SNOW': 3, 'QA_CLOUD': 4 } dates = np.array(dfPyCCD['ord_time']) blues = np.array(dfPyCCD['BLUE']) greens = np.array(dfPyCCD['GREEN']) reds = np.array(dfPyCCD['RED']) nirs = np.array(dfPyCCD['NIR']) swir1s = np.array(dfPyCCD['SWIR1']) swir2s = np.array(dfPyCCD['SWIR2']) thermals = np.array(dfPyCCD['THERMAL']) qas = np.array(dfPyCCD['pixel_qa']) results = ccd.detect(dates, blues, greens, reds, nirs, swir1s, swir2s, thermals, qas, params=params) band_names = [ 'Blue SR', 'Green SR', 'Red SR', 'NIR SR', 'SWIR1 SR', 'SWIR2 SR', 'THERMAL' ] plotlabel = band_names[Plot_interface.band_index2] plot_arrays = [blues, greens, reds, nirs, swir1s, swir2s] plotband = plot_arrays[Plot_interface.band_index2] Plot_interface.plot_pyccd(results, Plot_interface.band_index2, plotband, dates, (0, 4000), 'PyCCD Results', 'clicked_ts') ylim.observe(change_yaxis) xlim.observe(change_xaxis) ylim2.observe(change_yaxis2) xlim2.observe(change_xaxis2) next_pt.on_click(advance) previous_pt.on_click(decrease) pyccd_button.on_click(run_pyccd) pyccd_button2.on_click(run_pyccd2) clear_layers.on_click(clear_map) band_selector1.observe(on_band_selection1, names='value') band_selector2.observe(on_band_selection2, names='value') image_band_1.observe(change_image_band1, names='value') image_band_2.observe(change_image_band2, names='value') image_band_3.observe(change_image_band3, names='value') lc2.on_element_click(click_event) lc2.tooltip = hover_label lc2.on_hover(hover_event) lc3.on_element_click(click_event2) lc3.tooltip = hover_label lc3.on_hover(hover_event) idBox.on_submit(go_to_sample) dc.on_draw(handle_draw) m.add_control(dc) m.add_control(ipyleaflet.LayersControl())
# the above domain; make layer now domainf = 'data/ABoVE_Study_Domain/ABoVE_Study_Domain.json' with open(domainf, 'r') as file: above_domain = json.load(file) # get some info about ABoVE collection in CMR for ORNL above_search = collections.keyword( "*Boreal Vulnerability Experiment*").get_all() above_results = [ r for r in above_search if any(["ABoVE" in r["dataset_id"], "ABoVE" in r["summary"]]) ] above_results_df = pd.DataFrame(above_results) # load a basemap from ESRI #basemaps.NASAGIBS.ModisTerraTrueColorCR esri = basemap_to_tiles(basemaps.Esri.WorldImagery) # map draw poly styling draw_style = { "shapeOptions": { "fillColor": "lightgreen", "color": "lightgreen", "fillOpacity": 0.5 } } # ---------------------------------------------------------------------------- # JSON input interface and some other ui elements geojson_label = HTML("<h4><b> or paste your GeoJSON: </b></h4>")
import ipywidgets as widgets from ipywidgets import Button, Layout from IPython.display import display, clear_output, Markdown as md #need this to stop numpy from returning truncated arrays import sys np.set_printoptions(threshold=sys.maxsize) # for automatic linebreaks and multi-line cells pd.options.display.max_colwidth = 10000 output = widgets.Output() data_output = widgets.Output() center = (40.7210907, -73.9877836) basemap = basemap_to_tiles(basemaps.CartoDB.Positron) m = Map(layers=(basemap, ), center=center, zoom=14, min_zoom=7, max_zoom=20) def extract_location(): global gdf, lat, lon lat = str(markerlocation[0]) lon = str(markerlocation[1]) df2 = pd.DataFrame(markerlocation) df = df2.transpose() df.columns = ['Latitude', 'Longitude'] gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.Longitude,
name="USGS Hydrography", attribution="USGS", format="image/png", transparent=True, ), "USGS 3DEP Elevation": WMSLayer( url="https://elevation.nationalmap.gov/arcgis/services/3DEPElevation/ImageServer/WMSServer?", layers="3DEPElevation:None", name="USGS 3DEP Elevation", attribution="USGS", format="image/png", transparent=True, ), } # Adds ipyleaflet basemaps for item in ipybasemaps.values(): try: name = item["name"] basemap = "ipybasemaps.{}".format(name) _ee_basemaps[name] = basemap_to_tiles(eval(basemap)) except Exception: for sub_item in item: name = item[sub_item]["name"] basemap = "ipybasemaps.{}".format(name) basemap = basemap.replace("Mids", "Modis") _ee_basemaps[name] = basemap_to_tiles(eval(basemap)) basemap_tiles = Box(_ee_basemaps, frozen_box=True) basemaps = Box( dict(zip(list(_ee_basemaps.keys()), list(_ee_basemaps.keys()))), frozen_box=True)
def draw_map(lat_ext=None, lon_ext=None): """ Description: Create an empty map with a blue rectangle of given <lat_ext>, <lon_ext> to be used to manually draw a polygon or rectangle ----- Input: lat_ext: latitude extent lon_ext: longitude extent Output: m: empty map ti interact with dc: draw control Usage: Draw a polygon or a rectangle """ # check options combination assert not((lat_ext is None) or (lon_ext is None)), \ 'lat_ext and lon_ext are required' assert lat_ext[0] < lat_ext[1], 'lat_ext values are in the wrong order' assert lon_ext[0] < lon_ext[1], 'lon_ext values are in the wrong order' # Location center = [np.mean(lat_ext), np.mean(lon_ext)] # source: https://sdc.unepgrid.ch:8080/edit/utils/data_cube_utilities/dc_display_map.py margin = -0.5 zoom_bias = 0 lat_zoom_level = _degree_to_zoom_level(margin=margin, *lat_ext) + zoom_bias lon_zoom_level = _degree_to_zoom_level(margin=margin, *lon_ext) + zoom_bias zoom = min(lat_zoom_level, lon_zoom_level) m = Map(center=center, zoom=zoom, scroll_wheel_zoom=True) # 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) rectangle = Rectangle(bounds=((lat_ext[0], lon_ext[0]), (lat_ext[1], lon_ext[1])), color='red', weight=2, fill=False) m.add_layer(rectangle) 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