diff --git a/sample/mrt_classes.py b/sample/mrt_classes.py index f181d8076cf4e2d02a0e84993e5b17404834164f..eeae75b7e40e08a4a49a67ac7bf104afe7393944 100644 --- a/sample/mrt_classes.py +++ b/sample/mrt_classes.py @@ -160,9 +160,9 @@ class ReClass: self.models = [x for x in list(self.downstream_df) if x.lower() not in ['description', 'newval']] pd.testing.assert_series_equal(left=self.rules_df.newval, right=self.downstream_df.newval), "Difference detected between upstream and downstream sheets" - if self.verbose: - print('Models are: ') - print('\n'.join(self.models)) + if self.verbose: + print('Models are: ') + print('\n'.join(self.models)) if self.models: # Create model objects and attach as attributes @@ -209,7 +209,7 @@ class ReClass: print('\nWarning, not all valid values for are employed in a Reclass Rule') for s in self.not_classified_lst: print("{}".format(s.name)) - print('\n'.join([str(x) for x in s])) + print('\n'.join([' {}'.format(str(x)) for x in s])) def parse_rules(self): """ @@ -222,11 +222,15 @@ class ReClass: # Create dummy rule (Rule999) to catch all values in the combined raster RAT. # For dict merge: https://stackoverflow.com/questions/38987/ # how-do-i-merge-two-dictionaries-in-a-single-expression-in-python-taking-union-o - data_p1 = dict(zip(self.source_rasters, ['n'] * len(self.source_rasters))) - data_p2 = {'newval': 0, 'reclass': True, 'description': 'No other rule applies'} + data_p1 = dict.fromkeys(self.source_rasters, 'n') + data_p2 = {'newval': 0, 'reclass': True, 'description': 'No other rule applies', 'join_type': 'and'} dummy_rule = pd.Series(data={**data_p1, **data_p2}, name=999) self.rules_df = self.rules_df.append(dummy_rule) + # Dict to map user provided information to AND or OR join type for rule + join_types = {'and': '&', 'or': '|', 'en': '&', 'of': '|', 'And': '&', 'Or': '|', 'AND': '&', 'OR': '|', + 'En': '&', 'Of': '|', 'EN': '&', 'OF': '|'} + for row in self.rules_df.iterrows(): series = row[1] rule = Rule() @@ -236,7 +240,11 @@ class ReClass: rule.apply = True if series.loc['reclass'] == 1 else False rule.comment = series.loc['remark'] # idem rule.name = 'rule{:03}'.format(row[0]) - rule.join_type = series.loc['join_type'] + try: + rule.join_type = join_types[series.loc['join_type']] + except KeyError: + print('Invalid join type indicator "{0}" for rule {1}'.format(series.loc['join_type'], row[0])) + raise # Build query based on the dataframe contents for each source raster for reclass_rast in self.source_rasters: @@ -245,8 +253,7 @@ class ReClass: rule.queries.append('{0}.isin({1})'.format(reclass_rast, reclass_rast_query)) if rule.queries: # Build query using the rule join type as connector between the individual queries. - join_type = rule.join_type - rule.query = ' {} '.format(join_type).join(rule.queries) + rule.query = ' {} '.format(rule.join_type).join(rule.queries) else: rule.apply = False # never apply a rule that does not have a valid query @@ -400,7 +407,7 @@ class ReClass: assert os.path.isdir(self.base_out), 'Invalid output directory' excel_out = '{0}_report.xlsx'.format(self.project_name) - with pd.ExcelWriter(os.path.join(self.base_out, excel_out), mode='a') as writer: + with pd.ExcelWriter(os.path.join(self.base_out, excel_out), mode='w') as writer: # Report on input metadata = {'input_XLS': self.__xls, @@ -425,10 +432,11 @@ class ReClass: self.rules_df.to_excel(writer, sheet_name='ReclassRules', index=False, freeze_panes=(1, 2)) # Write downstream table for applied rules only - applied_newvals = [getattr(getattr(self, rule), 'newval') for rule in self.rules if - getattr(getattr(self, rule), 'apply')] - self.downstream_df.loc[self.downstream_df.newval.isin(applied_newvals), :] \ - .to_excel(writer, sheet_name='downstream', index=False, freeze_panes=(1,2)) + if self.models: + applied_newvals = [getattr(getattr(self, rule), 'newval') for rule in self.rules if + getattr(getattr(self, rule), 'apply')] + self.downstream_df.loc[self.downstream_df.newval.isin(applied_newvals), :] \ + .to_excel(writer, sheet_name='downstream', index=False, freeze_panes=(1,2)) # Report on combi raster RAT self.combi_raster.rat.drop(labels=self.combi_raster.rule_cols + ['geometry'], axis=1) \ @@ -601,9 +609,12 @@ class CombinedRaster: self.raster = rio.open(os.path.join(rast_dir, rast_in)) try: self.rat = gp.read_file(os.path.join(rast_dir, '{}.tif.vat.dbf'.format(self.basename))) + # AGPro delivers columnnames inconsistently: sometimes Count, sometimes COUNT. + self.rat.columns = [x.capitalize() if x.lower() in ['count', 'value'] else x for x in list(self.rat)] except ValueError: print('Raster Attribute Table not found') raise + self.source_rasters = [x for x in list(self.rat) if x not in ['Value', 'Count', 'geometry']] self.pxl_area_m2 = np.square(self.raster.res[0]) self.pixel_area_ha = np.divide(self.pxl_area_m2, 10000) diff --git a/sample/mrt_helpers.py b/sample/mrt_helpers.py index 6e45048b8a10eddc5d5a5df560d4b9a56020a810..4edfa243301ab89c91fbd8b2f204f57b30604d83 100644 --- a/sample/mrt_helpers.py +++ b/sample/mrt_helpers.py @@ -64,6 +64,7 @@ def parse_rule(rule, category=None, negate=True): raise else: raise Exception('unexpected reclass rule found: {0}'.format(rule)) + # out = False return out