From dd96d931bfd3598aebb1b9abc83eae9612ce19c6 Mon Sep 17 00:00:00 2001 From: emanuel-schmid Date: Thu, 30 Nov 2023 10:18:09 +0100 Subject: [PATCH 1/2] DiscRates: add csv support --- climada/entity/disc_rates/base.py | 76 +++++++++++++++++++-- climada/entity/disc_rates/test/test_base.py | 35 ++++++++-- 2 files changed, 101 insertions(+), 10 deletions(-) diff --git a/climada/entity/disc_rates/base.py b/climada/entity/disc_rates/base.py index 683ec5be53..0d51e7597e 100755 --- a/climada/entity/disc_rates/base.py +++ b/climada/entity/disc_rates/base.py @@ -259,9 +259,11 @@ def from_mat(cls, file_name, var_names=None): return cls(years=years, rates=rates) def read_mat(self, *args, **kwargs): - """This function is deprecated, use DiscRates.from_mats instead.""" - LOGGER.warning("The use of DiscRates.read_mats is deprecated." - "Use DiscRates.from_mats instead.") + """This function is deprecated, use ``DiscRates.from_mat`` instead.""" + LOGGER.warning( + "The use of DiscRates.read_mat is deprecated." + "Use DiscRates.from_mat instead." + ) self.__dict__ = DiscRates.from_mat(*args, **kwargs).__dict__ @classmethod @@ -307,8 +309,7 @@ def read_excel(self, *args, **kwargs): """This function is deprecated, use DiscRates.from_excel instead.""" LOGGER.warning("The use of DiscRates.read_excel is deprecated." "Use DiscRates.from_excel instead.") - self.__dict__ = DiscRates.from_mat(*args, **kwargs).__dict__ - + self.__dict__ = DiscRates.from_excel(*args, **kwargs).__dict__ def write_excel(self, file_name, var_names=None): """ @@ -341,3 +342,68 @@ def write_excel(self, file_name, var_names=None): disc_ws.write(i_yr, 0, disc_yr) disc_ws.write(i_yr, 1, disc_rt) disc_wb.close() + + @classmethod + def from_csv( + cls, file_name, year_column="year", disc_column="discount_rate", **kwargs + ): + """ + Read DiscRate from a csv file following template and store variables. + + Parameters + ---------- + file_name: str + filename including path and extension + year_column: str, optional + name of the column that contains the years, + Default: "year" + disc_column: str, optional + name of the column that contains the discount rates, + Default: "discount_rate" + **kwargs: + any additional arguments, e.g., `sep`, `delimiter`, `head`, + are forwarded to ``pandas.read_csv`` + + Returns + ------- + climada.entity.DiscRates : + The disc rates from the csv file + """ + dfr = pd.read_csv(file_name, **kwargs) + try: + years = dfr[year_column].values.astype(int, copy=False) + rates = dfr[disc_column].values + except KeyError as err: + raise ValueError( + f"missing column in csv file ({year_column} or {disc_column})" + ) from err + + return cls(years=years, rates=rates) + + def write_csv( + self, file_name, year_column="year", disc_column="discount_rate", **kwargs + ): + """ + Write DiscRate to a csv file following template and store variables. + + Parameters + ---------- + file_name: str + filename including path and extension + year_column: str, optional + name of the column that contains the years, + Default: "year" + disc_column: str, optional + name of the column that contains the discount rates, + Default: "discount_rate" + **kwargs: + any additional arguments, e.g., `sep`, `delimiter`, `head`, + are forwarded to ``pandas.read_csv`` + """ + dfr = pd.DataFrame( + { + year_column: self.years, + disc_column: self.rates, + } + ) + dfr.to_csv(file_name, **kwargs) diff --git a/climada/entity/disc_rates/test/test_base.py b/climada/entity/disc_rates/test/test_base.py index d31ab3cb26..2458a75464 100644 --- a/climada/entity/disc_rates/test/test_base.py +++ b/climada/entity/disc_rates/test/test_base.py @@ -21,6 +21,8 @@ import unittest import numpy as np import copy +from pathlib import Path +from tempfile import TemporaryDirectory from climada import CONFIG from climada.entity.disc_rates.base import DiscRates @@ -216,16 +218,25 @@ def test_demo_file_pass(self): self.assertEqual(disc_rate.rates.max(), 0.02) -class TestWriter(unittest.TestCase): - """Test excel reader for discount rates""" +class TestWriteRead(unittest.TestCase): + """Test file write read cycle for discount rates""" + + @classmethod + def setUpClass(cls): + cls._td = TemporaryDirectory() + cls.tempdir = Path(cls._td.name) + + @classmethod + def tearDownClass(cls): + cls._td.cleanup() - def test_write_read_pass(self): + def test_write_read_excel_pass(self): """Read demo excel file.""" years = np.arange(1950, 2150) rates = np.ones(years.size) * 0.03 disc_rate = DiscRates(years=years, rates=rates) - file_name = CONFIG.disc_rates.test_data.dir().joinpath('test_disc.xlsx') + file_name = self.tempdir.joinpath('test_disc.xlsx') disc_rate.write_excel(file_name) disc_read = DiscRates.from_excel(file_name) @@ -233,6 +244,20 @@ def test_write_read_pass(self): self.assertTrue(np.array_equal(disc_read.years, disc_rate.years)) self.assertTrue(np.array_equal(disc_read.rates, disc_rate.rates)) + def test_write_read_csv_pass(self): + """Write and read csv file.""" + years = np.arange(1950, 2150) + rates = np.ones(years.size) * 0.03 + disc_rate = DiscRates(years=years, rates=rates) + + file_name = self.tempdir.joinpath('test_disc.csv') + disc_rate.write_csv(file_name) + + disc_read = DiscRates.from_csv(file_name) + + self.assertTrue(np.array_equal(disc_read.years, disc_rate.years)) + self.assertTrue(np.array_equal(disc_read.rates, disc_rate.rates)) + # Execute Tests if __name__ == "__main__": @@ -243,5 +268,5 @@ def test_write_read_pass(self): TESTS.addTests(unittest.TestLoader().loadTestsFromTestCase(TestNetPresValue)) TESTS.addTests(unittest.TestLoader().loadTestsFromTestCase(TestReaderExcel)) TESTS.addTests(unittest.TestLoader().loadTestsFromTestCase(TestReaderMat)) - TESTS.addTests(unittest.TestLoader().loadTestsFromTestCase(TestWriter)) + TESTS.addTests(unittest.TestLoader().loadTestsFromTestCase(TestWriteRead)) unittest.TextTestRunner(verbosity=2).run(TESTS) From 5e41203995b7dfae82da6915fbc98bce796fecde Mon Sep 17 00:00:00 2001 From: emanuel-schmid Date: Thu, 30 Nov 2023 15:57:33 +0100 Subject: [PATCH 2/2] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dcd96f135..5df3222cf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ Code freeze date: YYYY-MM-DD ### Added +- Read and Write methods to and from csv files for the `DiscRates` class. [#818](ttps://github.com/CLIMADA-project/climada_python/pull/818) + ### Changed - Add `shapes` argument to `geo_im_from_array` to allow flexible turning on/off of plotting coastline in `plot_intensity`. [#805](https://github.com/CLIMADA-project/climada_python/pull/805)