diff --git a/hydromt_fiat/workflows/exposure_vector.py b/hydromt_fiat/workflows/exposure_vector.py index 7140eeaf..4b172356 100644 --- a/hydromt_fiat/workflows/exposure_vector.py +++ b/hydromt_fiat/workflows/exposure_vector.py @@ -26,7 +26,7 @@ from hydromt_fiat.workflows.damage_values import ( preprocess_jrc_damage_values, preprocess_hazus_damage_values, - preprocess_damage_values + preprocess_damage_values, ) from hydromt_fiat.workflows.exposure import Exposure from hydromt_fiat.workflows.utils import detect_delimiter @@ -150,7 +150,7 @@ def setup_buildings_from_single_source( gfh_unit: Units = None, ground_elevation: Union[int, float, str, Path, None] = None, grnd_elev_unit: Units = None, - eur_to_us_dollar: bool = False + eur_to_us_dollar: bool = False, ) -> None: """Set up asset locations and other available data from a single source. @@ -241,10 +241,7 @@ def setup_buildings_from_single_source( # Set the ground_flht if not yet set # TODO: Check a better way to access to to the geometries, self.empousure_geoms is a list an not a geodataframe if ground_elevation is not None: - self.setup_ground_elevation( - ground_elevation, - grnd_elev_unit - ) + self.setup_ground_elevation(ground_elevation, grnd_elev_unit) # Remove the geometry column from the exposure_db if "geometry" in self.exposure_db: @@ -316,14 +313,33 @@ def setup_roads( crs = self.exposure_geoms[0].crs roads = roads.to_crs(crs) + # recreate object_id for buildings and roads + full_exposure = pd.concat( + [self.get_full_gdf(self.exposure_db), roads] + ).reset_index(drop=True) + full_exposure["object_id"] = full_exposure["object_id"].index + roads = full_exposure[ + full_exposure["primary_object_type"].str.contains( + "road", regex=False, na=False + ) + ] + buildings = full_exposure[ + ~full_exposure["primary_object_type"].str.contains( + "road", regex=False, na=False + ) + ] + # Set the exposure_geoms self.set_exposure_geoms(roads[["object_id", "geometry"]]) self.set_geom_names("roads") + idx_buildings = self.geom_names.index("buildings") + self.exposure_geoms[idx_buildings] = buildings[["object_id", "geometry"]] + del full_exposure["geometry"] - del roads["geometry"] + assert not full_exposure["object_id"].duplicated().any() # Update the exposure_db - self.exposure_db = pd.concat([self.exposure_db, roads]).reset_index(drop=True) + self.exposure_db = full_exposure def setup_buildings_from_multiple_sources( self, @@ -344,7 +360,7 @@ def setup_buildings_from_multiple_sources( bf_conversion: bool = False, keep_unclassified: bool = True, damage_translation_fn: Union[Path, str] = None, - eur_to_us_dollar: bool = False, + eur_to_us_dollar: bool = False, ): """ Set up the exposure data using multiple sources. @@ -416,13 +432,19 @@ def setup_buildings_from_multiple_sources( occupancy_source, occupancy_attr, keep_unclassified=keep_unclassified ) self.setup_max_potential_damage( - max_potential_damage, damage_types, country=country, damage_translation_fn = damage_translation_fn, eur_to_us_dollar = eur_to_us_dollar + max_potential_damage, + damage_types, + country=country, + damage_translation_fn=damage_translation_fn, + eur_to_us_dollar=eur_to_us_dollar, ) if ( any( isinstance(geom, Polygon) for geom in self.exposure_geoms[0]["geometry"] - ) or any(isinstance(geom, MultiPolygon) for geom in self.exposure_geoms[0]["geometry"] - + ) + or any( + isinstance(geom, MultiPolygon) + for geom in self.exposure_geoms[0]["geometry"] ) and bf_conversion ): @@ -447,7 +469,7 @@ def setup_asset_locations(self, asset_locations: str) -> None: a point or polygon dataset. """ self.logger.info("Setting up asset locations...") - #if isinstance(asset_locations, str): + # if isinstance(asset_locations, str): if str(asset_locations).upper() == "OSM": polygon = self.region.to_crs(4326).geometry.values[0] assets = get_assets_from_osm(polygon) @@ -478,7 +500,7 @@ def setup_asset_locations(self, asset_locations: str) -> None: # Set the asset locations to the geometry variable (self.exposure_geoms) # and set the geom name if len(assets.columns) > 2: - assets = assets[['object_id', 'geometry']] + assets = assets[["object_id", "geometry"]] self.set_exposure_geoms(assets) self.set_geom_names("buildings") @@ -539,7 +561,9 @@ def setup_occupancy_type( occupancy_source, geom=self.region ) if occupancy_attr is not None: - occupancy_building.rename(columns={occupancy_attr: type_add}, inplace=True) + occupancy_building.rename( + columns={occupancy_attr: type_add}, inplace=True + ) occupancy_types = [type_add] # Check if the CRS of the occupancy map is the same as the exposure data @@ -563,14 +587,17 @@ def setup_occupancy_type( # occupancy_landuse. Only take the largest overlapping object from the # occupancy_landuse. gdf = gpd.sjoin( - self.exposure_geoms[0], occupancy_building[to_keep], how = "left", predicate="intersects" + self.exposure_geoms[0], + occupancy_building[to_keep], + how="left", + predicate="intersects", ) gdf.drop(columns=["index_right"], inplace=True) - if occupancy_source == 'OSM': - - ## Landuse - # Replace values with landuse if applicable for Primary and Secondary Object Type + if occupancy_source == "OSM": + + ## Landuse + # Replace values with landuse if applicable for Primary and Secondary Object Type occupancy_landuse.rename( columns={ "primary_object_type": "pot", @@ -578,11 +605,13 @@ def setup_occupancy_type( }, inplace=True, ) - + gdf_landuse = gdf.sjoin( - occupancy_landuse[["geometry", "pot", "pot_2"]], how="left", predicate="intersects" + occupancy_landuse[["geometry", "pot", "pot_2"]], + how="left", + predicate="intersects", ) - gdf_landuse.reset_index(inplace = True, drop=True) + gdf_landuse.reset_index(inplace=True, drop=True) # Replace values with landuse gdf_landuse.loc[gdf_landuse["pot"].notna(), "primary_object_type"] = ( @@ -593,7 +622,6 @@ def setup_occupancy_type( ) gdf_landuse.drop(columns=["index_right", "pot", "pot_2"], inplace=True) - ## Amenity # Fill nan values with values amenity for Primary and Secondary Object Type occupancy_amenity.rename( @@ -605,40 +633,53 @@ def setup_occupancy_type( ) gdf_amenity = gdf_landuse.sjoin( - occupancy_amenity[["geometry", "pot", "pot_2"]], how="left", predicate="intersects" + occupancy_amenity[["geometry", "pot", "pot_2"]], + how="left", + predicate="intersects", ) - gdf_amenity.reset_index(inplace = True, drop=True) + gdf_amenity.reset_index(inplace=True, drop=True) # Replace values with amenity - gdf_amenity.loc[gdf_amenity["pot"].notna(), "primary_object_type"] = gdf_amenity["pot"] - gdf_amenity.loc[gdf_amenity["pot_2"].notna(), "secondary_object_type"] = gdf_amenity["pot_2"] - + gdf_amenity.loc[gdf_amenity["pot"].notna(), "primary_object_type"] = ( + gdf_amenity["pot"] + ) + gdf_amenity.loc[ + gdf_amenity["pot_2"].notna(), "secondary_object_type" + ] = gdf_amenity["pot_2"] + gdf_amenity.drop(columns=["index_right", "pot", "pot_2"], inplace=True) # Rename some major catgegories gdf_amenity.loc[ - gdf_amenity["secondary_object_type"] == "yes", "secondary_object_type" + gdf_amenity["secondary_object_type"] == "yes", + "secondary_object_type", ] = "residential" gdf_amenity.loc[ - gdf_amenity["secondary_object_type"] == "house", "secondary_object_type" + gdf_amenity["secondary_object_type"] == "house", + "secondary_object_type", ] = "residential" gdf_amenity.loc[ - gdf_amenity["secondary_object_type"] == "apartments", "secondary_object_type" + gdf_amenity["secondary_object_type"] == "apartments", + "secondary_object_type", ] = "residential" gdf = gdf_amenity - gdf.drop_duplicates(subset='geometry', inplace=True) + gdf.drop_duplicates(subset="geometry", inplace=True) # Remove the objects that do not have a primary_object_type, that were not # overlapping with the land use map, or that had a land use type of 'nan'. if "primary_object_type" in gdf.columns: - gdf.loc[gdf["primary_object_type"] == "", "primary_object_type"] = np.nan + gdf.loc[gdf["primary_object_type"] == "", "primary_object_type"] = ( + np.nan + ) nr_without_primary_object = len( gdf.loc[gdf["primary_object_type"].isna()].index ) if keep_unclassified: # merge assets with occupancy if len(self.exposure_geoms[0]) > len(gdf): - gdf = pd.concat([gdf, self.exposure_geoms[0]], ignore_index = True) - gdf.drop_duplicates(subset = "object_id", inplace = True) + gdf = pd.concat( + [gdf, self.exposure_geoms[0]], ignore_index=True + ) + gdf.drop_duplicates(subset="object_id", inplace=True) # assign residential if no primary object type gdf.loc[ gdf["primary_object_type"].isna(), "secondary_object_type" @@ -674,7 +715,7 @@ def setup_occupancy_type( # Add secondary Object Type if not in columns if "secondary_object_type" not in gdf.columns: - gdf["secondary_object_type"] =gdf["primary_object_type"] + gdf["secondary_object_type"] = gdf["primary_object_type"] # Update the exposure geoms self.exposure_geoms[0] = gdf[["object_id", "geometry"]] @@ -827,7 +868,7 @@ def setup_ground_floor_height( gfh_attribute_name: Union[str, List[str], None] = None, gfh_method: Union[str, List[str], None] = "nearest", max_dist: float = 10, - gfh_unit: Units = None + gfh_unit: Units = None, ) -> None: """Set the ground_flht of the exposure data. This function overwrites the existing ground_flht column if it already exists. @@ -931,7 +972,7 @@ def setup_max_potential_damage( max_dist: float = 10, country: Union[str, None] = None, damage_translation_fn: Union[str, Path] = None, - eur_to_us_dollar: bool = False + eur_to_us_dollar: bool = False, ) -> None: """Setup the max potential damage column of the exposure data in various ways. @@ -969,13 +1010,17 @@ def setup_max_potential_damage( ): # Set the column(s) to a single value for damage_type in damage_types: - self.exposure_db[f"max_damage_{damage_type}"] = ( - max_potential_damage - ) + self.exposure_db[f"max_damage_{damage_type}"] = max_potential_damage elif isinstance(max_potential_damage, list): # Multiple files are used to assign the ground_flht to the assets - for max_damage,attribute, method, max_dis,damage_type in zip(max_potential_damage,attribute_name,method_damages,max_dist,damage_types): + for max_damage, attribute, method, max_dis, damage_type in zip( + max_potential_damage, + attribute_name, + method_damages, + max_dist, + damage_types, + ): # When the max_potential_damage is a string but not jrc_damage_values # or hazus_max_potential_damages. Here, a single file is used to # assign the ground_flht to the assets @@ -1040,7 +1085,9 @@ def setup_max_potential_damage( f"No country specified, using the '{country}' JRC damage values." ) - damage_values = preprocess_jrc_damage_values(damage_source, country, eur_to_us_dollar) + damage_values = preprocess_jrc_damage_values( + damage_source, country, eur_to_us_dollar + ) elif max_potential_damage == "hazus_max_potential_damages": damage_source = self.data_catalog.get_dataframe(max_potential_damage) @@ -1054,7 +1101,9 @@ def setup_max_potential_damage( gdf = gdf.dropna(subset="primary_object_type") # Set the damage values to the exposure data - self.set_max_potential_damage_columns(damage_types, damage_values,gdf, max_potential_damage) + self.set_max_potential_damage_columns( + damage_types, damage_values, gdf, max_potential_damage + ) elif isinstance(max_potential_damage, str) or isinstance( max_potential_damage, Path @@ -1063,9 +1112,13 @@ def setup_max_potential_damage( max_potential_damage = str(max_potential_damage) # Using a csv file with a translation table to assign damages to damage curves - if max_potential_damage.endswith(".csv") or max_potential_damage.endswith(".xlsx"): + if max_potential_damage.endswith(".csv") or max_potential_damage.endswith( + ".xlsx" + ): damage_source = self.data_catalog.get_dataframe(max_potential_damage) - damage_values = preprocess_damage_values(damage_source, damage_translation_fn) + damage_values = preprocess_damage_values( + damage_source, damage_translation_fn + ) # Calculate the area of each object gdf = self.get_full_gdf(self.exposure_db)[ @@ -1075,7 +1128,9 @@ def setup_max_potential_damage( gdf = gdf.dropna(subset="primary_object_type") # Set the damage values to the exposure data - self.set_max_potential_damage_columns(damage_types, damage_values,gdf, max_potential_damage) + self.set_max_potential_damage_columns( + damage_types, damage_values, gdf, max_potential_damage + ) else: # When the max_potential_damage is a string but not jrc_damage_values # or hazus_max_potential_damages. Here, a single file is used to @@ -1083,13 +1138,17 @@ def setup_max_potential_damage( mpd = self.data_catalog.get_geodataframe(max_potential_damage) gdf = self.get_full_gdf(self.exposure_db) - # If roads in model filter out for spatial joint if gdf["primary_object_type"].str.contains("road").any(): gdf_roads = gdf[gdf["primary_object_type"].str.contains("road")] # Spatial joint exposure and updated damages gdf = join_spatial_data( - gdf[~gdf.isin(gdf_roads)].dropna(subset=["geometry"]), mpd, attribute_name, method_damages, max_dist, self.logger + gdf[~gdf.isin(gdf_roads)].dropna(subset=["geometry"]), + mpd, + attribute_name, + method_damages, + max_dist, + self.logger, ) gdf = pd.concat([gdf, gdf_roads]) else: @@ -1101,7 +1160,7 @@ def setup_max_potential_damage( f"max_damage_{damage_types[0]}", attribute_name, ) - + def setup_ground_elevation( self, ground_elevation: Union[None, str, Path], grnd_elev_unit: Units = None ) -> None: @@ -1123,10 +1182,10 @@ def setup_ground_elevation( exposure_db=self.exposure_db, exposure_geoms=self.get_full_gdf(self.exposure_db), ) - + # Unit conversion if grnd_elev_unit: - self.unit_conversion(parameter = "grnd_elevtn", unit = grnd_elev_unit) + self.unit_conversion(parameter="grnd_elevtn", unit=grnd_elev_unit) else: self.logger.warning( @@ -1134,7 +1193,7 @@ def setup_ground_elevation( ) self.logger.warning("ground_elevtn will be set to 0") self.exposure_db["ground_elevtn"] = 0 - + def setup_impacted_population( self, impacted_population_fn: Union[ @@ -1167,35 +1226,45 @@ def setup_impacted_population( # TODO: Add support for other methods if isinstance(impacted_population_fn, str) or isinstance( - impacted_population_fn, Path): + impacted_population_fn, Path + ): # When the max_potential_damage is a string but not jrc_damage_values # or hazus_max_potential_damages. Here, a single file is used to # assign the mpd to the assets pop_impacted = self.data_catalog.get_geodataframe(impacted_population_fn) gdf = self.get_full_gdf(self.exposure_db) - # If roads in model filter out for spatial joint if gdf["primary_object_type"].str.contains("road").any(): gdf_roads = gdf[gdf["primary_object_type"].str.contains("road")] # Spatial joint exposure and updated damages gdf = join_spatial_data( - gdf[~gdf.isin(gdf_roads)].dropna(subset=["geometry"]), pop_impacted, attribute_name, method_impacted_pop, max_dist, self.logger + gdf[~gdf.isin(gdf_roads)].dropna(subset=["geometry"]), + pop_impacted, + attribute_name, + method_impacted_pop, + max_dist, + self.logger, ) gdf = pd.concat([gdf, gdf_roads]) else: gdf = join_spatial_data( - gdf, pop_impacted, attribute_name, method_impacted_pop, max_dist, self.logger + gdf, + pop_impacted, + attribute_name, + method_impacted_pop, + max_dist, + self.logger, ) - del gdf['geometry'] + del gdf["geometry"] self.exposure_db = self._set_values_from_other_column( gdf, "max_affected_people", attribute_name, ) self.exposure_db["fn_affected_people"] = "population" - + def update_max_potential_damage( self, updated_max_potential_damages: pd.DataFrame ) -> None: @@ -1218,9 +1287,7 @@ def update_max_potential_damage( return damage_cols = [ - c - for c in updated_max_potential_damages.columns - if "max_damage_" in c + c for c in updated_max_potential_damages.columns if "max_damage_" in c ] updated_max_potential_damages.set_index("object_id", inplace=True) self.exposure_db.set_index("object_id", inplace=True, drop=False) @@ -1279,15 +1346,13 @@ def raise_ground_floor_height( ) self.exposure_db.loc[ ( - self.exposure_db["ground_flht"] - + self.exposure_db["ground_elevtn"] + self.exposure_db["ground_flht"] + self.exposure_db["ground_elevtn"] < raise_by ) & self.exposure_db.index.isin(idx), "ground_flht", ] += raise_by - ( - self.exposure_db["ground_flht"] - + self.exposure_db["ground_elevtn"] + self.exposure_db["ground_flht"] + self.exposure_db["ground_elevtn"] ) elif height_reference.lower() in ["geom", "table"]: @@ -1371,9 +1436,7 @@ def truncate_damage_function( dfs_to_modify = [ d for d in list( - self.exposure_db.iloc[idx, :][ - f"fn_damage_{df_type}" - ].unique() + self.exposure_db.iloc[idx, :][f"fn_damage_{df_type}"].unique() ) if d == d ] @@ -1438,9 +1501,7 @@ def calculate_damages_new_exposure_object( # Potential Structural/Content/Other Damage. for c in damages_cols: total_damages = sum(self.exposure_db[c].fillna(0)) - new_damages[c.split("max_damage_")[-1]] = ( - total_damages * percent_growth - ) + new_damages[c.split("max_damage_")[-1]] = total_damages * percent_growth return new_damages @@ -1519,9 +1580,7 @@ def setup_new_composite_areas( for damage_type in damage_types } df_value_counts_dict = { - damage_type: self.exposure_db[ - "fn_damage_" + damage_type - ].value_counts() + damage_type: self.exposure_db["fn_damage_" + damage_type].value_counts() for damage_type in damage_types } new_damage_functions = vulnerability.calculate_weighted_damage_function( @@ -1531,19 +1590,23 @@ def setup_new_composite_areas( # Add the new development area as an object to the Exposure Modification file. new_area = gpd.read_file(geom_file, engine="pyogrio") # check_crs(new_area, geom_file) #TODO implement again - + # Check if the column "height" is in the provided spatial file, which indicates the individual heights above the reference # If not the provided value will be used uniformly if "height" not in new_area.columns: new_area["height"] = ground_floor_height - self.logger.info(f"Using uniform value of {ground_floor_height}" - f"to specify the elevation above {elevation_reference} of FFE of new composite area(s).") + self.logger.info( + f"Using uniform value of {ground_floor_height}" + f"to specify the elevation above {elevation_reference} of FFE of new composite area(s)." + ) else: - self.logger.info(f"Using 'height' column from {geom_file} to specify the elevation above {elevation_reference} " - "for FFE of new composite area(s).") + self.logger.info( + f"Using 'height' column from {geom_file} to specify the elevation above {elevation_reference} " + "for FFE of new composite area(s)." + ) + + new_area["object_id"] = None # add object_id column to area file - new_area["object_id"] = None # add object_id column to area file - new_objects = [] # Calculate the total area to use for adding the damages relative to area @@ -1566,7 +1629,7 @@ def setup_new_composite_areas( for i in range(len(new_area.index)): new_geom = new_area.geometry.iloc[i] new_id = max_id + 1 - new_area["object_id"].iloc[i] = new_id # assign object_id to polygons + new_area["object_id"].iloc[i] = new_id # assign object_id to polygons perc_damages = new_geom.area / total_area # Idea: Reduction factor for the part of the area is not build-up? @@ -1582,9 +1645,7 @@ def setup_new_composite_areas( } dict_new_objects_data.update( { - f"fn_damage_{damage_type}": [ - new_damage_functions[damage_type] - ] + f"fn_damage_{damage_type}": [new_damage_functions[damage_type]] for damage_type in damage_types } ) @@ -1617,12 +1678,15 @@ def setup_new_composite_areas( exposure_db=new_objects, exposure_geoms=_new_exposure_geoms, ) - + if elevation_reference == "datum": # Ensure that the new objects have a first floor height that elevates them above the requirement new_objects["ground_flht"] = new_objects.apply( - lambda row: max(row["ground_flht"], new_area.loc[row.name, "height"] - row["ground_elevtn"]), - axis=1 + lambda row: max( + row["ground_flht"], + new_area.loc[row.name, "height"] - row["ground_elevtn"], + ), + axis=1, ) self.logger.info( f"The elevation of the new development area is {new_area['height'].values} {self.unit}" @@ -1689,7 +1753,9 @@ def link_exposure_vulnerability( linking_per_damage_type = exposure_linking_table.loc[ exposure_linking_table["Damage Type"] == damage_type, : ] - assert not linking_per_damage_type.empty, f"Damage type {damage_type} not found in the exposure-vulnerability linking table" + assert ( + not linking_per_damage_type.empty + ), f"Damage type {damage_type} not found in the exposure-vulnerability linking table" # Create a dictionary that links the exposure data to the vulnerability data linking_dict = dict( @@ -1758,9 +1824,9 @@ def link_exposure_vulnerability( f"{str(list(diff_secondary_linking_types))}" ) - self.exposure_db[f"fn_damage_{damage_type}"] = ( - self.exposure_db[linking_column].map(linking_dict) - ) + self.exposure_db[f"fn_damage_{damage_type}"] = self.exposure_db[ + linking_column + ].map(linking_dict) self.logger.info( f"The {linking_column} was used to link the exposure data to the " @@ -1785,7 +1851,9 @@ def get_max_potential_damage_columns(self) -> List[str]: """ return [c for c in self.exposure_db.columns if "max_damage_" in c] - def set_max_potential_damage_columns(self, damage_types, damage_values,gdf, max_potential_damage) -> None: + def set_max_potential_damage_columns( + self, damage_types, damage_values, gdf, max_potential_damage + ) -> None: """Calculate and set the maximum potential damage columns based on the provided damage types and values. Parameters @@ -1803,22 +1871,20 @@ def set_max_potential_damage_columns(self, damage_types, damage_values,gdf, max_ None """ for damage_type in damage_types: - # Calculate the maximum potential damage for each object and per damage type - try: - self.exposure_db[ - f"max_damage_{damage_type}" - ] = [ - damage_values[building_type][damage_type.lower()] - * square_meters - for building_type, square_meters in zip( - gdf["primary_object_type"], gdf["area"] - ) - ] - except KeyError as e: - self.logger.warning( - f"Not found in the {max_potential_damage} damage " - f"value data: {e}" - ) + # Calculate the maximum potential damage for each object and per damage type + try: + self.exposure_db[f"max_damage_{damage_type}"] = [ + damage_values[building_type][damage_type.lower()] * square_meters + for building_type, square_meters in zip( + gdf["primary_object_type"], gdf["area"] + ) + ] + except KeyError as e: + self.logger.warning( + f"Not found in the {max_potential_damage} damage " + f"value data: {e}" + ) + def get_damage_function_columns(self) -> List[str]: """Returns the damage function columns in @@ -1965,7 +2031,7 @@ def get_full_gdf( # Check how many exposure geoms there are if len(self.exposure_geoms) == 1: - #NOTE: This is only used for the transition time from old to new models and for the translation script! + # NOTE: This is only used for the transition time from old to new models and for the translation script! if "Object ID" in self.exposure_geoms[0].columns: assert set(self.exposure_geoms[0]["Object ID"]) == set(df["Object ID"]) else: @@ -2093,7 +2159,7 @@ def set_height_relative_to_reference( # Ensure that the raise_by variable has the correct type if not isinstance(raise_by, pd.Series): raise_by = pd.Series(raise_by, index=exposure_to_modify.index) - + # Find indices of properties that are below the required level properties_below_level = ( exposure_to_modify.loc[:, "ground_flht"] @@ -2188,18 +2254,20 @@ def get_continent_name(self, continent_code: str) -> str: } return continent_dict[continent_code] - def unit_conversion(self, parameter: str,unit: Union[str, Units]) -> Union[str, Units]: - # Unit conversion + def unit_conversion( + self, parameter: str, unit: Union[str, Units] + ) -> Union[str, Units]: + # Unit conversion if unit != self.unit: if (unit == Units.meters.value) and (self.unit == Units.feet.value): - self.exposure_db[parameter] = self.exposure_db[ - parameter - ].apply(lambda x: x * Conversion.meters_to_feet.value) + self.exposure_db[parameter] = self.exposure_db[parameter].apply( + lambda x: x * Conversion.meters_to_feet.value + ) elif (unit == Units.feet.value) and (self.unit == Units.meters.value): - self.exposure_db[parameter] = self.exposure_db[ - parameter - ].apply(lambda x: x * Conversion.feet_to_meters.value) + self.exposure_db[parameter] = self.exposure_db[parameter].apply( + lambda x: x * Conversion.feet_to_meters.value + ) else: self.logger.warning( f"The {parameter} unit is not valid. Please provide the unit of your {parameter} in 'meters' or 'feet'" @@ -2218,4 +2286,4 @@ def _set_values_from_other_column( df[col_to_copy].notna(), col_to_copy ] del df[col_to_copy] - return df \ No newline at end of file + return df