def set_data(self, dataset, geometry, name, aoi_name): """set the dataset and the geometry to allow the download""" self.geometry = geometry self.dataset = dataset self.name = name self.aoi_name = aoi_name # add vizualization properties to the image # cast to image as set is a ee.Element method self.dataset = ee.Image( dataset.set({ "visualization_0_bands": "constant", "visualization_0_max": 5, "visualization_0_min": 0, "visualization_0_name": "restauration index", "visualization_0_palette": ",".join(cp.no_data_color + cp.gradient(5)), "visualization_0_type": "continuous", })) return self
def _apply(self, widget, event, data): """download the dataset using the given parameters""" folder = Path(ee.data.getAssetRoots()[0]["id"]) # check if a dataset is existing if self.dataset == None or self.geometry == None: return self # set the parameters name = self.name or dt.now().strftime("%Y-%m-%d_%H-%M-%S") export_params = { "image": self.dataset, "description": name, "scale": self.w_scale.v_model, "region": self.geometry, "maxPixels": 1e13, } # launch the task if self.w_method.v_model == "gee": export_params.update(assetId=str(folder / name)) task = ee.batch.Export.image.toAsset(**export_params) task.start() self.alert.add_msg( "the task have been launched in your GEE acount", "success") elif self.w_method.v_model == "sepal": gdrive = cs.gdrive() files = gdrive.get_files(name) if files == []: task = ee.batch.Export.image.toDrive(**export_params) task.start() gee.wait_for_completion(name, self.alert) files = gdrive.get_files(name) # save everything in the same folder as the json file # no need to create it it's created when the recipe is saved result_dir = cp.result_dir / aoi_name tile_list = gdrive.download_files(files, result_dir) gdrive.delete_files(files) # add the colormap to each tile colormap = {} for code, color in enumerate(no_data_color + cp.gradient(5)): colormap[i] = tuple(int(c * 255) for c in to_rgba(color)) for tile in tile_list: with rio.open(tile) as f: dst_f.write_colormap(self.band, colormap) self.alert.add_msg("map exported", "success") return self
def digest_layers(self, layer_io=None, question_io=None): """ Digest the layers as a json list. This list should be composed of at least 6 information : id, name, layer, theme and subtheme When digestion, the layout will represent each layer sorted by categories fore each one of them if the layer used is the default one we'll write default, if not the name of the layer. for each one of them the value of the weight will also be set """ if layer_io == None or question_io == None: return self # read the json str into a panda dataframe layer_list = layer_io.layer_list layer_list = pd.DataFrame(layer_list) if layer_list else self.LAYER_LIST # get all the themes themes = np.unique(layer_list.theme) ep_content = [] for theme in themes: # filter the layers tmp_layers = layer_list[layer_list.theme == theme] # add the theme title title = v.ExpansionPanelHeader(children=[theme.capitalize()]) # loop in these layers and create the widgets theme_layer_widgets = [] for i, row in tmp_layers.iterrows(): # get the original layer asset original_asset = self.LAYER_LIST[self.LAYER_LIST.layer_id == row["id"]][ "layer" ].values[0] # cannot make the slots work with icons so I need to move to intermediate layout if row["theme"] == "benefits": # get the weight from questionnaire weight = json.loads(question_io.priorities)[row["id"]] # create the widget theme_layer_widgets.append( v.Row( class_="ml-2 mr-2", children=[ v.TextField( small=True, hint=row["layer"] if row["layer"] != original_asset else "default", persistent_hint=True, color=cp.gradient(5)[weight], readonly=True, v_model=row["name"], ), v.Icon( class_="ml-2", color=cp.gradient(5)[weight], children=[f"mdi-numeric-{weight}-circle"], ), ], ) ) elif row["theme"] == "costs": active = True theme_layer_widgets.append( v.Row( class_="ml-2 mr-2", children=[ v.TextField( small=True, hint=row["layer"] if row["layer"] != original_asset else "default", persistent_hint=True, color=cp.gradient(2)[active], readonly=True, v_model=row["name"], ), v.Icon( class_="ml-2", color=cp.gradient(2)[active], children=["mdi-circle-slice-8"], ), ], ) ) elif row["id"] not in [ "ecozones", "land_cover", "treecover_with_potential", ]: # get the activation from questionnaire_io if constraint active = json.loads(question_io.constraints)[row["name"]] != -1 theme_layer_widgets.append( v.Row( class_="ml-2 mr-2", children=[ v.TextField( small=True, hint=row["layer"] if row["layer"] != original_asset else "default", persistent_hint=True, color=cp.gradient(2)[active], readonly=True, v_model=row["name"], ), v.Icon( class_="ml-2", color=cp.gradient(2)[active], children=["mdi-circle-slice-8"], ), ], ) ) # add the lines to the layout content = v.ExpansionPanelContent(children=theme_layer_widgets) # create the ep ep_content.append(v.ExpansionPanel(children=[title, content])) # add the layout element to the global layout self.children = ep_content return self
class PriorityTable(v.SimpleTable): _labels = [ "no importance", "low importance", "neutral", "important", "very important", ] _colors = cp.gradient(5) _BENEFITS = pd.read_csv(cp.layer_list).fillna("") _BENEFITS = _BENEFITS[_BENEFITS.theme == "benefits"] _DEFAULT_V_MODEL = {layer_id: 0 for layer_id in _BENEFITS.layer_id} def __init__(self): # construct the checkbox list self.checkbox_list = {} for layer_id in self._BENEFITS.layer_id: line = [] for i, color in enumerate(self._colors): line.append( v.Checkbox( color=color, _metadata={"label": layer_id, "val": i}, v_model=i == 0, ) ) self.checkbox_list[layer_id] = line # construct the rows of the table rows = [] self.btn_list = [] for i, layer_row in self._BENEFITS.iterrows(): edit_btn = v.Icon( children=["mdi-pencil"], _metadata={"layer": layer_row.layer_id} ) self.btn_list.append(edit_btn) row = [v.Html(tag="td", children=[edit_btn])] row.append(v.Html(tag="td", children=[layer_row.layer_name])) for j in range(len(self._colors)): row.append( v.Html( tag="td", children=[self.checkbox_list[layer_row.layer_id][j]] ) ) rows.append(v.Html(tag="tr", children=row)) # create the table super().__init__( v_model=json.dumps(self._DEFAULT_V_MODEL), children=[ v.Html( tag="thead", children=[ v.Html( tag="tr", children=( [v.Html(tag="th", children=["action"])] + [v.Html(tag="th", children=["indicator"])] + [ v.Html(tag="th", children=[label]) for label in self._labels ] ), ) ], ), v.Html(tag="tbody", children=rows), ], ) # link the checks with the v_model for name in self._BENEFITS.layer_id.tolist(): for check in self.checkbox_list[name]: check.observe(self._on_check_change, "v_model") # action on clicks for icon in self.btn_list: icon.on_event("click", lambda *args: print("toto")) def _on_check_change(self, change): line = change["owner"]._metadata["label"] # if checkbox is unique and change == false recheck if change["new"] == False: unique = True for check in self.checkbox_list[line]: if check.v_model == True: unique = False break change["owner"].v_model = unique else: # uncheck all the others in the line for check in self.checkbox_list[line]: if check != change["owner"]: check.v_model = False # change the table model tmp = json.loads(self.v_model) tmp[line] = change["owner"]._metadata["val"] self.v_model = json.dumps(tmp) return def load_data(self, data): """load the data from a questionnaire io""" data = json.loads(data) # check the appropriate checkboxes for k, v in data.items(): self.checkbox_list[k][v].v_model = True return self
class AreaSumUp(v.Layout): NAMES = [ "restoration potential", "surface (MHa)", "ratio over total surface (%)" ] COLORS = cp.gradient(5) + cp.no_data_color POTENTIALS = [ "Very low", "Low", "Medium", "High", "Very High", "Unsuitable land" ] def __init__(self, title, surfaces=[0] * 6): # get the total surface for ratio total_surface = sum(surfaces) # normalize surfaces norm_surfaces = [(s / total_surface) * 100 for s in surfaces] # create a matplotlib stack horizontal bar chart chart = Output() with chart: # create the chart fig, ax = plt.subplots(figsize=[50, 2], facecolor=((0, 0, 0, 0))) # add the axis for i, surface in enumerate(norm_surfaces): ax.barh(title, surface, left=sum(norm_surfaces[:i]), color=self.COLORS[i]) # cosmetic tuning ax.set_xlim(0, 100) ax.set_axis_off() plt.show() # init the table head = [ v.Html( tag="thead", children=[ v.Html( tag="tr", children=[ v.Html(tag="th", children=[name]) for name in self.NAMES ], ) ], ) ] self.rows = [] for clr, ptl, val, norm in zip(self.COLORS, self.POTENTIALS, surfaces, norm_surfaces): row = v.Html( tag="tr", children=[ v.Html( tag="td", children=[ptl], style_=f"color: {clr}", ), v.Html(tag="td", children=[f"{float(val):.1f}"]), v.Html(tag="td", children=[f"{float(norm):.1f}"]), ], ) self.rows.append(row) body = [v.Html(tag="tbody", children=self.rows)] table = v.SimpleTable(small=True, xs12=True, children=head + body) # the table should not be displayed by default but as a detail expansion panel ep = v.ExpansionPanels(children=[ v.ExpansionPanel(children=[ v.ExpansionPanelHeader(children=[cm.dashboard.region.detail]), v.ExpansionPanelContent(children=[table]), ]) ]) # init the title title = v.Html(xs12=True, class_="mb-2", tag="h2", children=[title]) # create the widget super().__init__( row=True, class_="ma-5", children=[ v.Flex(xs12=True, children=[title]), v.Flex(xs12=True, children=[chart]), v.Flex(xs12=True, children=[ep]), ], )
class LayerFull(sw.Layout): COLORS = cp.gradient(5) + ["grey"] def __init__(self, layer_name, values, aoi_names, colors): # read the layer list and find the layer information based on the layer name layer_list = pd.read_csv(cp.layer_list).fillna("") layer_row = layer_list[layer_list.layer_name == layer_name] if len(layer_row) != 1: raise IndexError( f"The layer {layer_name} is not part of the existing layers of the application. Please contact our maintainer." ) # build the internal details details = sw.ExpansionPanels( xs12=True, class_="mt-3", children=[ sw.ExpansionPanel(children=[ sw.ExpansionPanelHeader( children=["Details"], expand_icon="mdi-help-circle-outline", disable_icon_rotate=True, ), sw.ExpansionPanelContent( children=[layer_row.layer_info.values[0]]), ]) ], ) # create a title with the layer name title = sw.Html( class_="mt-2 mb-2", xs12=True, tag="h3", children=[f"{layer_name} ({layer_row.unit.values[0]})"], ) # taken from https://stackoverflow.com/questions/579310/formatting-long-numbers-as-strings-in-python def human_format(num, round_to=2): magnitude = 0 while abs(num) >= 1000: magnitude += 1 num = round(num / 1000.0, round_to) return "{:.{}f}{}".format(round(num, round_to), round_to, ["", "k", "M", "G", "T", "P"][magnitude]) # create a matplotlib stack horizontal bar chart chart = Output() with chart: # change pyplot style plt.style.use("dark_background") # create the chart fig, ax = plt.subplots(figsize=[50, len(values) * 2], facecolor=((0, 0, 0, 0))) # set the datas max_value = max(values) norm_values = [v / max_value * 100 for v in reversed(values)] human_values = [f"{human_format(val)}" for val in reversed(values)] colors = [ colors[i - 1] if i else scolor.primary for i in range(len(values)) ][::-1] # add the axes ax.barh(aoi_names, norm_values, color=colors) # add the text for i, (norm, name, val, color) in enumerate( zip(norm_values, aoi_names, human_values, colors)): ax.text(norm + 1, i, val, fontsize=40, color=color) # cosmetic tuning ax.set_xlim(0, 110) ax.tick_params(axis="y", which="major", pad=30, labelsize=40, left=False) ax.tick_params(axis="x", bottom=False, labelbottom=False) ax.set_frame_on(False) plt.show() super().__init__( class_="ma-5", row=True, children=[ sw.Flex(xs12=True, children=[title]), sw.Flex(xs12=True, children=[chart]), sw.Flex(xs12=True, children=[details]), ], )