diff --git a/climada/engine/forecast.py b/climada/engine/forecast.py index 6d9a0ca19e..1be74cb4c6 100644 --- a/climada/engine/forecast.py +++ b/climada/engine/forecast.py @@ -186,7 +186,7 @@ def __init__( if exposure_name is None: try: self.exposure_name = u_coord.country_to_iso( - exposure.gdf.region_id.unique()[0], "name" + exposure.gdf["region_id"].unique()[0], "name" ) except (KeyError, AttributeError): self.exposure_name = "custom" diff --git a/climada/engine/impact.py b/climada/engine/impact.py index 97bbd6d90f..f357538e53 100644 --- a/climada/engine/impact.py +++ b/climada/engine/impact.py @@ -243,8 +243,8 @@ def from_eih(cls, exposures, hazard, at_event, eai_exp, aai_agg, imp_mat=None): date = hazard.date, frequency = hazard.frequency, frequency_unit = hazard.frequency_unit, - coord_exp = np.stack([exposures.gdf.latitude.values, - exposures.gdf.longitude.values], + coord_exp = np.stack([exposures.gdf['latitude'].values, + exposures.gdf['longitude'].values], axis=1), crs = exposures.crs, unit = exposures.value_unit, @@ -1081,25 +1081,25 @@ def from_csv(cls, file_name): # pylint: disable=no-member LOGGER.info('Reading %s', file_name) imp_df = pd.read_csv(file_name) - imp = cls(haz_type=imp_df.haz_type[0]) - imp.unit = imp_df.unit[0] - imp.tot_value = imp_df.tot_value[0] - imp.aai_agg = imp_df.aai_agg[0] - imp.event_id = imp_df.event_id[~np.isnan(imp_df.event_id)].values + imp = cls(haz_type=imp_df['haz_type'][0]) + imp.unit = imp_df['unit'][0] + imp.tot_value = imp_df['tot_value'][0] + imp.aai_agg = imp_df['aai_agg'][0] + imp.event_id = imp_df['event_id'][~np.isnan(imp_df['event_id'])].values num_ev = imp.event_id.size - imp.event_name = imp_df.event_name[:num_ev].values.tolist() - imp.date = imp_df.event_date[:num_ev].values - imp.at_event = imp_df.at_event[:num_ev].values - imp.frequency = imp_df.event_frequency[:num_ev].values - imp.frequency_unit = imp_df.frequency_unit[0] if 'frequency_unit' in imp_df \ + imp.event_name = imp_df['event_name'][:num_ev].values.tolist() + imp.date = imp_df['event_date'][:num_ev].values + imp.at_event = imp_df['at_event'][:num_ev].values + imp.frequency = imp_df['event_frequency'][:num_ev].values + imp.frequency_unit = imp_df['frequency_unit'][0] if 'frequency_unit' in imp_df \ else DEF_FREQ_UNIT - imp.eai_exp = imp_df.eai_exp[~np.isnan(imp_df.eai_exp)].values + imp.eai_exp = imp_df['eai_exp'][~np.isnan(imp_df['eai_exp'])].values num_exp = imp.eai_exp.size imp.coord_exp = np.zeros((num_exp, 2)) - imp.coord_exp[:, 0] = imp_df.exp_lat[:num_exp] - imp.coord_exp[:, 1] = imp_df.exp_lon[:num_exp] + imp.coord_exp[:, 0] = imp_df['exp_lat'][:num_exp] + imp.coord_exp[:, 1] = imp_df['exp_lon'][:num_exp] try: - imp.crs = u_coord.to_crs_user_input(imp_df.exp_crs.values[0]) + imp.crs = u_coord.to_crs_user_input(imp_df['exp_crs'].values[0]) except AttributeError: imp.crs = DEF_CRS @@ -1129,23 +1129,23 @@ def from_excel(cls, file_name): dfr = pd.read_excel(file_name) imp = cls(haz_type=str(dfr['haz_type'][0])) - imp.unit = dfr.unit[0] - imp.tot_value = dfr.tot_value[0] - imp.aai_agg = dfr.aai_agg[0] + imp.unit = dfr['unit'][0] + imp.tot_value = dfr['tot_value'][0] + imp.aai_agg = dfr['aai_agg'][0] - imp.event_id = dfr.event_id[~np.isnan(dfr.event_id.values)].values - imp.event_name = dfr.event_name[:imp.event_id.size].values - imp.date = dfr.event_date[:imp.event_id.size].values - imp.frequency = dfr.event_frequency[:imp.event_id.size].values - imp.frequency_unit = dfr.frequency_unit[0] if 'frequency_unit' in dfr else DEF_FREQ_UNIT - imp.at_event = dfr.at_event[:imp.event_id.size].values + imp.event_id = dfr['event_id'][~np.isnan(dfr['event_id'].values)].values + imp.event_name = dfr['event_name'][:imp.event_id.size].values + imp.date = dfr['event_date'][:imp.event_id.size].values + imp.frequency = dfr['event_frequency'][:imp.event_id.size].values + imp.frequency_unit = dfr['frequency_unit'][0] if 'frequency_unit' in dfr else DEF_FREQ_UNIT + imp.at_event = dfr['at_event'][:imp.event_id.size].values - imp.eai_exp = dfr.eai_exp[~np.isnan(dfr.eai_exp.values)].values + imp.eai_exp = dfr['eai_exp'][~np.isnan(dfr['eai_exp'].values)].values imp.coord_exp = np.zeros((imp.eai_exp.size, 2)) - imp.coord_exp[:, 0] = dfr.exp_lat.values[:imp.eai_exp.size] - imp.coord_exp[:, 1] = dfr.exp_lon.values[:imp.eai_exp.size] + imp.coord_exp[:, 0] = dfr['exp_lat'].values[:imp.eai_exp.size] + imp.coord_exp[:, 1] = dfr['exp_lon'].values[:imp.eai_exp.size] try: - imp.crs = u_coord.to_csr_user_input(dfr.exp_crs.values[0]) + imp.crs = u_coord.to_csr_user_input(dfr['exp_crs'].values[0]) except AttributeError: imp.crs = DEF_CRS @@ -1324,14 +1324,14 @@ def video_direct_impact(exp, impf_set, haz_list, file_name='', np.array([haz.intensity.max() for haz in haz_list]).max()] if 'vmin' not in args_exp: - args_exp['vmin'] = exp.gdf.value.values.min() + args_exp['vmin'] = exp.gdf['value'].values.min() if 'vmin' not in args_imp: args_imp['vmin'] = np.array([imp.eai_exp.min() for imp in imp_list if imp.eai_exp.size]).min() if 'vmax' not in args_exp: - args_exp['vmax'] = exp.gdf.value.values.max() + args_exp['vmax'] = exp.gdf['value'].values.max() if 'vmax' not in args_imp: args_imp['vmax'] = np.array([imp.eai_exp.max() for imp in imp_list diff --git a/climada/engine/impact_calc.py b/climada/engine/impact_calc.py index f050607c50..d0fc052869 100644 --- a/climada/engine/impact_calc.py +++ b/climada/engine/impact_calc.py @@ -154,8 +154,8 @@ def impact(self, save_mat=True, assign_centroids=True, exp_gdf.size, self.n_events) imp_mat_gen = self.imp_mat_gen(exp_gdf, impf_col) - insured = ('cover' in exp_gdf and exp_gdf.cover.max() >= 0) \ - or ('deductible' in exp_gdf and exp_gdf.deductible.max() > 0) + insured = ('cover' in exp_gdf and exp_gdf['cover'].max() >= 0) \ + or ('deductible' in exp_gdf and exp_gdf['deductible'].max() > 0) if insured: LOGGER.info("cover and/or deductible columns detected," " going to calculate insured impact") @@ -253,8 +253,8 @@ def minimal_exp_gdf(self, impf_col, assign_centroids, ignore_cover, ignore_deduc " Run 'exposures.assign_centroids()' beforehand or set" " 'assign_centroids' to 'True'") mask = ( - (self.exposures.gdf.value.values == self.exposures.gdf.value.values) # value != NaN - & (self.exposures.gdf.value.values != 0) # value != 0 + (self.exposures.gdf['value'].values == self.exposures.gdf['value'].values)# value != NaN + & (self.exposures.gdf['value'].values != 0) # value != 0 & (self.exposures.gdf[self.hazard.centr_exp_col].values >= 0) # centroid assigned ) @@ -320,7 +320,7 @@ def _chunk_exp_idx(haz_size, idx_exp_impf): ) idx_exp_impf = (exp_gdf[impf_col].values == impf_id).nonzero()[0] for exp_idx in _chunk_exp_idx(self.hazard.size, idx_exp_impf): - exp_values = exp_gdf.value.values[exp_idx] + exp_values = exp_gdf['value'].values[exp_idx] cent_idx = exp_gdf[self.hazard.centr_exp_col].values[exp_idx] yield ( self.impact_matrix(exp_values, cent_idx, impf), @@ -363,10 +363,10 @@ def insured_mat_gen(self, imp_mat_gen, exp_gdf, impf_col): haz_type=self.hazard.haz_type, fun_id=impf_id) if 'deductible' in exp_gdf: - deductible = exp_gdf.deductible.values[exp_idx] + deductible = exp_gdf['deductible'].values[exp_idx] mat = self.apply_deductible_to_mat(mat, deductible, self.hazard, cent_idx, impf) if 'cover' in exp_gdf: - cover = exp_gdf.cover.values[exp_idx] + cover = exp_gdf['cover'].values[exp_idx] mat = self.apply_cover_to_mat(mat, cover) yield (mat, exp_idx) diff --git a/climada/engine/impact_data.py b/climada/engine/impact_data.py index 805773220d..98ca074e53 100644 --- a/climada/engine/impact_data.py +++ b/climada/engine/impact_data.py @@ -355,23 +355,23 @@ def create_lookup(emdat_data, start, end, disaster_subtype='Tropical cyclone'): 'Date_start_EM_ordinal', 'Disaster_name', 'EM_ID', 'ibtracsID', 'allocation_level', 'possible_track', 'possible_track_all']) - lookup.hit_country = data.ISO - lookup.Date_start_EM = data.Date_start_clean - lookup.Disaster_name = data.Disaster_name - lookup.EM_ID = data.Disaster_No + lookup['hit_country'] = data['ISO'] + lookup['Date_start_EM'] = data['Date_start_clean'] + lookup['Disaster_name'] = data['Disaster_name'] + lookup['EM_ID'] = data['Disaster_No'] lookup = lookup.reset_index(drop=True) # create ordinals - for i in range(0, len(data.Date_start_clean.values)): - lookup.Date_start_EM_ordinal[i] = datetime.toordinal( - datetime.strptime(lookup.Date_start_EM.values[i], '%Y-%m-%d')) + for i in range(0, len(data['Date_start_clean'].values)): + lookup['Date_start_EM_ordinal'][i] = datetime.toordinal( + datetime.strptime(lookup['Date_start_EM'].values[i], '%Y-%m-%d')) # ordinals to numeric - lookup.Date_start_EM_ordinal = pd.to_numeric(lookup.Date_start_EM_ordinal) + lookup['Date_start_EM_ordinal'] = pd.to_numeric(lookup['Date_start_EM_ordinal']) # select time emdat_start = datetime.toordinal(datetime.strptime(start, '%Y-%m-%d')) emdat_end = datetime.toordinal(datetime.strptime(end, '%Y-%m-%d')) - lookup = lookup[lookup.Date_start_EM_ordinal.values > emdat_start] - lookup = lookup[lookup.Date_start_EM_ordinal.values < emdat_end] + lookup = lookup[lookup['Date_start_EM_ordinal'].values > emdat_start] + lookup = lookup[lookup['Date_start_EM_ordinal'].values < emdat_end] return lookup @@ -397,15 +397,16 @@ def emdat_possible_hit(lookup, hit_countries, delta_t): # tracks: processed IBtracks with info which track hit which country # delta_t: time difference of start of EMdat and IBrtacks possible_hit_all = [] - for i in range(0, len(lookup.EM_ID.values)): + for i in range(0, len(lookup['EM_ID'].values)): possible_hit = [] country_tracks = hit_countries[ - hit_countries['hit_country'] == lookup.hit_country.values[i]] - for j in range(0, len(country_tracks.Date_start.values)): - if (lookup.Date_start_EM_ordinal.values[i] - country_tracks.Date_start.values[j]) < \ - delta_t and (lookup.Date_start_EM_ordinal.values[i] - - country_tracks.Date_start.values[j]) >= 0: - possible_hit.append(country_tracks.ibtracsID.values[j]) + hit_countries['hit_country'] == lookup['hit_country'].values[i]] + for j in range(0, len(country_tracks['Date_start'].values)): + if (lookup['Date_start_EM_ordinal'].values[i] - + country_tracks['Date_start'].values[j]) < \ + delta_t and (lookup['Date_start_EM_ordinal'].values[i] - + country_tracks['Date_start'].values[j]) >= 0: + possible_hit.append(country_tracks['ibtracsID'].values[j]) possible_hit_all.append(possible_hit) return possible_hit_all @@ -428,14 +429,14 @@ def match_em_id(lookup, poss_hit): with all possible hits per EMdat ID """ possible_hit_all = [] - for i in range(0, len(lookup.EM_ID.values)): + for i in range(0, len(lookup['EM_ID'].values)): possible_hit = [] # lookup without line i #lookup_match = lookup.drop(i) lookup_match = lookup # Loop over check if EM dat ID is the same - for i_match in range(0, len(lookup_match.EM_ID.values)): - if lookup.EM_ID.values[i] == lookup_match.EM_ID.values[i_match]: + for i_match in range(0, len(lookup_match['EM_ID'].values)): + if lookup['EM_ID'].values[i] == lookup_match['EM_ID'].values[i_match]: possible_hit.append(poss_hit[i]) possible_hit_all.append(possible_hit) return possible_hit_all @@ -467,7 +468,7 @@ def assign_track_to_em(lookup, possible_tracks_1, possible_tracks_2, level): """ for i, _ in enumerate(possible_tracks_1): - if np.isnan(lookup.allocation_level.values[i]): + if np.isnan(lookup['allocation_level'].values[i]): number_emdat_id = len(possible_tracks_1[i]) # print(number_emdat_id) for j in range(0, number_emdat_id): @@ -479,14 +480,15 @@ def assign_track_to_em(lookup, possible_tracks_1, possible_tracks_2, level): if all(possible_tracks_1[i][0] == possible_tracks_1[i][k] for k in range(0, len(possible_tracks_1[i]))): # check that track ID has not been assigned to that country already - ctry_lookup = lookup[lookup['hit_country'] == lookup.hit_country.values[i]] - if possible_tracks_1[i][0][0] not in ctry_lookup.ibtracsID.values: - lookup.ibtracsID.values[i] = possible_tracks_1[i][0][0] - lookup.allocation_level.values[i] = level + ctry_lookup = lookup[lookup['hit_country'] + == lookup['hit_country'].values[i]] + if possible_tracks_1[i][0][0] not in ctry_lookup['ibtracsID'].values: + lookup['ibtracsID'].values[i] = possible_tracks_1[i][0][0] + lookup['allocation_level'].values[i] = level elif possible_tracks_1[i][j] != []: - lookup.possible_track.values[i] = possible_tracks_1[i] + lookup['possible_track'].values[i] = possible_tracks_1[i] else: - lookup.possible_track_all.values[i] = possible_tracks_1[i] + lookup['possible_track_all'].values[i] = possible_tracks_1[i] return lookup @@ -507,13 +509,13 @@ def check_assigned_track(lookup, checkset): # merge checkset and lookup check = pd.merge(checkset, lookup[['hit_country', 'EM_ID', 'ibtracsID']], on=['hit_country', 'EM_ID']) - check_size = len(check.ibtracsID.values) - # not assigned values - not_assigned = check.ibtracsID.isnull().sum(axis=0) + check_size = len(check['ibtracsID'].values) + # not assigned values] + not_assigned = check['ibtracsID'].isnull().sum(axis=0) # correct assigned values - correct = sum(check.ibtracsID.values == check.IBtracsID_checked.values) + correct = sum(check['ibtracsID'].values == check['IBtracsID_checked'].values) # wrongly assigned values - wrong = len(check.ibtracsID.values) - not_assigned - correct + wrong = len(check['ibtracsID'].values) - not_assigned - correct print('%.1f%% tracks assigned correctly, %.1f%% wrongly, %.1f%% not assigned' % (correct / check_size * 100, wrong / check_size * 100, @@ -707,7 +709,7 @@ def emdat_countries_by_hazard(emdat_file_csv, hazard=None, year_range=None): List of names of countries impacted by the disaster (sub-)types """ df_data = clean_emdat_df(emdat_file_csv, hazard=hazard, year_range=year_range) - countries_iso3a = list(df_data.ISO.unique()) + countries_iso3a = list(df_data['ISO'].unique()) countries_names = list() for iso3a in countries_iso3a: try: @@ -800,26 +802,27 @@ def emdat_impact_yearlysum(emdat_file_csv, countries=None, hazard=None, year_ran year_range=year_range, target_version=version) df_data[imp_str + " scaled"] = scale_impact2refyear(df_data[imp_str].values, - df_data.Year.values, df_data.ISO.values, + df_data['Year'].values, + df_data['ISO'].values, reference_year=reference_year) def country_df(df_data): - for data_iso in df_data.ISO.unique(): + for data_iso in df_data['ISO'].unique(): country = u_coord.country_to_iso(data_iso, "alpha3") - df_country = df_data.loc[df_data.ISO == country] + df_country = df_data.loc[df_data['ISO'] == country] if not df_country.size: continue # Retrieve impact data for all years - all_years = np.arange(min(df_data.Year), max(df_data.Year) + 1) + all_years = np.arange(min(df_data['Year']), max(df_data['Year']) + 1) data_out = pd.DataFrame.from_records( [ ( year, - np.nansum(df_country[df_country.Year.isin([year])][imp_str]), + np.nansum(df_country[df_country['Year'].isin([year])][imp_str]), np.nansum( - df_country[df_country.Year.isin([year])][ + df_country[df_country['Year'].isin([year])][ imp_str + " scaled" ] ), @@ -894,13 +897,13 @@ def emdat_impact_event(emdat_file_csv, countries=None, hazard=None, year_range=N df_data['year'] = df_data['Year'] df_data['reference_year'] = reference_year df_data['impact'] = df_data[imp_str] - df_data['impact_scaled'] = scale_impact2refyear(df_data[imp_str].values, df_data.Year.values, - df_data.ISO.values, + df_data['impact_scaled'] = scale_impact2refyear(df_data[imp_str].values, df_data['Year'].values, + df_data['ISO'].values, reference_year=reference_year) df_data['region_id'] = np.nan - for country in df_data.ISO.unique(): + for country in df_data['ISO'].unique(): try: - df_data.loc[df_data.ISO == country, 'region_id'] = \ + df_data.loc[df_data['ISO'] == country, 'region_id'] = \ u_coord.country_to_iso(country, "numeric") except LookupError: LOGGER.warning('ISO3alpha code not found in iso_country: %s', country) diff --git a/climada/engine/test/test_impact.py b/climada/engine/test/test_impact.py index 0e70e993b0..7b7d6fc9b6 100644 --- a/climada/engine/test/test_impact.py +++ b/climada/engine/test/test_impact.py @@ -111,7 +111,7 @@ def test_from_eih_pass(self): np.testing.assert_array_almost_equal(imp.at_event, fake_at_event) np.testing.assert_array_almost_equal( imp.coord_exp, - np.stack([exp.gdf.latitude.values, exp.gdf.longitude.values], axis=1) + np.stack([exp.gdf['latitude'].values, exp.gdf['longitude'].values], axis=1) ) def test_pyproj_crs(self): @@ -513,7 +513,7 @@ def test_local_exceedance_imp_pass(self): impact_rp = impact.local_exceedance_imp(return_periods=(10, 40)) self.assertIsInstance(impact_rp, np.ndarray) - self.assertEqual(impact_rp.size, 2 * ent.exposures.gdf.value.size) + self.assertEqual(impact_rp.size, 2 * ent.exposures.gdf['value'].size) self.assertAlmostEqual(np.max(impact_rp), 2916964966.388219, places=5) self.assertAlmostEqual(np.min(impact_rp), 444457580.131494, places=5) @@ -941,7 +941,7 @@ def test_match_centroids(self): fake_aai_agg = np.sum(fake_eai_exp) imp = Impact.from_eih(exp, HAZ, fake_at_event, fake_eai_exp, fake_aai_agg) imp_centr = imp.match_centroids(HAZ) - np.testing.assert_array_equal(imp_centr, exp.gdf.centr_TC) + np.testing.assert_array_equal(imp_centr, exp.gdf['centr_TC']) class TestImpactH5IO(unittest.TestCase): diff --git a/climada/engine/test/test_impact_calc.py b/climada/engine/test/test_impact_calc.py index c4ee5e26b4..cd03a089aa 100644 --- a/climada/engine/test/test_impact_calc.py +++ b/climada/engine/test/test_impact_calc.py @@ -50,8 +50,8 @@ def check_impact(self, imp, haz, exp, aai_agg, eai_exp, at_event, imp_mat_array= """Test properties of imapcts""" self.assertEqual(len(haz.event_id), len(imp.at_event)) self.assertIsInstance(imp, Impact) - np.testing.assert_allclose(imp.coord_exp[:,0], exp.gdf.latitude) - np.testing.assert_allclose(imp.coord_exp[:,1], exp.gdf.longitude) + np.testing.assert_allclose(imp.coord_exp[:,0], exp.gdf['latitude']) + np.testing.assert_allclose(imp.coord_exp[:,1], exp.gdf['longitude']) self.assertAlmostEqual(imp.aai_agg, aai_agg, 3) np.testing.assert_allclose(imp.eai_exp, eai_exp, rtol=1e-5) np.testing.assert_allclose(imp.at_event, at_event, rtol=1e-5) @@ -271,7 +271,7 @@ def test_calc_impact_save_mat_pass(self): self.assertIsInstance(impact.imp_mat, sparse.csr_matrix) self.assertEqual(impact.imp_mat.shape, (HAZ.event_id.size, - ENT.exposures.gdf.value.size)) + ENT.exposures.gdf['value'].size)) np.testing.assert_array_almost_equal_nulp( np.array(impact.imp_mat.sum(axis=1)).ravel(), impact.at_event, nulp=5) np.testing.assert_array_almost_equal_nulp( @@ -294,8 +294,8 @@ def test_calc_impact_save_mat_pass(self): def test_calc_insured_impact_pass(self): """Test compute insured impact""" exp = ENT.exposures.copy() - exp.gdf.cover /= 1e3 - exp.gdf.deductible += 1e5 + exp.gdf['cover'] /= 1e3 + exp.gdf['deductible'] += 1e5 icalc = ImpactCalc(exp, ENT.impact_funcs, HAZ) with self.assertLogs(ILOG, level='INFO') as logs: impact = icalc.impact() @@ -316,8 +316,8 @@ def test_calc_insured_impact_pass(self): def test_calc_insured_impact_no_cover(self): """Test compute insured impact""" exp = ENT.exposures.copy() - exp.gdf.cover /= 1e3 - exp.gdf.deductible += 1e5 + exp.gdf['cover'] /= 1e3 + exp.gdf['deductible'] += 1e5 icalc = ImpactCalc(exp, ENT.impact_funcs, HAZ) with self.assertLogs(ILOG, level='INFO') as logs: impact = icalc.impact(ignore_cover=True) @@ -338,8 +338,8 @@ def test_calc_insured_impact_no_cover(self): def test_calc_insured_impact_no_deductible(self): """Test compute insured impact""" exp = ENT.exposures.copy() - exp.gdf.cover /= 1e3 - exp.gdf.deductible += 1e5 + exp.gdf['cover'] /= 1e3 + exp.gdf['deductible'] += 1e5 icalc = ImpactCalc(exp, ENT.impact_funcs, HAZ) with self.assertLogs(ILOG, level='INFO') as logs: impact = icalc.impact(ignore_deductible=True) @@ -360,8 +360,8 @@ def test_calc_insured_impact_no_deductible(self): def test_calc_insured_impact_no_insurance(self): """Test compute insured impact""" exp = ENT.exposures.copy() - exp.gdf.cover /= 1e3 - exp.gdf.deductible += 1e5 + exp.gdf['cover'] /= 1e3 + exp.gdf['deductible'] += 1e5 icalc = ImpactCalc(exp, ENT.impact_funcs, HAZ) with self.assertLogs(ILOG, level='INFO') as logs: impact = icalc.impact(ignore_cover=True, ignore_deductible=True) @@ -384,14 +384,14 @@ def test_calc_insured_impact_no_insurance(self): def test_calc_insured_impact_save_mat_pass(self): """Test compute impact with impact matrix""" exp = ENT.exposures.copy() - exp.gdf.cover /= 1e3 - exp.gdf.deductible += 1e5 + exp.gdf['cover'] /= 1e3 + exp.gdf['deductible'] += 1e5 icalc = ImpactCalc(exp, ENT.impact_funcs, HAZ) impact = icalc.impact(save_mat=True) self.assertIsInstance(impact.imp_mat, sparse.csr_matrix) self.assertEqual(impact.imp_mat.shape, (HAZ.event_id.size, - ENT.exposures.gdf.value.size)) + ENT.exposures.gdf['value'].size)) np.testing.assert_array_almost_equal_nulp( np.array(impact.imp_mat.sum(axis=1)).ravel(), impact.at_event, nulp=5) np.testing.assert_array_almost_equal_nulp( @@ -418,9 +418,9 @@ def test_minimal_exp_gdf(self): ignore_cover=True, ignore_deductible=True) self.assertSetEqual(set(exp_min_gdf.columns), set(['value', 'impf_TC', 'centr_TC'])) - np.testing.assert_array_equal(exp_min_gdf.value, ENT.exposures.gdf.value) - np.testing.assert_array_equal(exp_min_gdf.impf_TC, ENT.exposures.gdf.impf_TC) - np.testing.assert_array_equal(exp_min_gdf.centr_TC, ENT.exposures.gdf.centr_TC) + np.testing.assert_array_equal(exp_min_gdf['value'], ENT.exposures.gdf['value']) + np.testing.assert_array_equal(exp_min_gdf['impf_TC'], ENT.exposures.gdf['impf_TC']) + np.testing.assert_array_equal(exp_min_gdf['centr_TC'], ENT.exposures.gdf['centr_TC']) def test_stitch_impact_matrix(self): """Check how sparse matrices from a generator are stitched together""" diff --git a/climada/engine/test/test_impact_data.py b/climada/engine/test/test_impact_data.py index ccb3d966a6..5391a3b14d 100644 --- a/climada/engine/test/test_impact_data.py +++ b/climada/engine/test/test_impact_data.py @@ -43,8 +43,8 @@ def test_clean_emdat_df_2018_load(self): year_range=[2000, 2017], target_version=2018) self.assertIn('ISO', df.columns) self.assertIn('Year', df.columns) - iso3 = list(df.ISO.unique()) - years = np.arange(df.Year.min(), df.Year.max() + 1) + iso3 = list(df['ISO'].unique()) + years = np.arange(df['Year'].min(), df['Year'].max() + 1) self.assertListEqual(['BGD'], iso3) self.assertEqual(18, len(years)) @@ -63,8 +63,8 @@ def test_emdat_df_2018_to_2020_load(self): year_range=[2000, 2017], target_version=2020) self.assertIn('ISO', df.columns) self.assertIn('Year', df.columns) - iso3 = list(df.ISO.unique()) - years = np.arange(df.Year.min(), df.Year.max() + 1) + iso3 = list(df['ISO'].unique()) + years = np.arange(df['Year'].min(), df['Year'].max() + 1) self.assertListEqual(['USA'], iso3) self.assertEqual(18, len(years)) self.assertEqual(2017, years[-1]) @@ -82,8 +82,8 @@ def test_emdat_df_2020_load(self): year_range=[2005, 2008], target_version=2020) self.assertIn('ISO', df.columns) self.assertIn('Year', df.columns) - iso3 = list(df.ISO.unique()) - years = np.arange(df.Year.min(), df.Year.max() + 1) + iso3 = list(df['ISO'].unique()) + years = np.arange(df['Year'].min(), df['Year'].max() + 1) self.assertIn('THA', iso3) self.assertIn('VNM', iso3) self.assertNotIn('USA', iso3) @@ -165,7 +165,7 @@ def test_emdat_affected_yearlysum(self): self.assertEqual(36, df.size) self.assertEqual(df["impact"][1], 91000) - self.assertEqual(df.impact.sum(), 11517946) + self.assertEqual(df['impact'].sum(), 11517946) self.assertEqual(df["year"][5], 2017) self.assertIn('USA', list(df['ISO'])) diff --git a/climada/engine/unsequa/input_var.py b/climada/engine/unsequa/input_var.py index b0ca91ff67..62d7729f4e 100644 --- a/climada/engine/unsequa/input_var.py +++ b/climada/engine/unsequa/input_var.py @@ -722,9 +722,9 @@ def _exp_uncfunc(EN, ET, EL, exp_list, bounds_noise): if EN is not None: rng = np.random.RandomState(int(EN)) rnd_vals = rng.uniform(bounds_noise[0], bounds_noise[1], size = len(exp_tmp.gdf)) - exp_tmp.gdf.value *= rnd_vals + exp_tmp.gdf['value'] *= rnd_vals if ET is not None: - exp_tmp.gdf.value *= ET + exp_tmp.gdf['value'] *= ET return exp_tmp def _exp_unc_dict(bounds_totval, bounds_noise, n_exp): diff --git a/climada/engine/unsequa/test/test_unsequa.py b/climada/engine/unsequa/test/test_unsequa.py index 04b568caa8..0bc05f0bb9 100755 --- a/climada/engine/unsequa/test/test_unsequa.py +++ b/climada/engine/unsequa/test/test_unsequa.py @@ -69,7 +69,7 @@ def exp_dem(x_exp=1, exp=None): # possibly raised by pd.HDFStore when the file is locked by another process due to multiprocessing time.sleep(0.1) exp_tmp = exp.copy(deep=True) - exp_tmp.gdf.value *= x_exp + exp_tmp.gdf['value'] *= x_exp return exp_tmp @@ -676,11 +676,11 @@ def test_sensitivity_method(exp_unc, impf_unc, haz_unc, sensitivity_method, para sensitivity_kwargs=param_dict['sensitivity_kwargs']) self.assertEqual(param_dict['test_param_name'][0], - unc_data.aai_agg_sens_df.param[param_dict['test_param_name'][1]]) + unc_data.aai_agg_sens_df['param'][param_dict['test_param_name'][1]]) self.assertEqual(param_dict['test_si_name'][0], - unc_data.aai_agg_sens_df.si[param_dict['test_si_name'][1]]) + unc_data.aai_agg_sens_df['si'][param_dict['test_si_name'][1]]) self.assertAlmostEqual(param_dict['test_si_value'][0], - unc_data.aai_agg_sens_df.aai_agg[param_dict['test_si_value'][1]], + unc_data.aai_agg_sens_df['aai_agg'][param_dict['test_si_value'][1]], places=5) self.assertEqual( diff --git a/climada/engine/unsequa/unc_output.py b/climada/engine/unsequa/unc_output.py index e86fe25fa9..4a833df2b6 100644 --- a/climada/engine/unsequa/unc_output.py +++ b/climada/engine/unsequa/unc_output.py @@ -1025,7 +1025,7 @@ def plot_sensitivity_map(self, salib_si='S1', **kwargs): eai_max_si_df = self.get_largest_si(salib_si, metric_list=['eai_exp']) plot_val = eai_max_si_df['param'] - coord = np.array([self.coord_df.latitude, self.coord_df.longitude]).transpose() # pylint: disable=no-member + coord = np.array([self.coord_df['latitude'], self.coord_df['longitude']]).transpose() # pylint: disable=no-member if 'var_name' not in kwargs: kwargs['var_name'] = 'Input parameter with largest ' + salib_si if 'title' not in kwargs: diff --git a/climada/entity/exposures/base.py b/climada/entity/exposures/base.py index d1d6d0235d..645127f7cb 100644 --- a/climada/entity/exposures/base.py +++ b/climada/entity/exposures/base.py @@ -273,8 +273,8 @@ def check(self): # check whether geometry corresponds to lat/lon try: - if (self.gdf.geometry.values[0].x != self.gdf.longitude.values[0] or - self.gdf.geometry.values[0].y != self.gdf.latitude.values[0]): + if (self.gdf.geometry.values[0].x != self.gdf['longitude'].values[0] or + self.gdf.geometry.values[0].y != self.gdf['latitude'].values[0]): raise ValueError("Geometry values do not correspond to latitude and" + " longitude. Use set_geometry_points() or set_lat_lon().") except AttributeError: # no geometry column @@ -560,12 +560,12 @@ def plot_scatter(self, mask=None, ignore_zero=False, pop_name=True, if mask is None: mask = np.ones((self.gdf.shape[0],), dtype=bool) if ignore_zero: - pos_vals = self.gdf.value[mask].values > 0 + pos_vals = self.gdf['value'][mask].values > 0 else: - pos_vals = np.ones((self.gdf.value[mask].values.size,), dtype=bool) - value = self.gdf.value[mask][pos_vals].values - coord = np.stack([self.gdf.latitude[mask][pos_vals].values, - self.gdf.longitude[mask][pos_vals].values], axis=1) + pos_vals = np.ones((self.gdf['value'][mask].values.size,), dtype=bool) + value = self.gdf['value'][mask][pos_vals].values + coord = np.stack([self.gdf['latitude'][mask][pos_vals].values, + self.gdf['longitude'][mask][pos_vals].values], axis=1) return u_plot.geo_scatter_from_array(array_sub=value, geo_coord=coord, var_name=f'Value ({self.value_unit})', @@ -629,12 +629,12 @@ def plot_hexbin(self, mask=None, ignore_zero=False, pop_name=True, if mask is None: mask = np.ones((self.gdf.shape[0],), dtype=bool) if ignore_zero: - pos_vals = self.gdf.value[mask].values > 0 + pos_vals = self.gdf['value'][mask].values > 0 else: - pos_vals = np.ones((self.gdf.value[mask].values.size,), dtype=bool) - value = self.gdf.value[mask][pos_vals].values - coord = np.stack([self.gdf.latitude[mask][pos_vals].values, - self.gdf.longitude[mask][pos_vals].values], axis=1) + pos_vals = np.ones((self.gdf['value'][mask].values.size,), dtype=bool) + value = self.gdf['value'][mask][pos_vals].values + coord = np.stack([self.gdf['latitude'][mask][pos_vals].values, + self.gdf['longitude'][mask][pos_vals].values], axis=1) return u_plot.geo_bin_from_array(array_sub=value, geo_coord=coord, var_name=f'Value ({self.value_unit})', @@ -692,12 +692,12 @@ def plot_raster(self, res=None, raster_res=None, save_tiff=None, matplotlib.figure.Figure, cartopy.mpl.geoaxes.GeoAxesSubplot """ if self.meta and self.meta.get('height', 0) * self.meta.get('height', 0) == len(self.gdf): - raster = self.gdf.value.values.reshape((self.meta['height'], + raster = self.gdf['value'].values.reshape((self.meta['height'], self.meta['width'])) # check raster starts by upper left corner - if self.gdf.latitude.values[0] < self.gdf.latitude.values[-1]: + if self.gdf['latitude'].values[0] < self.gdf['latitude'].values[-1]: raster = np.flip(raster, axis=0) - if self.gdf.longitude.values[0] > self.gdf.longitude.values[-1]: + if self.gdf['longitude'].values[0] > self.gdf['longitude'].values[-1]: raise ValueError('Points are not ordered according to meta raster.') else: raster, meta = u_coord.points_to_raster(self.gdf, ['value'], res, raster_res, scheduler) @@ -715,11 +715,11 @@ def plot_raster(self, res=None, raster_res=None, save_tiff=None, if isinstance(proj_data, ccrs.PlateCarree): # use different projections for plot and data to shift the central lon in the plot xmin, ymin, xmax, ymax = u_coord.latlon_bounds( - self.gdf.latitude.values, self.gdf.longitude.values) + self.gdf['latitude'].values, self.gdf['longitude'].values) proj_plot = ccrs.PlateCarree(central_longitude=0.5 * (xmin + xmax)) else: - xmin, ymin, xmax, ymax = (self.gdf.longitude.min(), self.gdf.latitude.min(), - self.gdf.longitude.max(), self.gdf.latitude.max()) + xmin, ymin, xmax, ymax = (self.gdf['longitude'].min(), self.gdf['latitude'].min(), + self.gdf['longitude'].max(), self.gdf['latitude'].max()) if not axis: _, axis, fontsize = u_plot.make_map(proj=proj_plot, figsize=figsize, @@ -987,9 +987,9 @@ def write_raster(self, file_name, value_name='value', scheduler=None): raster = self.gdf[value_name].values.reshape((self.meta['height'], self.meta['width'])) # check raster starts by upper left corner - if self.gdf.latitude.values[0] < self.gdf.latitude.values[-1]: + if self.gdf['latitude'].values[0] < self.gdf['latitude'].values[-1]: raster = np.flip(raster, axis=0) - if self.gdf.longitude.values[0] > self.gdf.longitude.values[-1]: + if self.gdf['longitude'].values[0] > self.gdf['longitude'].values[-1]: raise ValueError('Points are not ordered according to meta raster.') u_coord.write_raster(file_name, raster, self.meta) else: @@ -1061,10 +1061,10 @@ def centroids_total_value(self, hazard): """ nz_mask = ( - (self.gdf.value.values > 0) + (self.gdf['value'].values > 0) & (self.gdf[hazard.centr_exp_col].values >= 0) ) - return np.sum(self.gdf.value.values[nz_mask]) + return np.sum(self.gdf['value'].values[nz_mask]) def affected_total_value( self, @@ -1109,7 +1109,7 @@ def affected_total_value( """ self.assign_centroids(hazard=hazard, overwrite=overwrite_assigned_centroids) assigned_centroids = self.gdf[hazard.centr_exp_col] - nz_mask = (self.gdf.value.values > 0) & (assigned_centroids.values >= 0) + nz_mask = (self.gdf['value'].values > 0) & (assigned_centroids.values >= 0) cents = np.unique(assigned_centroids[nz_mask]) cent_with_inten_above_thres = ( hazard.intensity[:, cents].max(axis=0) > threshold_affected @@ -1117,7 +1117,7 @@ def affected_total_value( above_thres_mask = np.isin( self.gdf[hazard.centr_exp_col].values, cents[cent_with_inten_above_thres] ) - return np.sum(self.gdf.value.values[above_thres_mask]) + return np.sum(self.gdf['value'].values[above_thres_mask]) def add_sea(exposures, sea_res, scheduler=None): @@ -1145,10 +1145,10 @@ def add_sea(exposures, sea_res, scheduler=None): sea_res = (sea_res[0] / ONE_LAT_KM, sea_res[1] / ONE_LAT_KM) - min_lat = max(-90, float(exposures.gdf.latitude.min()) - sea_res[0]) - max_lat = min(90, float(exposures.gdf.latitude.max()) + sea_res[0]) - min_lon = max(-180, float(exposures.gdf.longitude.min()) - sea_res[0]) - max_lon = min(180, float(exposures.gdf.longitude.max()) + sea_res[0]) + min_lat = max(-90, float(exposures.gdf['latitude'].min()) - sea_res[0]) + max_lat = min(90, float(exposures.gdf['latitude'].max()) + sea_res[0]) + min_lon = max(-180, float(exposures.gdf['longitude'].min()) - sea_res[0]) + max_lon = min(180, float(exposures.gdf['longitude'].max()) + sea_res[0]) lat_arr = np.arange(min_lat, max_lat + sea_res[1], sea_res[1]) lon_arr = np.arange(min_lon, max_lon + sea_res[1], sea_res[1]) @@ -1160,14 +1160,14 @@ def add_sea(exposures, sea_res, scheduler=None): sea_exp_gdf = GeoDataFrame() sea_exp_gdf['latitude'] = lat_mgrid[on_land] sea_exp_gdf['longitude'] = lon_mgrid[on_land] - sea_exp_gdf['region_id'] = np.zeros(sea_exp_gdf.latitude.size, int) - 1 + sea_exp_gdf['region_id'] = np.zeros(sea_exp_gdf['latitude'].size, int) - 1 if 'geometry' in exposures.gdf.columns: u_coord.set_df_geometry_points(sea_exp_gdf, crs=exposures.crs, scheduler=scheduler) for var_name in exposures.gdf.columns: if var_name not in ('latitude', 'longitude', 'region_id', 'geometry'): - sea_exp_gdf[var_name] = np.zeros(sea_exp_gdf.latitude.size, + sea_exp_gdf[var_name] = np.zeros(sea_exp_gdf['latitude'].size, exposures.gdf[var_name].dtype) return Exposures( diff --git a/climada/entity/exposures/litpop/litpop.py b/climada/entity/exposures/litpop/litpop.py index c60de6da85..7fe2047bd0 100644 --- a/climada/entity/exposures/litpop/litpop.py +++ b/climada/entity/exposures/litpop/litpop.py @@ -199,9 +199,9 @@ def from_countries(cls, countries, res_arcsec=30, exponents=(1,1), try: rows, cols, ras_trans = u_coord.pts_to_raster_meta( - (exp.gdf.longitude.min(), exp.gdf.latitude.min(), - exp.gdf.longitude.max(), exp.gdf.latitude.max()), - u_coord.get_resolution(exp.gdf.longitude, exp.gdf.latitude)) + (exp.gdf['longitude'].min(), exp.gdf['latitude'].min(), + exp.gdf['longitude'].max(), exp.gdf['latitude'].max()), + u_coord.get_resolution(exp.gdf['longitude'], exp.gdf['latitude'])) exp.meta = { 'width': cols, 'height': rows, @@ -435,9 +435,9 @@ def from_shape_and_countries(cls, shape, countries, res_arcsec=30, exponents=(1, try: rows, cols, ras_trans = u_coord.pts_to_raster_meta( - (exp.gdf.longitude.min(), exp.gdf.latitude.min(), - exp.gdf.longitude.max(), exp.gdf.latitude.max()), - u_coord.get_resolution(exp.gdf.longitude, exp.gdf.latitude)) + (exp.gdf['longitude'].min(), exp.gdf['latitude'].min(), + exp.gdf['longitude'].max(), exp.gdf['latitude'].max()), + u_coord.get_resolution(exp.gdf['longitude'], exp.gdf['latitude'])) exp.meta = { 'width': cols, 'height': rows, @@ -557,12 +557,12 @@ def from_shape( description=description ) - if min(len(exp.gdf.latitude.unique()), len(exp.gdf.longitude.unique())) > 1: + if min(len(exp.gdf['latitude'].unique()), len(exp.gdf['longitude'].unique())) > 1: #if exp.gdf.shape[0] > 1 and len(exp.gdf.latitude.unique()) > 1: rows, cols, ras_trans = u_coord.pts_to_raster_meta( - (exp.gdf.longitude.min(), exp.gdf.latitude.min(), - exp.gdf.longitude.max(), exp.gdf.latitude.max()), - u_coord.get_resolution(exp.gdf.longitude, exp.gdf.latitude)) + (exp.gdf['longitude'].min(), exp.gdf['latitude'].min(), + exp.gdf['longitude'].max(), exp.gdf['latitude'].max()), + u_coord.get_resolution(exp.gdf['longitude'], exp.gdf['latitude'])) exp.meta = { 'width': cols, 'height': rows, @@ -783,7 +783,7 @@ def _get_litpop_single_polygon(polygon, reference_year, res_arcsec, data_dir, gdf['region_id'] = region_id else: gdf['region_id'] = u_coord.get_country_code( - gdf.latitude, gdf.longitude, gridded=True + gdf['latitude'], gdf['longitude'], gridded=True ) # remove entries outside polygon with `dropna` and return GeoDataFrame: return gdf.dropna(), meta_out diff --git a/climada/entity/exposures/test/test_base.py b/climada/entity/exposures/test/test_base.py index 4a1146e26d..867e39c299 100644 --- a/climada/entity/exposures/test/test_base.py +++ b/climada/entity/exposures/test/test_base.py @@ -120,7 +120,7 @@ def test_read_raster_pass(self): -69.2471495969998 + 0.009000000000000341 / 2 + 49 * 0.009000000000000341) self.assertEqual(len(exp.gdf), 60 * 50) - self.assertAlmostEqual(exp.gdf.value.values.reshape((60, 50))[25, 12], 0.056825936) + self.assertAlmostEqual(exp.gdf['value'].values.reshape((60, 50))[25, 12], 0.056825936) def test_assign_raster_pass(self): """Test assign_centroids with raster hazard""" @@ -176,14 +176,14 @@ def test_assign_raster_same_pass(self): def test_assign_large_hazard_subset_pass(self): """Test assign_centroids with raster hazard""" exp = Exposures.from_raster(HAZ_DEMO_FL, window=Window(10, 20, 50, 60)) - exp.gdf.latitude[[0, 1]] = exp.gdf.latitude[[1, 0]] - exp.gdf.longitude[[0, 1]] = exp.gdf.longitude[[1, 0]] + exp.gdf['latitude'][[0, 1]] = exp.gdf['latitude'][[1, 0]] + exp.gdf['longitude'][[0, 1]] = exp.gdf['longitude'][[1, 0]] exp.check() haz = Hazard.from_raster([HAZ_DEMO_FL], haz_type='FL') exp.assign_centroids(haz) assigned_centroids = haz.centroids.select(sel_cen=exp.gdf[INDICATOR_CENTR + 'FL'].values) - np.testing.assert_array_equal(np.unique(assigned_centroids.lat), np.unique(exp.gdf.latitude)) - np.testing.assert_array_equal(np.unique(assigned_centroids.lon), np.unique(exp.gdf.longitude)) + np.testing.assert_array_equal(np.unique(assigned_centroids.lat), np.unique(exp.gdf['latitude'])) + np.testing.assert_array_equal(np.unique(assigned_centroids.lon), np.unique(exp.gdf['longitude'])) def test_affected_total_value(self): haz_type = "RF" @@ -206,15 +206,15 @@ def test_affected_total_value(self): tot_val = exp.affected_total_value( haz, threshold_affected=0, overwrite_assigned_centroids=False ) - self.assertEqual(tot_val, np.sum(exp.gdf.value[[1, 2, 3, 5]])) + self.assertEqual(tot_val, np.sum(exp.gdf['value'][[1, 2, 3, 5]])) tot_val = exp.affected_total_value( haz, threshold_affected=3, overwrite_assigned_centroids=False ) - self.assertEqual(tot_val, np.sum(exp.gdf.value[[3]])) + self.assertEqual(tot_val, np.sum(exp.gdf['value'][[3]])) tot_val = exp.affected_total_value( haz, threshold_affected=-2, overwrite_assigned_centroids=False ) - self.assertEqual(tot_val, np.sum(exp.gdf.value[[0, 1, 2, 3, 5]])) + self.assertEqual(tot_val, np.sum(exp.gdf['value'][[0, 1, 2, 3, 5]])) tot_val = exp.affected_total_value( haz, threshold_affected=11, overwrite_assigned_centroids=False ) @@ -280,7 +280,7 @@ def test_error_geometry_fail(self): """Wrong exposures definition""" expo = good_exposures() expo.set_geometry_points() - expo.gdf.latitude.values[0] = 5 + expo.gdf['latitude'].values[0] = 5 with self.assertRaises(ValueError): expo.check() @@ -323,17 +323,17 @@ def test_io_hdf5_pass(self): self.assertTrue(u_coord.equal_crs(exp_df.crs, exp_read.crs)) self.assertTrue(u_coord.equal_crs(exp_df.gdf.crs, exp_read.gdf.crs)) self.assertEqual(exp_df.description, exp_read.description) - np.testing.assert_array_equal(exp_df.gdf.latitude.values, exp_read.gdf.latitude.values) - np.testing.assert_array_equal(exp_df.gdf.longitude.values, exp_read.gdf.longitude.values) - np.testing.assert_array_equal(exp_df.gdf.value.values, exp_read.gdf.value.values) - np.testing.assert_array_equal(exp_df.gdf.deductible.values, exp_read.gdf.deductible.values) - np.testing.assert_array_equal(exp_df.gdf.cover.values, exp_read.gdf.cover.values) - np.testing.assert_array_equal(exp_df.gdf.region_id.values, exp_read.gdf.region_id.values) - np.testing.assert_array_equal(exp_df.gdf.category_id.values, exp_read.gdf.category_id.values) - np.testing.assert_array_equal(exp_df.gdf.impf_TC.values, exp_read.gdf.impf_TC.values) - np.testing.assert_array_equal(exp_df.gdf.centr_TC.values, exp_read.gdf.centr_TC.values) - np.testing.assert_array_equal(exp_df.gdf.impf_FL.values, exp_read.gdf.impf_FL.values) - np.testing.assert_array_equal(exp_df.gdf.centr_FL.values, exp_read.gdf.centr_FL.values) + np.testing.assert_array_equal(exp_df.gdf['latitude'].values, exp_read.gdf['latitude'].values) + np.testing.assert_array_equal(exp_df.gdf['longitude'].values, exp_read.gdf['longitude'].values) + np.testing.assert_array_equal(exp_df.gdf['value'].values, exp_read.gdf['value'].values) + np.testing.assert_array_equal(exp_df.gdf['deductible'].values, exp_read.gdf['deductible'].values) + np.testing.assert_array_equal(exp_df.gdf['cover'].values, exp_read.gdf['cover'].values) + np.testing.assert_array_equal(exp_df.gdf['region_id'].values, exp_read.gdf['region_id'].values) + np.testing.assert_array_equal(exp_df.gdf['category_id'].values, exp_read.gdf['category_id'].values) + np.testing.assert_array_equal(exp_df.gdf['impf_TC'].values, exp_read.gdf['impf_TC'].values) + np.testing.assert_array_equal(exp_df.gdf['centr_TC'].values, exp_read.gdf['centr_TC'].values) + np.testing.assert_array_equal(exp_df.gdf['impf_FL'].values, exp_read.gdf['impf_FL'].values) + np.testing.assert_array_equal(exp_df.gdf['centr_FL'].values, exp_read.gdf['centr_FL'].values) for point_df, point_read in zip(exp_df.gdf.geometry.values, exp_read.gdf.geometry.values): self.assertEqual(point_df.x, point_read.x) @@ -368,22 +368,22 @@ def test_add_sea_pass(self): max_lat = max_lat + sea_coast min_lon = min_lon - sea_coast max_lon = max_lon + sea_coast - self.assertEqual(np.min(exp_sea.gdf.latitude), min_lat) - self.assertEqual(np.min(exp_sea.gdf.longitude), min_lon) + self.assertEqual(np.min(exp_sea.gdf['latitude']), min_lat) + self.assertEqual(np.min(exp_sea.gdf['longitude']), min_lon) np.testing.assert_array_equal(exp_sea.gdf.value.values[:10], np.arange(0, 1.0e6, 1.0e5)) self.assertEqual(exp_sea.ref_year, exp.ref_year) self.assertEqual(exp_sea.value_unit, exp.value_unit) - on_sea_lat = exp_sea.gdf.latitude.values[11:] - on_sea_lon = exp_sea.gdf.longitude.values[11:] + on_sea_lat = exp_sea.gdf['latitude'].values[11:] + on_sea_lon = exp_sea.gdf['longitude'].values[11:] res_on_sea = u_coord.coord_on_land(on_sea_lat, on_sea_lon) res_on_sea = ~res_on_sea self.assertTrue(np.all(res_on_sea)) dist = DistanceMetric.get_metric('haversine') self.assertAlmostEqual(dist.pairwise([ - [exp_sea.gdf.longitude.values[-1], exp_sea.gdf.latitude.values[-1]], - [exp_sea.gdf.longitude.values[-2], exp_sea.gdf.latitude.values[-2]], + [exp_sea.gdf['longitude'].values[-1], exp_sea.gdf['latitude'].values[-1]], + [exp_sea.gdf['longitude'].values[-2], exp_sea.gdf['latitude'].values[-2]], ])[0][1], sea_res_km) @@ -431,8 +431,8 @@ def test_copy_pass(self): self.assertEqual(exp_copy.ref_year, exp.ref_year) self.assertEqual(exp_copy.value_unit, exp.value_unit) self.assertEqual(exp_copy.description, exp.description) - np.testing.assert_array_equal(exp_copy.gdf.latitude.values, exp.gdf.latitude.values) - np.testing.assert_array_equal(exp_copy.gdf.longitude.values, exp.gdf.longitude.values) + np.testing.assert_array_equal(exp_copy.gdf['latitude'].values, exp.gdf['latitude'].values) + np.testing.assert_array_equal(exp_copy.gdf['longitude'].values, exp.gdf['longitude'].values) def test_to_crs_inplace_pass(self): """Test to_crs function inplace.""" @@ -466,7 +466,7 @@ def test_constructor_pass(self): in_gpd.ref_year = 2015 in_exp = Exposures(in_gpd, ref_year=2015) self.assertEqual(in_exp.ref_year, 2015) - np.testing.assert_array_equal(in_exp.gdf.value, np.zeros(10)) + np.testing.assert_array_equal(in_exp.gdf['value'], np.zeros(10)) def test_error_on_access_item(self): """Test error output when trying to access items as in CLIMADA 1.x""" diff --git a/climada/entity/exposures/test/test_mat.py b/climada/entity/exposures/test/test_mat.py index a4b30bab32..c6fbe09f8c 100644 --- a/climada/entity/exposures/test/test_mat.py +++ b/climada/entity/exposures/test/test_mat.py @@ -41,40 +41,40 @@ def test_read_demo_pass(self): self.assertEqual(expo.gdf.index[0], 0) self.assertEqual(expo.gdf.index[n_expos - 1], n_expos - 1) - self.assertEqual(expo.gdf.value.shape, (n_expos,)) - self.assertEqual(expo.gdf.value[0], 13927504367.680632) - self.assertEqual(expo.gdf.value[n_expos - 1], 12624818493.687229) + self.assertEqual(expo.gdf['value'].shape, (n_expos,)) + self.assertEqual(expo.gdf['value'][0], 13927504367.680632) + self.assertEqual(expo.gdf['value'][n_expos - 1], 12624818493.687229) - self.assertEqual(expo.gdf.deductible.shape, (n_expos,)) - self.assertEqual(expo.gdf.deductible[0], 0) - self.assertEqual(expo.gdf.deductible[n_expos - 1], 0) + self.assertEqual(expo.gdf['deductible'].shape, (n_expos,)) + self.assertEqual(expo.gdf['deductible'][0], 0) + self.assertEqual(expo.gdf['deductible'][n_expos - 1], 0) - self.assertEqual(expo.gdf.cover.shape, (n_expos,)) - self.assertEqual(expo.gdf.cover[0], 13927504367.680632) - self.assertEqual(expo.gdf.cover[n_expos - 1], 12624818493.687229) + self.assertEqual(expo.gdf['cover'].shape, (n_expos,)) + self.assertEqual(expo.gdf['cover'][0], 13927504367.680632) + self.assertEqual(expo.gdf['cover'][n_expos - 1], 12624818493.687229) - self.assertIn('int', str(expo.gdf.impf_.dtype)) - self.assertEqual(expo.gdf.impf_.shape, (n_expos,)) - self.assertEqual(expo.gdf.impf_[0], 1) - self.assertEqual(expo.gdf.impf_[n_expos - 1], 1) + self.assertIn('int', str(expo.gdf['impf_'].dtype)) + self.assertEqual(expo.gdf['impf_'].shape, (n_expos,)) + self.assertEqual(expo.gdf['impf_'][0], 1) + self.assertEqual(expo.gdf['impf_'][n_expos - 1], 1) - self.assertIn('int', str(expo.gdf.category_id.dtype)) - self.assertEqual(expo.gdf.category_id.shape, (n_expos,)) - self.assertEqual(expo.gdf.category_id[0], 1) - self.assertEqual(expo.gdf.category_id[n_expos - 1], 1) + self.assertIn('int', str(expo.gdf['category_id'].dtype)) + self.assertEqual(expo.gdf['category_id'].shape, (n_expos,)) + self.assertEqual(expo.gdf['category_id'][0], 1) + self.assertEqual(expo.gdf['category_id'][n_expos - 1], 1) - self.assertIn('int', str(expo.gdf.centr_.dtype)) - self.assertEqual(expo.gdf.centr_.shape, (n_expos,)) - self.assertEqual(expo.gdf.centr_[0], 47) - self.assertEqual(expo.gdf.centr_[n_expos - 1], 46) + self.assertIn('int', str(expo.gdf['centr_'].dtype)) + self.assertEqual(expo.gdf['centr_'].shape, (n_expos,)) + self.assertEqual(expo.gdf['centr_'][0], 47) + self.assertEqual(expo.gdf['centr_'][n_expos - 1], 46) self.assertTrue('region_id' not in expo.gdf) - self.assertEqual(expo.gdf.latitude.shape, (n_expos,)) - self.assertEqual(expo.gdf.latitude[0], 26.93389900000) - self.assertEqual(expo.gdf.latitude[n_expos - 1], 26.34795700000) - self.assertEqual(expo.gdf.longitude[0], -80.12879900000) - self.assertEqual(expo.gdf.longitude[n_expos - 1], -80.15885500000) + self.assertEqual(expo.gdf['latitude'].shape, (n_expos,)) + self.assertEqual(expo.gdf['latitude'][0], 26.93389900000) + self.assertEqual(expo.gdf['latitude'][n_expos - 1], 26.34795700000) + self.assertEqual(expo.gdf['longitude'][0], -80.12879900000) + self.assertEqual(expo.gdf['longitude'][n_expos - 1], -80.15885500000) self.assertEqual(expo.ref_year, 2016) self.assertEqual(expo.value_unit, 'USD') diff --git a/climada/entity/measures/base.py b/climada/entity/measures/base.py index cdb584ebc9..40c4cac4ef 100755 --- a/climada/entity/measures/base.py +++ b/climada/entity/measures/base.py @@ -315,10 +315,10 @@ def _change_all_exposures(self, exposures): else: raise ValueError(f'{self.exposures_set} is neither a string nor an Exposures object') - if not np.array_equal(np.unique(exposures.gdf.latitude.values), - np.unique(new_exp.gdf.latitude.values)) or \ - not np.array_equal(np.unique(exposures.gdf.longitude.values), - np.unique(new_exp.gdf.longitude.values)): + if not np.array_equal(np.unique(exposures.gdf['latitude'].values), + np.unique(new_exp.gdf['latitude'].values)) or \ + not np.array_equal(np.unique(exposures.gdf['longitude'].values), + np.unique(new_exp.gdf['longitude'].values)): LOGGER.warning('Exposures locations have changed.') return new_exp @@ -415,7 +415,7 @@ def _cutoff_hazard_damage(self, exposures, impf_set, hazard): if self.exp_region_id: # compute impact only in selected region in_reg = np.logical_or.reduce( - [exposures.gdf.region_id.values == reg for reg in self.exp_region_id] + [exposures.gdf['region_id'].values == reg for reg in self.exp_region_id] ) exp_imp = Exposures(exposures.gdf[in_reg], crs=exposures.crs) else: @@ -489,7 +489,7 @@ def _filter_exposures(self, exposures, imp_set, hazard, new_exp, new_impfs, new_impfs.get_func()[self.haz_type].update(imp_set.get_func()[self.haz_type]) # get the indices for changing and inert regions - chg_reg = exposures.gdf.region_id.isin(self.exp_region_id) + chg_reg = exposures.gdf['region_id'].isin(self.exp_region_id) no_chg_reg = ~chg_reg LOGGER.debug('Number of changed exposures: %s', chg_reg.sum()) diff --git a/climada/entity/measures/test/test_base.py b/climada/entity/measures/test/test_base.py index 0890fec26a..84ac988c40 100644 --- a/climada/entity/measures/test/test_base.py +++ b/climada/entity/measures/test/test_base.py @@ -119,7 +119,7 @@ def test_cutoff_hazard_region_pass(self): haz = Hazard.from_hdf5(HAZ_TEST_TC) exp = Exposures.from_mat(ENT_TEST_MAT) exp.gdf['region_id'] = np.zeros(exp.gdf.shape[0]) - exp.gdf.region_id.values[10:] = 1 + exp.gdf['region_id'].values[10:] = 1 exp.check() exp.assign_centroids(haz) @@ -141,7 +141,7 @@ def test_cutoff_hazard_region_pass(self): all_haz = np.arange(haz.intensity.shape[0]) all_haz[pos_no_null] = -1 pos_null = np.argwhere(all_haz > 0).reshape(-1) - centr_null = np.unique(exp.gdf.centr_[exp.gdf.region_id == 0]) + centr_null = np.unique(exp.gdf['centr_'][exp.gdf['region_id'] == 0]) for i_ev in pos_null: self.assertEqual(new_haz.intensity[i_ev, centr_null].max(), 0) @@ -170,9 +170,9 @@ def test_change_exposures_impf_pass(self): self.assertEqual(new_exp.ref_year, exp.ref_year) self.assertEqual(new_exp.value_unit, exp.value_unit) self.assertEqual(new_exp.description, exp.description) - self.assertTrue(np.array_equal(new_exp.gdf.value.values, exp.gdf.value.values)) - self.assertTrue(np.array_equal(new_exp.gdf.latitude.values, exp.gdf.latitude.values)) - self.assertTrue(np.array_equal(new_exp.gdf.longitude.values, exp.gdf.longitude.values)) + self.assertTrue(np.array_equal(new_exp.gdf['value'].values, exp.gdf['value'].values)) + self.assertTrue(np.array_equal(new_exp.gdf['latitude'].values, exp.gdf['latitude'].values)) + self.assertTrue(np.array_equal(new_exp.gdf['longitude'].values, exp.gdf['longitude'].values)) self.assertTrue(np.array_equal(exp.gdf[INDICATOR_IMPF + 'TC'].values, np.ones(new_exp.gdf.shape[0]))) self.assertTrue(np.array_equal(new_exp.gdf[INDICATOR_IMPF + 'TC'].values, np.ones(new_exp.gdf.shape[0]) * 3)) @@ -207,9 +207,9 @@ def test_change_all_exposures_pass(self): self.assertEqual(new_exp.ref_year, ref_exp.ref_year) self.assertEqual(new_exp.value_unit, ref_exp.value_unit) self.assertEqual(new_exp.description, ref_exp.description) - self.assertTrue(np.array_equal(new_exp.gdf.value.values, ref_exp.gdf.value.values)) - self.assertTrue(np.array_equal(new_exp.gdf.latitude.values, ref_exp.gdf.latitude.values)) - self.assertTrue(np.array_equal(new_exp.gdf.longitude.values, ref_exp.gdf.longitude.values)) + self.assertTrue(np.array_equal(new_exp.gdf['value'].values, ref_exp.gdf['value'].values)) + self.assertTrue(np.array_equal(new_exp.gdf['latitude'].values, ref_exp.gdf['latitude'].values)) + self.assertTrue(np.array_equal(new_exp.gdf['longitude'].values, ref_exp.gdf['longitude'].values)) def test_not_filter_exposures_pass(self): """Test _filter_exposures method with []""" @@ -244,8 +244,8 @@ def test_filter_exposures_pass(self): exp = Exposures.from_mat(ENT_TEST_MAT) exp.gdf.rename(columns={'impf_': 'impf_TC', 'centr_': 'centr_TC'}, inplace=True) exp.gdf['region_id'] = np.ones(exp.gdf.shape[0]) - exp.gdf.region_id.values[:exp.gdf.shape[0] // 2] = 3 - exp.gdf.region_id[0] = 4 + exp.gdf['region_id'].values[:exp.gdf.shape[0] // 2] = 3 + exp.gdf['region_id'][0] = 4 exp.check() imp_set = ImpactFuncSet.from_mat(ENT_TEST_MAT) @@ -278,23 +278,23 @@ def test_filter_exposures_pass(self): self.assertFalse(hasattr(res_exp.gdf, "crs")) # regions (that is just input data, no need for testing, but it makes the changed and unchanged parts obious) - self.assertTrue(np.array_equal(res_exp.gdf.region_id.values[0], 4)) - self.assertTrue(np.array_equal(res_exp.gdf.region_id.values[1:25], np.ones(24) * 3)) - self.assertTrue(np.array_equal(res_exp.gdf.region_id.values[25:], np.ones(25))) + self.assertTrue(np.array_equal(res_exp.gdf['region_id'].values[0], 4)) + self.assertTrue(np.array_equal(res_exp.gdf['region_id'].values[1:25], np.ones(24) * 3)) + self.assertTrue(np.array_equal(res_exp.gdf['region_id'].values[25:], np.ones(25))) # changed exposures - self.assertTrue(np.array_equal(res_exp.gdf.value.values[:25], new_exp.gdf.value.values[:25])) - self.assertTrue(np.all(np.not_equal(res_exp.gdf.value.values[:25], exp.gdf.value.values[:25]))) - self.assertTrue(np.all(np.not_equal(res_exp.gdf.impf_TC.values[:25], new_exp.gdf.impf_TC.values[:25]))) - self.assertTrue(np.array_equal(res_exp.gdf.latitude.values[:25], new_exp.gdf.latitude.values[:25])) - self.assertTrue(np.array_equal(res_exp.gdf.longitude.values[:25], new_exp.gdf.longitude.values[:25])) + self.assertTrue(np.array_equal(res_exp.gdf['value'].values[:25], new_exp.gdf['value'].values[:25])) + self.assertTrue(np.all(np.not_equal(res_exp.gdf['value'].values[:25], exp.gdf['value'].values[:25]))) + self.assertTrue(np.all(np.not_equal(res_exp.gdf['impf_TC'].values[:25], new_exp.gdf['impf_TC'].values[:25]))) + self.assertTrue(np.array_equal(res_exp.gdf['latitude'].values[:25], new_exp.gdf['latitude'].values[:25])) + self.assertTrue(np.array_equal(res_exp.gdf['longitude'].values[:25], new_exp.gdf['longitude'].values[:25])) # unchanged exposures - self.assertTrue(np.array_equal(res_exp.gdf.value.values[25:], exp.gdf.value.values[25:])) - self.assertTrue(np.all(np.not_equal(res_exp.gdf.value.values[25:], new_exp.gdf.value.values[25:]))) - self.assertTrue(np.array_equal(res_exp.gdf.impf_TC.values[25:], exp.gdf.impf_TC.values[25:])) - self.assertTrue(np.array_equal(res_exp.gdf.latitude.values[25:], exp.gdf.latitude.values[25:])) - self.assertTrue(np.array_equal(res_exp.gdf.longitude.values[25:], exp.gdf.longitude.values[25:])) + self.assertTrue(np.array_equal(res_exp.gdf['value'].values[25:], exp.gdf['value'].values[25:])) + self.assertTrue(np.all(np.not_equal(res_exp.gdf['value'].values[25:], new_exp.gdf['value'].values[25:]))) + self.assertTrue(np.array_equal(res_exp.gdf['impf_TC'].values[25:], exp.gdf['impf_TC'].values[25:])) + self.assertTrue(np.array_equal(res_exp.gdf['latitude'].values[25:], exp.gdf['latitude'].values[25:])) + self.assertTrue(np.array_equal(res_exp.gdf['longitude'].values[25:], exp.gdf['longitude'].values[25:])) # unchanged impact functions self.assertEqual(list(res_ifs.get_func().keys()), [meas.haz_type]) @@ -387,8 +387,8 @@ def test_calc_impact_pass(self): self.assertAlmostEqual(imp.at_event[12], 1.470194187501225e+07) self.assertAlmostEqual(imp.at_event[41], 4.7226357936631286e+08) self.assertAlmostEqual(imp.at_event[11890], 1.742110428135755e+07) - self.assertTrue(np.array_equal(imp.coord_exp[:, 0], entity.exposures.gdf.latitude)) - self.assertTrue(np.array_equal(imp.coord_exp[:, 1], entity.exposures.gdf.longitude)) + self.assertTrue(np.array_equal(imp.coord_exp[:, 0], entity.exposures.gdf['latitude'])) + self.assertTrue(np.array_equal(imp.coord_exp[:, 1], entity.exposures.gdf['longitude'])) self.assertAlmostEqual(imp.eai_exp[0], 1.15677655725858e+08) self.assertAlmostEqual(imp.eai_exp[-1], 7.528669956120645e+07) self.assertAlmostEqual(imp.tot_value, 6.570532945599105e+11) diff --git a/climada/entity/test/test_entity.py b/climada/entity/test/test_entity.py index 54ab7aa725..46e712c571 100644 --- a/climada/entity/test/test_entity.py +++ b/climada/entity/test/test_entity.py @@ -41,8 +41,8 @@ def test_default_pass(self): def_entity = Entity.from_excel(ENT_TEMPLATE_XLS) # Check default demo excel file has been loaded - self.assertEqual(len(def_entity.exposures.gdf.deductible), 24) - self.assertEqual(def_entity.exposures.gdf.value[2], 12596064143.542929) + self.assertEqual(len(def_entity.exposures.gdf['deductible']), 24) + self.assertEqual(def_entity.exposures.gdf['value'][2], 12596064143.542929) self.assertEqual(len(def_entity.impact_funcs.get_func('TC', 1).mdd), 25) diff --git a/climada/hazard/centroids/centr.py b/climada/hazard/centroids/centr.py index b02f7569d6..df57fbdc3d 100644 --- a/climada/hazard/centroids/centr.py +++ b/climada/hazard/centroids/centr.py @@ -138,14 +138,14 @@ def geometry(self): @property def on_land(self): """ Get the on_land property """ - if self.gdf.on_land.isna().all(): + if self.gdf['on_land'].isna().all(): return None return self.gdf['on_land'].values @property def region_id(self): """ Get the assigned region_id """ - if self.gdf.region_id.isna().all(): + if self.gdf['region_id'].isna().all(): return None return self.gdf['region_id'].values @@ -479,7 +479,7 @@ def select_mask(self, sel_cen=None, reg_id=None, extent=None): (self.lat >= lat_min) & (self.lat <= lat_max) ) return sel_cen - + def plot(self, *, axis=None, figsize=(9, 13), **kwargs): """Plot centroids geodataframe using geopandas and cartopy plotting functions. @@ -494,7 +494,7 @@ def plot(self, *, axis=None, figsize=(9, 13), **kwargs): positional arguments for geopandas.GeoDataFrame.plot kwargs : optional keyword arguments for geopandas.GeoDataFrame.plot - + Returns ------- ax : cartopy.mpl.geoaxes.GeoAxes instance diff --git a/climada/hazard/isimip_data.py b/climada/hazard/isimip_data.py index 6235bfda55..8630d59d70 100644 --- a/climada/hazard/isimip_data.py +++ b/climada/hazard/isimip_data.py @@ -56,6 +56,6 @@ def _read_one_nc(file_name, bbox=None, years=None): if not years: return data.sel(lat=slice(bbox[3], bbox[1]), lon=slice(bbox[0], bbox[2])) - time_id = years - int(data.time.units[12:16]) + time_id = years - int(data['time'].units[12:16]) return data.sel(lat=slice(bbox[3], bbox[1]), lon=slice(bbox[0], bbox[2]), time=slice(time_id[0], time_id[1])) diff --git a/climada/hazard/storm_europe.py b/climada/hazard/storm_europe.py index a0c5b77718..359c3d8a3f 100644 --- a/climada/hazard/storm_europe.py +++ b/climada/hazard/storm_europe.py @@ -238,19 +238,19 @@ def _read_one_nc(cls, file_name, centroids, intensity_thres): # xarray does not penalise repeated assignments, see # http://xarray.pydata.org/en/stable/data-structures.html - stacked = ncdf.max_wind_gust.stack( + stacked = ncdf['max_wind_gust'].stack( intensity=('latitude', 'longitude', 'time') ) stacked = stacked.where(stacked > intensity_thres) stacked = stacked.fillna(0) # fill in values from netCDF - ssi_wisc = np.array([float(ncdf.ssi)]) + ssi_wisc = np.array([float(ncdf.attrs['ssi'])]) intensity = sparse.csr_matrix(stacked) new_haz = cls(ssi_wisc=ssi_wisc, intensity=intensity, - event_name=[ncdf.storm_name], - date=np.array([datetime64_to_ordinal(ncdf.time.data[0])]), + event_name=[ncdf.attrs['storm_name']], + date=np.array([datetime64_to_ordinal(ncdf['time'].data[0])]), # fill in default values centroids=centroids, event_id=np.array([1]), @@ -334,18 +334,18 @@ def from_cosmoe_file(cls, fp_file, run_datetime, event_date=None, .stack(intensity=('y_1', 'x_1')) considered_dates = stacked['date'].values stacked = stacked.stack(date_ensemble=('date', 'epsd_1')) - stacked = stacked.where(stacked.VMAX_10M > intensity_thres) + stacked = stacked.where(stacked['VMAX_10M'] > intensity_thres) stacked = stacked.fillna(0) # fill in values from netCDF - intensity = sparse.csr_matrix(stacked.VMAX_10M.T) - event_id = np.arange(stacked.date_ensemble.size) + 1 + intensity = sparse.csr_matrix(stacked['VMAX_10M'].T) + event_id = np.arange(stacked['date_ensemble'].size) + 1 date = np.repeat( np.array(datetime64_to_ordinal(considered_dates)), - np.unique(ncdf.epsd_1).size + np.unique(ncdf['epsd_1']).size ) orig = np.full_like(event_id, False) - orig[(stacked.epsd_1 == 0).values] = True + orig[(stacked['epsd_1'] == 0).values] = True if description is None: description = (model_name + ' weather forecast windfield ' + @@ -362,10 +362,10 @@ def from_cosmoe_file(cls, fp_file, run_datetime, event_date=None, date=date, event_name=[date_i + '_ens' + str(ens_i) for date_i, ens_i - in zip(date_to_str(date), stacked.epsd_1.values + 1)], + in zip(date_to_str(date), stacked['epsd_1'].values + 1)], frequency=np.divide( np.ones_like(event_id), - np.unique(ncdf.epsd_1).size), + np.unique(ncdf['epsd_1']).size), ) # close netcdf file @@ -477,30 +477,30 @@ def from_icon_grib(cls, run_datetime, event_date=None, model_name='icon-eu-eps', stacked = stacked.where(stacked > intensity_thres) stacked = stacked.fillna(0) - event_id = np.arange(stacked.date_ensemble.size) + 1 + event_id = np.arange(stacked['date_ensemble'].size) + 1 date = np.repeat( np.array(datetime64_to_ordinal(considered_dates)), - np.unique(stacked.number).size + np.unique(stacked['number']).size ) orig = np.full_like(event_id, False) - orig[(stacked.number == 1).values] = True + orig[(stacked['number'] == 1).values] = True if description is None: description = ('icon weather forecast windfield for run started at ' + run_datetime.strftime('%Y%m%d%H')) # Create Hazard haz = cls( - intensity=sparse.csr_matrix(stacked.gust.T), + intensity=sparse.csr_matrix(stacked['gust'].T), centroids=cls._centroids_from_nc(nc_centroids_file), event_id=event_id, date=date, orig=orig, event_name=[date_i + '_ens' + str(ens_i) for date_i, ens_i - in zip(date_to_str(date), stacked.number.values)], + in zip(date_to_str(date), stacked['number'].values)], frequency=np.divide( np.ones_like(event_id), - np.unique(stacked.number).size), + np.unique(stacked['number']).size), ) haz.check() @@ -527,25 +527,25 @@ def _centroids_from_nc(file_name): ncdf = xr.open_dataset(file_name) create_meshgrid = True if hasattr(ncdf, 'latitude'): - lats = ncdf.latitude.data - lons = ncdf.longitude.data + lats = ncdf['latitude'].data + lons = ncdf['longitude'].data elif hasattr(ncdf, 'lat'): - lats = ncdf.lat.data - lons = ncdf.lon.data + lats = ncdf['lat'].data + lons = ncdf['lon'].data elif hasattr(ncdf, 'lat_1'): - if len(ncdf.lon_1.shape)>1 & \ - (ncdf.lon_1.shape == ncdf.lat_1.shape) \ + if len(ncdf['lon_1'].shape)>1 & \ + (ncdf['lon_1'].shape == ncdf['lat_1'].shape) \ : - lats = ncdf.lat_1.data.flatten() - lons = ncdf.lon_1.data.flatten() + lats = ncdf['lat_1'].data.flatten() + lons = ncdf['lon_1'].data.flatten() create_meshgrid = False else: - lats = ncdf.lat_1.data - lons = ncdf.lon_1.data + lats = ncdf['lat_1'].data + lons = ncdf['lon_1'].data elif hasattr(ncdf, 'clat'): - lats = ncdf.clat.data - lons = ncdf.clon.data - if ncdf.clat.attrs['units']=='radian': + lats = ncdf['clat'].data + lons = ncdf['clon'].data + if ncdf['clat'].attrs['units']=='radian': lats = np.rad2deg(lats) lons = np.rad2deg(lons) create_meshgrid = False @@ -713,16 +713,16 @@ def plot_ssi(self, full_area=False): 'orig': self.orig, }) ssi_freq = ssi_freq.sort_values('ssi', ascending=False) - ssi_freq['freq_cum'] = np.cumsum(ssi_freq.freq) + ssi_freq['freq_cum'] = np.cumsum(ssi_freq['freq']) - ssi_hist = ssi_freq.loc[ssi_freq.orig].copy() - ssi_hist.freq = ssi_hist.freq * self.orig.size / self.orig.sum() - ssi_hist['freq_cum'] = np.cumsum(ssi_hist.freq) + ssi_hist = ssi_freq.loc[ssi_freq['orig']].copy() + ssi_hist['freq'] = ssi_hist['freq'] * self.orig.size / self.orig.sum() + ssi_hist['freq_cum'] = np.cumsum(ssi_hist['freq']) # plotting fig, axs = plt.subplots() - axs.plot(ssi_freq.freq_cum, ssi_freq.ssi, label='All Events') - axs.scatter(ssi_hist.freq_cum, ssi_hist.ssi, + axs.plot(ssi_freq['freq_cum'], ssi_freq['ssi'], label='All Events') + axs.scatter(ssi_hist['freq_cum'], ssi_hist['ssi'], color='red', label='Historic Events') axs.legend() axs.set_xlabel('Exceedance Frequency [1/a]') diff --git a/climada/hazard/tc_clim_change.py b/climada/hazard/tc_clim_change.py index 21b40a0b05..5230ac247e 100644 --- a/climada/hazard/tc_clim_change.py +++ b/climada/hazard/tc_clim_change.py @@ -159,7 +159,7 @@ def calc_scale_knutson(ref_year=2050, rcp_scenario=45): rad_force = pd.read_excel(TOT_RADIATIVE_FORCE) years = np.array([year for year in rad_force.columns if isinstance(year, int)]) rad_rcp = np.array([int(float(sce[sce.index('.') - 1:sce.index('.') + 2]) * 10) - for sce in rad_force.Scenario if isinstance(sce, str)]) + for sce in rad_force['Scenario'] if isinstance(sce, str)]) # mean values for Knutson values rf_vals = np.argwhere(rad_rcp == rcp_knu).reshape(-1)[0] diff --git a/climada/hazard/tc_tracks.py b/climada/hazard/tc_tracks.py index 315e364f0a..fd8c333c67 100644 --- a/climada/hazard/tc_tracks.py +++ b/climada/hazard/tc_tracks.py @@ -242,7 +242,7 @@ def get_track(self, track_name=None): return self.data for track in self.data: - if track.name == track_name: + if track.attrs['name'] == track_name: return track if hasattr(track, 'sid') and track.sid == track_name: return track @@ -518,7 +518,7 @@ def from_ibtracs_netcdf(cls, provider=None, rescale_windspeeds=True, storm_id=No return cls() ibtracs_ds = ibtracs_ds.sel(storm=match) - ibtracs_ds['valid_t'] = ibtracs_ds.time.notnull() + ibtracs_ds['valid_t'] = ibtracs_ds['time'].notnull() if rescale_windspeeds: for agency in IBTRACS_AGENCIES: @@ -585,13 +585,13 @@ def from_ibtracs_netcdf(cls, provider=None, rescale_windspeeds=True, storm_id=No if estimate_missing: ibtracs_ds['pres'][:] = _estimate_pressure( - ibtracs_ds.pres, ibtracs_ds.lat, ibtracs_ds.lon, ibtracs_ds.wind) + ibtracs_ds['pres'], ibtracs_ds['lat'], ibtracs_ds['lon'], ibtracs_ds['wind']) ibtracs_ds['wind'][:] = _estimate_vmax( - ibtracs_ds.wind, ibtracs_ds.lat, ibtracs_ds.lon, ibtracs_ds.pres) + ibtracs_ds['wind'], ibtracs_ds['lat'], ibtracs_ds['lon'], ibtracs_ds['pres']) - ibtracs_ds['valid_t'] &= (ibtracs_ds.lat.notnull() & ibtracs_ds.lon.notnull() - & ibtracs_ds.wind.notnull() & ibtracs_ds.pres.notnull()) - valid_storms_mask = ibtracs_ds.valid_t.any(dim="date_time") + ibtracs_ds['valid_t'] &= (ibtracs_ds['lat'].notnull() & ibtracs_ds['lon'].notnull() + & ibtracs_ds['wind'].notnull() & ibtracs_ds['pres'].notnull()) + valid_storms_mask = ibtracs_ds['valid_t'].any(dim="date_time") invalid_storms_idx = np.nonzero(~valid_storms_mask.data)[0] if invalid_storms_idx.size > 0: invalid_sids = list(ibtracs_ds.sid.sel(storm=invalid_storms_idx).astype(str).data) @@ -601,7 +601,7 @@ def from_ibtracs_netcdf(cls, provider=None, rescale_windspeeds=True, storm_id=No ibtracs_ds = ibtracs_ds.sel(storm=valid_storms_mask) if discard_single_points: - valid_storms_mask = ibtracs_ds.valid_t.sum(dim="date_time") > 1 + valid_storms_mask = ibtracs_ds['valid_t'].sum(dim="date_time") > 1 invalid_storms_idx = np.nonzero(~valid_storms_mask.data)[0] if invalid_storms_idx.size > 0: invalid_sids = list(ibtracs_ds.sid.sel(storm=invalid_storms_idx).astype(str).data) @@ -617,7 +617,7 @@ def from_ibtracs_netcdf(cls, provider=None, rescale_windspeeds=True, storm_id=No 'requirements.') return cls() - max_wind = ibtracs_ds.wind.max(dim="date_time").data.ravel() + max_wind = ibtracs_ds['wind'].max(dim="date_time").data.ravel() category_test = (max_wind[:, None] < np.array(SAFFIR_SIM_CAT)[None]) category = np.argmax(category_test, axis=1) - 1 basin_map = {b.encode("utf-8"): v for b, v in BASIN_ENV_PRESSURE.items()} @@ -629,7 +629,7 @@ def from_ibtracs_netcdf(cls, provider=None, rescale_windspeeds=True, storm_id=No last_perc = 0 all_tracks = [] - for i_track, t_msk in enumerate(ibtracs_ds.valid_t.data): + for i_track, t_msk in enumerate(ibtracs_ds['valid_t'].data): perc = 100 * len(all_tracks) / ibtracs_ds.sid.size if perc - last_perc >= 10: LOGGER.info("Progress: %d%%", perc) @@ -647,42 +647,43 @@ def from_ibtracs_netcdf(cls, provider=None, rescale_windspeeds=True, storm_id=No # A track that crosses the antimeridian in IBTrACS might be truncated by `t_msk` in # such a way that the remaining part is not crossing the antimeridian: - if (track_ds.lon.values > 180).all(): + if (track_ds['lon'].values > 180).all(): track_ds['lon'] -= 360 # set time_step in hours - track_ds['time_step'] = xr.ones_like(track_ds.time, dtype=float) - if track_ds.time.size > 1: - track_ds.time_step.values[1:] = (track_ds.time.diff(dim="date_time") + track_ds['time_step'] = xr.ones_like(track_ds['time'], dtype=float) + if track_ds['time'].size > 1: + track_ds['time_step'].values[1:] = (track_ds['time'].diff(dim="date_time") / np.timedelta64(1, 'h')) - track_ds.time_step.values[0] = track_ds.time_step[1] + track_ds['time_step'].values[0] = track_ds['time_step'][1] with warnings.catch_warnings(): # See https://github.com/pydata/xarray/issues/4167 warnings.simplefilter(action="ignore", category=FutureWarning) - track_ds['rmw'] = track_ds.rmw \ + track_ds['rmw'] = track_ds['rmw'] \ .ffill(dim='date_time', limit=1) \ .bfill(dim='date_time', limit=1) \ .fillna(0) - track_ds['roci'] = track_ds.roci \ + track_ds['roci'] = track_ds['roci'] \ .ffill(dim='date_time', limit=1) \ .bfill(dim='date_time', limit=1) \ .fillna(0) - track_ds['poci'] = track_ds.poci \ + track_ds['poci'] = track_ds['poci'] \ .ffill(dim='date_time', limit=4) \ .bfill(dim='date_time', limit=4) # this is the most time consuming line in the processing: - track_ds['poci'] = track_ds.poci.fillna(tr_basin_penv) + track_ds['poci'] = track_ds['poci'].fillna(tr_basin_penv) if estimate_missing: - track_ds['rmw'][:] = estimate_rmw(track_ds.rmw.values, track_ds.pres.values) - track_ds['roci'][:] = estimate_roci(track_ds.roci.values, track_ds.pres.values) - track_ds['roci'][:] = np.fmax(track_ds.rmw.values, track_ds.roci.values) + track_ds['rmw'][:] = estimate_rmw(track_ds['rmw'].values, track_ds['pres'].values) + track_ds['roci'][:] = estimate_roci(track_ds['roci'].values, + track_ds['pres'].values) + track_ds['roci'][:] = np.fmax(track_ds['rmw'].values, track_ds['roci'].values) # ensure environmental pressure >= central pressure # this is the second most time consuming line in the processing: - track_ds['poci'][:] = np.fmax(track_ds.poci, track_ds.pres) + track_ds['poci'][:] = np.fmax(track_ds['poci'], track_ds['pres']) provider_str = f"ibtracs_{provider[0]}" if len(provider) > 1: @@ -691,16 +692,16 @@ def from_ibtracs_netcdf(cls, provider=None, rescale_windspeeds=True, storm_id=No for v in phys_vars) data_vars = { - 'radius_max_wind': ('time', track_ds.rmw.data), - 'radius_oci': ('time', track_ds.roci.data), - 'max_sustained_wind': ('time', track_ds.wind.data), - 'central_pressure': ('time', track_ds.pres.data), - 'environmental_pressure': ('time', track_ds.poci.data), + 'radius_max_wind': ('time', track_ds['rmw'].data), + 'radius_oci': ('time', track_ds['roci'].data), + 'max_sustained_wind': ('time', track_ds['wind'].data), + 'central_pressure': ('time', track_ds['pres'].data), + 'environmental_pressure': ('time', track_ds['poci'].data), } coords = { - 'time': ('time', track_ds.time.dt.round('s').data), - 'lat': ('time', track_ds.lat.data), - 'lon': ('time', track_ds.lon.data), + 'time': ('time', track_ds['time'].dt.round('s').data), + 'lat': ('time', track_ds['lat'].data), + 'lon': ('time', track_ds['lon'].data), } attrs = { 'max_sustained_wind_unit': 'kn', @@ -840,24 +841,24 @@ def from_simulations_chaz(cls, file_names, year_range=None, ensemble_nums=None): for path in get_file_names(file_names): LOGGER.info('Reading %s.', path) chaz_ds = xr.open_dataset(path) - chaz_ds.time.attrs["units"] = "days since 1950-1-1" - chaz_ds.time.attrs["missing_value"] = -54786.0 + chaz_ds['time'].attrs["units"] = "days since 1950-1-1" + chaz_ds['time'].attrs["missing_value"] = -54786.0 chaz_ds = xr.decode_cf(chaz_ds) - chaz_ds['id_no'] = chaz_ds.stormID * 1000 + chaz_ds.ensembleNum + chaz_ds['id_no'] = chaz_ds['stormID'] * 1000 + chaz_ds['ensembleNum'] for var in ['time', 'longitude', 'latitude']: - chaz_ds[var] = chaz_ds[var].expand_dims(ensembleNum=chaz_ds.ensembleNum) + chaz_ds[var] = chaz_ds[var].expand_dims(ensembleNum=chaz_ds['ensembleNum']) chaz_ds = chaz_ds.stack(id=("ensembleNum", "stormID")) - years_uniq = chaz_ds.time.dt.year.data + years_uniq = chaz_ds['time'].dt.year.data years_uniq = np.unique(years_uniq[~np.isnan(years_uniq)]) LOGGER.info("File contains %s tracks (at most %s nodes each), " "representing %s years (%d-%d).", - chaz_ds.id_no.size, chaz_ds.lifelength.size, + chaz_ds['id_no'].size, chaz_ds['lifelength'].size, years_uniq.size, years_uniq[0], years_uniq[-1]) # filter by year range if given if year_range: - match = ((chaz_ds.time.dt.year >= year_range[0]) - & (chaz_ds.time.dt.year <= year_range[1])).sel(lifelength=0) + match = ((chaz_ds['time'].dt.year >= year_range[0]) + & (chaz_ds['time'].dt.year <= year_range[1])).sel(lifelength=0) if np.count_nonzero(match) == 0: LOGGER.info('No tracks in time range (%s, %s).', *year_range) continue @@ -865,15 +866,15 @@ def from_simulations_chaz(cls, file_names, year_range=None, ensemble_nums=None): # filter by ensembleNum if given if ensemble_nums is not None: - match = np.isin(chaz_ds.ensembleNum.values, ensemble_nums) + match = np.isin(chaz_ds['ensembleNum'].values, ensemble_nums) if np.count_nonzero(match) == 0: LOGGER.info('No tracks with specified ensemble numbers.') continue chaz_ds = chaz_ds.sel(id=match) # remove invalid tracks from selection - chaz_ds['valid_t'] = chaz_ds.time.notnull() & chaz_ds.Mwspd.notnull() - valid_st = chaz_ds.valid_t.any(dim="lifelength") + chaz_ds['valid_t'] = chaz_ds['time'].notnull() & chaz_ds['Mwspd'].notnull() + valid_st = chaz_ds['valid_t'].any(dim="lifelength") invalid_st = np.nonzero(~valid_st.data)[0] if invalid_st.size > 0: LOGGER.info('No valid Mwspd values found for %d out of %d storm tracks.', @@ -881,57 +882,57 @@ def from_simulations_chaz(cls, file_names, year_range=None, ensemble_nums=None): chaz_ds = chaz_ds.sel(id=valid_st) # estimate central pressure from location and max wind - chaz_ds['pres'] = xr.full_like(chaz_ds.Mwspd, -1, dtype=float) + chaz_ds['pres'] = xr.full_like(chaz_ds['Mwspd'], -1, dtype=float) chaz_ds['pres'][:] = _estimate_pressure( - chaz_ds.pres, chaz_ds.latitude, chaz_ds.longitude, chaz_ds.Mwspd) + chaz_ds['pres'], chaz_ds['latitude'], chaz_ds['longitude'], chaz_ds['Mwspd']) # compute time stepsizes - chaz_ds['time_step'] = xr.zeros_like(chaz_ds.time, dtype=float) - chaz_ds['time_step'][1:, :] = (chaz_ds.time.diff(dim="lifelength") + chaz_ds['time_step'] = xr.zeros_like(chaz_ds['time'], dtype=float) + chaz_ds['time_step'][1:, :] = (chaz_ds['time'].diff(dim="lifelength") / np.timedelta64(1, 'h')) - chaz_ds['time_step'][0, :] = chaz_ds.time_step[1, :] + chaz_ds['time_step'][0, :] = chaz_ds['time_step'][1, :] # determine Saffir-Simpson category - max_wind = chaz_ds.Mwspd.max(dim="lifelength").data.ravel() + max_wind = chaz_ds['Mwspd'].max(dim="lifelength").data.ravel() category_test = (max_wind[:, None] < np.array(SAFFIR_SIM_CAT)[None]) chaz_ds['category'] = ("id", np.argmax(category_test, axis=1) - 1) fname = Path(path).name - chaz_ds.time[:] = chaz_ds.time.dt.round('s').data - chaz_ds['radius_max_wind'] = xr.full_like(chaz_ds.pres, np.nan) - chaz_ds['environmental_pressure'] = xr.full_like(chaz_ds.pres, DEF_ENV_PRESSURE) + chaz_ds['time'][:] = chaz_ds['time'].dt.round('s').data + chaz_ds['radius_max_wind'] = xr.full_like(chaz_ds['pres'], np.nan) + chaz_ds['environmental_pressure'] = xr.full_like(chaz_ds['pres'], DEF_ENV_PRESSURE) chaz_ds["track_name"] = ("id", [f"{fname}-{track_id.item()[1]}-{track_id.item()[0]}" - for track_id in chaz_ds.id]) + for track_id in chaz_ds['id']]) # add tracks one by one last_perc = 0 - for cnt, i_track in enumerate(chaz_ds.id_no): - perc = 100 * cnt / chaz_ds.id_no.size + for cnt, i_track in enumerate(chaz_ds['id_no']): + perc = 100 * cnt / chaz_ds['id_no'].size if perc - last_perc >= 10: LOGGER.info("Progress: %d%%", perc) last_perc = perc - track_ds = chaz_ds.sel(id=i_track.id.item()) - track_ds = track_ds.sel(lifelength=track_ds.valid_t.data) + track_ds = chaz_ds.sel(id=i_track['id'].item()) + track_ds = track_ds.sel(lifelength=track_ds['valid_t'].data) data.append(xr.Dataset({ - 'time_step': ('time', track_ds.time_step.values), - 'max_sustained_wind': ('time', track_ds.Mwspd.values), - 'central_pressure': ('time', track_ds.pres.values), - 'radius_max_wind': ('time', track_ds.radius_max_wind.values), - 'environmental_pressure': ('time', track_ds.environmental_pressure.values), - 'basin': ('time', np.full(track_ds.time.size, "GB", dtype=" 1 - else Point(track.lon.data, track.lat.data) + LineString(np.c_[track['lon'], track['lat']]) if track['lon'].size > 1 + else Point(track['lon'].data, track['lat'].data) for track in self.data ]) gdf.crs = DEF_CRS @@ -1528,15 +1529,15 @@ def _one_interp_data(track, time_step_h, land_geom=None): """ if time_step_h is None: return track - if track.time.size < 2: + if track['time'].size < 2: LOGGER.warning('Track interpolation not done. ' 'Not enough elements for %s', track.name) track_int = track else: - method = ['linear', 'quadratic', 'cubic'][min(2, track.time.size - 2)] + method = ['linear', 'quadratic', 'cubic'][min(2, track['time'].size - 2)] # handle change of sign in longitude - lon = u_coord.lon_normalize(track.lon.copy(), center=0) + lon = u_coord.lon_normalize(track['lon'].copy(), center=0) if (lon < -170).any() and (lon > 170).any(): # crosses 180 degrees east/west -> use positive degrees east lon[lon < 0] += 360 @@ -1551,14 +1552,15 @@ def _one_interp_data(track, time_step_h, land_geom=None): lon_int = lon.resample(time=time_step).interpolate(method) lon_int[lon_int > 180] -= 360 track_int.coords['lon'] = lon_int - track_int.coords['lat'] = track.lat.resample(time=time_step)\ + track_int.coords['lat'] = track['lat'].resample(time=time_step)\ .interpolate(method) track_int.attrs['category'] = set_category( - track_int.max_sustained_wind.values, - track_int.max_sustained_wind_unit) + track_int['max_sustained_wind'].values, + track_int.attrs['max_sustained_wind_unit']) # restrict to time steps within original bounds track_int = track_int.sel( - time=(track.time[0] <= track_int.time) & (track_int.time <= track.time[-1])) + time=(track['time'][0] <= track_int['time']) & + (track_int['time'] <= track['time'][-1])) if land_geom: track_land_params(track_int, land_geom) @@ -1702,8 +1704,8 @@ def _read_one_gettelman(nc_data, i_track): # construct xarray tr_ds = xr.Dataset.from_dataframe(tr_df.set_index('time')) - tr_ds.coords['lat'] = ('time', tr_ds.lat.values) - tr_ds.coords['lon'] = ('time', tr_ds.lon.values) + tr_ds.coords['lat'] = ('time', tr_ds['lat'].values) + tr_ds.coords['lon'] = ('time', tr_ds['lon'].values) tr_ds['basin'] = tr_ds['basin'].astype(' 0: # Assume the landfall started between this and the previous point - orig_lf[i_lf][0] = track.lat[lf_point - 1] + \ - (track.lat[lf_point] - track.lat[lf_point - 1]) / 2 - orig_lf[i_lf][1] = track.lon[lf_point - 1] + \ - (track.lon[lf_point] - track.lon[lf_point - 1]) / 2 + orig_lf[i_lf][0] = track['lat'][lf_point - 1] + \ + (track['lat'][lf_point] - track['lat'][lf_point - 1]) / 2 + orig_lf[i_lf][1] = track['lon'][lf_point - 1] + \ + (track['lon'][lf_point] - track['lon'][lf_point - 1]) / 2 else: # track starts over land, assume first 'landfall' starts here - orig_lf[i_lf][0] = track.lat[lf_point] - orig_lf[i_lf][1] = track.lon[lf_point] + orig_lf[i_lf][0] = track['lat'][lf_point] + orig_lf[i_lf][1] = track['lon'][lf_point] dist = DistanceMetric.get_metric('haversine') - nodes1 = np.radians(np.array([track.lat.values[1:], - track.lon.values[1:]]).transpose()) - nodes0 = np.radians(np.array([track.lat.values[:-1], - track.lon.values[:-1]]).transpose()) + nodes1 = np.radians(np.array([track['lat'].values[1:], + track['lon'].values[1:]]).transpose()) + nodes0 = np.radians(np.array([track['lat'].values[:-1], + track['lon'].values[:-1]]).transpose()) dist_since_lf[1:] = dist.pairwise(nodes1, nodes0).diagonal() - dist_since_lf[~track.on_land.values] = 0.0 - nodes1 = np.array([track.lat.values[sea_land_idx], - track.lon.values[sea_land_idx]]).transpose() / 180 * np.pi + dist_since_lf[~track['on_land'].values] = 0.0 + nodes1 = np.array([track['lat'].values[sea_land_idx], + track['lon'].values[sea_land_idx]]).transpose() / 180 * np.pi dist_since_lf[sea_land_idx] = \ dist.pairwise(nodes1, orig_lf / 180 * np.pi).diagonal() for sea_land, land_sea in zip(sea_land_idx, land_sea_idx): @@ -1978,7 +1980,7 @@ def _dist_since_lf(track): np.cumsum(dist_since_lf[sea_land:land_sea]) dist_since_lf *= EARTH_RADIUS_KM - dist_since_lf[~track.on_land.values] = np.nan + dist_since_lf[~track['on_land'].values] = np.nan return dist_since_lf @@ -2004,13 +2006,13 @@ def _get_landfall_idx(track, include_starting_landfall=False): ends over land, the last value is set to track.time.size. """ # Index in land that comes from previous sea index - sea_land_idx = np.where(np.diff(track.on_land.astype(int)) == 1)[0] + 1 + sea_land_idx = np.where(np.diff(track['on_land'].astype(int)) == 1)[0] + 1 # Index in sea that comes from previous land index - land_sea_idx = np.where(np.diff(track.on_land.astype(int)) == -1)[0] + 1 - if track.on_land[-1]: + land_sea_idx = np.where(np.diff(track['on_land'].astype(int)) == -1)[0] + 1 + if track['on_land'][-1]: # track ends over land: add last track point as the end of that landfall - land_sea_idx = np.append(land_sea_idx, track.time.size) - if track.on_land[0]: + land_sea_idx = np.append(land_sea_idx, track['time'].size) + if track['on_land'][0]: # track starts over land: remove first land-to-sea transition (not a landfall)? if include_starting_landfall: sea_land_idx = np.append(0, sea_land_idx) @@ -2293,9 +2295,9 @@ def ibtracs_track_agency(ds_sel): agency_map[b''] = agency_map[b'wmo'] agency_fun = lambda x: agency_map[x] if "track_agency" not in ds_sel.data_vars.keys(): - ds_sel['track_agency'] = ds_sel.wmo_agency.where(ds_sel.wmo_agency != b'', - ds_sel.usa_agency) - track_agency_ix = xr.apply_ufunc(agency_fun, ds_sel.track_agency, vectorize=True) + ds_sel['track_agency'] = ds_sel['wmo_agency'].where(ds_sel['wmo_agency'] != b'', + ds_sel['usa_agency']) + track_agency_ix = xr.apply_ufunc(agency_fun, ds_sel['track_agency'], vectorize=True) return agency_pref, track_agency_ix def ibtracs_add_official_variable(ibtracs_ds, tc_var, add_3h=False): @@ -2318,7 +2320,7 @@ def ibtracs_add_official_variable(ibtracs_ds, tc_var, add_3h=False): """ if "nan_var" not in ibtracs_ds.data_vars.keys(): # add an array full of NaN as a fallback value in the procedure - ibtracs_ds['nan_var'] = xr.full_like(ibtracs_ds.lat, np.nan) + ibtracs_ds['nan_var'] = xr.full_like(ibtracs_ds['lat'], np.nan) # determine which of the official agencies report this variable at all available_agencies = [a for a in IBTRACS_AGENCIES @@ -2336,7 +2338,7 @@ def ibtracs_add_official_variable(ibtracs_ds, tc_var, add_3h=False): # read from officially responsible agencies that report this variable, but only # at official reporting times (usually 6-hourly) official_agency_ix = xr.apply_ufunc( - lambda x: agency_map[x], ibtracs_ds.wmo_agency, vectorize=True) + lambda x: agency_map[x], ibtracs_ds['wmo_agency'], vectorize=True) available_cols = ['nan_var'] + [f'{a}_{tc_var}' for a in available_agencies] all_vals = ibtracs_ds[available_cols].to_array(dim='agency') ibtracs_ds[f'official_{tc_var}'] = all_vals.isel(agency=official_agency_ix) diff --git a/climada/hazard/tc_tracks_synth.py b/climada/hazard/tc_tracks_synth.py index 7027a0c664..7592450102 100644 --- a/climada/hazard/tc_tracks_synth.py +++ b/climada/hazard/tc_tracks_synth.py @@ -181,15 +181,15 @@ def calc_perturbed_trajectories(tracks, # hence sum is nb_synth_tracks * (2 + 2*(size-1)) = nb_synth_tracks * 2 * size # https://stats.stackexchange.com/questions/48086/algorithm-to-produce-autocorrelated-uniformly-distributed-number if autocorr_ddirection == 0 and autocorr_dspeed == 0: - random_vec = [np.random.uniform(size=nb_synth_tracks * (2 * track.time.size)) + random_vec = [np.random.uniform(size=nb_synth_tracks * (2 * track['time'].size)) for track in tracks.data] else: random_vec = [np.concatenate((np.random.uniform(size=nb_synth_tracks * 2), - _random_uniform_ac(nb_synth_tracks * (track.time.size - 1), + _random_uniform_ac(nb_synth_tracks * (track['time'].size - 1), autocorr_ddirection, time_step_h), - _random_uniform_ac(nb_synth_tracks * (track.time.size - 1), + _random_uniform_ac(nb_synth_tracks * (track['time'].size - 1), autocorr_dspeed, time_step_h))) - if track.time.size > 1 else np.random.uniform(size=nb_synth_tracks * 2) + if track['time'].size > 1 else np.random.uniform(size=nb_synth_tracks * 2) for track in tracks.data] if pool: @@ -280,7 +280,7 @@ def _one_rnd_walk(track, nb_synth_tracks, max_shift_ini, max_dspeed_rel, max_ddi latitudes with a wind speed up to TC category 1. """ ens_track = list() - n_dat = track.time.size + n_dat = track['time'].size n_seg = n_dat - 1 xy_ini = max_shift_ini * (2 * rnd_vec[:2 * nb_synth_tracks].reshape((2, nb_synth_tracks)) - 1) [dt] = np.unique(track['time_step']) @@ -293,32 +293,32 @@ def _one_rnd_walk(track, nb_synth_tracks, max_shift_ini, max_dspeed_rel, max_ddi # select angular perturbation for that synthetic track i_start_ang = 2 * nb_synth_tracks + i_ens * n_seg - i_end_ang = i_start_ang + track.time.size - 1 + i_end_ang = i_start_ang + track['time'].size - 1 # scale by maximum perturbation and time step in hour (temporal-resolution independent) ang_pert = dt * np.degrees(max_ddirection * (2 * rnd_vec[i_start_ang:i_end_ang] - 1)) ang_pert_cum = np.cumsum(ang_pert) # select translational speed perturbation for that synthetic track i_start_trans = 2 * nb_synth_tracks + nb_synth_tracks * n_seg + i_ens * n_seg - i_end_trans = i_start_trans + track.time.size - 1 + i_end_trans = i_start_trans + track['time'].size - 1 # scale by maximum perturbation and time step in hour (temporal-resolution independent) trans_pert = 1 + max_dspeed_rel * (2 * rnd_vec[i_start_trans:i_end_trans] - 1) # get bearings and angular distance for the original track - bearings = _get_bearing_angle(i_track.lon.values, i_track.lat.values) - angular_dist = climada.util.coordinates.dist_approx(i_track.lat.values[:-1, None], - i_track.lon.values[:-1, None], - i_track.lat.values[1:, None], - i_track.lon.values[1:, None], + bearings = _get_bearing_angle(i_track['lon'].values, i_track['lat'].values) + angular_dist = climada.util.coordinates.dist_approx(i_track['lat'].values[:-1, None], + i_track['lon'].values[:-1, None], + i_track['lat'].values[1:, None], + i_track['lon'].values[1:, None], method="geosphere", units="degree")[:, 0, 0] # apply perturbation to lon / lat - new_lon = np.zeros_like(i_track.lon.values) - new_lat = np.zeros_like(i_track.lat.values) - new_lon[0] = i_track.lon.values[0] + xy_ini[0, i_ens] - new_lat[0] = i_track.lat.values[0] + xy_ini[1, i_ens] - last_idx = i_track.time.size + new_lon = np.zeros_like(i_track['lon'].values) + new_lat = np.zeros_like(i_track['lat'].values) + new_lon[0] = i_track['lon'].values[0] + xy_ini[0, i_ens] + new_lat[0] = i_track['lat'].values[0] + xy_ini[1, i_ens] + last_idx = i_track['time'].size for i in range(0, len(new_lon) - 1): new_lon[i + 1], new_lat[i + 1] = \ _get_destination_points(new_lon[i], new_lat[i], @@ -330,9 +330,9 @@ def _one_rnd_walk(track, nb_synth_tracks, max_shift_ini, max_dspeed_rel, max_ddi if i+2 < last_idx and (new_lat[i + 1] > 70 or new_lat[i + 1] < -70): last_idx = i + 2 # end the track here - max_wind_end = i_track.max_sustained_wind.values[last_idx] + max_wind_end = i_track['max_sustained_wind'].values[last_idx] ss_scale_end = climada.hazard.tc_tracks.set_category(max_wind_end, - i_track.max_sustained_wind_unit) + i_track.attrs['max_sustained_wind_unit']) # TC category at ending point should not be higher than 1 cutoff_txt = (f"{i_track.attrs['name']}_gen{i_ens + 1}" f" ({climada.hazard.tc_tracks.CAT_NAMES[ss_scale_end]})") @@ -344,8 +344,8 @@ def _one_rnd_walk(track, nb_synth_tracks, max_shift_ini, max_dspeed_rel, max_ddi # make sure longitude values are within (-180, 180) climada.util.coordinates.lon_normalize(new_lon, center=0.0) - i_track.lon.values = new_lon - i_track.lat.values = new_lat + i_track['lon'].values = new_lon + i_track['lat'].values = new_lat i_track.attrs['orig_event_flag'] = False i_track.attrs['name'] = f"{i_track.attrs['name']}_gen{i_ens + 1}" i_track.attrs['sid'] = f"{i_track.attrs['sid']}_gen{i_ens + 1}" @@ -642,8 +642,8 @@ def _apply_land_decay(tracks, v_rel, p_rel, land_geom, s_rel=True, if check_plot: orig_wind, orig_pres = [], [] for track in sy_tracks: - orig_wind.append(np.copy(track.max_sustained_wind.values)) - orig_pres.append(np.copy(track.central_pressure.values)) + orig_wind.append(np.copy(track['max_sustained_wind'].values)) + orig_pres.append(np.copy(track['central_pressure'].values)) if pool: chunksize = max(min(len(tracks) // pool.ncpus, 1000), 1) @@ -696,18 +696,18 @@ def _decay_values(track, land_geom, s_rel): sea_land_idx, land_sea_idx = climada.hazard.tc_tracks._get_landfall_idx(track) if sea_land_idx.size: for sea_land, land_sea in zip(sea_land_idx, land_sea_idx): - v_landfall = track.max_sustained_wind[sea_land - 1].values + v_landfall = track['max_sustained_wind'][sea_land - 1].values ss_scale = climada.hazard.tc_tracks.set_category(v_landfall, - track.max_sustained_wind_unit) + track.attrs['max_sustained_wind_unit']) - v_land = track.max_sustained_wind[sea_land - 1:land_sea].values + v_land = track['max_sustained_wind'][sea_land - 1:land_sea].values if v_land[0] > 0: v_land = (v_land[1:] / v_land[0]).tolist() else: v_land = v_land[1:].tolist() - p_landfall = float(track.central_pressure[sea_land - 1].values) - p_land = track.central_pressure[sea_land - 1:land_sea].values + p_landfall = float(track['central_pressure'][sea_land - 1].values) + p_land = track['central_pressure'][sea_land - 1:land_sea].values p_land = (p_land[1:] / p_land[0]).tolist() p_land_s = _calc_decay_ps_value( @@ -719,12 +719,12 @@ def _decay_values(track, land_geom, s_rel): p_lf[ss_scale] = (array.array('f', p_land_s), array.array('f', p_land)) x_val[ss_scale] = array.array('f', - track.dist_since_lf[sea_land:land_sea]) + track['dist_since_lf'][sea_land:land_sea]) else: v_lf[ss_scale].extend(v_land) p_lf[ss_scale][0].extend(p_land_s) p_lf[ss_scale][1].extend(p_land) - x_val[ss_scale].extend(track.dist_since_lf[sea_land:land_sea]) + x_val[ss_scale].extend(track['dist_since_lf'][sea_land:land_sea]) return v_lf, p_lf, x_val @@ -870,20 +870,21 @@ def _apply_decay_coeffs(track, v_rel, p_rel, land_geom, s_rel): return track for idx, (sea_land, land_sea) \ in enumerate(zip(sea_land_idx, land_sea_idx)): - v_landfall = track.max_sustained_wind[sea_land - 1].values - p_landfall = float(track.central_pressure[sea_land - 1].values) + v_landfall = track['max_sustained_wind'][sea_land - 1].values + p_landfall = float(track['central_pressure'][sea_land - 1].values) ss_scale = climada.hazard.tc_tracks.set_category(v_landfall, - track.max_sustained_wind_unit) + track.attrs['max_sustained_wind_unit']) if land_sea - sea_land == 1: continue S = _calc_decay_ps_value(track, p_landfall, land_sea - 1, s_rel) if S <= 1: # central_pressure at start of landfall > env_pres after landfall: # set central_pressure to environmental pressure during whole lf - track.central_pressure[sea_land:land_sea] = track.environmental_pressure[sea_land:land_sea] + track['central_pressure'][sea_land:land_sea] = \ + track['environmental_pressure'][sea_land:land_sea] else: p_decay = _decay_p_function(S, p_rel[ss_scale][1], - track.dist_since_lf[sea_land:land_sea].values) + track['dist_since_lf'][sea_land:land_sea].values) # dont apply decay if it would decrease central pressure if np.any(p_decay < 1): LOGGER.info('Landfall decay would decrease pressure for ' @@ -892,12 +893,12 @@ def _apply_decay_coeffs(track, v_rel, p_rel, land_geom, s_rel): 'unphysical and therefore landfall decay is not ' 'applied in this case.', track.sid) - p_decay[p_decay < 1] = (track.central_pressure[sea_land:land_sea][p_decay < 1] + p_decay[p_decay < 1] = (track['central_pressure'][sea_land:land_sea][p_decay < 1] / p_landfall) - track.central_pressure[sea_land:land_sea] = p_landfall * p_decay + track['central_pressure'][sea_land:land_sea] = p_landfall * p_decay v_decay = _decay_v_function(v_rel[ss_scale], - track.dist_since_lf[sea_land:land_sea].values) + track['dist_since_lf'][sea_land:land_sea].values) # dont apply decay if it would increase wind speeds if np.any(v_decay > 1): # should not happen unless v_rel is negative @@ -905,13 +906,13 @@ def _apply_decay_coeffs(track, v_rel, p_rel, land_geom, s_rel): 'track id %s. This behavious in unphysical and ' 'therefore landfall decay is not applied in this ' 'case.', - track.sid) - v_decay[v_decay > 1] = (track.max_sustained_wind[sea_land:land_sea][v_decay > 1] + track['sid']) + v_decay[v_decay > 1] = (track['max_sustained_wind'][sea_land:land_sea][v_decay > 1] / v_landfall) - track.max_sustained_wind[sea_land:land_sea] = v_landfall * v_decay + track['max_sustained_wind'][sea_land:land_sea] = v_landfall * v_decay # correct values of sea after a landfall (until next landfall, if any) - if land_sea < track.time.size: + if land_sea < track['time'].size: if idx + 1 < sea_land_idx.size: # if there is a next landfall, correct until last point before # reaching land again @@ -919,25 +920,25 @@ def _apply_decay_coeffs(track, v_rel, p_rel, land_geom, s_rel): else: # if there is no further landfall, correct until the end of # the track - end_cor = track.time.size + end_cor = track['time'].size rndn = 0.1 * float(np.abs(np.random.normal(size=1) * 5) + 6) - r_diff = track.central_pressure[land_sea].values - \ - track.central_pressure[land_sea - 1].values + rndn - track.central_pressure[land_sea:end_cor] += - r_diff + r_diff = track['central_pressure'][land_sea].values - \ + track['central_pressure'][land_sea - 1].values + rndn + track['central_pressure'][land_sea:end_cor] += - r_diff rndn = rndn * 10 # mean value 10 - r_diff = track.max_sustained_wind[land_sea].values - \ - track.max_sustained_wind[land_sea - 1].values - rndn - track.max_sustained_wind[land_sea:end_cor] += - r_diff + r_diff = track['max_sustained_wind'][land_sea].values - \ + track['max_sustained_wind'][land_sea - 1].values - rndn + track['max_sustained_wind'][land_sea:end_cor] += - r_diff # correct limits warnings.filterwarnings('ignore') - cor_p = track.central_pressure.values > track.environmental_pressure.values - track.central_pressure[cor_p] = track.environmental_pressure[cor_p] - track.max_sustained_wind[track.max_sustained_wind < 0] = 0 + cor_p = track['central_pressure'].values > track['environmental_pressure'].values + track['central_pressure'][cor_p] = track['environmental_pressure'][cor_p] + track['max_sustained_wind'][track['max_sustained_wind'] < 0] = 0 track.attrs['category'] = climada.hazard.tc_tracks.set_category( - track.max_sustained_wind.values, track.max_sustained_wind_unit) + track['max_sustained_wind'].values, track.attrs['max_sustained_wind_unit']) return track @@ -973,9 +974,9 @@ def _check_apply_decay_plot(all_tracks, syn_orig_wind, syn_orig_pres): def _calc_decay_ps_value(track, p_landfall, pos, s_rel): if s_rel: - p_land_s = track.environmental_pressure[pos].values + p_land_s = track['environmental_pressure'][pos].values else: - p_land_s = track.central_pressure[pos].values + p_land_s = track['central_pressure'][pos].values return float(p_land_s / p_landfall) @@ -1041,34 +1042,34 @@ def _check_apply_decay_syn_plot(sy_tracks, syn_orig_wind, sea_land_idx, land_sea_idx = climada.hazard.tc_tracks._get_landfall_idx(track) if sea_land_idx.size: for sea_land, land_sea in zip(sea_land_idx, land_sea_idx): - v_lf = track.max_sustained_wind[sea_land - 1].values - p_lf = track.central_pressure[sea_land - 1].values + v_lf = track['max_sustained_wind'][sea_land - 1].values + p_lf = track['central_pressure'][sea_land - 1].values scale_thresholds = climada.hazard.tc_tracks.SAFFIR_SIM_CAT ss_scale_idx = np.where(v_lf < scale_thresholds)[0][0] - on_land = np.arange(track.time.size)[sea_land:land_sea] + on_land = np.arange(track['time'].size)[sea_land:land_sea] - graph_v_a.plot(on_land, track.max_sustained_wind[on_land], + graph_v_a.plot(on_land, track['max_sustained_wind'][on_land], 'o', c=climada.hazard.tc_tracks.CAT_COLORS[ss_scale_idx]) graph_v_b.plot(on_land, orig_wind[on_land], 'o', c=climada.hazard.tc_tracks.CAT_COLORS[ss_scale_idx]) - graph_p_a.plot(on_land, track.central_pressure[on_land], + graph_p_a.plot(on_land, track['central_pressure'][on_land], 'o', c=climada.hazard.tc_tracks.CAT_COLORS[ss_scale_idx]) graph_p_b.plot(on_land, orig_pres[on_land], 'o', c=climada.hazard.tc_tracks.CAT_COLORS[ss_scale_idx]) - graph_pd_a.plot(track.dist_since_lf[on_land], - track.central_pressure[on_land] / p_lf, + graph_pd_a.plot(track['dist_since_lf'][on_land], + track['central_pressure'][on_land] / p_lf, 'o', c=climada.hazard.tc_tracks.CAT_COLORS[ss_scale_idx]) - graph_ped_a.plot(track.dist_since_lf[on_land], - track.environmental_pressure[on_land] - - track.central_pressure[on_land], + graph_ped_a.plot(track['dist_since_lf'][on_land], + track['environmental_pressure'][on_land] - + track['central_pressure'][on_land], 'o', c=climada.hazard.tc_tracks.CAT_COLORS[ss_scale_idx]) - on_sea = np.arange(track.time.size)[~track.on_land] - graph_v_a.plot(on_sea, track.max_sustained_wind[on_sea], + on_sea = np.arange(track['time'].size)[~track['on_land']] + graph_v_a.plot(on_sea, track['max_sustained_wind'][on_sea], 'o', c='k', markersize=5) graph_v_b.plot(on_sea, orig_wind[on_sea], 'o', c='k', markersize=5) - graph_p_a.plot(on_sea, track.central_pressure[on_sea], + graph_p_a.plot(on_sea, track['central_pressure'][on_sea], 'o', c='k', markersize=5) graph_p_b.plot(on_sea, orig_pres[on_sea], 'o', c='k', markersize=5) @@ -1104,27 +1105,27 @@ def _check_apply_decay_hist_plot(hist_tracks): if sea_land_idx.size: for sea_land, land_sea in zip(sea_land_idx, land_sea_idx): scale_thresholds = climada.hazard.tc_tracks.SAFFIR_SIM_CAT - ss_scale_idx = np.where(track.max_sustained_wind[sea_land - 1].values + ss_scale_idx = np.where(track['max_sustained_wind'][sea_land - 1].values < scale_thresholds)[0][0] - on_land = np.arange(track.time.size)[sea_land:land_sea] + on_land = np.arange(track['time'].size)[sea_land:land_sea] - graph_hv.add_curve(on_land, track.max_sustained_wind[on_land], + graph_hv.add_curve(on_land, track['max_sustained_wind'][on_land], 'o', c=climada.hazard.tc_tracks.CAT_COLORS[ss_scale_idx]) - graph_hp.add_curve(on_land, track.central_pressure[on_land], + graph_hp.add_curve(on_land, track['central_pressure'][on_land], 'o', c=climada.hazard.tc_tracks.CAT_COLORS[ss_scale_idx]) - graph_hpd_a.plot(track.dist_since_lf[on_land], - track.central_pressure[on_land] - / track.central_pressure[sea_land - 1].values, + graph_hpd_a.plot(track['dist_since_lf'][on_land], + track['central_pressure'][on_land] + / track['central_pressure'][sea_land - 1].values, 'o', c=climada.hazard.tc_tracks.CAT_COLORS[ss_scale_idx]) - graph_hped_a.plot(track.dist_since_lf[on_land], - track.environmental_pressure[on_land] - - track.central_pressure[on_land], + graph_hped_a.plot(track['dist_since_lf'][on_land], + track['environmental_pressure'][on_land] - + track['central_pressure'][on_land], 'o', c=climada.hazard.tc_tracks.CAT_COLORS[ss_scale_idx]) - on_sea = np.arange(track.time.size)[~track.on_land] - graph_hp.plot(on_sea, track.central_pressure[on_sea], + on_sea = np.arange(track['time'].size)[~track.on_land] + graph_hp.plot(on_sea, track['central_pressure'][on_sea], 'o', c='k', markersize=5) - graph_hv.plot(on_sea, track.max_sustained_wind[on_sea], + graph_hv.plot(on_sea, track['max_sustained_wind'][on_sea], 'o', c='k', markersize=5) return graph_hv, graph_hp, graph_hpd_a, graph_hped_a diff --git a/climada/hazard/test/test_tc_tracks.py b/climada/hazard/test/test_tc_tracks.py index 20cdb0318e..75daa58c74 100644 --- a/climada/hazard/test/test_tc_tracks.py +++ b/climada/hazard/test/test_tc_tracks.py @@ -76,9 +76,9 @@ def test_penv_rmax_penv_pass(self): penv_ref[26:36] = [1011, 1012, 1013, 1014, 1015, 1014, 1014, 1014, 1014, 1012] self.assertTrue(np.allclose( - tc_track.get_track().environmental_pressure.values, penv_ref)) + tc_track.get_track()['environmental_pressure'].values, penv_ref)) self.assertTrue(np.allclose( - tc_track.get_track().radius_max_wind.values, np.zeros(97))) + tc_track.get_track()['radius_max_wind'].values, np.zeros(97))) def test_ibtracs_raw_pass(self): """Read a tropical cyclone.""" @@ -86,62 +86,62 @@ def test_ibtracs_raw_pass(self): tc_track = tc.TCTracks.from_ibtracs_netcdf(storm_id='2017242N16333') track_ds = tc_track.get_track() self.assertEqual(len(tc_track.data), 1) - self.assertEqual(track_ds.time.dt.year.values[0], 2017) - self.assertEqual(track_ds.time.dt.month.values[0], 8) - self.assertEqual(track_ds.time.dt.day.values[0], 30) - self.assertEqual(track_ds.time.dt.hour.values[0], 0) - self.assertAlmostEqual(track_ds.lat.values[0], 16.1, places=5) - self.assertAlmostEqual(track_ds.lon.values[0], -26.9, places=5) - self.assertAlmostEqual(track_ds.max_sustained_wind.values[0], 30) - self.assertAlmostEqual(track_ds.central_pressure.values[0], 1008) - self.assertAlmostEqual(track_ds.environmental_pressure.values[0], 1012) - self.assertAlmostEqual(track_ds.radius_max_wind.values[0], 60) - self.assertEqual(track_ds.time.size, 123) - - self.assertAlmostEqual(track_ds.lat.values[-1], 36.8, places=5) - self.assertAlmostEqual(track_ds.lon.values[-1], -90.1, places=4) - self.assertAlmostEqual(track_ds.central_pressure.values[-1], 1005) - self.assertAlmostEqual(track_ds.max_sustained_wind.values[-1], 15) - self.assertAlmostEqual(track_ds.environmental_pressure.values[-1], 1008) - self.assertAlmostEqual(track_ds.radius_max_wind.values[-1], 60) - - self.assertFalse(np.isnan(track_ds.radius_max_wind.values).any()) - self.assertFalse(np.isnan(track_ds.environmental_pressure.values).any()) - self.assertFalse(np.isnan(track_ds.max_sustained_wind.values).any()) - self.assertFalse(np.isnan(track_ds.central_pressure.values).any()) - self.assertFalse(np.isnan(track_ds.lat.values).any()) - self.assertFalse(np.isnan(track_ds.lon.values).any()) - - np.testing.assert_array_equal(track_ds.basin, 'NA') - self.assertEqual(track_ds.max_sustained_wind_unit, 'kn') - self.assertEqual(track_ds.central_pressure_unit, 'mb') - self.assertEqual(track_ds.sid, '2017242N16333') - self.assertEqual(track_ds.name, 'IRMA') - self.assertEqual(track_ds.orig_event_flag, True) - self.assertEqual(track_ds.data_provider, + self.assertEqual(track_ds['time'].dt.year.values[0], 2017) + self.assertEqual(track_ds['time'].dt.month.values[0], 8) + self.assertEqual(track_ds['time'].dt.day.values[0], 30) + self.assertEqual(track_ds['time'].dt.hour.values[0], 0) + self.assertAlmostEqual(track_ds['lat'].values[0], 16.1, places=5) + self.assertAlmostEqual(track_ds['lon'].values[0], -26.9, places=5) + self.assertAlmostEqual(track_ds['max_sustained_wind'].values[0], 30) + self.assertAlmostEqual(track_ds['central_pressure'].values[0], 1008) + self.assertAlmostEqual(track_ds['environmental_pressure'].values[0], 1012) + self.assertAlmostEqual(track_ds['radius_max_wind'].values[0], 60) + self.assertEqual(track_ds['time'].size, 123) + + self.assertAlmostEqual(track_ds['lat'].values[-1], 36.8, places=5) + self.assertAlmostEqual(track_ds['lon'].values[-1], -90.1, places=4) + self.assertAlmostEqual(track_ds['central_pressure'].values[-1], 1005) + self.assertAlmostEqual(track_ds['max_sustained_wind'].values[-1], 15) + self.assertAlmostEqual(track_ds['environmental_pressure'].values[-1], 1008) + self.assertAlmostEqual(track_ds['radius_max_wind'].values[-1], 60) + + self.assertFalse(np.isnan(track_ds['radius_max_wind'].values).any()) + self.assertFalse(np.isnan(track_ds['environmental_pressure'].values).any()) + self.assertFalse(np.isnan(track_ds['max_sustained_wind'].values).any()) + self.assertFalse(np.isnan(track_ds['central_pressure'].values).any()) + self.assertFalse(np.isnan(track_ds['lat'].values).any()) + self.assertFalse(np.isnan(track_ds['lon'].values).any()) + + np.testing.assert_array_equal(track_ds['basin'], 'NA') + self.assertEqual(track_ds.attrs['max_sustained_wind_unit'], 'kn') + self.assertEqual(track_ds.attrs['central_pressure_unit'], 'mb') + self.assertEqual(track_ds.attrs['sid'], '2017242N16333') + self.assertEqual(track_ds.attrs['name'], 'IRMA') + self.assertEqual(track_ds.attrs['orig_event_flag'], True) + self.assertEqual(track_ds.attrs['data_provider'], 'ibtracs_mixed:lat(official_3h),lon(official_3h),wind(official_3h),' 'pres(official_3h),rmw(official_3h),poci(official_3h),roci(official_3h)') - self.assertEqual(track_ds.category, 5) + self.assertEqual(track_ds.attrs['category'], 5) def test_ibtracs_with_provider(self): """Read a tropical cyclone with and without explicit provider.""" storm_id = '2012152N12130' tc_track = tc.TCTracks.from_ibtracs_netcdf(storm_id=storm_id, provider='usa') track_ds = tc_track.get_track() - self.assertEqual(track_ds.time.size, 51) - self.assertEqual(track_ds.data_provider, 'ibtracs_usa') - self.assertAlmostEqual(track_ds.lat.values[50], 34.3, places=5) - self.assertAlmostEqual(track_ds.central_pressure.values[50], 989, places=5) - self.assertAlmostEqual(track_ds.radius_max_wind.values[46], 20, places=5) + self.assertEqual(track_ds['time'].size, 51) + self.assertEqual(track_ds.attrs['data_provider'], 'ibtracs_usa') + self.assertAlmostEqual(track_ds['lat'].values[50], 34.3, places=5) + self.assertAlmostEqual(track_ds['central_pressure'].values[50], 989, places=5) + self.assertAlmostEqual(track_ds['radius_max_wind'].values[46], 20, places=5) tc_track = tc.TCTracks.from_ibtracs_netcdf(storm_id=storm_id) track_ds = tc_track.get_track() - self.assertEqual(track_ds.time.size, 35) - self.assertEqual(track_ds.data_provider, + self.assertEqual(track_ds['time'].size, 35) + self.assertEqual(track_ds.attrs['data_provider'], 'ibtracs_mixed:lat(official_3h),lon(official_3h),wind(official_3h),' 'pres(official_3h),rmw(usa),poci(usa),roci(usa)') - self.assertAlmostEqual(track_ds.lat.values[-1], 31.40, places=5) - self.assertAlmostEqual(track_ds.central_pressure.values[-1], 980, places=5) + self.assertAlmostEqual(track_ds['lat'].values[-1], 31.40, places=5) + self.assertAlmostEqual(track_ds['central_pressure'].values[-1], 980, places=5) def test_ibtracs_antimeridian(self): """Read a track that crosses the antimeridian and make sure that lon is consistent""" @@ -152,7 +152,7 @@ def test_ibtracs_antimeridian(self): tc_track = tc.TCTracks.from_ibtracs_netcdf(storm_id=storm_id, provider=['official_3h'], estimate_missing=True) track_ds = tc_track.get_track() - np.testing.assert_array_less(0, track_ds.lon) + np.testing.assert_array_less(0, track_ds['lon']) def test_ibtracs_estimate_missing(self): """Read a tropical cyclone and estimate missing values.""" @@ -161,20 +161,20 @@ def test_ibtracs_estimate_missing(self): tc_track = tc.TCTracks.from_ibtracs_netcdf(storm_id=storm_id, estimate_missing=True) track_ds = tc_track.get_track() # less time steps are discarded, leading to a larger total size - self.assertEqual(track_ds.time.size, 99) - self.assertEqual(track_ds.data_provider, + self.assertEqual(track_ds['time'].size, 99) + self.assertEqual(track_ds.attrs['data_provider'], 'ibtracs_mixed:lat(official_3h),lon(official_3h),wind(official_3h),' 'pres(official_3h),rmw(usa),poci(usa),roci(usa)') - self.assertAlmostEqual(track_ds.lat.values[44], 33.30, places=5) - self.assertAlmostEqual(track_ds.central_pressure.values[44], 976, places=5) - self.assertAlmostEqual(track_ds.central_pressure.values[42], 980, places=5) + self.assertAlmostEqual(track_ds['lat'].values[44], 33.30, places=5) + self.assertAlmostEqual(track_ds['central_pressure'].values[44], 976, places=5) + self.assertAlmostEqual(track_ds['central_pressure'].values[42], 980, places=5) # the wind speed at position 44 is missing in the original data - self.assertAlmostEqual(track_ds.max_sustained_wind.values[44], 58, places=0) - self.assertAlmostEqual(track_ds.radius_oci.values[40], 160, places=0) + self.assertAlmostEqual(track_ds['max_sustained_wind'].values[44], 58, places=0) + self.assertAlmostEqual(track_ds['radius_oci'].values[40], 160, places=0) # after position 42, ROCI is missing in the original data - self.assertAlmostEqual(track_ds.radius_oci.values[42], 200, places=-1) - self.assertAlmostEqual(track_ds.radius_oci.values[85], 165, places=-1) - self.assertAlmostEqual(track_ds.radius_oci.values[95], 155, places=-1) + self.assertAlmostEqual(track_ds['radius_oci'].values[42], 200, places=-1) + self.assertAlmostEqual(track_ds['radius_oci'].values[85], 165, places=-1) + self.assertAlmostEqual(track_ds['radius_oci'].values[95], 155, places=-1) def test_ibtracs_official(self): """Read a tropical cyclone, only officially reported values.""" @@ -183,11 +183,11 @@ def test_ibtracs_official(self): tc_track = tc.TCTracks.from_ibtracs_netcdf( storm_id=storm_id, interpolate_missing=False, provider='official') track_ds = tc_track.get_track() - self.assertEqual(track_ds.time.size, 21) - self.assertEqual(track_ds.data_provider, 'ibtracs_official') - self.assertAlmostEqual(track_ds.lon.values[19], 137.6, places=4) - self.assertAlmostEqual(track_ds.central_pressure.values[19], 980, places=5) - np.testing.assert_array_equal(track_ds.radius_max_wind.values, 0) + self.assertEqual(track_ds['time'].size, 21) + self.assertEqual(track_ds.attrs['data_provider'], 'ibtracs_official') + self.assertAlmostEqual(track_ds['lon'].values[19], 137.6, places=4) + self.assertAlmostEqual(track_ds['central_pressure'].values[19], 980, places=5) + np.testing.assert_array_equal(track_ds['radius_max_wind'].values, 0) def test_ibtracs_scale_wind(self): """Read a tropical cyclone and scale wind speed according to agency.""" @@ -195,11 +195,11 @@ def test_ibtracs_scale_wind(self): tc_track = tc.TCTracks.from_ibtracs_netcdf(storm_id=storm_id, rescale_windspeeds=True) track_ds = tc_track.get_track() - self.assertAlmostEqual(track_ds.max_sustained_wind.values[34], (55 - 23.3) / 0.6, places=5) + self.assertAlmostEqual(track_ds['max_sustained_wind'].values[34], (55 - 23.3) / 0.6, places=5) tc_track = tc.TCTracks.from_ibtracs_netcdf(storm_id=storm_id, rescale_windspeeds=False) track_ds = tc_track.get_track() - self.assertAlmostEqual(track_ds.max_sustained_wind.values[34], 55, places=5) + self.assertAlmostEqual(track_ds['max_sustained_wind'].values[34], 55, places=5) def test_ibtracs_interpolate_missing(self): """Read a tropical cyclone with and without interpolating missing values.""" @@ -208,15 +208,15 @@ def test_ibtracs_interpolate_missing(self): tc_track = tc.TCTracks.from_ibtracs_netcdf(storm_id=storm_id, interpolate_missing=False) track_ds = tc_track.get_track() self.assertEqual(track_ds.time.size, 50) - self.assertAlmostEqual(track_ds.central_pressure.values[30], 992, places=5) - self.assertAlmostEqual(track_ds.central_pressure.values[31], 1006, places=5) + self.assertAlmostEqual(track_ds['central_pressure'].values[30], 992, places=5) + self.assertAlmostEqual(track_ds['central_pressure'].values[31], 1006, places=5) tc_track = tc.TCTracks.from_ibtracs_netcdf(storm_id=storm_id, interpolate_missing=True) track_ds = tc_track.get_track() - self.assertEqual(track_ds.time.size, 65) - self.assertAlmostEqual(track_ds.central_pressure.values[30], 992, places=5) - self.assertAlmostEqual(track_ds.central_pressure.values[38], 999, places=5) - self.assertAlmostEqual(track_ds.central_pressure.values[46], 1006, places=5) + self.assertEqual(track_ds['time'].size, 65) + self.assertAlmostEqual(track_ds['central_pressure'].values[30], 992, places=5) + self.assertAlmostEqual(track_ds['central_pressure'].values[38], 999, places=5) + self.assertAlmostEqual(track_ds['central_pressure'].values[46], 1006, places=5) def test_ibtracs_range(self): """Read several TCs.""" @@ -239,9 +239,9 @@ def test_ibtracs_correct_pass(self): """Check estimate_missing option""" tc_try = tc.TCTracks.from_ibtracs_netcdf( provider='usa', storm_id='1982267N25289', estimate_missing=True) - self.assertAlmostEqual(tc_try.data[0].central_pressure.values[0], 1013, places=0) - self.assertAlmostEqual(tc_try.data[0].central_pressure.values[5], 1008, places=0) - self.assertAlmostEqual(tc_try.data[0].central_pressure.values[-1], 1012, places=0) + self.assertAlmostEqual(tc_try.data[0]['central_pressure'].values[0], 1013, places=0) + self.assertAlmostEqual(tc_try.data[0]['central_pressure'].values[5], 1008, places=0) + self.assertAlmostEqual(tc_try.data[0]['central_pressure'].values[-1], 1012, places=0) def test_ibtracs_discard_single_points(self): """Check discard_single_points option""" @@ -249,7 +249,7 @@ def test_ibtracs_discard_single_points(self): for year in range(1863, 1981): tc_track_singlept = tc.TCTracks.from_ibtracs_netcdf( provider='usa', year_range=(year,year), discard_single_points=False) - n_singlepts = np.sum([x.time.size == 1 for x in tc_track_singlept.data]) + n_singlepts = np.sum([x['time'].size == 1 for x in tc_track_singlept.data]) if n_singlepts > 0: tc_track = tc.TCTracks.from_ibtracs_netcdf(provider='usa', year_range=(year,year)) if tc_track.size == tc_track_singlept.size - n_singlepts: @@ -316,8 +316,8 @@ def test_read_legacy_netcdf(self): anti_track = tc.TCTracks.from_netcdf(TEST_TRACKS_ANTIMERIDIAN) for tr in anti_track.data: - self.assertEqual(tr.basin.shape, tr.time.shape) - np.testing.assert_array_equal(tr.basin, "SP") + self.assertEqual(tr['basin'].shape, tr['time'].shape) + np.testing.assert_array_equal(tr['basin'], "SP") def test_hdf5_io(self): """Test writing and reading hdf5 TCTracks instances""" @@ -348,69 +348,69 @@ def test_hdf5_io(self): def test_from_processed_ibtracs_csv(self): tc_track = tc.TCTracks.from_processed_ibtracs_csv(TEST_TRACK) - self.assertEqual(tc_track.data[0].time.size, 38) - self.assertEqual(tc_track.data[0].lon[11], -39.60) - self.assertEqual(tc_track.data[0].lat[23], 14.10) - self.assertEqual(tc_track.data[0].time_step[7], 6) - self.assertEqual(np.max(tc_track.data[0].radius_max_wind), 0) - self.assertEqual(np.min(tc_track.data[0].radius_max_wind), 0) - self.assertEqual(tc_track.data[0].max_sustained_wind[21], 55) - self.assertAlmostEqual(tc_track.data[0].central_pressure.values[29], 976, places=0) - self.assertEqual(np.max(tc_track.data[0].environmental_pressure), 1010) - self.assertEqual(np.min(tc_track.data[0].environmental_pressure), 1010) - self.assertEqual(tc_track.data[0].time.dt.year[13], 1951) - self.assertEqual(tc_track.data[0].time.dt.month[26], 9) - self.assertEqual(tc_track.data[0].time.dt.day[7], 29) - self.assertEqual(tc_track.data[0].max_sustained_wind_unit, 'kn') - self.assertEqual(tc_track.data[0].central_pressure_unit, 'mb') - self.assertEqual(tc_track.data[0].orig_event_flag, 1) - self.assertEqual(tc_track.data[0].name, '1951239N12334') - self.assertEqual(tc_track.data[0].sid, '1951239N12334') - self.assertEqual(tc_track.data[0].id_no, 1951239012334) - self.assertEqual(tc_track.data[0].data_provider, 'hurdat_atl') - np.testing.assert_array_equal(tc_track.data[0].basin, 'NA') - self.assertEqual(tc_track.data[0].id_no, 1951239012334) - self.assertEqual(tc_track.data[0].category, 1) + self.assertEqual(tc_track.data[0]['time'].size, 38) + self.assertEqual(tc_track.data[0]['lon'][11], -39.60) + self.assertEqual(tc_track.data[0]['lat'][23], 14.10) + self.assertEqual(tc_track.data[0]['time_step'][7], 6) + self.assertEqual(np.max(tc_track.data[0]['radius_max_wind']), 0) + self.assertEqual(np.min(tc_track.data[0]['radius_max_wind']), 0) + self.assertEqual(tc_track.data[0]['max_sustained_wind'][21], 55) + self.assertAlmostEqual(tc_track.data[0]['central_pressure'].values[29], 976, places=0) + self.assertEqual(np.max(tc_track.data[0]['environmental_pressure']), 1010) + self.assertEqual(np.min(tc_track.data[0]['environmental_pressure']), 1010) + self.assertEqual(tc_track.data[0]['time'].dt.year[13], 1951) + self.assertEqual(tc_track.data[0]['time'].dt.month[26], 9) + self.assertEqual(tc_track.data[0]['time'].dt.day[7], 29) + self.assertEqual(tc_track.data[0].attrs['max_sustained_wind_unit'], 'kn') + self.assertEqual(tc_track.data[0].attrs['central_pressure_unit'], 'mb') + self.assertEqual(tc_track.data[0].attrs['orig_event_flag'], 1) + self.assertEqual(tc_track.data[0].attrs['name'], '1951239N12334') + self.assertEqual(tc_track.data[0].attrs['sid'], '1951239N12334') + self.assertEqual(tc_track.data[0].attrs['id_no'], 1951239012334) + self.assertEqual(tc_track.data[0].attrs['data_provider'], 'hurdat_atl') + np.testing.assert_array_equal(tc_track.data[0]['basin'], 'NA') + self.assertEqual(tc_track.data[0].attrs['id_no'], 1951239012334) + self.assertEqual(tc_track.data[0].attrs['category'], 1) def test_from_simulations_emanuel(self): tc_track = tc.TCTracks.from_simulations_emanuel(TEST_TRACK_EMANUEL, hemisphere='N') self.assertEqual(len(tc_track.data), 4) - self.assertEqual(tc_track.data[0].time.size, 93) - self.assertEqual(tc_track.data[0].lon[11], -115.57) - self.assertEqual(tc_track.data[0].lat[23], 10.758) - self.assertEqual(tc_track.data[0].time_step[7], 2.0) - self.assertEqual(tc_track.data[0].time_step.dtype, float) - self.assertAlmostEqual(tc_track.data[0].radius_max_wind[15], 44.27645788336934) - self.assertEqual(tc_track.data[0].max_sustained_wind[21], 27.1) - self.assertEqual(tc_track.data[0].central_pressure[29], 995.31) - self.assertTrue(np.all(tc_track.data[0].environmental_pressure == 1010)) - self.assertTrue(np.all(tc_track.data[0].time.dt.year == 1950)) - self.assertEqual(tc_track.data[0].time.dt.month[26], 10) - self.assertEqual(tc_track.data[0].time.dt.day[7], 26) - self.assertEqual(tc_track.data[0].max_sustained_wind_unit, 'kn') - self.assertEqual(tc_track.data[0].central_pressure_unit, 'mb') - self.assertEqual(tc_track.data[0].sid, '1') - self.assertEqual(tc_track.data[0].name, '1') - self.assertEqual(tc_track.data[0].basin.dtype, ' 0)) def test_category_pass(self): @@ -876,8 +876,8 @@ def test_estimate_rmw_pass(self): tc_track = tc.TCTracks.from_processed_ibtracs_csv(TEST_TRACK) tc_track.equal_timestep() rad_max_wind = tc.estimate_rmw( - tc_track.data[0].radius_max_wind.values, - tc_track.data[0].central_pressure.values) * NM_TO_KM + tc_track.data[0]['radius_max_wind'].values, + tc_track.data[0]['central_pressure'].values) * NM_TO_KM self.assertAlmostEqual(rad_max_wind[0], 87, places=0) self.assertAlmostEqual(rad_max_wind[10], 87, places=0) @@ -900,7 +900,7 @@ def test_tracks_in_exp_pass(self): # Define exposure from geopandas world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres')) exp_world = Exposures(world) - exp = Exposures(exp_world.gdf[exp_world.gdf.name=='Cuba']) + exp = Exposures(exp_world.gdf[exp_world.gdf['name']=='Cuba']) # Compute tracks in exp tracks_in_exp = tc_track.tracks_in_exp(exp, buffer=1.0) diff --git a/climada/hazard/test/test_tc_tracks_synth.py b/climada/hazard/test/test_tc_tracks_synth.py index 3a2c32ed2a..6d170cf70b 100644 --- a/climada/hazard/test/test_tc_tracks_synth.py +++ b/climada/hazard/test/test_tc_tracks_synth.py @@ -52,13 +52,13 @@ def test_apply_decay_no_landfall_pass(self): tc_ref = tc_track.data[0].copy() tc_synth._apply_land_decay(tc_track.data, dict(), dict(), land_geom) - self.assertTrue(np.allclose(tc_track.data[0].max_sustained_wind.values, - tc_ref.max_sustained_wind.values)) - self.assertTrue(np.allclose(tc_track.data[0].central_pressure.values, - tc_ref.central_pressure.values)) - self.assertTrue(np.allclose(tc_track.data[0].environmental_pressure.values, - tc_ref.environmental_pressure.values)) - self.assertTrue(np.all(np.isnan(tc_track.data[0].dist_since_lf.values))) + self.assertTrue(np.allclose(tc_track.data[0]['max_sustained_wind'].values, + tc_ref['max_sustained_wind'].values)) + self.assertTrue(np.allclose(tc_track.data[0]['central_pressure'].values, + tc_ref['central_pressure'].values)) + self.assertTrue(np.allclose(tc_track.data[0]['environmental_pressure'].values, + tc_ref['environmental_pressure'].values)) + self.assertTrue(np.all(np.isnan(tc_track.data[0]['dist_since_lf'].values))) def test_apply_decay_pass(self): """Test _apply_land_decay against MATLAB reference.""" @@ -110,7 +110,7 @@ def test_apply_decay_pass(self): 1.00818354609, 1.00941850023, 1.00986192053, 1.00998400565 ]) * 1e3 - self.assertTrue(np.allclose(p_ref, tc_track.data[0].central_pressure.values)) + self.assertTrue(np.allclose(p_ref, tc_track.data[0]['central_pressure'].values)) v_ref = np.array([ 0.250000000000000, 0.300000000000000, 0.300000000000000, @@ -130,11 +130,11 @@ def test_apply_decay_pass(self): 0.1302099557, 0.0645385918, 0.0225325851 ]) * 1e2 - self.assertTrue(np.allclose(v_ref, tc_track.data[0].max_sustained_wind.values)) + self.assertTrue(np.allclose(v_ref, tc_track.data[0]['max_sustained_wind'].values)) - cat_ref = tc.set_category(tc_track.data[0].max_sustained_wind.values, - tc_track.data[0].max_sustained_wind_unit) - self.assertEqual(cat_ref, tc_track.data[0].category) + cat_ref = tc.set_category(tc_track.data[0]['max_sustained_wind'].values, + tc_track.data[0].attrs['max_sustained_wind_unit']) + self.assertEqual(cat_ref, tc_track.data[0].attrs['category']) def test_func_decay_p_pass(self): """Test decay function for pressure with its inverse.""" @@ -169,9 +169,9 @@ def test_decay_ps_value(self): p_landfall = 100 res = tc_synth._calc_decay_ps_value(tr_ds, p_landfall, on_land_idx, s_rel=True) - self.assertEqual(res, float(tr_ds.environmental_pressure[on_land_idx] / p_landfall)) + self.assertEqual(res, float(tr_ds['environmental_pressure'][on_land_idx] / p_landfall)) res = tc_synth._calc_decay_ps_value(tr_ds, p_landfall, on_land_idx, s_rel=False) - self.assertEqual(res, float(tr_ds.central_pressure[on_land_idx] / p_landfall)) + self.assertEqual(res, float(tr_ds['central_pressure'][on_land_idx] / p_landfall)) def test_calc_decay_no_landfall_pass(self): """Test _calc_land_decay with no historical tracks with landfall""" @@ -353,7 +353,7 @@ def test_wrong_decay_pass(self): extent=extent, resolution=10 ) track_res = tc_synth._apply_decay_coeffs(track_gen, v_rel, p_rel, land_geom, True) - self.assertTrue(np.array_equal(cp_ref, track_res.central_pressure[9:11])) + self.assertTrue(np.array_equal(cp_ref, track_res['central_pressure'][9:11])) def test_decay_end_ocean(self): """Test decay is applied after landfall if the track ends over the ocean""" @@ -382,28 +382,28 @@ def test_decay_end_ocean(self): lf_idx = tc._get_landfall_idx(track) last_lf_idx = lf_idx[-1][1] # only suitable if track ends over the ocean - self.assertTrue(last_lf_idx < track.time.size-2, + self.assertTrue(last_lf_idx < track['time'].size-2, 'This test should be re-written, data not suitable') # check pressure and wind values - p_hist_end = track_hist.central_pressure.values[last_lf_idx:] - p_synth_end = track.central_pressure.values[last_lf_idx:] + p_hist_end = track_hist['central_pressure'].values[last_lf_idx:] + p_synth_end = track['central_pressure'].values[last_lf_idx:] self.assertTrue(np.all(p_synth_end > p_hist_end)) - v_hist_end = track_hist.max_sustained_wind.values[last_lf_idx:] - v_synth_end = track.max_sustained_wind.values[last_lf_idx:] + v_hist_end = track_hist['max_sustained_wind'].values[last_lf_idx:] + v_synth_end = track['max_sustained_wind'].values[last_lf_idx:] self.assertTrue(np.all(v_synth_end < v_hist_end)) # Part 2: is landfall applied in all landfalls? - p_hist_lf = np.concatenate([track_hist.central_pressure.values[lfs:lfe] + p_hist_lf = np.concatenate([track_hist['central_pressure'].values[lfs:lfe] for lfs,lfe in zip(*lf_idx)]) - p_synth_lf = np.concatenate([track.central_pressure.values[lfs:lfe] + p_synth_lf = np.concatenate([track['central_pressure'].values[lfs:lfe] for lfs,lfe in zip(*lf_idx)]) - v_hist_lf = np.concatenate([track_hist.max_sustained_wind.values[lfs:lfe] + v_hist_lf = np.concatenate([track_hist['max_sustained_wind'].values[lfs:lfe] for lfs,lfe in zip(*lf_idx)]) - v_synth_lf = np.concatenate([track.max_sustained_wind.values[lfs:lfe] + v_synth_lf = np.concatenate([track['max_sustained_wind'].values[lfs:lfe] for lfs,lfe in zip(*lf_idx)]) self.assertTrue(np.all(p_synth_lf > p_hist_lf)) self.assertTrue(np.all(v_synth_lf < v_hist_lf)) - self.assertTrue(np.all(track.central_pressure.values <= track.environmental_pressure.values)) + self.assertTrue(np.all(track['central_pressure'].values <= track['environmental_pressure'].values)) def test_decay_penv_gt_pcen(self): """Test decay is applied if penv at end of landfall < pcen just before landfall""" @@ -433,39 +433,39 @@ def test_decay_penv_gt_pcen(self): start_lf_idx, end_lf_idx = lf_idx[0][0], lf_idx[1][0] # check pressure and wind values - p_hist_end = track_hist.central_pressure.values[end_lf_idx:] - p_synth_end = track.central_pressure.values[end_lf_idx:] + p_hist_end = track_hist['central_pressure'].values[end_lf_idx:] + p_synth_end = track['central_pressure'].values[end_lf_idx:] self.assertTrue(np.all(p_synth_end > p_hist_end)) - v_hist_end = track_hist.max_sustained_wind.values[end_lf_idx:] - v_synth_end = track.max_sustained_wind.values[end_lf_idx:] + v_hist_end = track_hist['max_sustained_wind'].values[end_lf_idx:] + v_synth_end = track['max_sustained_wind'].values[end_lf_idx:] self.assertTrue(np.all(v_synth_end < v_hist_end)) # Part 2: is landfall applied in all landfalls? # central pressure - p_hist_lf = track_hist.central_pressure.values[start_lf_idx:end_lf_idx] - p_synth_lf = track.central_pressure.values[start_lf_idx:end_lf_idx] + p_hist_lf = track_hist['central_pressure'].values[start_lf_idx:end_lf_idx] + p_synth_lf = track['central_pressure'].values[start_lf_idx:end_lf_idx] # central pressure should be higher in synth than hist; unless it was set to p_env self.assertTrue(np.all( np.logical_or(p_synth_lf > p_hist_lf, - p_synth_lf == track.environmental_pressure.values[start_lf_idx:end_lf_idx]) + p_synth_lf == track['environmental_pressure'].values[start_lf_idx:end_lf_idx]) )) # but for this track is should be higher towards the end self.assertTrue(np.any(p_synth_lf > p_hist_lf)) self.assertTrue(np.all(p_synth_lf >= p_hist_lf)) # wind speed - v_hist_lf = track_hist.max_sustained_wind.values[start_lf_idx:end_lf_idx] - v_synth_lf = track.max_sustained_wind.values[start_lf_idx:end_lf_idx] + v_hist_lf = track_hist['max_sustained_wind'].values[start_lf_idx:end_lf_idx] + v_synth_lf = track['max_sustained_wind'].values[start_lf_idx:end_lf_idx] # wind should decrease over time for that landfall - v_before_lf = track_hist.max_sustained_wind.values[start_lf_idx-1] + v_before_lf = track_hist['max_sustained_wind'].values[start_lf_idx-1] self.assertTrue(np.all(v_synth_lf[1:] < v_before_lf)) # and wind speed should be lower in synth than hist at the end of and after this landfall self.assertTrue(np.all( - track.max_sustained_wind.values[end_lf_idx:] < track_hist.max_sustained_wind.values[end_lf_idx:] + track['max_sustained_wind'].values[end_lf_idx:] < track_hist['max_sustained_wind'].values[end_lf_idx:] )) # finally, central minus env pressure cannot increase during this landfall - p_env_lf = track.central_pressure.values[start_lf_idx:end_lf_idx] + p_env_lf = track['central_pressure'].values[start_lf_idx:end_lf_idx] self.assertTrue(np.all(np.diff(p_env_lf - p_synth_lf) <= 0)) class TestSynth(unittest.TestCase): @@ -505,35 +505,35 @@ def test_random_walk_ref_pass(self): self.assertEqual(len(tc_track.data), nb_synth_tracks + 1) - self.assertFalse(tc_track.data[1].orig_event_flag) - self.assertEqual(tc_track.data[1].name, '1951239N12334_gen1') - self.assertEqual(tc_track.data[1].id_no, 1.951239012334010e+12) - self.assertAlmostEqual(tc_track.data[1].lon[0].values, -25.0448138) - self.assertAlmostEqual(tc_track.data[1].lon[1].values, -25.74439739) - self.assertAlmostEqual(tc_track.data[1].lon[2].values, -26.54491644) - self.assertAlmostEqual(tc_track.data[1].lon[3].values, -27.73156829) - self.assertAlmostEqual(tc_track.data[1].lon[4].values, -28.63175987) - self.assertAlmostEqual(tc_track.data[1].lon[8].values, -34.05293373) - - self.assertAlmostEqual(tc_track.data[1].lat[0].values, 11.96825841) - self.assertAlmostEqual(tc_track.data[1].lat[4].values, 11.86769405) - self.assertAlmostEqual(tc_track.data[1].lat[5].values, 11.84378139) - self.assertAlmostEqual(tc_track.data[1].lat[6].values, 11.85957282) - self.assertAlmostEqual(tc_track.data[1].lat[7].values, 11.84555291) - self.assertAlmostEqual(tc_track.data[1].lat[8].values, 11.8065998) - - self.assertFalse(tc_track.data[2].orig_event_flag) - self.assertEqual(tc_track.data[2].name, '1951239N12334_gen2') - self.assertAlmostEqual(tc_track.data[2].id_no, 1.951239012334020e+12) - self.assertAlmostEqual(tc_track.data[2].lon[0].values, -25.47658461) - self.assertAlmostEqual(tc_track.data[2].lon[3].values, -28.08465841) - self.assertAlmostEqual(tc_track.data[2].lon[4].values, -28.85901852) - self.assertAlmostEqual(tc_track.data[2].lon[8].values, -33.62144837) - - self.assertAlmostEqual(tc_track.data[2].lat[0].values, 11.82886685) - self.assertAlmostEqual(tc_track.data[2].lat[6].values, 11.71068012) - self.assertAlmostEqual(tc_track.data[2].lat[7].values, 11.69832976) - self.assertAlmostEqual(tc_track.data[2].lat[8].values, 11.64145734) + self.assertFalse(tc_track.data[1].attrs['orig_event_flag']) + self.assertEqual(tc_track.data[1].attrs['name'], '1951239N12334_gen1') + self.assertEqual(tc_track.data[1].attrs['id_no'], 1.951239012334010e+12) + self.assertAlmostEqual(tc_track.data[1]['lon'][0].values, -25.0448138) + self.assertAlmostEqual(tc_track.data[1]['lon'][1].values, -25.74439739) + self.assertAlmostEqual(tc_track.data[1]['lon'][2].values, -26.54491644) + self.assertAlmostEqual(tc_track.data[1]['lon'][3].values, -27.73156829) + self.assertAlmostEqual(tc_track.data[1]['lon'][4].values, -28.63175987) + self.assertAlmostEqual(tc_track.data[1]['lon'][8].values, -34.05293373) + + self.assertAlmostEqual(tc_track.data[1]['lat'][0].values, 11.96825841) + self.assertAlmostEqual(tc_track.data[1]['lat'][4].values, 11.86769405) + self.assertAlmostEqual(tc_track.data[1]['lat'][5].values, 11.84378139) + self.assertAlmostEqual(tc_track.data[1]['lat'][6].values, 11.85957282) + self.assertAlmostEqual(tc_track.data[1]['lat'][7].values, 11.84555291) + self.assertAlmostEqual(tc_track.data[1]['lat'][8].values, 11.8065998) + + self.assertFalse(tc_track.data[2].attrs['orig_event_flag']) + self.assertEqual(tc_track.data[2].attrs['name'], '1951239N12334_gen2') + self.assertAlmostEqual(tc_track.data[2].attrs['id_no'], 1.951239012334020e+12) + self.assertAlmostEqual(tc_track.data[2]['lon'][0].values, -25.47658461) + self.assertAlmostEqual(tc_track.data[2]['lon'][3].values, -28.08465841) + self.assertAlmostEqual(tc_track.data[2]['lon'][4].values, -28.85901852) + self.assertAlmostEqual(tc_track.data[2]['lon'][8].values, -33.62144837) + + self.assertAlmostEqual(tc_track.data[2]['lat'][0].values, 11.82886685) + self.assertAlmostEqual(tc_track.data[2]['lat'][6].values, 11.71068012) + self.assertAlmostEqual(tc_track.data[2]['lat'][7].values, 11.69832976) + self.assertAlmostEqual(tc_track.data[2]['lat'][8].values, 11.64145734) def test_random_walk_decay_pass(self): """Test land decay is called from calc_perturbed_trajectories.""" @@ -573,8 +573,8 @@ def test_random_walk_identical_pass(self): max_shift_ini=0, max_dspeed_rel=0, max_ddirection=0, decay=False) orig_track = tc_track.data[0] for syn_track in tc_track.data[1:]: - np.testing.assert_allclose(orig_track.lon.values, syn_track.lon.values, atol=1e-4) - np.testing.assert_allclose(orig_track.lat.values, syn_track.lat.values, atol=1e-4) + np.testing.assert_allclose(orig_track['lon'].values, syn_track['lon'].values, atol=1e-4) + np.testing.assert_allclose(orig_track['lat'].values, syn_track['lat'].values, atol=1e-4) for varname in ["time", "time_step", "radius_max_wind", "max_sustained_wind", "central_pressure", "environmental_pressure"]: np.testing.assert_array_equal(orig_track[varname].values, @@ -586,7 +586,7 @@ def test_random_walk_single_point(self): tc_track = tc.TCTracks.from_ibtracs_netcdf(provider='usa', year_range=(year,year), discard_single_points=False) - singlept = np.where([x.time.size == 1 for x in tc_track.data])[0] + singlept = np.where([x['time'].size == 1 for x in tc_track.data])[0] found = len(singlept) > 0 if found: # found a case with a single-point track, keep max three tracks for efficiency diff --git a/climada/hazard/trop_cyclone/trop_cyclone.py b/climada/hazard/trop_cyclone/trop_cyclone.py index 6fc8347e97..43c1ed7822 100644 --- a/climada/hazard/trop_cyclone/trop_cyclone.py +++ b/climada/hazard/trop_cyclone/trop_cyclone.py @@ -290,7 +290,7 @@ def from_tracks( if 'dist_coast' not in centroids.gdf.columns: dist_coast = centroids.get_dist_coast() else: - dist_coast = centroids.gdf.dist_coast.values + dist_coast = centroids.gdf['dist_coast'].values [idx_centr_filter] = ( (dist_coast <= max_dist_inland_km * 1000) & (np.abs(centroids.lat) <= max_latitude) @@ -463,29 +463,29 @@ def video_intensity( if not track: raise ValueError(f'{track_name} not found in track data.') idx_plt = np.argwhere( - (track.lon.values < centroids.total_bounds[2] + 1) - & (centroids.total_bounds[0] - 1 < track.lon.values) - & (track.lat.values < centroids.total_bounds[3] + 1) - & (centroids.total_bounds[1] - 1 < track.lat.values) + (track['lon'].values < centroids.total_bounds[2] + 1) + & (centroids.total_bounds[0] - 1 < track['lon'].values) + & (track['lat'].values < centroids.total_bounds[3] + 1) + & (centroids.total_bounds[1] - 1 < track['lat'].values) ).reshape(-1) tc_list = [] tr_coord = {'lat': [], 'lon': []} for node in range(idx_plt.size - 2): tr_piece = track.sel( - time=slice(track.time.values[idx_plt[node]], - track.time.values[idx_plt[node + 2]])) + time=slice(track['time'].values[idx_plt[node]], + track['time'].values[idx_plt[node + 2]])) tr_piece.attrs['n_nodes'] = 2 # plot only one node tr_sel = TCTracks() tr_sel.append(tr_piece) - tr_coord['lat'].append(tr_sel.data[0].lat.values[:-1]) - tr_coord['lon'].append(tr_sel.data[0].lon.values[:-1]) + tr_coord['lat'].append(tr_sel.data[0]['lat'].values[:-1]) + tr_coord['lon'].append(tr_sel.data[0]['lon'].values[:-1]) tc_tmp = cls.from_tracks(tr_sel, centroids=centroids) tc_tmp.event_name = [ - track.name + ' ' + time.strftime( + track['name'] + ' ' + time.strftime( "%d %h %Y %H:%M", - time.gmtime(tr_sel.data[0].time[1].values.astype(int) + time.gmtime(tr_sel.data[0]['time'][1].values.astype(int) / 1000000000) ) ] @@ -525,8 +525,8 @@ def frequency_from_tracks(self, tracks: List): """ if not tracks: return - year_max = np.amax([t.time.dt.year.values.max() for t in tracks]) - year_min = np.amin([t.time.dt.year.values.min() for t in tracks]) + year_max = np.amax([t['time'].dt.year.values.max() for t in tracks]) + year_min = np.amin([t['time'].dt.year.values.min() for t in tracks]) year_delta = year_max - year_min + 1 num_orig = np.count_nonzero(self.orig) ens_size = (self.event_id.size / num_orig) if num_orig > 0 else 1 @@ -610,20 +610,20 @@ def from_single_track( new_haz.centroids = centroids new_haz.event_id = np.array([1]) new_haz.frequency = np.array([1]) - new_haz.event_name = [track.sid] + new_haz.event_name = [track.attrs['sid']] new_haz.fraction = sparse.csr_matrix(new_haz.intensity.shape) # store first day of track as date new_haz.date = np.array([ - dt.datetime(track.time.dt.year.values[0], - track.time.dt.month.values[0], - track.time.dt.day.values[0]).toordinal() + dt.datetime(track['time'].dt.year.values[0], + track['time'].dt.month.values[0], + track['time'].dt.day.values[0]).toordinal() ]) - new_haz.orig = np.array([track.orig_event_flag]) - new_haz.category = np.array([track.category]) + new_haz.orig = np.array([track.attrs['orig_event_flag']]) + new_haz.category = np.array([track.attrs['category']]) # users that pickle TCTracks objects might still have data with the legacy basin attribute, # so we have to deal with it here - new_haz.basin = [track.basin if isinstance(track.basin, str) - else str(track.basin.values[0])] + new_haz.basin = [track['basin'] if isinstance(track['basin'], str) + else str(track['basin'].values[0])] return new_haz def _apply_knutson_criterion( diff --git a/climada/test/test_api_client.py b/climada/test/test_api_client.py index 4e0994acef..3b60a016ea 100644 --- a/climada/test/test_api_client.py +++ b/climada/test/test_api_client.py @@ -148,7 +148,7 @@ def test_get_exposures(self): version='v1', dump_dir=DATA_DIR) self.assertEqual(len(exposures.gdf), 5782) - self.assertEqual(np.unique(exposures.gdf.region_id), 40) + self.assertEqual(np.unique(exposures.gdf['region_id']), 40) self.assertEqual(exposures.description, "LitPop Exposure for ['AUT'] at 150 as, year: 2018, financial mode: pop, exp: [0, 1], admin1_calc: False") @@ -202,7 +202,7 @@ def test_get_litpop(self): client = Client() litpop = client.get_litpop(country='LUX', version='v1', dump_dir=DATA_DIR) self.assertEqual(len(litpop.gdf), 188) - self.assertEqual(np.unique(litpop.gdf.region_id), 442) + self.assertEqual(np.unique(litpop.gdf['region_id']), 442) self.assertEqual(litpop.description, "LitPop Exposure for ['LUX'] at 150 as, year: 2018, financial mode: pc, exp: [1, 1], admin1_calc: False") @@ -212,7 +212,7 @@ def test_get_litpop_fail(self): client.get_litpop(['AUT', 'CHE']) self.assertIn(" can only query single countries. Download the data for multiple countries individually and concatenate ", str(cm.exception)) - + def test_get_centroids_plot(self): client = Client() client.get_centroids(country='COM').plot() diff --git a/climada/test/test_calibration.py b/climada/test/test_calibration.py index 0986580d48..72dcca3a46 100644 --- a/climada/test/test_calibration.py +++ b/climada/test/test_calibration.py @@ -51,7 +51,7 @@ def test_calib_instance(self): # get impact function from set imp_func = ent.impact_funcs.get_func(hazard.haz_type, - ent.exposures.gdf.impf_TC.median()) + ent.exposures.gdf['impf_TC'].median()) # Assign centroids to exposures ent.exposures.assign_centroids(hazard) diff --git a/climada/test/test_engine.py b/climada/test/test_engine.py index 215d94ba5b..ab078b29f4 100644 --- a/climada/test/test_engine.py +++ b/climada/test/test_engine.py @@ -66,7 +66,7 @@ def exp_dem(x_exp=1, exp=None): except HDF5ExtError: time.sleep(0.1) exp_tmp = exp.copy(deep=True) - exp_tmp.gdf.value *= x_exp + exp_tmp.gdf['value'] *= x_exp return exp_tmp @@ -152,8 +152,8 @@ def test_emdat_damage_yearlysum(self): ) self.assertEqual(36, df.size) - self.assertAlmostEqual(df.impact.max(), 15150000000.0) - self.assertAlmostEqual(df.impact_scaled.min(), 10939000.0) + self.assertAlmostEqual(df['impact'].max(), 15150000000.0) + self.assertAlmostEqual(df['impact_scaled'].min(), 10939000.0) self.assertEqual(df["year"][5], 2017) self.assertEqual(df["reference_year"].max(), 2000) self.assertIn("USA", list(df["ISO"])) diff --git a/climada/test/test_hazard.py b/climada/test/test_hazard.py index 6166e9ecd3..6ae8dbfb44 100644 --- a/climada/test/test_hazard.py +++ b/climada/test/test_hazard.py @@ -299,8 +299,8 @@ def test_ibtracs_with_basin(self): year_range=(1995, 1995), basin="SP", estimate_missing=True ) self.assertEqual(tc_track.size, 6) - self.assertEqual(tc_track.data[0].basin[0], "SP") - self.assertEqual(tc_track.data[5].basin[0], "SI") + self.assertEqual(tc_track.data[0]['basin'][0], "SP") + self.assertEqual(tc_track.data[5]['basin'][0], "SI") # genesis in NI tc_track = tc.TCTracks.from_ibtracs_netcdf( @@ -308,7 +308,7 @@ def test_ibtracs_with_basin(self): ) self.assertEqual(tc_track.size, 5) for tr in tc_track.data: - self.assertEqual(tr.basin[0], "NI") + self.assertEqual(tr['basin'][0], "NI") # genesis in EP, but crosses WP at some point tc_track = tc.TCTracks.from_ibtracs_netcdf( @@ -316,8 +316,8 @@ def test_ibtracs_with_basin(self): ) self.assertEqual(tc_track.size, 3) for tr in tc_track.data: - self.assertEqual(tr.basin[0], "EP") - self.assertIn("WP", tr.basin) + self.assertEqual(tr['basin'][0], "EP") + self.assertIn("WP", tr['basin']) def test_cutoff_tracks(self): tc_track = tc.TCTracks.from_ibtracs_netcdf(storm_id="1986226N30276") diff --git a/climada/test/test_litpop_integr.py b/climada/test/test_litpop_integr.py index 3699fca218..3a963d0df5 100644 --- a/climada/test/test_litpop_integr.py +++ b/climada/test/test_litpop_integr.py @@ -65,10 +65,10 @@ def test_switzerland300_pass(self): reference_year=2016) self.assertIn('LitPop: Init Exposure for country: CHE', cm.output[0]) - self.assertEqual(ent.gdf.region_id.min(), 756) - self.assertEqual(ent.gdf.region_id.max(), 756) + self.assertEqual(ent.gdf['region_id'].min(), 756) + self.assertEqual(ent.gdf['region_id'].max(), 756) # confirm that the total value is equal to GDP * (income_group+1): - self.assertAlmostEqual(ent.gdf.value.sum()/gdp('CHE', 2016)[1], + self.assertAlmostEqual(ent.gdf['value'].sum()/gdp('CHE', 2016)[1], (income_group('CHE', 2016)[1] + 1)) self.assertIn("LitPop Exposure for ['CHE'] at 300 as, year: 2016", ent.description) self.assertIn('income_group', ent.description) @@ -95,9 +95,9 @@ def test_switzerland30normPop_pass(self): fin_mode=fin_mode, reference_year=2015) # print(cm) self.assertIn('LitPop: Init Exposure for country: CHE', cm.output[0]) - self.assertEqual(ent.gdf.region_id.min(), 756) - self.assertEqual(ent.gdf.region_id.max(), 756) - self.assertEqual(ent.gdf.value.sum(), 1.0) + self.assertEqual(ent.gdf['region_id'].min(), 756) + self.assertEqual(ent.gdf['region_id'].max(), 756) + self.assertEqual(ent.gdf['value'].sum(), 1.0) self.assertEqual(ent.ref_year, 2015) def test_suriname30_nfw_pass(self): @@ -106,8 +106,8 @@ def test_suriname30_nfw_pass(self): fin_mode = 'nfw' ent = lp.LitPop.from_countries(country_name, reference_year=2016, fin_mode=fin_mode) - self.assertEqual(ent.gdf.region_id.min(), 740) - self.assertEqual(ent.gdf.region_id.max(), 740) + self.assertEqual(ent.gdf['region_id'].min(), 740) + self.assertEqual(ent.gdf['region_id'].max(), 740) self.assertEqual(ent.ref_year, 2016) def test_switzerland300_admin1_pc2016_pass(self): @@ -122,7 +122,7 @@ def test_switzerland300_admin1_pc2016_pass(self): reference_year=ref_year, fin_mode=fin_mode, admin1_calc=adm1) - self.assertAlmostEqual(np.around(ent.gdf.value.sum()*1e-9, 0), + self.assertAlmostEqual(np.around(ent.gdf['value'].sum()*1e-9, 0), np.around(comparison_total_val*1e-9, 0), places=0) self.assertEqual(ent.value_unit, 'USD') @@ -131,15 +131,15 @@ def test_from_shape_zurich_pass(self): Distributing an imaginary total value of 1000 USD""" total_value=1000 ent = lp.LitPop.from_shape(shape, total_value, res_arcsec=30, reference_year=2016) - self.assertEqual(ent.gdf.value.sum(), 1000.0) - self.assertEqual(ent.gdf.value.min(), 0.0) - self.assertEqual(ent.gdf.region_id.min(), 756) - self.assertEqual(ent.gdf.region_id.max(), 756) - self.assertAlmostEqual(ent.gdf.latitude.min(), 47.20416666666661) + self.assertEqual(ent.gdf['value'].sum(), 1000.0) + self.assertEqual(ent.gdf['value'].min(), 0.0) + self.assertEqual(ent.gdf['region_id'].min(), 756) + self.assertEqual(ent.gdf['region_id'].max(), 756) + self.assertAlmostEqual(ent.gdf['latitude'].min(), 47.20416666666661) # index and coord. of largest value: - self.assertEqual(ent.gdf.loc[ent.gdf.value == ent.gdf.value.max()].index[0], 482) - self.assertAlmostEqual(ent.gdf.loc[ent.gdf.value == ent.gdf.value.max()].latitude.values[0], 47.34583333333325) - self.assertAlmostEqual(ent.gdf.loc[ent.gdf.value == ent.gdf.value.max()].longitude.values[0], 8.529166666666658) + self.assertEqual(ent.gdf.loc[ent.gdf['value'] == ent.gdf['value'].max()].index[0], 482) + self.assertAlmostEqual(ent.gdf.loc[ent.gdf['value'] == ent.gdf['value'].max()]['latitude'].values[0], 47.34583333333325) + self.assertAlmostEqual(ent.gdf.loc[ent.gdf['value'] == ent.gdf['value'].max()]['longitude'].values[0], 8.529166666666658) def test_from_shape_and_countries_zurich_pass(self): """test initiating LitPop for custom shape (square around Zurich City) @@ -147,14 +147,14 @@ def test_from_shape_and_countries_zurich_pass(self): ent = lp.LitPop.from_shape_and_countries( shape, 'Switzerland', res_arcsec=30, reference_year=2016) - self.assertEqual(ent.gdf.value.min(), 0.0) - self.assertEqual(ent.gdf.region_id.min(), 756) - self.assertEqual(ent.gdf.region_id.max(), 756) - self.assertAlmostEqual(ent.gdf.latitude.min(), 47.20416666666661) + self.assertEqual(ent.gdf['value'].min(), 0.0) + self.assertEqual(ent.gdf['region_id'].min(), 756) + self.assertEqual(ent.gdf['region_id'].max(), 756) + self.assertAlmostEqual(ent.gdf['latitude'].min(), 47.20416666666661) # coord of largest value: - self.assertEqual(ent.gdf.loc[ent.gdf.value == ent.gdf.value.max()].index[0], 434) - self.assertAlmostEqual(ent.gdf.loc[ent.gdf.value == ent.gdf.value.max()].latitude.values[0], 47.34583333333325) - self.assertAlmostEqual(ent.gdf.loc[ent.gdf.value == ent.gdf.value.max()].longitude.values[0], 8.529166666666658) + self.assertEqual(ent.gdf.loc[ent.gdf['value'] == ent.gdf['value'].max()].index[0], 434) + self.assertAlmostEqual(ent.gdf.loc[ent.gdf['value'] == ent.gdf['value'].max()]['latitude'].values[0], 47.34583333333325) + self.assertAlmostEqual(ent.gdf.loc[ent.gdf['value'] == ent.gdf['value'].max()]['longitude'].values[0], 8.529166666666658) def test_Liechtenstein_15_lit_pass(self): """Create Nightlights entity for Liechtenstein 2016:""" @@ -162,10 +162,10 @@ def test_Liechtenstein_15_lit_pass(self): ref_year = 2016 ent = lp.LitPop.from_nightlight_intensity(country_name, reference_year=ref_year) - self.assertEqual(ent.gdf.value.sum(), 36469.0) - self.assertEqual(ent.gdf.region_id[1], 438) + self.assertEqual(ent.gdf['value'].sum(), 36469.0) + self.assertEqual(ent.gdf['region_id'][1], 438) self.assertEqual(ent.value_unit, '') - self.assertAlmostEqual(ent.gdf.latitude.max(), 47.260416666666664) + self.assertAlmostEqual(ent.gdf['latitude'].max(), 47.260416666666664) self.assertAlmostEqual(ent.meta['transform'][4], -15/3600) def test_Liechtenstein_30_pop_pass(self): @@ -174,10 +174,10 @@ def test_Liechtenstein_30_pop_pass(self): ref_year = 2015 ent = lp.LitPop.from_population(country_name, reference_year=ref_year) - self.assertEqual(ent.gdf.value.sum(), 30068.970703125) - self.assertEqual(ent.gdf.region_id[1], 438) + self.assertEqual(ent.gdf['value'].sum(), 30068.970703125) + self.assertEqual(ent.gdf['region_id'][1], 438) self.assertEqual(ent.value_unit, 'people') - self.assertAlmostEqual(ent.gdf.latitude.max(), 47.2541666666666) + self.assertAlmostEqual(ent.gdf['latitude'].max(), 47.2541666666666) self.assertAlmostEqual(ent.meta['transform'][0], 30/3600) def test_from_nightlight_intensity(self): @@ -247,8 +247,8 @@ def test_calc_admin1(self): 2016, lp.GPW_VERSION, SYSTEM_DIR) self.assertEqual(ent.gdf.shape[0], 699) - self.assertEqual(ent.gdf.region_id[88], 756) - self.assertAlmostEqual(ent.gdf.latitude.max(), 47.708333333333336) + self.assertEqual(ent.gdf['region_id'][88], 756) + self.assertAlmostEqual(ent.gdf['latitude'].max(), 47.708333333333336) # shape must be same as with admin1_calc = False, otherwise there # is a problem with handling of the admin1 shapes: ent_adm0 = lp.LitPop.from_countries(country, res_arcsec=resolution, fin_mode='pc', @@ -276,7 +276,7 @@ def test_brandenburg(self): admin1_shapes[idx], country, res_arcsec=reslution_arcsec, reference_year=2016) exp_bra = lp.LitPop.from_shape( admin1_shapes[idx], 1000, res_arcsec=reslution_arcsec, reference_year=2016) - self.assertAlmostEqual(exp_bra.gdf.value.sum(), 1000) + self.assertAlmostEqual(exp_bra.gdf['value'].sum(), 1000) # compare number of data points: self.assertEqual(exp_bra.gdf.shape[0], exp_bra2.gdf.shape[0]) self.assertEqual(exp_bra.gdf.shape[0], 3566) diff --git a/climada/util/api_client.py b/climada/util/api_client.py index df95935822..c6afca7a09 100644 --- a/climada/util/api_client.py +++ b/climada/util/api_client.py @@ -739,7 +739,7 @@ def purge_cache_db(local_path): def _multi_version(datasets): ddf = pd.DataFrame(datasets) gdf = ddf.groupby("name").agg({"version": "nunique"}) - return list(gdf[gdf.version > 1].index) + return list(gdf[gdf["version"] > 1].index) def get_hazard( self, @@ -1101,7 +1101,7 @@ def into_datasets_df(dataset_infos): """ dsdf = pd.DataFrame(dataset_infos) ppdf = pd.DataFrame([ds.properties for ds in dataset_infos]) - dtdf = pd.DataFrame([pd.Series(dt) for dt in dsdf.data_type]) + dtdf = pd.DataFrame([pd.Series(dt) for dt in dsdf["data_type"]]) return ( dtdf.loc[ diff --git a/climada/util/coordinates.py b/climada/util/coordinates.py index e32e649060..b26c1f8d06 100644 --- a/climada/util/coordinates.py +++ b/climada/util/coordinates.py @@ -1582,16 +1582,16 @@ def get_admin1_geometries(countries): for country in admin1_info: # fill admin 1 region names and codes to GDF for single country: gdf_tmp = gpd.GeoDataFrame(columns=gdf.columns) - gdf_tmp.admin1_name = [record['name'] for record in admin1_info[country]] - gdf_tmp.iso_3166_2 = [record['iso_3166_2'] for record in admin1_info[country]] + gdf_tmp['admin1_name'] = [record['name'] for record in admin1_info[country]] + gdf_tmp['iso_3166_2'] = [record['iso_3166_2'] for record in admin1_info[country]] # With this initiation of GeoSeries in a list comprehension, # the ability of geopandas to convert shapereader.Shape to (Multi)Polygon is exploited: geoseries = gpd.GeoSeries([gpd.GeoSeries(shape).values[0] for shape in admin1_shapes[country]]) gdf_tmp.geometry = list(geoseries) # fill columns with country identifiers (admin 0): - gdf_tmp.iso_3n = pycountry.countries.lookup(country).numeric - gdf_tmp.iso_3a = country + gdf_tmp['iso_3n'] = pycountry.countries.lookup(country).numeric + gdf_tmp['iso_3a'] = country gdf = pd.concat([gdf, gdf_tmp], ignore_index=True) return gdf @@ -2401,13 +2401,13 @@ def points_to_raster(points_df, val_names=None, res=0.0, raster_res=0.0, crs=DEF if not val_names: val_names = ['value'] if not res: - res = np.abs(get_resolution(points_df.latitude.values, - points_df.longitude.values)).min() + res = np.abs(get_resolution(points_df['latitude'].values, + points_df['longitude'].values)).min() if not raster_res: raster_res = res def apply_box(df_exp): - fun = lambda r: Point(r.longitude, r.latitude).buffer(res / 2).envelope + fun = lambda r: Point(r['longitude'], r['latitude']).buffer(res / 2).envelope return df_exp.apply(fun, axis=1) LOGGER.info('Raster from resolution %s to %s.', res, raster_res) @@ -2431,16 +2431,16 @@ def apply_box(df_exp): # renormalize longitude if necessary if equal_crs(df_poly.crs, DEF_CRS): - xmin, ymin, xmax, ymax = latlon_bounds(points_df.latitude.values, - points_df.longitude.values) + xmin, ymin, xmax, ymax = latlon_bounds(points_df['latitude'].values, + points_df['longitude'].values) x_mid = 0.5 * (xmin + xmax) # we don't really change the CRS when rewrapping, so we reset the CRS attribute afterwards df_poly = df_poly \ .to_crs({"proj": "longlat", "lon_wrap": x_mid}) \ .set_crs(DEF_CRS, allow_override=True) else: - xmin, ymin, xmax, ymax = (points_df.longitude.min(), points_df.latitude.min(), - points_df.longitude.max(), points_df.latitude.max()) + xmin, ymin, xmax, ymax = (points_df['longitude'].min(), points_df['latitude'].min(), + points_df['longitude'].max(), points_df['latitude'].max()) # construct raster rows, cols, ras_trans = pts_to_raster_meta((xmin, ymin, xmax, ymax), @@ -2666,9 +2666,9 @@ def set_df_geometry_points(df_val, scheduler=None, crs=None): " effect and will be removed in a future version.", DeprecationWarning) # keep the original crs if any - crs = df_val.crs if crs is None else crs # crs might now still be None + crs = df_val['crs'] if crs is None else crs # crs might now still be None - df_val.set_geometry(gpd.points_from_xy(df_val.longitude, df_val.latitude), + df_val.set_geometry(gpd.points_from_xy(df_val['longitude'], df_val['latitude']), inplace=True, crs=crs) diff --git a/climada/util/finance.py b/climada/util/finance.py index 2b405c5937..f12b5e0007 100644 --- a/climada/util/finance.py +++ b/climada/util/finance.py @@ -299,14 +299,14 @@ def wealth2gdp(cntry_iso, non_financial=True, ref_year=2016, if non_financial: try: val = factors_all_countries[ - factors_all_countries.country_iso3 == cntry_iso]['NFW-to-GDP-ratio'].values[0] + factors_all_countries['country_iso3'] == cntry_iso]['NFW-to-GDP-ratio'].values[0] except (AttributeError, KeyError, IndexError): LOGGER.warning('No data for country, using mean factor.') val = factors_all_countries["NFW-to-GDP-ratio"].mean() else: try: val = factors_all_countries[ - factors_all_countries.country_iso3 == cntry_iso]['TW-to-GDP-ratio'].values[0] + factors_all_countries['country_iso3'] == cntry_iso]['TW-to-GDP-ratio'].values[0] except (AttributeError, KeyError, IndexError): LOGGER.warning('No data for country, using mean factor.') val = factors_all_countries["TW-to-GDP-ratio"].mean() diff --git a/climada/util/lines_polys_handler.py b/climada/util/lines_polys_handler.py index adb98b4de4..22d27793e8 100755 --- a/climada/util/lines_polys_handler.py +++ b/climada/util/lines_polys_handler.py @@ -89,9 +89,9 @@ def calc_geom_impact( disagg_val: float, optional Specifies what number should be taken as the value, which is to be disaggregated according to the method provided in disagg_met. - None: The shape's value is taken from the exp.gdf.value column. + None: The shape's value is taken from the exp.gdf['value'] column. float: This given number will be disaggregated according to the method. - In case exp.gdf.value column exists, original values in there will be + In case exp.gdf['value'] column exists, original values in there will be ignored. The default is None. agg_met : AggMethod @@ -261,9 +261,9 @@ def calc_grid_impact( disagg_val: float, optional Specifies what number should be taken as the value, which is to be disaggregated according to the method provided in disagg_met. - None: The shape's value is taken from the exp.gdf.value column. + None: The shape's value is taken from the exp.gdf['value'] column. float: This given number will be disaggregated according to the method. - In case exp.gdf.value column exists, original values in there will be + In case exp.gdf['value'] column exists, original values in there will be ignored The default is None. agg_met : AggMethod @@ -368,9 +368,9 @@ def exp_geom_to_pnt(exp, res, to_meters, disagg_met, disagg_val): disagg_val: float, optional Specifies what number should be taken as the value, which is to be disaggregated according to the method provided in disagg_met. - None: The shape's value is taken from the exp.gdf.value column. + None: The shape's value is taken from the exp.gdf['value'] column. float: This given number will be disaggregated according to the method. - In case exp.gdf.value column exists, original values in there will be + In case exp.gdf['value'] column exists, original values in there will be ignored The default is None. @@ -425,9 +425,9 @@ def exp_geom_to_grid(exp, grid, disagg_met, disagg_val): disagg_val: float, optional Specifies what number should be taken as the value, which is to be disaggregated according to the method provided in disagg_met. - None: The shape's value is taken from the exp.gdf.value column. + None: The shape's value is taken from the exp.gdf['value'] column. float: This given number will be disaggregated according to the method. - In case exp.gdf.value column exists, original values in there will be + In case exp.gdf['value'] column exists, original values in there will be ignored The default is None. @@ -445,7 +445,7 @@ def exp_geom_to_grid(exp, grid, disagg_met, disagg_val): if disagg_val is not None: exp = exp.copy() - exp.gdf.value = disagg_val + exp.gdf['value'] = disagg_val if ((disagg_val is None) and ('value' not in exp.gdf.columns)): raise ValueError('There is no value column in the exposure gdf to'+ @@ -615,7 +615,7 @@ def _disagg_values_div(gdf_pnts): gdf_disagg = gdf_pnts.copy(deep=False) group = gdf_pnts.groupby(axis=0, level=0) - vals = group.value.mean() / group.value.count() + vals = group['value'].mean() / group['value'].count() vals = vals.reindex(gdf_pnts.index, level=0) gdf_disagg['value'] = vals diff --git a/climada/util/test/test_coordinates.py b/climada/util/test/test_coordinates.py index 9426ad1dd7..aea4d5e6bb 100644 --- a/climada/util/test/test_coordinates.py +++ b/climada/util/test/test_coordinates.py @@ -567,7 +567,7 @@ def test_match_centroids(self): }) gdf = gpd.GeoDataFrame( df, - geometry=gpd.points_from_xy(df.longitude, df.latitude), + geometry=gpd.points_from_xy(df['longitude'], df['latitude']), crs=DEF_CRS, ) assigned = u_coord.match_centroids(gdf, centroids) @@ -591,7 +591,7 @@ def test_match_centroids(self): 'longitude': gdf_coords[:, 1], 'latitude': gdf_coords[:, 0] }) - gdf = gpd.GeoDataFrame(df,geometry=gpd.points_from_xy(df.longitude, df.latitude), + gdf = gpd.GeoDataFrame(df,geometry=gpd.points_from_xy(df['longitude'], df['latitude']), crs=DEF_CRS) coords_to_assign = np.array([(2.1, 3), (0, 0), (0, 2), (0.9, 1.0), (0, -179.9)]) @@ -626,7 +626,7 @@ def test_match_centroids(self): 'longitude': [10, 20, 30], 'latitude': [50, 60, 70] }) - gdf = gpd.GeoDataFrame(df,geometry=gpd.points_from_xy(df.longitude, df.latitude), + gdf = gpd.GeoDataFrame(df,geometry=gpd.points_from_xy(df['longitude'], df['latitude']), crs = 'EPSG:4326') coords_to_assign = np.array([(2.1, 3), (0, 0), (0, 2), (0.9, 1.0), (0, -179.9)]) @@ -1152,11 +1152,11 @@ def test_get_admin1_geometries_pass(self): self.assertEqual(len(gdf.iso_3a.unique()), 4) # 4 countries self.assertEqual(gdf.loc[gdf.iso_3a=='CHE'].shape[0], 26) # 26 cantons in CHE self.assertEqual(gdf.shape[0], 121) # 121 admin 1 regions in the 4 countries - self.assertIn('ARM', gdf.iso_3a.values) # Armenia (region_id 051) - self.assertIn('756', gdf.iso_3n.values) # Switzerland (region_id 756) - self.assertIn('CH-AI', gdf.iso_3166_2.values) # canton in CHE - self.assertIn('Sulawesi Tengah', gdf.admin1_name.values) # region in Indonesia - self.assertIsInstance(gdf.loc[gdf.iso_3166_2 == 'CH-AI'].geometry.values[0], + self.assertIn('ARM', gdf['iso_3a'].values) # Armenia (region_id 051) + self.assertIn('756', gdf['iso_3n'].values) # Switzerland (region_id 756) + self.assertIn('CH-AI', gdf['iso_3166_2'].values) # canton in CHE + self.assertIn('Sulawesi Tengah', gdf['admin1_name'].values) # region in Indonesia + self.assertIsInstance(gdf.loc[gdf['iso_3166_2'] == 'CH-AI'].geometry.values[0], shapely.geometry.MultiPolygon) self.assertIsInstance(gdf.loc[gdf.admin1_name == 'Sulawesi Tengah'].geometry.values[0], shapely.geometry.MultiPolygon) @@ -1273,7 +1273,7 @@ def test_pts_to_raster_irreg_pass(self): def test_points_to_raster_pass(self): """Test points_to_raster""" for scheduler in [None, "threads", "synchronous", "processes"]: - + df_val = gpd.GeoDataFrame() x, y = np.meshgrid(np.linspace(0, 2, 5), np.linspace(40, 50, 10)) df_val['latitude'] = y.flatten() diff --git a/climada/util/test/test_lines_polys_handler.py b/climada/util/test/test_lines_polys_handler.py index 070da95e3f..b9275d548c 100644 --- a/climada/util/test/test_lines_polys_handler.py +++ b/climada/util/test/test_lines_polys_handler.py @@ -100,7 +100,7 @@ def test_point_exposure_from_polygons(self): EXP_POLY, res=1, to_meters=False, disagg_met=u_lp.DisaggMethod.FIX, disagg_val=None ) - np.testing.assert_array_equal(exp_pnt.gdf.value, EXP_POLY.gdf.value) + np.testing.assert_array_equal(exp_pnt.gdf['value'], EXP_POLY.gdf['value']) self.check_unchanged_exp(EXP_POLY, exp_pnt) #to_meters=False, DIV @@ -115,14 +115,14 @@ def test_point_exposure_from_polygons(self): 8.54188667e+10, 8.54188667e+10, 1.43895450e+11, 1.43895450e+11, 1.16221500e+11, 3.70562500e+11, 1.35359600e+11, 3.83689000e+10 ]) - np.testing.assert_allclose(exp_pnt.gdf.value, val_avg) + np.testing.assert_allclose(exp_pnt.gdf['value'], val_avg) lat = np.array([ 53.15019278, 52.90814037, 52.48232657, 52.23482697, 52.23482697, 51.26574748, 51.30438894, 51.71676713, 51.71676713, 51.71676713, 52.13772724, 52.13772724, 52.61538869, 53.10328543, 52.54974468, 52.11286591 ]) - np.testing.assert_allclose(exp_pnt.gdf.latitude, lat) + np.testing.assert_allclose(exp_pnt.gdf['latitude'], lat) #to_meters=TRUE, FIX, dissag_val res = 20000 @@ -132,7 +132,7 @@ def test_point_exposure_from_polygons(self): ) self.check_unchanged_exp(EXP_POLY, exp_pnt) val = res**2 - self.assertEqual(np.unique(exp_pnt.gdf.value)[0], val) + self.assertEqual(np.unique(exp_pnt.gdf['value'])[0], val) lat = np.array([ 53.13923671, 53.13923671, 53.13923671, 53.13923671, 53.43921725, 53.43921725, 52.90782155, 52.90782155, 52.90782155, 52.90782155, @@ -150,7 +150,7 @@ def test_point_exposure_from_polygons(self): 53.38649582, 53.38649582, 53.38649582, 52.55795685, 52.55795685, 52.55795685, 52.55795685, 52.23308448, 52.23308448 ]) - np.testing.assert_allclose(exp_pnt.gdf.latitude, lat) + np.testing.assert_allclose(exp_pnt.gdf['latitude'], lat) #projected crs, to_meters=TRUE, FIX, dissag_val res = 20000 @@ -161,7 +161,7 @@ def test_point_exposure_from_polygons(self): ) self.check_unchanged_exp(EXP_POLY_PROJ, exp_pnt) val = res**2 - self.assertEqual(np.unique(exp_pnt.gdf.value)[0], val) + self.assertEqual(np.unique(exp_pnt.gdf['value'])[0], val) self.assertEqual(exp_pnt.gdf.crs, EXP_POLY_PROJ.gdf.crs) @patch.multiple( @@ -252,7 +252,7 @@ def test_point_exposure_from_lines(self): EXP_LINE, res=1, to_meters=False, disagg_met=u_lp.DisaggMethod.FIX, disagg_val=None ) - np.testing.assert_array_equal(exp_pnt.gdf.value[:,0], EXP_LINE.gdf.value) + np.testing.assert_array_equal(exp_pnt.gdf['value'][:,0], EXP_LINE.gdf['value']) self.check_unchanged_exp(EXP_LINE, exp_pnt) #to_meters=False, DIV @@ -260,7 +260,7 @@ def test_point_exposure_from_lines(self): EXP_LINE, res=1, to_meters=False, disagg_met=u_lp.DisaggMethod.DIV, disagg_val=None ) - np.testing.assert_array_equal(exp_pnt.gdf.value[:,0], EXP_LINE.gdf.value) + np.testing.assert_array_equal(exp_pnt.gdf['value'][:,0], EXP_LINE.gdf['value']) self.check_unchanged_exp(EXP_LINE, exp_pnt) #to_meters=TRUE, FIX, dissag_val @@ -271,7 +271,7 @@ def test_point_exposure_from_lines(self): ) self.check_unchanged_exp(EXP_LINE, exp_pnt) val = res**2 - self.assertEqual(np.unique(exp_pnt.gdf.value)[0], val) + self.assertEqual(np.unique(exp_pnt.gdf['value'])[0], val) lat = np.array([ 50.83944191, 50.94706532, 51.85008694, 51.7524172 , 52.07732906, 50.889641 , 51.90287148, 51.53858598, 52.30223675, 53.15931081, @@ -280,7 +280,7 @@ def test_point_exposure_from_lines(self): 51.93188219, 51.10694216, 52.48596301, 50.87543042, 51.0801347 , 50.82145186, 50.81341953, 51.07235498, 50.9105503 ]) - np.testing.assert_allclose(exp_pnt.gdf.latitude, lat) + np.testing.assert_allclose(exp_pnt.gdf['latitude'], lat) class TestGeomImpactCalcs(unittest.TestCase): """Test main functions on impact calculation and impact aggregation""" @@ -510,13 +510,13 @@ def test_gdf_line_to_pnt(self): gdf_pnt = u_lp._line_to_pnts(GDF_LINE, 1, False) check_unchanged_geom_gdf(self, GDF_LINE, gdf_pnt) np.testing.assert_array_equal( - np.unique(GDF_LINE.value), np.unique(gdf_pnt.value) + np.unique(GDF_LINE['value']), np.unique(gdf_pnt['value']) ) gdf_pnt = u_lp._line_to_pnts(GDF_LINE, 1000, True) check_unchanged_geom_gdf(self, GDF_LINE, gdf_pnt) np.testing.assert_array_equal( - np.unique(GDF_LINE.value), np.unique(gdf_pnt.value) + np.unique(GDF_LINE['value']), np.unique(gdf_pnt['value']) ) gdf_pnt_d = u_lp._line_to_pnts(GDF_LINE.iloc[0:1], 0.01, False) @@ -549,13 +549,13 @@ def test_gdf_poly_to_pnts(self): gdf_pnt = u_lp._poly_to_pnts(GDF_POLY, 1, False) check_unchanged_geom_gdf(self, GDF_POLY, gdf_pnt) np.testing.assert_array_equal( - np.unique(GDF_POLY.value), np.unique(gdf_pnt.value) + np.unique(GDF_POLY['value']), np.unique(gdf_pnt['value']) ) gdf_pnt = u_lp._poly_to_pnts(GDF_POLY, 5000, True) check_unchanged_geom_gdf(self, GDF_POLY, gdf_pnt) np.testing.assert_array_equal( - np.unique(GDF_POLY.value), np.unique(gdf_pnt.value) + np.unique(GDF_POLY['value']), np.unique(gdf_pnt['value']) ) gdf_pnt_d = u_lp._poly_to_pnts(GDF_POLY.iloc[0:1], 0.2, False) diff --git a/doc/guide/Guide_CLIMADA_conventions.ipynb b/doc/guide/Guide_CLIMADA_conventions.ipynb index ac482562cc..a8776ef3b7 100644 --- a/doc/guide/Guide_CLIMADA_conventions.ipynb +++ b/doc/guide/Guide_CLIMADA_conventions.ipynb @@ -62,6 +62,22 @@ "**CLIMADA classes shall NOT inherit classes from external modules.**" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Avoid attribute-style accesses" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CLIMADA developers shall use item-style access instead of attribute-style access (e.g. centroids.gdf[\"dist_coast\"] instead of centroids.gdf.dist_coast) when accessing a column (in the example: “dist_coast”) in a DataFrame or GeoDataFrame, or variables and attributes of xarray Datasets and DataArrays.\n", + "\n", + "Reasons are: Improved syntax highlighting, more consistency (since in many cases you cannot use attribute-style access, so you are forced to fall back to item-style access), avoid mixing up attribute and column names. " + ] + }, { "cell_type": "markdown", "metadata": {