def btn_calculate(self): # Note that the super class has several tests in it - if they fail it # returns False, which would mean this function should stop execution # as well. ret = super(DlgCalculateTCSummaryTable, self).btn_calculate() if not ret: return ###################################################################### # Check that all needed input layers are selected if len(self.combo_layer_f_loss.layer_list) == 0: QtWidgets.QMessageBox.critical(None, self.tr("Error"), self.tr("You must add a forest loss layer to your map before you can use the carbon change summary tool.")) return if len(self.combo_layer_tc.layer_list) == 0: QtWidgets.QMessageBox.critical(None, self.tr("Error"), self.tr("You must add a total carbon layer to your map before you can use the carbon change summary tool.")) return ####################################################################### # Check that the layers cover the full extent needed if self.aoi.calc_frac_overlap(QgsGeometry.fromRect(self.combo_layer_f_loss.get_layer().extent())) < .99: QtWidgets.QMessageBox.critical(None, self.tr("Error"), self.tr("Area of interest is not entirely within the forest loss layer.")) return if self.aoi.calc_frac_overlap(QgsGeometry.fromRect(self.combo_layer_tc.get_layer().extent())) < .99: QtWidgets.QMessageBox.critical(None, self.tr("Error"), self.tr("Area of interest is not entirely within the total carbon layer.")) return ####################################################################### # Check that all of the productivity layers have the same resolution # and CRS def res(layer): return (round(layer.rasterUnitsPerPixelX(), 10), round(layer.rasterUnitsPerPixelY(), 10)) if res(self.combo_layer_f_loss.get_layer()) != res(self.combo_layer_tc.get_layer()): QtWidgets.QMessageBox.critical(None, self.tr("Error"), self.tr("Resolutions of forest loss and total carbon layers do not match.")) return self.close() # Load all datasets to VRTs (to select only the needed bands) f_loss_vrt = self.combo_layer_f_loss.get_vrt() tc_vrt = self.combo_layer_tc.get_vrt() # Figure out start and end dates year_start = self.combo_layer_f_loss.get_band_info()['metadata']['year_start'] year_end = self.combo_layer_f_loss.get_band_info()['metadata']['year_end'] summary_task = SummaryTask(self.aoi, year_start, year_end, f_loss_vrt, tc_vrt, self.output_tab.output_basename.text() + '.xlsx') log("Adding task to task manager") QgsApplication.taskManager().addTask(summary_task) if summary_task.status() not in [QgsTask.Complete, QgsTask.Terminated]: QCoreApplication.processEvents() # while QgsApplication.taskManager().countActiveTasks() > 0: # QCoreApplication.processEvents() return True
def login(email=None, password=None): if (email == None): email = get_user_email() if (password == None): password = QtCore.QSettings().value("LDMP/password", None) if not email or not password: log('API unable to login - check username/password') QtGui.QMessageBox.critical( None, QtGui.QApplication.translate("LDMP", "Error"), QtGui.QApplication.translate( "LDMP", "Unable to login to LDMP server. Check your username and password." )) resp = None resp = call_api('/auth', method='post', payload={ "email": email, "password": password }) if resp != None: QtCore.QSettings().setValue("LDMP/email", email) QtCore.QSettings().setValue("LDMP/password", password) return resp
def start(self): try: worker = RequestWorker(self.url, self.method, self.payload, self.headers) pause = QEventLoop() worker.finished.connect(pause.quit) worker.successfully_finished.connect(self.save_resp) worker.error.connect(self.save_exception) start_worker( worker, iface, tr_api.tr(u'Contacting {} server...'.format(self.server_name))) pause.exec_() if self.get_exception(): raise self.get_exception() except requests.exceptions.ConnectionError: log('API unable to access server - check internet connection') QMessageBox.critical( None, tr_api.tr("Error"), tr_api. tr(u"Unable to login to {} server. Check your internet connection." .format(self.server_name))) resp = None except requests.exceptions.Timeout: log('API unable to login - general error') QMessageBox.critical( None, tr_api.tr("Error"), tr_api.tr(u"Unable to connect to {} server.".format( self.server_name))) resp = None
def ok_clicked(self): self.close() rows = [] for i in self.layers_view.selectionModel().selectedRows(): rows.append(i.row()) if len(rows) > 0: results = get_results(self.file_lineedit.text()) if results: for row in rows: if results.get('local_format', None) == 'tif': f = os.path.splitext( self.file_lineedit.text())[0] + '.tif' elif results.get('local_format', None) == 'vrt': f = os.path.splitext( self.file_lineedit.text())[0] + '.vrt' else: raise Vband_infosalueError( "Unrecognized local file format in download results: {}" .format(results.get('local_format', None))) resp = add_layer(f, results['bands'][row]) if not resp: mb.pushMessage( tr("Error"), self. tr('Unable to automatically add "{}". No style is defined for this type of layer.' .format(results['bands'][row]['name'])), level=1, duration=5) else: log('Error loading "{}" results from {}'.format( layer, self.file_lineedit.text())) else: QtGui.QMessageBox.critical(None, self.tr("Error"), self.tr("Select a layer to load."))
def update_from_geojson(self, geojson, crs_src='epsg:4326', datatype='polygon', wrap=False): log('Setting up AOI with geojson. Wrap is {}.'.format(wrap)) self.datatype = datatype # Note geojson is assumed to be in 4326 l = QgsVectorLayer( "{datatype}?crs={crs}".format(datatype=self.datatype, crs=crs_src), "calculation boundary", "memory") fields = QgsJsonUtils.stringToFields(json.dumps(geojson), QTextCodec.codecForName('UTF8')) features = QgsJsonUtils.stringToFeatureList( json.dumps(geojson), fields, QTextCodec.codecForName('UTF8')) l.dataProvider().addFeatures(features) l.commitChanges() if not l.isValid(): QtWidgets.QMessageBox.critical( None, tr("Error"), tr("Failed to add geojson to temporary layer.")) log("Failed to add geojson to temporary layer.") return self.l = transform_layer(l, self.crs_dst, datatype=self.datatype, wrap=wrap)
def extract_zipfile(file, verify=True): filename = os.path.join(os.path.dirname(__file__), 'data', file) url = u'https://s3.amazonaws.com/trends.earth/sharing/{}'.format(file) if os.path.exists(filename) and verify: if not check_hash_against_etag(url, filename): os.remove(filename) if not os.path.exists(filename): log(u'Downloading {}'.format(file)) # TODO: Dialog box with two options: # 1) Download # 2) Load from local folder worker = Download(url, filename) worker.start() resp = worker.get_resp() if not resp: return None if not check_hash_against_etag(url, filename): return None try: with zipfile.ZipFile(filename, 'r') as fin: fin.extractall(os.path.join(os.path.dirname(__file__), 'data')) return True except zipfile.BadZipfile: os.remove(filename) return False
def read_json(file, verify=True): filename = os.path.join(os.path.dirname(__file__), 'data', file) url = u'https://s3.amazonaws.com/trends.earth/sharing/{}'.format(file) if os.path.exists(filename) and verify: if not check_hash_against_etag(url, filename): os.remove(filename) if not os.path.exists(filename): log(u'Downloading {}'.format(file)) # TODO: Dialog box with two options: # 1) Download # 2) Load from local folder worker = Download(url, filename) worker.start() resp = worker.get_resp() if not resp: return None if not check_hash_against_etag(url, filename): return None with gzip.GzipFile(filename, 'r') as fin: json_bytes = fin.read() json_str = json_bytes.decode('utf-8') return json.loads(json_str)
def start(self): try: worker = RequestWorker(self.url, self.method, self.payload, self.headers) pause = QtCore.QEventLoop() worker.finished.connect(pause.quit) worker.successfully_finished.connect(self.save_resp) worker.error.connect(self.save_exception) start_worker( worker, iface, QtGui.QApplication.translate("LDMP", 'Contacting LDMP server...')) pause.exec_() if self.get_exception(): raise self.get_exception() except requests.exceptions.ConnectionError: log('API unable to access server - check internet connection') QtGui.QMessageBox.critical( None, QtGui.QApplication.translate("LDMP", "Error"), QtGui.QApplication.translate( "LDMP", "Unable to login to LDMP server. Check your internet connection." )) resp = None except requests.exceptions.Timeout: log('API unable to login - general error') QtGui.QMessageBox.critical( None, QtGui.QApplication.translate("LDMP", "Error"), QtGui.QApplication.translate( "LDMP", "Unable to connect to LDMP server.")) resp = None
def get_execution(id=None, date=None): log('Fetching executions') query = [] if id: query.append('user_id={}'.format(quote_plus(id))) if date: query.append('updated_at={}'.format(date)) if len(query) > 0: query = "?" + "&".join(query) else: query = '' resp = call_api('/api/v1/execution{}'.format(query), method='get', use_token=True) if not resp: return None else: data = resp['data'] # Sort responses in descending order using start time by default data = sorted(data, key=lambda job: job['start_date'], reverse=True) # Convert start/end dates into datatime objects in local time zone for job in data: start_date = datetime.strptime(job['start_date'], '%Y-%m-%dT%H:%M:%S.%f') start_date = start_date.replace(tzinfo=tz.tzutc()) start_date = start_date.astimezone(tz.tzlocal()) job['start_date'] = start_date end_date = datetime.strptime(job['end_date'], '%Y-%m-%dT%H:%M:%S.%f') end_date = end_date.replace(tzinfo=tz.tzutc()) end_date = end_date.astimezone(tz.tzlocal()) job['end_date'] = end_date return data
def extract_zipfile(f, verify=True): filename = os.path.join(os.path.dirname(__file__), 'data', f) url = u'https://s3.amazonaws.com/trends.earth/sharing/{}'.format(f) if os.path.exists(filename) and verify: if not check_hash_against_etag(url, filename): os.remove(filename) if not os.path.exists(filename): log(u'Downloading {}'.format(f)) # TODO: Dialog box with two options: # 1) Download # 2) Load from local folder worker = Download(url, filename) try: worker.start() except PermissionError: QtWidgets.QMessageBox.critical(None, tr_download.tr("Error"), tr_download.tr("Unable to write to {}.".format(filename))) return None resp = worker.get_resp() if not resp: return None if not check_hash_against_etag(url, filename): return None try: with zipfile.ZipFile(filename, 'r') as fin: fin.extractall(os.path.join(os.path.dirname(__file__), 'data')) return True except zipfile.BadZipfile: os.remove(filename) return False
def get_sample(f, band_number, n=1e6): '''Get a gridded sample of a raster dataset''' ds = gdal.Open(f) b = ds.GetRasterBand(band_number) xsize = b.XSize ysize = b.YSize # Select grid size from shortest side to ensure we have enough samples if xsize > ysize: edge = ysize else: edge = xsize grid_size = np.ceil(edge / np.sqrt(n)) if (n > xsize * ysize) or ((grid_size * grid_size) > (xsize * ysize)): # Don't sample if the sample would be larger than the array itself return b.ReadAsArray().astype(np.float) else: rows = np.arange(0, ysize, grid_size) cols = np.arange(0, xsize, grid_size).astype('int64') out = np.zeros((rows.shape[0], cols.shape[0]), np.float64) log("Sampling from a ({}, {}) array to a {} array (grid size: {}, samples: {})".format(ysize, xsize, out.shape, grid_size, out.shape[0] * out.shape[1])) for n in range(rows.shape[0]): out[n, :] = b.ReadAsArray(0, int(rows[n]), xsize, 1)[:, cols] return out
def style_land_cover_land_deg(outfile): layer_deg = iface.addRasterLayer( outfile, QtGui.QApplication.translate('LDMPPlugin', 'Land cover (degradation)')) if not layer_deg.isValid(): log('Failed to add layer') return None fcn = QgsColorRampShader() fcn.setColorRampType(QgsColorRampShader.EXACT) #TODO The GPG doesn't seem to allow for possibility of improvement...? lst = [ QgsColorRampShader.ColorRampItem( -1, QtGui.QColor(153, 51, 4), QtGui.QApplication.translate('LDMPPlugin', 'Degradation')), QgsColorRampShader.ColorRampItem( 0, QtGui.QColor(246, 246, 234), QtGui.QApplication.translate('LDMPPlugin', 'Stable')), QgsColorRampShader.ColorRampItem( 1, QtGui.QColor(0, 140, 121), QtGui.QApplication.translate('LDMPPlugin', 'Improvement')) ] fcn.setColorRampItemList(lst) shader = QgsRasterShader() shader.setRasterShaderFunction(fcn) pseudoRenderer = QgsSingleBandPseudoColorRenderer(layer_deg.dataProvider(), 1, shader) layer_deg.setRenderer(pseudoRenderer) layer_deg.triggerRepaint() iface.legendInterface().refreshLayerSymbology(layer_deg)
def login(email=None, password=None): if (email == None): email = get_user_email() if (password == None): password = QSettings().value("LDMP/password", None) if not email or not password: log('API unable to login - check username/password') QMessageBox.critical( None, tr_api.tr("Error"), tr_api. tr("Unable to login to Trends.Earth. Check your username and password." )) return None resp = call_api('/auth', method='post', payload={ "email": email, "password": password }) if resp != None: QSettings().setValue("LDMP/email", email) QSettings().setValue("LDMP/password", password) return resp
def read_class_file(f): if not os.access(f, os.R_OK): QtWidgets.QMessageBox.critical( None, QtWidgets.QApplication.translate("Error"), QtWidgets.QApplication.translate(u"Cannot read {}.".format(f), None)) return None with open(f) as class_file: classes = json.load(class_file) if (not isinstance(classes, list) or not len(classes) > 0 or not isinstance(classes[0], dict) or 'Initial_Code' not in classes[0] or 'Final_Code' not in classes[0] or 'Final_Label' not in classes[0]): QtWidgets.QMessageBox.critical( None, QtWidgets.QApplication.translate('DlgCalculateLCSetAggregation', "Error"), QtWidgets.QApplication.translate( 'DlgCalculateLCSetAggregation', u"{} does not appear to contain a valid class definition.". format(f))) return None else: log(u'Loaded class definition from {}'.format(f)) return classes
def calculate_timeseries(self, geojson, ndvi_dataset): if self.traj_climate.currentText() != "": climate_gee_dataset = self.climate_datasets[self.traj_climate.currentText()]['GEE Dataset'] log('climate_gee_dataset {}'.format(climate_gee_dataset)) else: climate_gee_dataset = None payload = {'year_start': self.traj_year_start.date().year(), 'year_end': self.traj_year_end.date().year(), 'geojson': json.dumps(geojson), 'ndvi_gee_dataset': ndvi_dataset, 'task_name': self.task_name.text(), 'climate_gee_dataset': climate_gee_dataset} # This will add in the method parameter payload.update(self.scripts['productivity-trajectory']['functions'][self.traj_indic.currentText()]['params']) gee_script = 'time-series' + '-' + self.scripts['time-series']['script version'] resp = run_script(gee_script, payload) if resp: mb.pushMessage(self.tr("Submitted"), self.tr("Time series calculation task submitted to Google Earth Engine."), level=0, duration=5) else: mb.pushMessage(self.tr("Error"), self.tr("Unable to submit time series calculation task to Google Earth Engine."), level=1, duration=5)
def update_from_geojson(self, geojson, crs_src='epsg:4326', datatype='polygon', wrap=False): log('Setting up AOI with geojson. Wrap is {}.'.format(wrap)) self.datatype = datatype # Note geojson is assumed to be in 4326 l = QgsVectorLayer( "{datatype}?crs={crs}".format(datatype=self.datatype, crs=crs_src), "calculation boundary", "memory") ds = ogr.Open(json.dumps(geojson)) layer_in = ds.GetLayer() feats_out = [] for i in range(0, layer_in.GetFeatureCount()): feat_in = layer_in.GetFeature(i) feat = QgsFeature(l.fields()) geom = QgsGeometry() geom.fromWkb(feat_in.geometry().ExportToWkb()) feat.setGeometry(geom) feats_out.append(feat) l.dataProvider().addFeatures(feats_out) l.commitChanges() if not l.isValid(): QtWidgets.QMessageBox.critical( None, tr("Error"), tr("Failed to add geojson to temporary layer.")) log("Failed to add geojson to temporary layer.") return self.l = transform_layer(l, self.crs_dst, datatype=self.datatype, wrap=wrap)
def get_cutoff(f, band_number, band_info, percentiles): if len(percentiles) != 1 and len(percentiles) != 2: raise ValueError("Percentiles must have length 1 or 2. Percentiles that were passed: {}".format(percentiles)) d = get_sample(f, band_number) md = np.ma.masked_where(d == band_info['no_data_value'], d) if md.size == 0: # If all of the values are no data, return 0 log('All values are no data') return 0 else: cutoffs = np.nanpercentile(md.compressed(), percentiles) if cutoffs.size == 2: max_cutoff = np.amax(np.absolute(cutoffs)) if max_cutoff < 0: return 0 else: return round_to_n(max_cutoff, 2) elif cutoffs.size == 1: if cutoffs < 0: # Negative cutoffs are not allowed as stretch is either zero # centered or starting at zero return 0 else: return round_to_n(cutoffs, 2) else: # We only get here if cutoffs is not size 1 or 2, which should # never happen, so raise raise ValueError("Stretch calculation returned cutoffs array of size {} ({})".format(cutoffs.size, cutoffs))
def read_json(f, verify=True): filename = os.path.join(os.path.dirname(__file__), 'data', f) url = u'https://s3.amazonaws.com/trends.earth/sharing/{}'.format(f) if os.path.exists(filename) and verify: if not check_hash_against_etag(url, filename): os.remove(filename) if not os.path.exists(filename): log(u'Downloading {}'.format(f)) # TODO: Dialog box with two options: # 1) Download # 2) Load from local folder worker = Download(url, filename) try: worker.start() except PermissionError: QtWidgets.QMessageBox.critical(None, tr_download.tr("Error"), tr_download.tr("Unable to write to {}. Do you need administrator permissions?".format(filename))) return None resp = worker.get_resp() if not resp: return None if not check_hash_against_etag(url, filename): return None with gzip.GzipFile(filename, 'r') as fin: json_bytes = fin.read() json_str = json_bytes.decode('utf-8') return json.loads(json_str)
def point_chooser(self): log("Choosing point from canvas...") self.canvas.setMapTool(self.choose_point_tool) self.window().hide() QtWidgets.QMessageBox.critical( None, self.tr("Point chooser"), self.tr("Click the map to choose a point."))
def zoom(self): layer = None for lyr in QgsProject.instance().layerStore().mapLayers().values(): if self.lyr_source in os.path.normpath(lyr.source()): layer = lyr break if not layer: raise LookupError('Unable to locate layer for extent for admin code {}'.format(self.admin_code)) # Note that this layer will have the selected admin region filtered out, so # that data will not be masked in this area. So need to temporarily remove # this filter and then reapply it. subset_string = layer.subsetString() layer.setSubsetString('') feature = None for f in layer.getFeatures(): if f.attribute(self.field) == self.admin_code: feature = f break if not feature: raise LookupError('Unable to locate polygon for admin code {}'.format(self.admin_code)) # TODO: Need to reproject the geometry to match the canvas CRS self.canvas = iface.mapCanvas() # Reapply the original feature filter on this layer layer.setSubsetString(subset_string) self.bbox = feature.geometry().boundingBox() log('Bounding box for zoom is: {}'.format(self.bbox.toString())) self.canvas.setExtent(self.bbox) self.canvas.refresh()
def work(self): ds_in = gdal.Open(self.in_vrt) soc_band = ds_in.GetRasterBand(1) clim_band = ds_in.GetRasterBand(2) block_sizes = soc_band.GetBlockSize() x_block_size = block_sizes[0] y_block_size = block_sizes[1] xsize = soc_band.XSize ysize = soc_band.YSize driver = gdal.GetDriverByName("GTiff") # Need a band for SOC degradation, plus bands for annual SOC, and for # annual LC ds_out = driver.Create(self.out_f, xsize, ysize, 1 + len(self.lc_years) * 2, gdal.GDT_Int16, ['COMPRESS=LZW']) src_gt = ds_in.GetGeoTransform() ds_out.SetGeoTransform(src_gt) out_srs = osr.SpatialReference() out_srs.ImportFromWkt(ds_in.GetProjectionRef()) ds_out.SetProjection(out_srs.ExportToWkt()) blocks = 0 for y in range(0, ysize, y_block_size): if y + y_block_size < ysize: rows = y_block_size else: rows = ysize - y for x in range(0, xsize, x_block_size): if self.killed: log("Processing of {} killed by user after processing {} out of {} blocks." .format(self.prod_out_file, y, ysize)) break self.progress.emit(100 * (float(y) + (float(x) / xsize) * y_block_size) / ysize) if x + x_block_size < xsize: cols = x_block_size else: cols = xsize - x # Write initial soc to band 2 of the output file. Read SOC in # as float so the soc change calculations won't accumulate # error due to repeated truncation of ints soc = np.array(soc_band.ReadAsArray(x, y, cols, rows)).astype(np.float32) ds_out.GetRasterBand(2).WriteArray(soc, x, y) blocks += 1 if self.killed: del ds_in del ds_out os.remove(self.out_f) return None else: return True
def setup_class_table(self, f=None): default_class_file = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'data', 'land_cover_classes.json') if not f: f = default_class_file with open(f) as class_file: classes = json.load(class_file) if (not isinstance(classes, list) or not len(classes) > 0 or not isinstance(classes[0], dict) or not classes[0].has_key('Initial_Code') or not classes[0].has_key('Initial_Label') or not classes[0].has_key('Final_Code') or not classes[0].has_key('Final_Label')): QtGui.QMessageBox.critical( None, QtGui.QApplication.translate('DlgCalculateLCSetAggregation', "Error"), QtGui.QApplication.translate( 'DlgCalculateLCSetAggregation', "{} does not appear to contain a valid class definition.". format(f))) return None else: self.classes = classes log('Loaded class definition from {}'.format(f)) table_model = LCAggTableModel(self.classes, self) proxy_model = QtGui.QSortFilterProxyModel() proxy_model.setSourceModel(table_model) self.lc_agg_view.setModel(proxy_model) # Add selector in cell for row in range(0, len(self.classes)): lc_classes = QtGui.QComboBox() # Add the classes in order of their codes lc_classes.addItems( sorted(self.final_classes.keys(), key=lambda k: self.final_classes[k])) ind = lc_classes.findText(self.classes[row]['Final_Label']) if ind != -1: lc_classes.setCurrentIndex(ind) self.lc_agg_view.setIndexWidget(proxy_model.index(row, 1), lc_classes) self.lc_agg_view.setSelectionBehavior( QtGui.QAbstractItemView.SelectRows) self.lc_agg_view.setColumnWidth(0, 500) self.lc_agg_view.horizontalHeader().setStretchLastSection(True) # Load and emit the new remap matrix self.update_remap_matrix() return True
def btn_calculate(self): if self.area_admin.isChecked(): if not self.area_admin_0.currentText(): QtGui.QMessageBox.critical( None, self.tr("Error"), self.tr("Choose a first level administrative boundary."), None) return False self.button_calculate.setEnabled(False) geojson = self.load_admin_polys() self.button_calculate.setEnabled(True) if not geojson: QtGui.QMessageBox.critical( None, self.tr("Error"), self.tr("Unable to load administrative boundaries."), None) return False else: if not self.area_fromfile_file.text(): QtGui.QMessageBox.critical( None, self.tr("Error"), self.tr("Choose a file to define the area of interest."), None) return False layer = QgsVectorLayer(self.area_fromfile_file.text(), 'calculation boundary', 'ogr') if not layer.isValid(): QtGui.QMessageBox.critical( None, self.tr("Error"), self.tr("Unable to read area file."), None) return False log('Loaded layer: {}'.format( layer.dataProvider().dataSourceUri())) #TODO: Fix this kludge for f in layer.getFeatures(): aoi = f.geometry() break crs_source = layer.crs() crs_dest = QgsCoordinateReferenceSystem(4326) aoi.transform(QgsCoordinateTransform(crs_source, crs_dest)) geojson = json.loads(aoi.exportToGeoJSON()) # Calculate bounding box of input polygon and then convert back to # geojson fields = QgsJSONUtils.stringToFields(json.dumps(geojson), QTextCodec.codecForName('UTF8')) features = QgsJSONUtils.stringToFeatureList( json.dumps(geojson), fields, QTextCodec.codecForName('UTF8')) if len(features) > 1: log("Found {} features in geojson - using first feature only.". format(len(features))) # Make a copy of this geometry self.aoi = QgsGeometry(features[0].geometry()) self.bbox = json.loads( QgsGeometry.fromRect(self.aoi.boundingBox()).exportToGeoJSON()) return True
def download_timeseries(job): log("processing timeseries results...") table = job['results'].get('table', None) if not table: return None data = [x for x in table if x['name'] == 'mean'][0] dlg_plot = DlgPlot() dlg_plot.plot_data(data['time'], data['y'], job['task_name']) dlg_plot.show() dlg_plot.exec_()
def set_point_coords(self, point, button): log("Set point coords") #TODO: Show a messagebar while tool is active, and then remove the bar when a point is chosen. self.point = point # Disable the choose point tool self.canvas.setMapTool(QgsMapToolPan(self.canvas)) self.show() self.point = self.canvas.getCoordinateTransform().toMapCoordinates(self.canvas.mouseLastXY()) log("Chose point: {}, {}.".format(self.point.x(), self.point.y())) self.point_x.setText("{:.8f}".format(self.point.x())) self.point_y.setText("{:.8f}".format(self.point.y()))
def download_result(url, outfile, job): log("Downloading {}".format(url)) #TODO: Check if this file was already downloaded worker = Download(url, outfile) worker.start() if worker.get_resp(): create_json_metadata(job, outfile) check_goog_cloud_store_hash(url, outfile) return True else: return None
def make_summary_table(forest_change, carbon_change, area_missing, area_water, area_non_forest, area_site, initial_forest_area, initial_carbon_total, year_start, year_end, out_file): def tr(s): return QtWidgets.QApplication.translate("LDMP", s) wb = openpyxl.load_workbook( os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data', 'summary_table_tc.xlsx')) ########################################################################## # SDG table ws_summary = wb.get_sheet_by_name('Total Carbon Summary Table') ws_summary.cell(6, 3).value = initial_forest_area ws_summary.cell(7, 3).value = area_non_forest ws_summary.cell(8, 3).value = area_water ws_summary.cell(9, 3).value = area_missing #ws_summary.cell(10, 3).value = area_site ws_summary.cell(18, 2).value = initial_forest_area ws_summary.cell(18, 4).value = initial_carbon_total write_col_to_sheet(ws_summary, np.arange(year_start, year_end + 1), 1, 18) # Years write_table_to_sheet(ws_summary, forest_change, 19, 3) write_table_to_sheet(ws_summary, carbon_change, 19, 5) try: ws_summary_logo = Image( os.path.join(os.path.dirname(__file__), 'data', 'trends_earth_logo_bl_300width.png')) ws_summary.add_image(ws_summary_logo, 'E1') except ImportError: # add_image will fail on computers without PIL installed (this will be # an issue on some Macs, likely others). it is only used here to add # our logo, so no big deal. pass try: wb.save(out_file) log(u'Summary table saved to {}'.format(out_file)) QtWidgets.QMessageBox.information( None, QtWidgets.QApplication.translate("LDMP", "Success"), QtWidgets.QApplication.translate( "LDMP", u'Summary table saved to {}'.format(out_file))) except IOError: log(u'Error saving {}'.format(out_file)) QtWidgets.QMessageBox.critical( None, QtWidgets.QApplication.translate("LDMP", "Error"), QtWidgets.QApplication.translate( "LDMP", u"Error saving output table - check that {} is accessible and not already open." .format(out_file)))
def check_hash_against_etag(url, filename): h = get_header(url) expected = h.get('ETag', '').strip('"') md5hash = hashlib.md5(open(filename, 'rb').read()).hexdigest() if md5hash == expected: log("File hash verified for {}".format(filename)) return True else: log("Failed verification of file hash for {}. Expected {}, but got {}".format(filename, expected, md5hash), 2) return False
def btn_calculate(self): # Note that the super class has several tests in it - if they fail it # returns False, which would mean this function should stop execution # as well. ret = super(DlgTimeseries, self).btn_calculate() if not ret: return self.close() if self.traj_climate.currentText() != "": climate_gee_dataset = self.climate_datasets[ self.traj_climate.currentText()]['GEE Dataset'] log('climate_gee_dataset {}'.format(climate_gee_dataset)) else: climate_gee_dataset = None ndvi_dataset = self.datasets['NDVI'][ self.dataset_ndvi.currentText()]['GEE Dataset'] crosses_180th, geojsons = self.aoi.bounding_box_gee_geojson() payload = { 'year_start': self.traj_year_start.date().year(), 'year_end': self.traj_year_end.date().year(), 'crosses_180th': crosses_180th, 'geojsons': json.dumps(geojsons), 'crs': self.aoi.get_crs_dst_wkt(), 'ndvi_gee_dataset': ndvi_dataset, 'task_name': self.options_tab.task_name.text(), 'task_notes': self.options_tab.task_notes.toPlainText(), 'climate_gee_dataset': climate_gee_dataset } # This will add in the method parameter payload.update(self.scripts['productivity']['trajectory functions'][ self.traj_indic.currentText()]['params']) resp = run_script(get_script_slug('time-series'), payload) if resp: mb.pushMessage( self.tr("Submitted"), self. tr("Time series calculation task submitted to Google Earth Engine." ), level=0, duration=5) else: mb.pushMessage( self.tr("Error"), self. tr("Unable to submit time series calculation task to Google Earth Engine." ), level=1, duration=5)
def style_prod_traj_trend(outfile): # Trends layer layer_ndvi = iface.addRasterLayer( outfile, QtGui.QApplication.translate( 'LDMPPlugin', 'Productivity trajectory trend\n(slope of NDVI * 10000)')) if not layer_ndvi.isValid(): log('Failed to add layer') return None provider = layer_ndvi.dataProvider() # Set a colormap centred on zero, going to the extreme value significant to # three figures (after a 2 percent stretch) ds = gdal.Open(outfile) band1 = np.array(ds.GetRasterBand(1).ReadAsArray()) band1[band1 >= 9997] = 0 ds = None cutoffs = np.percentile(band1, [2, 98]) extreme = get_extreme(cutoffs[0], cutoffs[1]) fcn = QgsColorRampShader() fcn.setColorRampType(QgsColorRampShader.INTERPOLATED) lst = [ QgsColorRampShader.ColorRampItem( -extreme, QtGui.QColor(153, 51, 4), QtGui.QApplication.translate('LDMPPlugin', '-{} (declining)').format(extreme)), QgsColorRampShader.ColorRampItem( 0, QtGui.QColor(246, 246, 234), QtGui.QApplication.translate('LDMPPlugin', '0 (stable)')), QgsColorRampShader.ColorRampItem( extreme, QtGui.QColor(0, 140, 121), QtGui.QApplication.translate('LDMPPlugin', '{} (increasing)').format(extreme)), QgsColorRampShader.ColorRampItem( 9997, QtGui.QColor(0, 0, 0), QtGui.QApplication.translate('LDMPPlugin', 'No data')), QgsColorRampShader.ColorRampItem( 9998, QtGui.QColor(58, 77, 214), QtGui.QApplication.translate('LDMPPlugin', 'Water')), QgsColorRampShader.ColorRampItem( 9999, QtGui.QColor(192, 105, 223), QtGui.QApplication.translate('LDMPPlugin', 'Urban land cover')) ] fcn.setColorRampItemList(lst) shader = QgsRasterShader() shader.setRasterShaderFunction(fcn) pseudoRenderer = QgsSingleBandPseudoColorRenderer( layer_ndvi.dataProvider(), 1, shader) layer_ndvi.setRenderer(pseudoRenderer) layer_ndvi.triggerRepaint() iface.legendInterface().refreshLayerSymbology(layer_ndvi)