def bqbars(values, colors, title, stake): fig = plt.figure() eo_bars = plt.bar(x_ticks, values, colors=colors) plt.ylabel("Fraction (%)") plt.xlabel(stake) fig.title = title return fig
def feature_byProperty(features, xProperties, seriesProperty, **kwargs): """Generates a Chart from a set of features. Plots property values of one or more features. Reference: https://developers.google.com/earth-engine/guides/charts_feature#uichartfeaturebyproperty Args: features (ee.FeatureCollection): The features to include in the chart. xProperties (list | dict): One of (1) a list of properties to be plotted on the x-axis; or (2) a (property, label) dictionary specifying labels for properties to be used as values on the x-axis. seriesProperty (str): The name of the property used to label each feature in the legend. Raises: Exception: If the provided xProperties is not a list or dict. Exception: If the chart fails to create. """ try: df = ee_to_df(features) if isinstance(xProperties, list): x_data = xProperties y_data = df[xProperties].values elif isinstance(xProperties, dict): x_data = list(xProperties.values()) y_data = df[list(xProperties.keys())].values else: raise Exception("xProperties must be a list or dictionary.") labels = list(df[seriesProperty]) if "ylim" in kwargs: min_value = kwargs["ylim"][0] max_value = kwargs["ylim"][1] else: min_value = y_data.min() max_value = y_data.max() max_value = max_value + 0.2 * (max_value - min_value) if "title" not in kwargs: title = "" else: title = kwargs["title"] if "legend_location" not in kwargs: legend_location = "top-left" else: legend_location = kwargs["legend_location"] if "display_legend" not in kwargs: display_legend = True else: display_legend = kwargs["display_legend"] fig = plt.figure( title=title, legend_location=legend_location, ) if "width" in kwargs: fig.layout.width = kwargs["width"] if "height" in kwargs: fig.layout.height = kwargs["height"] bar_chart = plt.bar(x=x_data, y=y_data, labels=labels, display_legend=display_legend) bar_chart.type = "grouped" if "colors" in kwargs: bar_chart.colors = kwargs["colors"] if "xlabel" in kwargs: plt.xlabel(kwargs["xlabel"]) if "ylabel" in kwargs: plt.ylabel(kwargs["ylabel"]) plt.ylim(min_value, max_value) if "xlabel" in kwargs and ("ylabel" in kwargs): bar_chart.tooltip = Tooltip( fields=["x", "y"], labels=[kwargs["xlabel"], kwargs["ylabel"]]) else: bar_chart.tooltip = Tooltip(fields=["x", "y"]) plt.show() except Exception as e: raise Exception(e)
def feature_groups(features, xProperty, yProperty, seriesProperty, **kwargs): """Generates a Chart from a set of features. Plots the value of one property for each feature. Reference: https://developers.google.com/earth-engine/guides/charts_feature#uichartfeaturegroups Args: features (ee.FeatureCollection): The feature collection to make a chart from. xProperty (str): Features labeled by xProperty. yProperty (str): Features labeled by yProperty. seriesProperty (str): The property used to label each feature in the legend. Raises: Exception: Errors when creating the chart. """ try: df = ee_to_df(features) df[yProperty] = pd.to_numeric(df[yProperty]) unique_series_values = df[seriesProperty].unique().tolist() new_column_names = [] for value in unique_series_values: sample_filter = (df[seriesProperty] == value).map({ True: 1, False: 0 }) column_name = str(yProperty) + "_" + str(value) df[column_name] = df[yProperty] * sample_filter new_column_names.append(column_name) if "labels" in kwargs: labels = kwargs["labels"] else: labels = [str(x) for x in unique_series_values] if "ylim" in kwargs: min_value = kwargs["ylim"][0] max_value = kwargs["ylim"][1] else: min_value = df[yProperty].to_numpy().min() max_value = df[yProperty].to_numpy().max() max_value = max_value + 0.2 * (max_value - min_value) if "title" not in kwargs: title = "" else: title = kwargs["title"] if "legend_location" not in kwargs: legend_location = "top-left" else: legend_location = kwargs["legend_location"] x_data = list(df[xProperty]) y_data = [df[x] for x in new_column_names] plt.bar(x_data, y_data) fig = plt.figure( title=title, legend_location=legend_location, ) if "width" in kwargs: fig.layout.width = kwargs["width"] if "height" in kwargs: fig.layout.height = kwargs["height"] if "display_legend" not in kwargs: display_legend = True else: display_legend = kwargs["display_legend"] bar_chart = plt.bar(x_data, y_data, labels=labels, display_legend=display_legend) if "colors" in kwargs: bar_chart.colors = kwargs["colors"] if "xlabel" in kwargs: plt.xlabel(kwargs["xlabel"]) if "ylabel" in kwargs: plt.ylabel(kwargs["ylabel"]) plt.ylim(min_value, max_value) if "xlabel" in kwargs and ("ylabel" in kwargs): bar_chart.tooltip = Tooltip( fields=["x", "y"], labels=[kwargs["xlabel"], kwargs["ylabel"]]) else: bar_chart.tooltip = Tooltip(fields=["x", "y"]) plt.show() except Exception as e: raise Exception(e)
def feature_byFeature(features, xProperty, yProperties, **kwargs): """Generates a Chart from a set of features. Plots the value of one or more properties for each feature. Reference: https://developers.google.com/earth-engine/guides/charts_feature#uichartfeaturebyfeature Args: features (ee.FeatureCollection): The feature collection to generate a chart from. xProperty (str): Features labeled by xProperty. yProperties (list): Values of yProperties. Raises: Exception: Errors when creating the chart. """ try: df = ee_to_df(features) if "ylim" in kwargs: min_value = kwargs["ylim"][0] max_value = kwargs["ylim"][1] else: min_value = df[yProperties].to_numpy().min() max_value = df[yProperties].to_numpy().max() max_value = max_value + 0.2 * (max_value - min_value) if "title" not in kwargs: title = "" else: title = kwargs["title"] if "legend_location" not in kwargs: legend_location = "top-left" else: legend_location = kwargs["legend_location"] x_data = list(df[xProperty]) y_data = df[yProperties].values.T.tolist() plt.bar(x_data, y_data) fig = plt.figure( title=title, legend_location=legend_location, ) if "width" in kwargs: fig.layout.width = kwargs["width"] if "height" in kwargs: fig.layout.height = kwargs["height"] if "labels" in kwargs: labels = kwargs["labels"] else: labels = yProperties if "display_legend" not in kwargs: display_legend = True else: display_legend = kwargs["display_legend"] bar_chart = plt.bar(x_data, y_data, labels=labels, display_legend=display_legend) bar_chart.type = "grouped" if "colors" in kwargs: bar_chart.colors = kwargs["colors"] if "xlabel" in kwargs: plt.xlabel(kwargs["xlabel"]) if "ylabel" in kwargs: plt.ylabel(kwargs["ylabel"]) plt.ylim(min_value, max_value) if "xlabel" in kwargs and ("ylabel" in kwargs): bar_chart.tooltip = Tooltip( fields=["x", "y"], labels=[kwargs["xlabel"], kwargs["ylabel"]]) else: bar_chart.tooltip = Tooltip(fields=["x", "y"]) plt.show() except Exception as e: raise Exception(e)
def vue_do_aper_phot(self, *args, **kwargs): if self._selected_data is None or self._selected_subset is None: self.result_available = False self.results = [] self.plot_available = False self.radial_plot = '' self.hub.broadcast(SnackbarMessage( "No data for aperture photometry", color='error', sender=self)) return data = self._selected_data reg = self._selected_subset try: comp = data.get_component(data.main_components[0]) try: bg = float(self.background_value) except ValueError: # Clearer error message raise ValueError('Missing or invalid background value') comp_no_bg = comp.data - bg # TODO: Use photutils when it supports astropy regions. if not isinstance(reg, RectanglePixelRegion): aper_mask = reg.to_mask(mode='exact') else: # TODO: https://github.com/astropy/regions/issues/404 (moot if we use photutils?) aper_mask = reg.to_mask(mode='subpixels', subpixels=32) npix = np.sum(aper_mask) * u.pix img = aper_mask.get_values(comp_no_bg, mask=None) aper_mask_stat = reg.to_mask(mode='center') comp_no_bg_cutout = aper_mask_stat.cutout(comp_no_bg) img_stat = aper_mask_stat.get_values(comp_no_bg, mask=None) include_pixarea_fac = False include_counts_fac = False include_flux_scale = False if comp.units: img_unit = u.Unit(comp.units) img = img * img_unit img_stat = img_stat * img_unit bg = bg * img_unit comp_no_bg_cutout = comp_no_bg_cutout * img_unit if u.sr in img_unit.bases: # TODO: Better way to detect surface brightness unit? try: pixarea = float(self.pixel_area) except ValueError: # Clearer error message raise ValueError('Missing or invalid pixel area') if not np.allclose(pixarea, 0): include_pixarea_fac = True if img_unit != u.count: try: ctfac = float(self.counts_factor) except ValueError: # Clearer error message raise ValueError('Missing or invalid counts conversion factor') if not np.allclose(ctfac, 0): include_counts_fac = True try: flux_scale = float(self.flux_scaling) except ValueError: # Clearer error message raise ValueError('Missing or invalid flux scaling') if not np.allclose(flux_scale, 0): include_flux_scale = True rawsum = np.nansum(img) d = {'id': 1, 'xcenter': reg.center.x * u.pix, 'ycenter': reg.center.y * u.pix} if data.coords is not None: d['sky_center'] = data.coords.pixel_to_world(reg.center.x, reg.center.y) else: d['sky_center'] = None d.update({'background': bg, 'npix': npix}) if include_pixarea_fac: pixarea = pixarea * (u.arcsec * u.arcsec / u.pix) pixarea_fac = npix * pixarea.to(u.sr / u.pix) d.update({'aperture_sum': rawsum * pixarea_fac, 'pixarea_tot': pixarea_fac}) else: d.update({'aperture_sum': rawsum, 'pixarea_tot': None}) if include_counts_fac: ctfac = ctfac * (rawsum.unit / u.count) sum_ct = rawsum / ctfac d.update({'aperture_sum_counts': sum_ct, 'aperture_sum_counts_err': np.sqrt(sum_ct.value) * sum_ct.unit, 'counts_fac': ctfac}) else: d.update({'aperture_sum_counts': None, 'aperture_sum_counts_err': None, 'counts_fac': None}) if include_flux_scale: flux_scale = flux_scale * rawsum.unit d.update({'aperture_sum_mag': -2.5 * np.log10(rawsum / flux_scale) * u.mag, 'flux_scaling': flux_scale}) else: d.update({'aperture_sum_mag': None, 'flux_scaling': None}) # Extra stats beyond photutils. d.update({'mean': np.nanmean(img_stat), 'stddev': np.nanstd(img_stat), 'median': np.nanmedian(img_stat), 'min': np.nanmin(img_stat), 'max': np.nanmax(img_stat), 'data_label': data.label, 'subset_label': reg.meta.get('label', ''), 'timestamp': Time(datetime.utcnow())}) # Attach to app for Python extraction. if (not hasattr(self.app, '_aper_phot_results') or not isinstance(self.app._aper_phot_results, QTable)): self.app._aper_phot_results = _qtable_from_dict(d) else: try: d['id'] = self.app._aper_phot_results['id'].max() + 1 self.app._aper_phot_results.add_row(d.values()) except Exception: # Discard incompatible QTable d['id'] = 1 self.app._aper_phot_results = _qtable_from_dict(d) # Radial profile reg_bb = reg.bounding_box reg_ogrid = np.ogrid[reg_bb.iymin:reg_bb.iymax, reg_bb.ixmin:reg_bb.ixmax] radial_dx = reg_ogrid[1] - reg.center.x radial_dy = reg_ogrid[0] - reg.center.y radial_r = np.hypot(radial_dx, radial_dy).ravel() # pix radial_img = comp_no_bg_cutout.ravel() if comp.units: y_data = radial_img.value y_label = radial_img.unit.to_string() else: y_data = radial_img y_label = 'Value' bqplt.clear() # NOTE: default margin in bqplot is 60 in all directions fig = bqplt.figure(1, title='Radial profile from Subset center', fig_margin={'top': 60, 'bottom': 60, 'left': 40, 'right': 10}, title_style={'font-size': '12px'}) # TODO: Jenn wants title at bottom. # noqa bqplt.plot(radial_r, y_data, 'go', figure=fig, default_size=1) bqplt.xlabel(label='pix', mark=fig.marks[-1], figure=fig) bqplt.ylabel(label=y_label, mark=fig.marks[-1], figure=fig) except Exception as e: # pragma: no cover self.result_available = False self.results = [] self.plot_available = False self.radial_plot = '' self.hub.broadcast(SnackbarMessage( f"Aperture photometry failed: {repr(e)}", color='error', sender=self)) else: # Parse results for GUI. tmp = [] for key, x in d.items(): if key in ('id', 'data_label', 'subset_label', 'background', 'pixarea_tot', 'counts_fac', 'aperture_sum_counts_err', 'flux_scaling', 'timestamp'): continue if (isinstance(x, (int, float, u.Quantity)) and key not in ('xcenter', 'ycenter', 'sky_center', 'npix', 'aperture_sum_counts')): x = f'{x:.4e}' tmp.append({'function': key, 'result': x}) elif key == 'sky_center' and x is not None: tmp.append({'function': 'RA center', 'result': f'{x.ra.deg:.4f} deg'}) tmp.append({'function': 'Dec center', 'result': f'{x.dec.deg:.4f} deg'}) elif key in ('xcenter', 'ycenter', 'npix'): x = f'{x:.1f}' tmp.append({'function': key, 'result': x}) elif key == 'aperture_sum_counts' and x is not None: x = f'{x:.4e} ({d["aperture_sum_counts_err"]:.4e})' tmp.append({'function': key, 'result': x}) elif not isinstance(x, str): x = str(x) tmp.append({'function': key, 'result': x}) self.results = tmp self.result_available = True self.radial_plot = fig self.bqplot_figs_resize = [fig] self.plot_available = True
def plot_profitability_distributions(scenarios, backend): for id in scenarios: # Make scenario data scenario = scenarios[id] desc = scenario.description train_data = scenario.gendata("train") test_data = scenario.gendata("test") np.random.seed(42) X_train, y_train = scenario.get_modelling_data(train_data) X_test, y_test = scenario.get_modelling_data(test_data) data = { 'training': (X_train, y_train, train_data.disadv_flag), 'deployment': (X_test, y_test, test_data.disadv_flag), } figure_name = f"Profitability_{id}_{desc}" print(f"for Scenario {id}: {desc}") if backend == "matplotlib": l = len(data.items()) fig, ax = mplt.subplots(1, l, figsize=(5 * l, 5), dpi=DPI) i = 0 else: plts = [] for cohort, (X, y_true, prot) in data.items(): dis = prot.astype(int) mn, fn, mp, fp = confusion_matrix(y_true, dis).ravel() values = [[mp, fp], [mn, fn]] # half way between selected and not colors = ["#ff4045", "#48B748"] title = f"Representation in {cohort} cohort." ylabel = "Number of Applicants" if backend == "matplotlib": bars = mplt_bars(ax[i], scenario.ticks, values, colors, ylabel, title) mplt.legend( bars, ["profitable customers", "non-profitable customers"], bbox_to_anchor=(1.05, 0.5) # sit outside plot... ) i += 1 else: fig = plt.figure(min_aspect_ratio=1, max_aspect_ratio=1) # First index is colour, second index is X # Note - putting negative does cool weird stuff bars = plt.bar( scenario.ticks, values, colors=colors, # display_legend=False, # labels=["Good Customers", "Bad Customers"], ) siz = "4in" fig.layout.width = siz fig.layout.height = siz fig.title = title fig.axes[0].color = fig.axes[1].color = "Black" plt.ylabel(ylabel) plts.append(fig) if backend == "matplotlib": fig.savefig("images/" + figure_name + ".png", bbox_inches="tight", dpi=300) elif backend == "bqplot": box = widgets.HBox(plts) box.layout.width = "90%" display(box) figure_name = f"Profitability_{id}_{desc}"
def submit_clicked(b): with output_widget: output_widget.clear_output() print('Computing...') Map.default_style = {'cursor': 'wait'} try: admin1_id = admin1_widget.value admin2_id = admin2_widget.value band1 = first_band.value band2 = second_band.value selected_year = year_widget.value threshold = nd_threshold.value bands = band_combo.value.split('/') apply_fmask = fmask_widget.value palette = nd_color.value use_aoi = aoi_widget.value download = download_widget.value if use_aoi: if Map.user_roi is not None: roi = Map.user_roi layer_name = 'User drawn AOI' geom = roi else: output_widget.clear_output() print('No user AOI could be found.') return else: statefp = ee.Feature(states.filter(ee.Filter.eq('NAME', admin1_id)).first()).get('STATEFP') roi = fc.filter(ee.Filter.And(ee.Filter.eq('NAME', admin2_id), ee.Filter.eq('STATEFP', statefp))) layer_name = admin1_id + '-' + admin2_id geom = roi.geometry() Map.layers = Map.layers[:4] Map.addLayer(ee.Image().paint(geom, 0, 2), {'palette': 'red'}, layer_name) images = geemap.landsat_timeseries(roi=roi, start_year=1984, end_year=2020, start_date='01-01', end_date='12-31', apply_fmask=apply_fmask) nd_images = images.map(lambda img: img.normalizedDifference([band1, band2])) result_images = nd_images.map(lambda img: img.gt(threshold)) selected_image = ee.Image(images.toList(images.size()).get(selected_year - 1984)) selected_result_image = ee.Image(result_images.toList(result_images.size()).get(selected_year - 1984)).selfMask() vis_params = { 'bands': bands, 'min': 0, 'max': 3000 } Map.addLayer(selected_image, vis_params, 'Landsat ' + str(selected_year)) Map.addLayer(selected_result_image, {'palette': palette}, 'Result ' + str(selected_year)) def cal_area(img): pixel_area = img.multiply(ee.Image.pixelArea()).divide(1e4) img_area = pixel_area.reduceRegion(**{ 'geometry': geom, 'reducer': ee.Reducer.sum(), 'scale': 1000, 'maxPixels': 1e12, 'bestEffort': True }) return img.set({'area': img_area}) areas = result_images.map(cal_area) stats = areas.aggregate_array('area').getInfo() x = list(range(1984, 2021)) y = [item.get('nd') for item in stats] fig = plt.figure(1) fig.layout.height = '270px' plt.clear() plt.plot(x, y) plt.title('Temporal trend (1984-2020)') plt.xlabel('Year') plt.ylabel('Area (ha)') output_widget.clear_output() plt.show() if download: out_dir = os.path.join(os.path.expanduser('~'), 'Downloads') out_name = 'chart_' + geemap.random_string() + '.csv' out_csv = os.path.join(out_dir, out_name) if not os.path.exists(out_dir): os.makedirs(out_dir) with open(out_csv, 'w') as f: f.write('year, area (ha)\n') for index, item in enumerate(x): line = '{},{:.2f}\n'.format(item, y[index]) f.write(line) link = geemap.create_download_link( out_csv, title="Click here to download the chart data: ") display(link) except Exception as e: print(e) print('An error occurred during computation.') Map.default_style = {'cursor': 'default'}