diff --git a/i.sentinel_2.autotraining/i.sentinel_2.autotraining.py b/i.sentinel_2.autotraining/i.sentinel_2.autotraining.py index 42249cc..c26331e 100644 --- a/i.sentinel_2.autotraining/i.sentinel_2.autotraining.py +++ b/i.sentinel_2.autotraining/i.sentinel_2.autotraining.py @@ -142,18 +142,19 @@ # % label: Number of sampling points per class in the output vector map # %end - import atexit import os + import grass.script as grass rm_rasters = [] -tmp_mask_old = None +TMP_MASK_OLD = None def cleanup(): - nuldev = open(os.devnull, "w") - kwargs = {"flags": "f", "quiet": True, "stderr": nuldev} + """Cleaning up""" + nulldev = open(os.devnull, "w") + kwargs = {"flags": "f", "quiet": True, "stderr": nulldev} for rmrast in rm_rasters: if grass.find_file(name=rmrast, element="raster")["file"]: grass.run_command("g.remove", type="raster", name=rmrast, **kwargs) @@ -161,11 +162,12 @@ def cleanup(): if grass.find_file(name="MASK", element="raster")["file"]: grass.run_command("r.mask", flags="r") # reactivate potential old mask - if tmp_mask_old: - grass.run_command("r.mask", raster=tmp_mask_old, quiet=True) + if TMP_MASK_OLD: + grass.run_command("r.mask", raster=TMP_MASK_OLD, quiet=True) def test_percentage(raster, reference_cells, percentage_threshold): + """Test percentage of null value in raster""" n_raster = int(grass.parse_command("r.univar", map=raster, flags="g")["n"]) if n_raster / reference_cells > percentage_threshold * 0.01: return True @@ -174,6 +176,7 @@ def test_percentage(raster, reference_cells, percentage_threshold): def get_percentile(raster, percentile): + """Function to return the Xth percentile of a raster""" return float( list( ( @@ -189,11 +192,13 @@ def get_percentile(raster, percentile): def get_or_string(raster, values): - return " || ".join(["{} == {}".format(raster, value) for value in values]) + """Function to generte or string""" + return " || ".join([f"{raster} == {value}" for value in values]) def main(): - global rm_rasters, tmp_mask_old + """Main function of the module""" + global rm_rasters, TMP_MASK_OLD ndvi = options["ndvi"] ndbi = options["ndbi"] ndwi = options["ndwi"] @@ -229,18 +234,18 @@ def main(): water_cats_probav = ["80", "200"] water_cats_gong = ["60"] ndwi_percentile = "25" - both_class_water = "both_classifications_water_{}".format(os.getpid()) + both_class_water = f"both_classifications_water_{os.getpid()}" rm_rasters.append(both_class_water) if ref_class_gong: - exp_water1 = "{} = if(({}) && {},1,null())".format( - both_class_water, - get_or_string(ref_class_probav, water_cats_probav), - get_or_string(ref_class_gong, water_cats_gong), + exp_water1 = ( + f"{both_class_water} = if((" + f"{get_or_string(ref_class_probav, water_cats_probav)}) && " + f"{get_or_string(ref_class_gong, water_cats_gong)},1,null())" ) else: - exp_water1 = "{} = if(({}),1,null())".format( - both_class_water, - get_or_string(ref_class_probav, water_cats_probav), + exp_water1 = ( + f"{both_class_water} = if((" + f"{get_or_string(ref_class_probav, water_cats_probav)}),1,null())" ) grass.run_command("r.mapcalc", expression=exp_water1, quiet=True) @@ -248,13 +253,10 @@ def main(): water_ndwi_perc = get_percentile(ndwi, ndwi_percentile) # ndwi_thresh_inref = '0.3' # ndwi_thresh_notinref = '0.8' - water_raster = "water_raster_%s" % os.getpid() + water_raster = f"water_raster_{os.getpid()}" rm_rasters.append(water_raster) - water_exp = "%s = if(%s >= %s, %s, null())" % ( - water_raster, - ndwi, - water_ndwi_perc, - water[0], + water_exp = ( + f"{water_raster} = if({ndwi} >= {water_ndwi_perc}, {water[0]}, null())" ) grass.run_command("r.mapcalc", expression=water_exp, quiet=True) grass.run_command("r.mask", flags="r", quiet=True) @@ -263,7 +265,6 @@ def main(): training_rasters.append(water_raster) # find low vegetation training areas - grass.message(_("Checking for low vegetation areas...")) lowveg_cats_probav = [ "20", @@ -281,27 +282,25 @@ def main(): ndvi_thresh_lowveg = 0.5 treecov_max_lowveg = "25" # previously: 50 # ndvi_percentile_lowveg = '50' # previously: 50 - tmp_lowveg_raster = "lowveg_class_raster_%s" % os.getpid() + tmp_lowveg_raster = f"lowveg_class_raster_{os.getpid()}" rm_rasters.append(tmp_lowveg_raster) if ref_class_gong: - exp_lowveg1 = "{} = if(({}) && ({}),1,0)".format( - tmp_lowveg_raster, - get_or_string(ref_class_probav, lowveg_cats_probav), - get_or_string(ref_class_gong, lowveg_cats_gong), + exp_lowveg1 = ( + f"{tmp_lowveg_raster} = if((" + f"{get_or_string(ref_class_probav, lowveg_cats_probav)}) && (" + f"{get_or_string(ref_class_gong, lowveg_cats_gong)}),1,0)" ) else: - exp_lowveg1 = "{} = if(({}),1,0)".format( - tmp_lowveg_raster, - get_or_string(ref_class_probav, lowveg_cats_probav), + exp_lowveg1 = ( + f"{tmp_lowveg_raster} = if((" + f"{get_or_string(ref_class_probav, lowveg_cats_probav)}),1,0)" ) grass.run_command("r.mapcalc", expression=exp_lowveg1, quiet=True) - lowveg_mask_raster = "lowveg_mask_raster_%s" % os.getpid() + lowveg_mask_raster = f"lowveg_mask_raster_{os.getpid()}" rm_rasters.append(lowveg_mask_raster) - eq_lowveg2 = "%s = if(%s == 1 && %s <= %s,1,null())" % ( - lowveg_mask_raster, - tmp_lowveg_raster, - treecov, - treecov_max_lowveg, + eq_lowveg2 = ( + f"{lowveg_mask_raster} = if({tmp_lowveg_raster} == 1 && {treecov} <= " + f"{treecov_max_lowveg},1,null())" ) grass.run_command("r.mapcalc", expression=eq_lowveg2, quiet=True) grass.run_command("r.mask", raster=lowveg_mask_raster, quiet=True) @@ -315,13 +314,11 @@ def main(): # a major part of vegetation, so we have to set a strict threshold ndvi_percentile_lowveg = "75" lowveg_ndvi_perc = get_percentile(ndvi, ndvi_percentile_lowveg) - lowveg_raster = "lowveg_raster_%s" % os.getpid() + lowveg_raster = f"lowveg_raster_{os.getpid()}" rm_rasters.append(lowveg_raster) - eq_lowveg3 = "%s = if(%s > %s,%s,null())" % ( - lowveg_raster, - ndvi, - lowveg_ndvi_perc, - low_veg[0], + eq_lowveg3 = ( + f"{lowveg_raster} = if({ndvi} > {lowveg_ndvi_perc}," + f"{low_veg[0]},null())" ) grass.run_command("r.mapcalc", expression=eq_lowveg3, quiet=True) grass.run_command("r.mask", flags="r", quiet=True) @@ -349,38 +346,33 @@ def main(): forest_cats_gong = ["20"] treecov_min_forest = "60" # previously: 75 ndvi_percentile_forest = "25" - tmp_forest_raster = "forest_class_raster_%s" % os.getpid() + tmp_forest_raster = f"forest_class_raster_{os.getpid()}" rm_rasters.append(tmp_forest_raster) if ref_class_gong: - exp_forest1 = "{} = if(({}) && ({}),1,0)".format( - tmp_forest_raster, - get_or_string(ref_class_probav, forest_cats_probav), - get_or_string(ref_class_gong, forest_cats_gong), + exp_forest1 = ( + f"{tmp_forest_raster} = if((" + f"{get_or_string(ref_class_probav, forest_cats_probav)}) && (" + f"{get_or_string(ref_class_gong, forest_cats_gong)}),1,0)" ) else: - exp_forest1 = "{} = if(({}),1,0)".format( - tmp_forest_raster, - get_or_string(ref_class_probav, forest_cats_probav), + exp_forest1 = ( + f"{tmp_forest_raster} = if((" + f"{get_or_string(ref_class_probav, forest_cats_probav)}),1,0)" ) grass.run_command("r.mapcalc", expression=exp_forest1, quiet=True) - forest_mask_raster = "forest_mask_raster_%s" % os.getpid() + forest_mask_raster = f"forest_mask_raster_{os.getpid()}" rm_rasters.append(forest_mask_raster) - eq_forest2 = "%s = if(%s == 1 && %s >= %s,1,null())" % ( - forest_mask_raster, - tmp_forest_raster, - treecov, - treecov_min_forest, + eq_forest2 = ( + f"{forest_mask_raster} = if({tmp_forest_raster} == 1 && " + f"{treecov} >= {treecov_min_forest},1,null())" ) grass.run_command("r.mapcalc", expression=eq_forest2, quiet=True) grass.run_command("r.mask", raster=forest_mask_raster, quiet=True) forest_ndvi_perc = get_percentile(ndvi, ndvi_percentile_forest) - forest_raster = "forest_raster_%s" % os.getpid() + forest_raster = f"forest_raster_{os.getpid()}" rm_rasters.append(forest_raster) - eq_forest3 = "%s = if(%s > %s,%s,null())" % ( - forest_raster, - ndvi, - forest_ndvi_perc, - forest[0], + eq_forest3 = ( + f"{forest_raster} = if({ndvi} > {forest_ndvi_perc},{forest[0]},null())" ) grass.run_command("r.mapcalc", expression=eq_forest3, quiet=True) grass.run_command("r.mask", flags="r", quiet=True) @@ -389,7 +381,6 @@ def main(): training_rasters.append(forest_raster) # find bare soil training areas - grass.message(_("Checking for bare soil areas...")) # bare soil can also be part of low vegetation classes - we need to verify # later that training pixels don't mix @@ -401,27 +392,25 @@ def main(): # ndvi_percentile_baresoil = '75' # previously: 25, then 50/75 bsi_percentile_baresoil = "25" # previously: 75' - tmp_baresoil_raster = "baresoil_class_raster_%s" % os.getpid() + tmp_baresoil_raster = f"baresoil_class_raster_{os.getpid()}" rm_rasters.append(tmp_baresoil_raster) if ref_class_gong: - exp_baresoil1 = "{} = if(({}) && ({}),1,0)".format( - tmp_baresoil_raster, - get_or_string(ref_class_probav, baresoil_cats_probav), - get_or_string(ref_class_gong, baresoil_cats_gong), + exp_baresoil1 = ( + f"{tmp_baresoil_raster} = if((" + f"{get_or_string(ref_class_probav, baresoil_cats_probav)}) && (" + f"{get_or_string(ref_class_gong, baresoil_cats_gong)}),1,0)" ) else: - exp_baresoil1 = "{} = if(({}),1,0)".format( - tmp_baresoil_raster, - get_or_string(ref_class_probav, baresoil_cats_probav), + exp_baresoil1 = ( + f"{tmp_baresoil_raster} = if((" + f"{get_or_string(ref_class_probav, baresoil_cats_probav)}),1,0)" ) grass.run_command("r.mapcalc", expression=exp_baresoil1, quiet=True) - baresoil_mask_raster = "baresoil_mask_raster_%s" % os.getpid() + baresoil_mask_raster = f"baresoil_mask_raster_{os.getpid()}" rm_rasters.append(baresoil_mask_raster) - eq_baresoil2 = "%s = if(%s == 1 && %s <= %s,1,null())" % ( - baresoil_mask_raster, - tmp_baresoil_raster, - treecov, - treecov_max_baresoil, + eq_baresoil2 = ( + f"{baresoil_mask_raster} = if({tmp_baresoil_raster} == 1 && " + f"{treecov} <= {treecov_max_baresoil},1,null())" ) grass.run_command("r.mapcalc", expression=eq_baresoil2, quiet=True) grass.run_command("r.mask", raster=baresoil_mask_raster, quiet=True) @@ -436,15 +425,11 @@ def main(): ndvi_percentile_baresoil = "25" baresoil_ndvi_perc = get_percentile(ndvi, ndvi_percentile_baresoil) baresoil_bsi_perc = get_percentile(bsi, bsi_percentile_baresoil) - baresoil_raster = "baresoil_raster_%s" % os.getpid() + baresoil_raster = f"baresoil_raster_{os.getpid()}" rm_rasters.append(baresoil_raster) - eq_baresoil3 = "%s = if(%s >= %s && %s <= %s,%s,null())" % ( - baresoil_raster, - bsi, - baresoil_bsi_perc, - ndvi, - baresoil_ndvi_perc, - baresoil[0], + eq_baresoil3 = ( + f"{baresoil_raster} = if({bsi} >= {baresoil_bsi_perc} && " + f"{ndvi} <= {baresoil_ndvi_perc},{baresoil[0]},null())" ) grass.run_command("r.mapcalc", expression=eq_baresoil3, quiet=True) grass.run_command("r.mask", flags="r", quiet=True) @@ -453,33 +438,28 @@ def main(): training_rasters.append(baresoil_raster) # find built-up training areas - grass.message(_("Checking for built-up areas...")) builtup_cats_probav = ["50"] # builtup_cats_gong = ["80"] builtup_thresh_ghs = "3" ndvi_percentile_builtup = "50" # previously: 50, then 50 ndbi_percentile_builtup = "50" # previously: 75, then 50 - bu_mask_raster = "builtup_mask_raster_{}".format(os.getpid()) + bu_mask_raster = f"builtup_mask_raster_{os.getpid()}" rm_rasters.append(bu_mask_raster) - exp_builtup1 = "{} = if(({}) && ({}),1,null())".format( - bu_mask_raster, - get_or_string(ref_class_probav, builtup_cats_probav), - "{}>={}".format(ref_ghs_built, builtup_thresh_ghs), + exp_builtup1 = ( + f"{bu_mask_raster} = if((" + f"{get_or_string(ref_class_probav, builtup_cats_probav)}) && " + f"({ref_ghs_built}>={builtup_thresh_ghs}),1,null())" ) grass.run_command("r.mapcalc", expression=exp_builtup1, quiet=True) grass.run_command("r.mask", raster=bu_mask_raster, quiet=True) builtup_ndvi_perc = get_percentile(ndvi, ndvi_percentile_builtup) builtup_ndbi_perc = get_percentile(ndbi, ndbi_percentile_builtup) - builtup_raster = "builtup_raster_%s" % os.getpid() + builtup_raster = f"builtup_raster_{os.getpid()}" rm_rasters.append(builtup_raster) - eq_builtup = "%s = if(%s >= %s && %s <= %s,%s,null())" % ( - builtup_raster, - ndbi, - builtup_ndbi_perc, - ndvi, - builtup_ndvi_perc, - builtup[0], + eq_builtup = ( + f"{builtup_raster} = if({ndbi} >= {builtup_ndbi_perc} && " + f"{ndvi} <= {builtup_ndvi_perc},{builtup[0]},null())" ) grass.run_command("r.mapcalc", expression=eq_builtup, quiet=True) grass.run_command("r.mask", flags="r", quiet=True) @@ -488,7 +468,6 @@ def main(): training_rasters.append(builtup_raster) # merge training rasters - classes_in_extent = [class_n[1] for class_n in output_classes] if len(classes_in_extent) == 0: grass.fatal( @@ -499,37 +478,37 @@ def main(): ) elif len(classes_in_extent) == 1: grass.message( - _("Only found one class in region: %s" % classes_in_extent[0]) + _(f"Only found one class in region: {classes_in_extent[0]}") ) # in this case, no merging is necessary grass.run_command( "g.copy", - raster="%s,%s" % (training_rasters[0], output_raster), + raster=f"{training_rasters[0]},{output_raster}", quiet=True, ) else: grass.message( - _("Merging training data for classes %s" % classes_in_extent) + _(f"Merging training data for classes {classes_in_extent}") ) # make sure that pixels only belong to one class by masking - tr_sum = "tr_sum_%s" % os.getpid() + tr_sum = f"tr_sum_{os.getpid()}" rm_rasters.append(tr_sum) - eq = "%s =" % tr_sum + tr_sum_eq = f"{tr_sum} =" for rast in training_rasters: - eq += "if( isnull(" + rast + "), 0, 1 ) +" - grass.run_command("r.mapcalc", expression=eq[:-2], quiet=True) + tr_sum_eq += f"if( isnull({rast}), 0, 1 ) +" + grass.run_command("r.mapcalc", expression=tr_sum_eq[:-2], quiet=True) # save MASK if there is one if grass.find_file(name="MASK", element="raster")["file"]: - tmp_mask_old = "tmp_mask_old_%s" % os.getpid() + TMP_MASK_OLD = f"tmp_mask_old_{os.getpid()}" grass.run_command( - "g.rename", raster="%s,%s" % ("MASK", tmp_mask_old), quiet=True + "g.rename", raster=f"MASK,{TMP_MASK_OLD}", quiet=True ) # create mask where the pixels belong only to one class - tmp_mask_new = "tmp_mask_new_%s" % os.getpid() + tmp_mask_new = f"tmp_mask_new_{os.getpid()}" rm_rasters.append(tmp_mask_new) grass.run_command( "r.mapcalc", - expression="%s = if(%s == 1, 1, null())" % (tmp_mask_new, tr_sum), + expression=f"{tmp_mask_new} = if({tr_sum} == 1, 1, null())", quiet=True, ) grass.run_command("r.mask", raster=tr_sum, quiet=True) @@ -539,7 +518,7 @@ def main(): r_univar = grass.parse_command("r.univar", map=rast, flags="g") if int(r_univar["n"]) < int(npoints): grass.warning( - _("For <%s> only %s pixels found." % (rast, r_univar["n"])) + _(f"For <{rast}> only {r_univar['n']} pixels found.") ) # patch it together grass.run_command( @@ -547,12 +526,12 @@ def main(): ) grass.run_command("r.mask", flags="r", quiet=True) # reactivate mask if there was one before - if tmp_mask_old: - grass.run_command("r.mask", raster=tmp_mask_old, quiet=True) + if TMP_MASK_OLD: + grass.run_command("r.mask", raster=TMP_MASK_OLD, quiet=True) # extract points - grass.message(_("Extracting %s points per class..." % npoints)) + grass.message(_(f"Extracting {npoints} points per class...")) temp_output_column = output_raster.lower() # build table grass.run_command( @@ -565,13 +544,13 @@ def main(): grass.run_command( "v.db.renamecolumn", map=output_vector, - column="%s,%s" % (temp_output_column, int_column), + column=f"{temp_output_column},{int_column}", quiet=True, ) grass.run_command( "v.db.addcolumn", map=output_vector, - columns="%s VARCHAR(25)" % str_column, + columns=f"{str_column} VARCHAR(25)", quiet=True, ) for out_class in output_classes: @@ -579,17 +558,13 @@ def main(): "v.db.update", map=output_vector, column=str_column, - where="%s = %s" % (int_column, out_class[0]), + where=f"{int_column} = {out_class[0]}", value=out_class[1], quiet=True, ) - grass.message( - _("Generated output training raster map <%s>" % output_raster) - ) - grass.message( - _("Generated output training vector map <%s>" % output_vector) - ) + grass.message(_(f"Generated output training raster map <{output_raster}>")) + grass.message(_(f"Generated output training vector map <{output_vector}>")) if __name__ == "__main__": diff --git a/i.sentinel_2.autotraining/testsuite/test_i_sentinel_2_autotraining.py b/i.sentinel_2.autotraining/testsuite/test_i_sentinel_2_autotraining.py index e0c2b40..466e1d8 100644 --- a/i.sentinel_2.autotraining/testsuite/test_i_sentinel_2_autotraining.py +++ b/i.sentinel_2.autotraining/testsuite/test_i_sentinel_2_autotraining.py @@ -32,7 +32,9 @@ import grass.script as grass -class TestISentinelAutotraining(TestCase): +class TestISentinel2Autotraining(TestCase): + """Test class for i.sentinel_2.autotraining""" + pid_str = str(os.getpid()) # from actinia_test assets: probav_class = "probav_classification_2019" @@ -46,51 +48,54 @@ class TestISentinelAutotraining(TestCase): red = "lsat7_2002_30" nir = "lsat7_2002_40" swir = "lsat7_2002_50" - old_region = "saved_region_{}".format(pid_str) + old_region = f"saved_region_{pid_str}" # calculated from the nc_spm dataset: - ndvi = "ndvi_{}".format(pid_str) - ndwi = "ndwi_{}".format(pid_str) - ndbi = "ndbi_{}".format(pid_str) - bsi = "bsi_{}".format(pid_str) + ndvi = f"ndvi_{pid_str}" + ndwi = f"ndwi_{pid_str}" + ndbi = f"ndbi_{pid_str}" + bsi = f"bsi_{pid_str}" # to be generated str_column = "class_string" int_column = "class_int" - tr_map_rast = "tr_map_rast_{}".format(pid_str) - tr_map_vect = "tr_map_vect_{}".format(pid_str) + tr_map_rast = f"tr_map_rast_{pid_str}" + tr_map_vect = f"tr_map_vect_{pid_str}" @classmethod - def setUpClass(self): + # pylint: disable=invalid-name + def setUpClass(cls): """Ensures expected computational region and generated data""" - grass.run_command("g.region", save=self.old_region) - grass.run_command("g.region", raster=self.blue) + grass.run_command("g.region", save=cls.old_region) + grass.run_command("g.region", raster=cls.blue) # calculate indices ndvi_exp = ( - f"{self.ndvi} = float({self.nir}-{self.red}/" - f"float({self.nir}+{self.red}))" + f"{cls.ndvi} = float({cls.nir}-{cls.red}/" + f"float({cls.nir}+{cls.red}))" ) ndwi_exp = ( - f"{self.ndwi} = float({self.green}-{self.nir})/" - f"float({self.green}+{self.nir})" + f"{cls.ndwi} = float({cls.green}-{cls.nir})/" + f"float({cls.green}+{cls.nir})" ) ndbi_exp = ( - f"{self.ndbi} = float({self.swir}-{self.nir})/" - f"float({self.swir}+{self.nir})" + f"{cls.ndbi} = float({cls.swir}-{cls.nir})/" + f"float({cls.swir}+{cls.nir})" ) bsi_exp = ( - f"{self.bsi} = float(({self.swir}+{self.red})-" - f"({self.nir}+{self.blue}))/float(({self.swir}+" - f"{self.blue})+({self.nir}+{self.blue}))" + f"{cls.bsi} = float(({cls.swir}+{cls.red})-" + f"({cls.nir}+{cls.blue}))/float(({cls.swir}+" + f"{cls.blue})+({cls.nir}+{cls.blue}))" ) for exp in [ndvi_exp, ndwi_exp, ndbi_exp, bsi_exp]: grass.run_command("r.mapcalc", expression=exp) @classmethod - def tearDownClass(self): + # pylint: disable=invalid-name + def tearDownClass(cls): """Remove the temporary region and generated data""" - grass.run_command("g.region", region=self.old_region) - for rast in [self.ndvi, self.ndwi, self.ndbi, self.bsi]: + grass.run_command("g.region", region=cls.old_region) + for rast in [cls.ndvi, cls.ndwi, cls.ndbi, cls.bsi]: grass.run_command("g.remove", type="raster", name=rast, flags="f") + # pylint: disable=invalid-name def tearDown(self): """Remove the outputs created This is executed after each test run. @@ -140,7 +145,7 @@ def test_autotraining_vector(self): self.assertIn( col, vinfo_cols, - ("Column {} is not in the output" "vector map").format(col), + f"Column {col} is not in the output" "vector map", ) def test_autotraining_raster(self):