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, 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)
def _show_colorbar(self, da): if self.colorbar_position and self.colormap is not None: vmin = da.min().values vmax = da.max().values fig = plt.figure(figsize=(8, 3)) ax = fig.add_axes([0.05, 0.8, 0.5, 0.07]) norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax) cbar = mpl.colorbar.ColorbarBase(ax, cmap=self.colormap, norm=norm, orientation='horizontal') f = tempfile.NamedTemporaryFile(suffix='.png', delete=False) output = Output() try: plt.savefig(f.name, bbox_inches='tight') with output: display(Image(filename=f.name)) finally: os.unlink(f.name) f.close() self.colorbar = WidgetControl(widget=output, position=self.colorbar_position, transparent_bg=True) self.m.add_control(self.colorbar) plt.close()
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 tool_click(b): with output: output.clear_output() if b.icon == "folder-open": display(filechooser_widget) m.add_control(output_ctrl) elif b.icon == "gears": import whiteboxgui.whiteboxgui as wbt if hasattr(m, "whitebox") and m.whitebox is not None: if m.whitebox in m.controls: m.remove_control(m.whitebox) tools_dict = wbt.get_wbt_dict() wbt_toolbox = wbt.build_toolbox(tools_dict, max_width="800px", max_height="500px") wbt_control = WidgetControl(widget=wbt_toolbox, position="bottomright") m.whitebox = wbt_control m.add_control(wbt_control) elif b.icon == "map": display(basemap_widget) m.add_control(output_ctrl)
def convert_js2py(m): """A widget for converting Earth Engine JavaScript to Python. Args: m (object): geemap.Map """ full_widget = widgets.VBox( layout=widgets.Layout(width="465px", height="350px")) text_widget = widgets.Textarea( placeholder= "Paste your Earth Engine JavaScript into this textbox and click the Convert button below to convert the Javascript to Python", layout=widgets.Layout(width="455px", height="310px"), ) buttons = widgets.ToggleButtons( value=None, options=["Convert", "Clear", "Close"], tooltips=["Convert", "Clear", "Close"], button_style="primary", ) buttons.style.button_width = "142px" def button_clicked(change): if change["new"] == "Convert": from .conversion import js_snippet_to_py, create_new_cell if len(text_widget.value) > 0: out_lines = js_snippet_to_py( text_widget.value, add_new_cell=False, import_ee=False, import_geemap=False, show_map=False, ) if len(out_lines) > 0 and len(out_lines[0].strip()) == 0: out_lines = out_lines[1:] text_widget.value = "".join(out_lines) create_code_cell(text_widget.value) elif change["new"] == "Clear": text_widget.value = "" elif change["new"] == "Close": m.toolbar_reset() if m.convert_ctrl is not None and m.convert_ctrl in m.controls: m.remove_control(m.convert_ctrl) full_widget.close() buttons.value = None buttons.observe(button_clicked, "value") full_widget.children = [text_widget, buttons] widget_control = WidgetControl(widget=full_widget, position="topright") m.add_control(widget_control) m.convert_ctrl = widget_control
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 __init__(self, distance_choice="agat"): self.m = ipyl.Map(center=(45, 0), zoom=7, layout={"height": "500px"}) # Date date_picker = widg.DatePicker(value=dt.datetime(2020, 1, 26)) self._date = date_picker.value date_picker.observe(self.change_date, "value") self.step = 0 self.distance_choice = distance_choice variable_picker = widg.Dropdown( value="WWMF", options=["WWMF", "WME", "W1", "PRECIP", "T"]) variable_picker.observe(self.variable_change, "value") dept_picker = widg.Dropdown(value="41", options={ "Finistère": "29", "Isère": "38", "Hérault": "34", "Loire-et-cher": "41" }) dept_picker.observe(self.change_dept, "value") self.dept = dept_picker.value self._variable = variable_picker.value # Open dataset and mask self.open_file() # Add other widgets self.legend = widg.Image(layout=widg.Layout(height="430px")) self.html1 = HTML(''' <h4>Type de temps</h4> Hover over a pixel ''') self.html1.layout.margin = '0px 20px 20px 20px' # Add controls control1 = WidgetControl(widget=self.html1, position='bottomright') self.m.add_control(control1) self.m.add_control(ipyl.LayersControl()) slider = widg.IntSlider(min=0, max=len(self.da.step) - 1, step=1, value=0, description="step") slider.observe(self.change_step, 'value') self.m.add_control( ipyl.WidgetControl(widget=widg.VBox( [date_picker, slider, variable_picker, dept_picker]), position="topright")) self.m.add_control(ipyl.FullScreenControl()) self.render() super().__init__([self.m, self.legend])
def __init__(self): # create the extra widget self.state = sw.StateBar(done=True) self.color = v.ListItemGroup(v_model = None, children=[v.ListItem(children= [c], value=c) for c in cp.planet_colors[:4]]) self.palette = v.Menu( value=False, v_slots=[{ 'name': 'activator', 'variable': 'menu', 'children': v.Btn(v_model = False, v_on='menu.on', color='primary', icon = True, children=[v.Icon(children=['mdi-palette'])]) }], children = [v.List(dense=True, outlined=True, rounded=True, children=[self.color])] ) # create the map super().__init__(gee=False) # add the widget to the map (as to left and right items) self.add_control(WidgetControl(widget=self.state, position='topleft')) self.add_control(WidgetControl(widget=self.palette, position='topleft')) # create jslinks jslink((self, 'combo'), (self.color, 'v_model'))
def add_layer(self, l): # call the original function super().add_layer(l) # add a layer state object state = StateBar(name=l.name) self.layer_state_list += [state] self.add_control(WidgetControl(widget=state, position="topleft")) # link it to the layer state # layer = next(l for l in self.layers if l.name == name) l.observe(state.activate, "loading") return
def change_basemap(m): """Widget for change basemaps. Args: m (object): geemap.Map() """ from .basemaps import _ee_basemaps dropdown = widgets.Dropdown( options=list(_ee_basemaps.keys()), value="ROADMAP", layout=widgets.Layout(width="200px") # description="Basemaps", ) close_btn = widgets.Button( icon="times", tooltip="Close the basemap widget", button_style="primary", layout=widgets.Layout(width="32px"), ) basemap_widget = widgets.HBox([dropdown, close_btn]) def on_click(change): basemap_name = change["new"] if len(m.layers) == 1: old_basemap = m.layers[0] else: old_basemap = old_basemap = m.layers[1] m.substitute_layer(old_basemap, _ee_basemaps[basemap_name]) dropdown.observe(on_click, "value") def close_click(change): m.toolbar_reset() if m.basemap_ctrl is not None and m.basemap_ctrl in m.controls: m.remove_control(m.basemap_ctrl) basemap_widget.close() close_btn.on_click(close_click) basemap_control = WidgetControl(widget=basemap_widget, position="topright") m.add_control(basemap_control) m.basemap_ctrl = basemap_control
def tool_click(b): with output: output.clear_output() if b.icon == "folder-open": display(filechooser_widget) m.add_control(output_ctrl) elif b.icon == "filter": dropdown_layer.options = [ layer.name for layer in m.layers if not isinstance(layer, ipyleaflet.TileLayer) ] # display(layers) display(filter_widget) m.add_control(filter_layer_control) elif b.icon == "map": display(basemap_widget) m.add_control(basemap_control) elif b.icon == "gears": import whiteboxgui.whiteboxgui as wbt if hasattr(m, "whitebox") and m.whitebox is not None: if m.whitebox in m.controls: m.remove_control(m.whitebox) tools_dict = wbt.get_wbt_dict() wbt_toolbox = wbt.build_toolbox(tools_dict, max_width="800px", max_height="500px") wbt_control = WidgetControl(widget=wbt_toolbox, position="bottomright") m.whitebox = wbt_control m.add_control(wbt_control) elif b.icon == "map-marker": display(add_csv_widget) m.add_control(output_ctrl) # elif b.icon == "question": print(f"You clicked the {b.icon} button")
def __init__(self): # create a save widget self.save = cw.ExportMap() # create the map self.m = cw.CustomMap() self.m.max_zoom = ( 14 # after this zoom level GEE crash and refuse to display images ) # add a legend to the map self.m.add_legend(legend_title="Legend", legend_dict=cp.legend_dict) # add the export control self.m.add_control(WidgetControl(widget=self.save, position="topleft")) # create the tile super().__init__("result_tile", cm.tile.result, inputs=[self.m])
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
def addTimeseries(inMap,path,bands,new_plot): px_series = xr.open_dataset(path) date_start = px_series.t.min().values date_end = px_series.t.max().values color = ['blue','red','green','yellow'] for i,b in enumerate(bands): x_data = px_series.t.values y_data = px_series.to_array().loc[dict(variable=b)][:,0,0].values x_data = x_data[~np.isnan(y_data)] y_data = y_data[~np.isnan(y_data)] x_data = x_data[y_data!=0] y_data = y_data[y_data!=0] axes_options = {'x': {'label':'Time', 'side':'bottom', 'num_ticks':8, 'tick_format':'%b %y'}, 'y': {'orientation':'vertical', 'side':'left', 'num_ticks':10}} if i==0: title = '' for x in bands: title += (x + ' ') title += ' timeseries' if new_plot: inMap.figure = bqplt.figure(title=title,layout={'max_height': '250px', 'width': '600px'}) else: if inMap.figure is not None: pass else: inMap.figure = bqplt.figure(title=title,layout={'max_height': '250px', 'width': '600px'}) scatt = bqplt.scatter(x_data, y_data, labels=[b], display_legend=True, colors=[color[i]], default_size=30, axes_options=axes_options) widget_control = WidgetControl(widget=inMap.figure, position='bottomright') if inMap.figure_widget is not None: inMap.map.remove_control(inMap.figure_widget) inMap.figure_widget = widget_control inMap.map.add_control(inMap.figure_widget) return
def add_widget_as_control(self, widget, position, first=False): """ Add widget as control in the given position Args: widget (dom.widget): Widget to convert as map control position (str): 'topleft', 'topright', 'bottomright', 'bottomlreft' first (Bool): Whether set the control as first or last element """ new_control = WidgetControl( widget=widget, position=position, transparent_bg=True ) if first == True: self.controls = tuple( [new_control] + [control for control in self.controls] ) else: self.controls = self.controls + tuple([new_control]) return
def plot(self, m, x_dim='x', y_dim='y', fit_bounds=True, rgb_dim=None, transform0=None, transform1=passthrough, transform2=coarsen(), transform3=passthrough, colormap=None, persist=True, dynamic=False, tile_dir=None, tile_height=256, tile_width=256, resampling=Resampling.nearest, debug_output=None): """Display an array as an interactive map. Assumes that the pixels are given on a regular grid (fixed spacing in x and y). Parameters ---------- m : ipyleaflet.Map The map on while to show the layer. y_dim : str, optional Name of the y dimension/coordinate (default: 'y'). x_dim : str, optional Name of the x dimension/coordinate (default: 'x'). rgb_dim : str, optional Name of the RGB dimension/coordinate (default: None). transform0 : function, optional Transformation over the whole DataArray. transform1 : function, optional Transformation over the visible DataArray. transform2 : function, optional Transformation over a tile before reprojection. transform3 : function, optional Transformation over a tile before saving to PNG. colormap : function, optional The colormap function to use for the tile PNG (default: matplotlib.pyplot.cm.inferno). persist : bool, optional Whether to keep the tile files (True) or not (False). dynamic : bool, optional Whether the map is dynamic (True) or not (False). If True then the tiles will refreshed each time the map is dragged or zoomed. tile_dir : str, optional The path to the tile directory (must be absolute). tile_height : int, optional The heiht of a tile in pixels (default: 256). tile_width : int, optional The width of a tile in pixels (default: 256). resampling : int, optional The resampling method to use, see rasterio.warp.reproject (default: Resampling.nearest). Returns ------- l : ipyleaflet.LocalTileLayer A handler to the layer that is added to the map. """ if debug_output is None: self.debug_output = Output() else: self.debug_output = debug_output with self.debug_output: if 'proj4def' in m.crs: # it's a custom projection if dynamic: raise RuntimeError('Dynamic maps are only supported for Web Mercator (EPSG:3857), not {}'.format(m.crs)) self.dst_crs = m.crs['proj4def'] self.web_mercator = False self.custom_proj = True elif m.crs['name'].startswith('EPSG'): epsg = m.crs['name'][4:] if dynamic and epsg != '3857': raise RuntimeError('Dynamic maps are only supported for Web Mercator (EPSG:3857), not {}'.format(m.crs)) self.dst_crs = 'EPSG:' + epsg self.web_mercator = epsg == '3857' self.custom_proj = False else: raise RuntimeError('Unsupported map projection: {}'.format(m.crs)) self.nodata = self._da.rio.nodata var_dims = self._da.dims expected_dims = [y_dim, x_dim] if rgb_dim is not None: expected_dims.append(rgb_dim) if set(var_dims) != set(expected_dims): raise ValueError( "Invalid dimensions in DataArray: " "should include only {}, found {}." .format(tuple(expected_dims), var_dims) ) if rgb_dim is not None and colormap is not None: raise ValueError( "Cannot have a RGB dimension and a " "colormap at the same time." ) elif rgb_dim is None: if colormap is None: colormap = plt.cm.inferno if transform0 is None: transform0 = normalize else: # there is a RGB dimension if transform0 is None: transform0 = passthrough self.resampling = resampling self.tile_dir = tile_dir self.persist = persist self.attrs = self._da.attrs self.m = m self.dynamic = dynamic self.tile_width = tile_width self.tile_height = tile_height self.transform0 = transform0 self.transform1 = transform1 self.transform2 = transform2 self.transform3 = transform3 self.colormap = colormap if self.dynamic: self.persist = False self.tile_dir = None self._da = self._da.rename({y_dim: 'y', x_dim: 'x'}) if rgb_dim is None: self.is_rgb = False else: self.is_rgb = True self._da = self._da.rename({rgb_dim: 'rgb'}) # ensure latitudes are descending if np.any(np.diff(self._da.y.values) >= 0): self._da = self._da.sel(y=slice(None, None, -1)) # infer grid specifications (assume a rectangular grid) y = self._da.y.values x = self._da.x.values self.x_left = float(x.min()) self.x_right = float(x.max()) self.y_lower = float(y.min()) self.y_upper = float(y.max()) self.dx = float((self.x_right - self.x_left) / (x.size - 1)) self.dy = float((self.y_upper - self.y_lower) / (y.size - 1)) if fit_bounds: asyncio.ensure_future(self.async_fit_bounds()) else: asyncio.ensure_future(self.async_wait_for_bounds()) self.l = LocalTileLayer() if self._da.name is not None: self.l.name = self._da.name self._da_notransform = self._da self.spinner = Spinner() self.spinner.radius = 5 self.spinner.length = 3 self.spinner.width = 5 self.spinner.lines = 8 self.spinner.color = '#000000' self.spinner.layout.height = '30px' self.spinner.layout.width = '30px' self.spinner_control = WidgetControl(widget=self.spinner, position='bottomright') return self.l
def main_toolbar(m): padding = "0px 0px 0px 5px" # upper, right, bottom, left toolbar_button = widgets.ToggleButton( value=False, tooltip="Toolbar", icon="wrench", layout=widgets.Layout(width="28px", height="28px", padding=padding), ) close_button = widgets.ToggleButton( value=False, tooltip="Close the tool", icon="times", button_style="primary", layout=widgets.Layout(height="28px", width="28px", padding=padding), ) toolbar = widgets.HBox([toolbar_button]) def close_click(change): if change["new"]: toolbar_button.close() close_button.close() toolbar.close() close_button.observe(close_click, "value") rows = 2 cols = 3 grid = widgets.GridspecLayout(rows, cols, grid_gap="0px", layout=widgets.Layout(width="96px")) icons = ["folder-open", "map", "gears", "filter", "map-marker", "question"] for i in range(rows): for j in range(cols): grid[i, j] = widgets.Button(description="", button_style="primary", icon=icons[i * rows + j], layout=widgets.Layout(width="28px", padding="0px")) toolbar = widgets.VBox([toolbar_button]) def toolbar_click(change): if change["new"]: toolbar.children = [ widgets.HBox([close_button, toolbar_button]), grid ] else: toolbar.children = [toolbar_button] toolbar_button.observe(toolbar_click, "value") toolbar_ctrl = WidgetControl(widget=toolbar, position="topright") m.add_control(toolbar_ctrl) output = widgets.Output() output_ctrl = WidgetControl(widget=output, position="topright") buttons = widgets.ToggleButtons( value=None, options=["Apply", "Reset", "Close"], tooltips=["Apply", "Reset", "Close"], button_style="primary", ) buttons.style.button_width = "80px" data_dir = os.path.abspath('./data') # File Chooser Widget fc = FileChooser(data_dir) fc.use_dir_icons = True fc.filter_pattern = ['*.shp', '*.geojson', '*.json'] filechooser_widget = widgets.VBox([fc, buttons]) def button_click(change): if change["new"] == "Apply" and fc.selected is not None: if fc.selected.endswith(".shp"): m.add_shapefile(fc.selected, layer_name="Shapefile") elif fc.selected.endswith(".geojson"): m.add_geojson(fc.selected, layer_name="GeoJSON") elif fc.selected.endswith(".json"): m.add_geojson(fc.selected, layer_name="GeoJSON") elif change["new"] == "Reset": fc.reset() elif change["new"] == "Close": fc.reset() m.remove_control(output_ctrl) buttons.observe(button_click, "value") # Basemap Widget from .basemaps import _ee_basemaps dropdown_basemap = widgets.Dropdown( options=list(_ee_basemaps.keys()), value="ROADMAP", layout=widgets.Layout(width="200px"), description="Basemaps", ) close_button_basemap = widgets.Button( icon="times", tooltip="Close the basemap widget", button_style="primary", layout=widgets.Layout(width="32px"), ) basemap_widget = widgets.HBox([dropdown_basemap, close_button_basemap]) def on_click(change): basemap_name = change["new"] if len(m.layers) == 1: old_basemap = m.layers[0] else: old_basemap = m.layers[1] m.substitute_layer(old_basemap, _ee_basemaps[basemap_name]) dropdown_basemap.observe(on_click, "value") def close_click(change): if m.basemap_ctrl is not None and m.basemap_ctrl in m.controls: m.remove_control(m.basemap_ctrl) basemap_widget.close() close_button_basemap.on_click(close_click) basemap_control = WidgetControl(widget=basemap_widget, position="topright") m.basemap_ctrl = basemap_control # Select Layer for Filtering Widget layers = [ layer.name for layer in m.layers if not isinstance(layer, ipyleaflet.TileLayer) ] dropdown_layer = widgets.Dropdown(options=layers, description='Layer:') dropdown_layer_field = widgets.Dropdown(description='Field:') dropdown_layer_field_value = widgets.Dropdown(description='Value:') out_filter_layer = widgets.Output() def on_click_layer(change): with out_filter_layer: out_filter_layer.clear_output() dropdown_layer_field.options = list( m.find_layer( change.new).data['features'][0]['properties'].keys()) dropdown_layer.observe(on_click_layer, names="value") out_filter_layer_field = widgets.Output() def on_click_layer_field(change): with out_filter_layer_field: out_filter_layer_field.clear_output() field_values = set() for record in m.find_layer(dropdown_layer.value).data['features']: field_values.add( record['properties'][dropdown_layer_field.value]) dropdown_layer_field_value.options = sorted(field_values) dropdown_layer_field.observe(on_click_layer_field, names="value") add_filter_layer = widgets.Button( icon="plus", tooltip="Add a layer based on the filter options", button_color="lightgreen", layout=widgets.Layout(width="32px")) out_click_add_filter_layer = widgets.Output() def click_add_filter_layer(change): import itertools import copy data = copy.deepcopy(m.find_layer(dropdown_layer.value).data) filter_data = [ record for record in data['features'] if record['properties'][ dropdown_layer_field.value] == dropdown_layer_field_value.value ] data['features'] = filter_data style = { "stroke": True, "color": "#000000", "weight": 2, "opacity": 1, "fill": True, "fillColor": "#0000ff", "fillOpacity": 0.4, } geojson = ipyleaflet.GeoJSON(data=data, style=style, name="{} - {} - {} Layer".format( dropdown_layer.value, dropdown_layer_field.value, dropdown_layer_field_value.value)) m.add_layer(geojson) add_filter_layer.on_click(click_add_filter_layer) close_dropdown_layer = widgets.Button(icon="times", tooltip="Close the filter widget", button_style="primary", layout=widgets.Layout(width="32px")) box_layout = widgets.Layout(display='flex', flex_flow='row', align_items='stretch', width='70%') filter_buttons_box = widgets.Box([close_dropdown_layer, add_filter_layer]) filter_dropdown_box = widgets.Box( [dropdown_layer, dropdown_layer_field, dropdown_layer_field_value]) filter_widget = widgets.HBox([filter_dropdown_box, filter_buttons_box]) def close_click_dropdown(change): filter_widget.close() close_dropdown_layer.on_click(close_click_dropdown) filter_layer_control = WidgetControl(widget=filter_widget, position="bottomright") m.filter_layer_ctrl = filter_layer_control # Add CSV Widget buttons_csv = widgets.ToggleButtons( value=None, options=["Display", "Close"], tooltips=["Display", "Close"], button_style="primary", ) buttons_csv.style.button_width = "80px" layer_name_csv = widgets.Text(value="Untitled" + random_string(), placeholder="Type the layer name here", description="Layer name:", disabled=False) #observe(layer_name_csv, "value") fc_csv = FileChooser(data_dir) fc_csv.use_dir_icons = True fc_csv.filter_pattern = ['*.csv'] add_csv_widget = widgets.VBox([fc_csv, layer_name_csv, buttons_csv]) def button_click_csv(change): if change["new"] == "Display" and fc_csv.selected is not None: layer_name = "RandomForNow" m.add_points_from_csv(fc_csv.selected, layer_name=layer_name) elif change["new"] == "Close": fc_csv.reset() m.remove_control(output_ctrl) buttons_csv.observe(button_click_csv, "value") def tool_click(b): with output: output.clear_output() if b.icon == "folder-open": display(filechooser_widget) m.add_control(output_ctrl) elif b.icon == "filter": dropdown_layer.options = [ layer.name for layer in m.layers if not isinstance(layer, ipyleaflet.TileLayer) ] # display(layers) display(filter_widget) m.add_control(filter_layer_control) elif b.icon == "map": display(basemap_widget) m.add_control(basemap_control) elif b.icon == "gears": import whiteboxgui.whiteboxgui as wbt if hasattr(m, "whitebox") and m.whitebox is not None: if m.whitebox in m.controls: m.remove_control(m.whitebox) tools_dict = wbt.get_wbt_dict() wbt_toolbox = wbt.build_toolbox(tools_dict, max_width="800px", max_height="500px") wbt_control = WidgetControl(widget=wbt_toolbox, position="bottomright") m.whitebox = wbt_control m.add_control(wbt_control) elif b.icon == "map-marker": display(add_csv_widget) m.add_control(output_ctrl) # elif b.icon == "question": print(f"You clicked the {b.icon} button") for i in range(rows): for j in range(cols): tool = grid[i, j] tool.on_click(tool_click)
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
def __init__( self, a_map: Map, description: str = "H3", position: str = "topright", ): """Instantiate a tile grid tool and place it on a map. """ self._max_zoom_delta = -1 self.tile_id = "" self.level = int(a_map.zoom) style = {"color": "#888888", "weight": 1, "fillOpacity": 0} hover_style = {"weight": 3, "fillOpacity": 0.1} self.gj = GeoJSON(data=geojson.Feature(), name=description, style=style, hover_style=hover_style) min_, max_ = 0, int(a_map.zoom) + self._max_zoom_delta self.slider = IntSlider(description=description, min=min_, max=max_, value=self.level) self.ht = HTML(f"ID: {self.tile_id} Map zoom: {int(a_map.zoom)}") self.close_btn = Button( icon="times", button_style="info", tooltip="Close the widget", layout=Layout(width="32px"), ) self.widget = HBox([self.slider, self.ht, self.close_btn]) def hover(event, feature, **kwargs): if event == "mouseover": self.tile_id = feature["id"] self.ht.value = f"{self.tile_id} Map zoom: {int(a_map.zoom)}" def slider_moved(event): if event["type"] == "change" and event["name"] == "value": self.level = event["new"] # Ipyleaflet buglet(?): This name is updated in the GeoJSON layer, # but not in the LayersControl! self.gj.name = f"H3" # level {self.level}" self.tile_id = "" map_interacted({ "type": "change", "name": "bounds", "owner": a_map }) self.slider.observe(slider_moved) def map_interacted(event): if event["type"] == "change" and event["name"] == "bounds": self.ht.value = f"{self.tile_id}, Map zoom: {int(a_map.zoom)}" self.slider.max = int(a_map.zoom) + self._max_zoom_delta m = event["owner"] b_poly = list(m.bounds_polygon) b_poly += [tuple(b_poly[0])] # m += Polyline(locations=b_poly) poly = geojson.Polygon(coordinates=[[(p[0], p[1]) for p in b_poly]]) hexagons = list(h3.polyfill(dict(poly), self.slider.value)) fc = geojson.FeatureCollection(features=[ geojson.Polygon(coordinates=h3.h3_set_to_multi_polygon( [h], geo_json=True)[0], id=h) for h in hexagons ]) self.gj.data = fc # Ipyleaflet buglet(?): This name is updated in the GeoJSON layer, # but not in the LayersControl! self.gj.name = f"H3" # level {self.level}" self.gj.on_hover(hover) def close_click(change): self.widget.children = [] self.widget.close() self.close_btn.on_click(close_click) a_map += self.gj a_map.observe(map_interacted) map_interacted({"type": "change", "name": "bounds", "owner": a_map}) self.widget_control = WidgetControl(widget=self.widget, position=position) a_map.add_control(self.widget_control)
def open_data_widget(m): """A widget for opening local vector/raster data. Args: m (object): geemap.Map """ tool_output = widgets.Output() tool_output_ctrl = WidgetControl(widget=tool_output, position="topright") if m.tool_output_ctrl is not None and m.tool_output_ctrl in m.controls: m.remove_control(m.tool_output_ctrl) file_type = widgets.ToggleButtons( options=["Shapefile", "GeoJSON", "GeoTIFF"], tooltips=[ "Open a shapefile", "Open a GeoJSON file", "Open a GeoTIFF", ], ) file_chooser = FileChooser(os.getcwd()) file_chooser.filter_pattern = "*.shp" file_chooser.use_dir_icons = True style = {"description_width": "initial"} layer_name = widgets.Text( value="Shapefile", description="Enter a layer name:", tooltip="Enter a layer name for the selected file", style=style, layout=widgets.Layout(width="454px"), ) ok_cancel = widgets.ToggleButtons( value=None, options=["Apply", "Reset", "Close"], tooltips=["Apply", "Reset", "Close"], button_style="primary", ) bands = widgets.Text( value="1", description="Bands:", tooltip="Enter a list of band indices", style=style, layout=widgets.Layout(width="110px"), ) colormap = widgets.Dropdown( options=[], value=None, description="colormap:", layout=widgets.Layout(width="172px"), style=style, ) x_dim = widgets.Text( value="x", description="x_dim:", tooltip="The x dimension", style=style, layout=widgets.Layout(width="80px"), ) y_dim = widgets.Text( value="y", description="y_dim:", tooltip="The xydimension", style=style, layout=widgets.Layout(width="80px"), ) raster_options = widgets.HBox() main_widget = widgets.VBox( [file_type, file_chooser, layer_name, raster_options, ok_cancel] ) tool_output.clear_output() with tool_output: display(main_widget) # def chooser_callback(chooser): # if len(layer_name.value) == 0 and file_chooser.selected is not None: # layer_name.value = os.path.splitext(file_chooser.selected_filename)[0] def bands_changed(change): if change["new"] and "," in change["owner"].value: colormap.value = None colormap.disabled = True else: colormap.disabled = False bands.observe(bands_changed, "value") def file_type_changed(change): ok_cancel.value = None file_chooser.default_path = os.getcwd() file_chooser.reset() layer_name.value = file_type.value if change["new"] == "Shapefile": file_chooser.filter_pattern = "*.shp" raster_options.children = [] elif change["new"] == "GeoJSON": file_chooser.filter_pattern = "*.geojson" raster_options.children = [] elif change["new"] == "GeoTIFF": import matplotlib.pyplot as plt file_chooser.filter_pattern = "*.tif" colormap.options = plt.colormaps() colormap.value = "terrain" raster_options.children = [bands, colormap, x_dim, y_dim] def ok_cancel_clicked(change): if change["new"] == "Apply": m.default_style = {"cursor": "wait"} file_path = file_chooser.selected if file_path is not None: ext = os.path.splitext(file_path)[1] with tool_output: if ext.lower() == ".shp": ee_object = shp_to_ee(file_path) m.addLayer(ee_object, {}, layer_name.value) m.centerObject(ee_object) elif ext.lower() == ".geojson": ee_object = geojson_to_ee(file_path) m.addLayer(ee_object, {}, layer_name.value) m.centerObject(ee_object) elif ext.lower() == ".tif": sel_bands = [int(b.strip()) for b in bands.value.split(",")] m.add_raster( image=file_path, bands=sel_bands, layer_name=layer_name.value, colormap=colormap.value, x_dim=x_dim.value, y_dim=y_dim.value, ) else: print("Please select a file to open.") m.toolbar_reset() m.default_style = {"cursor": "default"} elif change["new"] == "Reset": file_chooser.reset() tool_output.clear_output() with tool_output: display(main_widget) m.toolbar_reset() elif change["new"] == "Close": if m.tool_output_ctrl is not None and m.tool_output_ctrl in m.controls: m.remove_control(m.tool_output_ctrl) m.tool_output_ctrl = None m.toolbar_reset() ok_cancel.value = None file_type.observe(file_type_changed, names="value") ok_cancel.observe(ok_cancel_clicked, names="value") # file_chooser.register_callback(chooser_callback) m.add_control(tool_output_ctrl) m.tool_output_ctrl = tool_output_ctrl
def __init__(self, questionnaire_tile, aoi_model, area_tile, theme_tile): # add the explanation mkd = sw.Markdown(" \n".join(cm.map.txt)) # create a save widget self.save = cw.ExportMap() # create the map self.m = sm.SepalMap(dc=True).hide_dc() self.m.add_control(WidgetControl(widget=self.save, position="topleft")) self.m.add_colorbar(colors=cp.red_to_green, vmin=1, vmax=5) # create a window to display AOI information self.html = HTML() self.html.layout.margin = "0em 2em 0em 20em" control = WidgetControl(widget=self.html, position="bottomright") self.m.add_control(control) # drawing managment self.draw_features = deepcopy(self.EMPTY_FEATURES) self.colors = [] self.name_dialog = cw.CustomAoiDialog() # create a layout with 2 btn self.map_btn = sw.Btn(cm.compute.btn, class_="ma-2") self.compute_dashboard = sw.Btn(cm.map.compute_dashboard, class_="ma-2", disabled=True) # models self.layer_model = questionnaire_tile.layer_model self.question_model = questionnaire_tile.question_model self.aoi_model = aoi_model # create the shape loader self.load_shape = cw.LoadShapes() # get the dashboard tile self.area_tile = area_tile self.theme_tile = theme_tile # init the final layers self.wlc_outputs = None self.area_dashboard = None self.theme_dashboard = None # create the tile super().__init__( id_="map_widget", title=cm.map.title, inputs=[mkd, self.load_shape, self.m, self.name_dialog], alert=sw.Alert(), btn=v.Layout(children=[self.map_btn, self.compute_dashboard]), ) # decorate the function self._compute = su.loading_button(self.alert, self.map_btn, debug=True)(self._compute) self._dashboard = su.loading_button(self.alert, self.compute_dashboard, debug=True)(self._dashboard) # add js behaviour self.compute_dashboard.on_event("click", self._dashboard) self.m.dc.on_draw(self._handle_draw) self.map_btn.on_event("click", self._compute) self.load_shape.btn.on_event("click", self._load_shapes) self.name_dialog.observe(self.save_draw, "value")
def __init__( self, a_map: Map, description: str = "Mercator", position: str = "topright", ): """Instantiate a tile grid tool and place it on a map. """ self._max_zoom_delta = 4 self.tile_id = "" self.level = int(a_map.zoom) style = {"color": "#888888", "weight": 1, "fillOpacity": 0} hover_style = {"weight": 3, "fillOpacity": 0.1} self.gj = GeoJSON(data=geojson.Feature(), name=description, style=style, hover_style=hover_style) min, max = 0, int(a_map.zoom) + self._max_zoom_delta self.slider = IntSlider(description=description, min=min, max=max, value=self.level) self.ht = HTML(f"ID: {self.tile_id} Map zoom: {int(a_map.zoom)}") self.close_btn = Button( icon="times", button_style="info", tooltip="Close the widget", layout=Layout(width="32px"), ) self.widget = HBox([self.slider, self.ht, self.close_btn]) def hover(event, feature, **kwargs): if event == "mouseover": self.tile_id = feature["id"] self.ht.value = f"{self.tile_id} Map zoom: {int(a_map.zoom)}" def slider_moved(event): if event["type"] == "change" and event["name"] == "value": self.level = event["new"] # Ipyleaflet buglet(?): This name is updated in the GeoJSON layer, # but not in the LayersControl! self.gj.name = f"Mercator" # level {self.level}" self.tile_id = "" map_interacted({ "type": "change", "name": "bounds", "owner": a_map }) self.slider.observe(slider_moved) def map_interacted(event): if event["type"] == "change" and event["name"] == "bounds": self.ht.value = f"{self.tile_id}, Map zoom: {int(a_map.zoom)}" self.slider.max = int(a_map.zoom) + self._max_zoom_delta m = event["owner"] ((south, west), (north, east)) = m.bounds b_poly = list(m.bounds_polygon) b_poly += [tuple(b_poly[0])] # m += Polyline(locations=b_poly) # Attention in the order of west, south, east, north! tiles = mercantile.tiles(west, south, east, north, zooms=self.level) features = [mercantile.feature(t) for t in tiles] self.gj.data = geojson.FeatureCollection(features=features) # Ipyleaflet buglet(?): This name is updated in the GeoJSON layer, # but not in the LayersControl! self.gj.name = f"Mercator" # level {self.level}" self.gj.on_hover(hover) def close_click(change): self.widget.children = [] self.widget.close() self.close_btn.on_click(close_click) a_map += self.gj a_map.observe(map_interacted) map_interacted({"type": "change", "name": "bounds", "owner": a_map}) self.widget_control = WidgetControl(widget=self.widget, position=position) a_map.add_control(self.widget_control)
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 __init__(self, basemaps=[], dc=False, vinspector=False, gee=True, **kwargs): self.world_copy_jump = True # Init the map super().__init__( ee_initialize= False, # we take care of the initialization on our side add_google_map=False, center=[0, 0], zoom=2, **kwargs) # init ee self.ee = gee if gee: su.init_ee() # init the rasters self.loaded_rasters = {} # add the basemaps self.clear_layers() if len(basemaps): [self.add_basemap(basemap) for basemap in set(basemaps)] else: self.add_basemap('CartoDB.DarkMatter') # add the base controls self.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)) # change the prefix for control in self.controls: if type(control) == AttributionControl: control.prefix = "SEPAL" # specific drawing control self.set_drawing_controls(dc) # Add value inspector self.w_vinspector = widgets.Checkbox( value=False, description='Inspect values', indent=False, layout=widgets.Layout(width='18ex')) if vinspector: self.add_control( WidgetControl(widget=self.w_vinspector, position='topright')) link((self.w_vinspector, 'value'), (self, 'vinspector')) # Create output space for raster interaction self.output_r = widgets.Output(layout={'border': '1px solid black'}) self.output_control_r = WidgetControl(widget=self.output_r, position='bottomright') self.add_control(self.output_control_r) # define interaction with rasters self.on_interaction(self._raster_interaction)
def tool_template(m): widget_width = "250px" padding = "0px 0px 0px 5px" # upper, right, bottom, left toolbar_button = widgets.ToggleButton( value=False, tooltip="Toolbar", icon="gear", layout=widgets.Layout(width="28px", height="28px", padding="0px 0px 0px 4px"), ) close_button = widgets.ToggleButton( value=False, tooltip="Close the tool", icon="times", button_style="primary", layout=widgets.Layout(height="28px", width="28px", padding="0px 0px 0px 4px"), ) checkbox = widgets.Checkbox( description="Checkbox", indent=False, layout=widgets.Layout(padding=padding, width=widget_width), ) dropdown = widgets.Dropdown( options=["Option 1", "Option 2", "Option 3"], value=None, description="Dropdown:", layout=widgets.Layout(width=widget_width, padding=padding), style={"description_width": "initial"}, ) int_slider = widgets.IntSlider( min=1, max=100, description="Int Slider: ", readout=False, continuous_update=True, layout=widgets.Layout(width="220px", padding=padding), style={"description_width": "initial"}, ) int_slider_label = widgets.Label() widgets.jslink((int_slider, "value"), (int_slider_label, "value")) float_slider = widgets.FloatSlider( min=1, max=100, description="Float Slider: ", readout=False, continuous_update=True, layout=widgets.Layout(width="220px", padding=padding), style={"description_width": "initial"}, ) float_slider_label = widgets.Label() widgets.jslink((float_slider, "value"), (float_slider_label, "value")) color = widgets.ColorPicker( concise=False, description="Color:", value="white", style={"description_width": "initial"}, layout=widgets.Layout(width=widget_width, padding=padding), ) text = widgets.Text( value="", description="Textbox:", placeholder="Placeholder", style={"description_width": "initial"}, layout=widgets.Layout(width=widget_width, padding=padding), ) textarea = widgets.Textarea( placeholder="Placeholder", layout=widgets.Layout(width=widget_width), ) buttons = widgets.ToggleButtons( value=None, options=["Apply", "Reset", "Close"], tooltips=["Apply", "Reset", "Close"], button_style="primary", ) buttons.style.button_width = "80px" output = widgets.Output( layout=widgets.Layout(width=widget_width, padding=padding)) toolbar_widget = widgets.VBox() toolbar_widget.children = [toolbar_button] toolbar_header = widgets.HBox() toolbar_header.children = [close_button, toolbar_button] toolbar_footer = widgets.VBox() toolbar_footer.children = [ checkbox, widgets.HBox([int_slider, int_slider_label]), widgets.HBox([float_slider, float_slider_label]), dropdown, text, color, textarea, buttons, output, ] toolbar_event = ipyevents.Event( source=toolbar_widget, watched_events=["mouseenter", "mouseleave"]) def handle_toolbar_event(event): if event["type"] == "mouseenter": toolbar_widget.children = [toolbar_header, toolbar_footer] elif event["type"] == "mouseleave": if not toolbar_button.value: toolbar_widget.children = [toolbar_button] toolbar_button.value = False close_button.value = False toolbar_event.on_dom_event(handle_toolbar_event) def toolbar_btn_click(change): if change["new"]: close_button.value = False toolbar_widget.children = [toolbar_header, toolbar_footer] else: if not close_button.value: toolbar_widget.children = [toolbar_button] toolbar_button.observe(toolbar_btn_click, "value") def close_btn_click(change): if change["new"]: toolbar_button.value = False if m.tool_control is not None and m.tool_control in m.controls: m.remove_control(m.tool_control) m.tool_control = None toolbar_widget.close() close_button.observe(close_btn_click, "value") def button_clicked(change): if change["new"] == "Apply": with output: output.clear_output() print("Running ...") elif change["new"] == "Reset": textarea.value = "" output.clear_output() elif change["new"] == "Close": m.toolbar_reset() if m.tool_control is not None and m.tool_control in m.controls: m.remove_control(m.tool_control) m.tool_control = None toolbar_widget.close() buttons.value = None buttons.observe(button_clicked, "value") toolbar_control = WidgetControl(widget=toolbar_widget, position="topright") if toolbar_control not in m.controls: m.add_control(toolbar_control) m.tool_control = toolbar_control toolbar_button.value = True
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): """Add a widget to the map that allows styling some given layer. At the moment only the stroke color, opacity and weight can be changed using a color picker and sliders. Dash array might follow later. :param m: The map object to which to add a styling widget. :param layer: The layer object which is to be styled. :param attr_name: The layer's attribute name storing the style object. This is usually one of: "style", "hover_style", and "point_style" :param kind: The kind of style, either "stroke" or "fill". :param orientation: The orientation of the UI elements, either "horizontal" (default) or "vertical". :param transparent: A flag to indicate if the widget background should be transparent (default: ``False``). :param position: The map corner where this widget will be placed. TODO: The UI elements should reflect changes to the layer triggered by others. """ assert kind in ["stroke", "fill"] assert orientation in ["horizontal", "vertical"] def restyle(change): if change["type"] != "change": return owner = change["owner"] style_copy = copy.copy(getattr(layer, attr_name)) attr_map = { p: "color" if kind == "stroke" else "fillColor", o: "opacity" if kind == "stroke" else "fillOpacity", w: "weight" } if owner in [p, o, w]: style_copy[attr_map[owner]] = owner.value setattr(layer, attr_name, style_copy) def close(button): a_map.remove_control(wc) attr = getattr(layer, attr_name) style = getattr(layer, "style") b = ToggleButton(description="Stroke", value=True, tooltip="Stroke or not?") dummy = ToggleButton(value=not b.value) b.layout.width = "80px" name = "color" if kind == "stroke" else "fillColor" p = ColorPicker(value=attr.get(name, style.get(name, "#3885ff"))) p.layout.width = "100px" name = "opacity" if kind == "stroke" else "fillOpacity" o = FloatSlider(min=0, max=1, value=attr.get(name, style.get(name, 0.5))) o.layout.width = "200px" w = IntSlider(min=0, max=50, value=attr.get("weight", style.get("weight", 5))) w.layout.width = "200px" layout = Layout(width="28px", height="28px", padding="0px 0px 0px 4px") q = Button(tooltip="Close", icon="close", button_style="info", layout=layout) for el in [p, o, w] if kind == "stroke" else [p, o]: link((dummy, "value"), (el, "disabled")) p.observe(restyle) o.observe(restyle) if kind == "stroke": w.observe(restyle) else: w.disabled = True q.on_click(close) desc = HTML(f"{kind} {attr_name}") if orientation == "horizontal": self.widget = HBox([desc, p, w, o, q]) elif orientation == "vertical": self.widget = VBox([HBox([desc, q]), p, w, o]) wc = WidgetControl(widget=self.widget, position=position, transparent_bg=transparent) a_map.add_control(wc)
# Add Earth Engine data fc = ee.FeatureCollection('TIGER/2018/Counties') Map.addLayer(fc, {}, 'US Counties') states = ee.FeatureCollection('TIGER/2018/States') # Map.addLayer(states, {}, 'US States') Map # Designe interactive widgets style = {'description_width': 'initial'} output_widget = widgets.Output(layout={'border': '1px solid black'}) output_control = WidgetControl(widget=output_widget, position='bottomright') admin1_widget = widgets.Text( description='State:', value='Tennessee', width=200, style=style ) admin2_widget = widgets.Text( description='County:', value='Knox', width=300, style=style )
def addLayer(inMap, path, name, clip=[0, 0.8], bands=None): #Check the filetype: netcdf or geotiff if path.split('.')[-1] == 'nc': da = xr.open_dataset(path) if 't' in da.dims: da = da.drop('t').squeeze('t').to_array().astype(np.float32) elif 'time' in da.dims: da = da.drop('time').squeeze('time').to_array().astype(np.float32) else: da = da.to_array().astype(np.float32) if 'variable' in da.dims and 'bands' in da.dims: da = da.drop('variable').squeeze('variable').rename( {'bands': 'variable'}) else: da = xr.open_rasterio(path) if 't' in da.dims: da = da.rename({ 'band': 'variable' }).drop('t').squeeze('t').astype(np.float32) else: da = da.rename({'band': 'variable'}).astype(np.float32) rds4326 = da.rio.reproject("epsg:4326") rds4326.name = name rds4326 = rds4326.rio.write_crs(4326) # WGS 84 if bands is not None: rds4326 = rds4326.loc[dict(variable=bands)] opacity_slider = FloatSlider(description=name + ' opacity:', min=0, max=1, value=1) def set_opacity(change): l.opacity = change['new'] if (len(rds4326.variable) == 3): rds4326 = rds4326.clip(clip[0], clip[1]) / clip[1] * 255 rds4326 = rds4326.fillna(0).rio.write_nodata(0) rds4326 = rds4326.chunk((1000, 1000)) l = rds4326.leaflet.plot(inMap.map, rgb_dim='variable') opacity_slider.observe(set_opacity, names='value') slider_control = WidgetControl(widget=opacity_slider, position='bottomleft') inMap.map.add_control(slider_control) elif (len(rds4326.variable) == 1): rds4326 = rds4326[0] rds4326 = rds4326.clip(clip[0], clip[1]) rds4326 = rds4326.fillna(0).rio.write_nodata(0) rds4326 = rds4326.chunk((1000, 1000)) cmap = plt.cm.get_cmap('Greys_r') l = rds4326.leaflet.plot(inMap.map, colormap=cmap) def set_opacity(change): l.opacity = change['new'] opacity_slider.observe(set_opacity, names='value') slider_control = WidgetControl(widget=opacity_slider, position='bottomleft') inMap.map.add_control(slider_control) else: rds4326 = rds4326[0] rds4326 = rds4326.fillna(0).rio.write_nodata(0) rds4326 = rds4326.chunk((1000, 1000)) rds4326 = rds4326.clip(clip[0], clip[1]) cmap = plt.cm.get_cmap('Greys_r') l = rds4326.leaflet.plot(inMap.map, colormap=cmap) def set_opacity(change): l.opacity = change['new'] opacity_slider.observe(set_opacity, names='value') slider_control = WidgetControl(widget=opacity_slider, position='bottomleft') inMap.map.add_control(slider_control) return
def collect_samples(m): full_widget = widgets.VBox() layout = widgets.Layout(width="100px") prop_label = widgets.Label( value="Property", layout=widgets.Layout(display="flex", justify_content="center", width="100px"), ) value_label = widgets.Label( value="Value", layout=widgets.Layout(display="flex", justify_content="center", width="100px"), ) color_label = widgets.Label( value="Color", layout=widgets.Layout(display="flex", justify_content="center", width="100px"), ) prop_text1 = widgets.Text(layout=layout, placeholder="Required") value_text1 = widgets.Text(layout=layout, placeholder="Integer") prop_text2 = widgets.Text(layout=layout, placeholder="Optional") value_text2 = widgets.Text(layout=layout, placeholder="String") color = widgets.ColorPicker( concise=False, value="#3388ff", layout=layout, style={"description_width": "initial"}, ) buttons = widgets.ToggleButtons( value=None, options=["Apply", "Clear", "Close"], tooltips=["Apply", "Clear", "Close"], button_style="primary", ) buttons.style.button_width = "99px" def button_clicked(change): if change["new"] == "Apply": if len(color.value) != 7: color.value = "#3388ff" draw_control = DrawControl( marker={"shapeOptions": {"color": color.value}}, rectangle={"shapeOptions": {"color": color.value}}, polygon={"shapeOptions": {"color": color.value}}, circlemarker={}, polyline={}, edit=False, remove=False, ) controls = [] old_draw_control = None for control in m.controls: if isinstance(control, DrawControl): controls.append(draw_control) old_draw_control = control else: controls.append(control) m.controls = tuple(controls) old_draw_control.close() m.draw_control = draw_control train_props = {} if prop_text1.value != "" and value_text1.value != "": train_props[prop_text1.value] = int(value_text1.value) if prop_text2.value != "" and value_text2.value != "": train_props[prop_text2.value] = value_text2.value if color.value != "": train_props["color"] = color.value # Handles draw events def handle_draw(target, action, geo_json): from .geemap import ee_tile_layer try: geom = geojson_to_ee(geo_json, False) m.user_roi = geom if len(train_props) > 0: feature = ee.Feature(geom, train_props) else: feature = ee.Feature(geom) m.draw_last_json = geo_json m.draw_last_feature = feature if action == "deleted" and len(m.draw_features) > 0: m.draw_features.remove(feature) m.draw_count -= 1 else: m.draw_features.append(feature) m.draw_count += 1 collection = ee.FeatureCollection(m.draw_features) m.user_rois = collection ee_draw_layer = ee_tile_layer( collection, {"color": "blue"}, "Drawn Features", False, 0.5 ) draw_layer_index = m.find_layer_index("Drawn Features") if draw_layer_index == -1: m.add_layer(ee_draw_layer) m.draw_layer = ee_draw_layer else: m.substitute_layer(m.draw_layer, ee_draw_layer) m.draw_layer = ee_draw_layer except Exception as e: m.draw_count = 0 m.draw_features = [] m.draw_last_feature = None m.draw_layer = None m.user_roi = None m.roi_start = False m.roi_end = False print("There was an error creating Earth Engine Feature.") raise Exception(e) draw_control.on_draw(handle_draw) elif change["new"] == "Clear": prop_text1.value = "" value_text1.value = "" prop_text2.value = "" value_text2.value = "" color.value = "#3388ff" elif change["new"] == "Close": m.toolbar_reset() if m.training_ctrl is not None and m.training_ctrl in m.controls: m.remove_control(m.training_ctrl) full_widget.close() buttons.value = None buttons.observe(button_clicked, "value") full_widget.children = [ widgets.HBox([prop_label, value_label, color_label]), widgets.HBox([prop_text1, value_text1, color]), widgets.HBox([prop_text2, value_text2, color]), buttons, ] widget_control = WidgetControl(widget=full_widget, position="topright") m.add_control(widget_control) m.training_ctrl = widget_control