From d499f52a877e88ab9abe689ad74991450f6a7bca Mon Sep 17 00:00:00 2001 From: Gustaf Larsson Date: Thu, 29 Feb 2024 21:02:03 +0100 Subject: [PATCH 1/8] test: #2 - Added tests that verify if generated dates are the same as the ones in the resulting plot * Added test_period_range_content which tests if plotted dates are equal to generated dates using period_range * Added test_date_range_content which tests if plotted dates are equal to generated dates using date_range --- pandas/tests/plotting/test_datetimelike.py | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index d478fbfb46b08..9acc40048ce0c 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -69,6 +69,46 @@ def test_fontsize_set_correctly(self): for label in ax.get_xticklabels() + ax.get_yticklabels(): assert label.get_fontsize() == 2 + + #TODO: Add more tests for different frequencies + @pytest.mark.parametrize("freq", ["1Y", "Y", "3Y", "10Y", "100Y"]) + def test_period_range_content(self, freq): + # Setup your DataFrame as in your scenario + idx = period_range("2000-01-01", freq=freq, periods=4) + df = DataFrame( + np.array([0, 1, 0, 1]), + index=idx, + columns=["A"], + ) + + ax = df.plot() + lines = ax.get_lines()[0].get_xdata() + + # Convert idx and lines to lists of strings representing dates + idx_dates = [str(period) for period in idx] + lines_dates = [str(period) for period in lines] + + assert idx_dates == lines_dates + + #TODO: Add more tests for different frequency formats + @pytest.mark.parametrize("freq", ["1Y", "Y", "3Y", "10Y", "100Y"]) + def test_date_range_content(self, freq): + # Setup your DataFrame as in your scenario + idx = date_range("2000/01/01", freq=freq, periods=4) + df = DataFrame( + np.array([0, 1, 0, 1]), + index=idx, + columns=["A"], + ) + ax = df.plot() + lines = ax.get_lines()[0].get_xdata() + # Convert idx and lines to lists of strings representing dates + idx_dates = [str(period).split("-")[0] for period in idx] + lines_dates = [str(period) for period in lines] + assert idx_dates == lines_dates + + + def test_frame_inferred(self): # inferred freq idx = date_range("1/1/1987", freq="MS", periods=100) From 5f8ad5e68ffa280fbe132700669bef9409e4e7fd Mon Sep 17 00:00:00 2001 From: Gustaf Larsson Date: Thu, 29 Feb 2024 21:45:00 +0100 Subject: [PATCH 2/8] fix: 2-removed 100Y test since it is out of bounds timestamp for the time format --- pandas/tests/plotting/test_datetimelike.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 9acc40048ce0c..09543508a2a18 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -71,7 +71,7 @@ def test_fontsize_set_correctly(self): #TODO: Add more tests for different frequencies - @pytest.mark.parametrize("freq", ["1Y", "Y", "3Y", "10Y", "100Y"]) + @pytest.mark.parametrize("freq", ["1Y", "Y", "3Y", "10Y"]) def test_period_range_content(self, freq): # Setup your DataFrame as in your scenario idx = period_range("2000-01-01", freq=freq, periods=4) @@ -91,7 +91,7 @@ def test_period_range_content(self, freq): assert idx_dates == lines_dates #TODO: Add more tests for different frequency formats - @pytest.mark.parametrize("freq", ["1Y", "Y", "3Y", "10Y", "100Y"]) + @pytest.mark.parametrize("freq", ["1YE", "YE", "3YE", "10YE"]) def test_date_range_content(self, freq): # Setup your DataFrame as in your scenario idx = date_range("2000/01/01", freq=freq, periods=4) From f3ce3dc9dc025f427a1fcf9213251cc5b26c358a Mon Sep 17 00:00:00 2001 From: Gustaf Larsson Date: Sat, 2 Mar 2024 12:43:53 +0100 Subject: [PATCH 3/8] feat: 2- Improved tests * Moved the checking of the plot data to a separate function * Added more frequencies to be tested --- pandas/tests/plotting/common.py | 24 +++++++++++++++++ pandas/tests/plotting/test_datetimelike.py | 31 +++++++--------------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index 5a46cdcb051b6..60c7eb3c83aac 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -541,6 +541,30 @@ def _check_plot_works(f, default_axes=False, **kwargs): plt.close(fig) return ret + +def _check_inputdata_equals_outputdata(idx, ax): + from pandas.core.indexes.datetimes import ( + DatetimeIndex, + ) + + """ + Check that the input data is equal to the output data + Parameters + ---------- + idx : PeriodIndex + The input data based on freq + ax : matplotlib Axes object + The input data after plotting + """ + + #Convert to periodIndex to use same formatting as the output + if isinstance(idx, DatetimeIndex): + idx = idx.to_period() + input = [str(period) for period in idx] + output_unformatted = ax.get_lines()[0].get_xdata() + output = [str(period) for period in output_unformatted] + # Convert idx and lines to lists of strings representing dates + assert input == output def _gen_default_plot(f, fig, **kwargs): diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 09543508a2a18..6b3cc7b011092 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -1,4 +1,5 @@ """ Test cases for time series specific (freq conversion, etc) """ + from datetime import ( date, datetime, @@ -38,6 +39,7 @@ ) from pandas.core.indexes.timedeltas import timedelta_range from pandas.tests.plotting.common import _check_ticks_props +from pandas.tests.plotting.common import _check_inputdata_equals_outputdata from pandas.tseries.offsets import WeekOfMonth @@ -69,11 +71,10 @@ def test_fontsize_set_correctly(self): for label in ax.get_xticklabels() + ax.get_yticklabels(): assert label.get_fontsize() == 2 - - #TODO: Add more tests for different frequencies - @pytest.mark.parametrize("freq", ["1Y", "Y", "3Y", "10Y"]) + # TODO: Add more tests for different frequencies + @pytest.mark.parametrize("freq", ["20s","3s","60min","5min","7h","4D","8W","11M","2Q","Y", "3Y", "10Y"]) def test_period_range_content(self, freq): - # Setup your DataFrame as in your scenario + # Setup your DataFrame as in your scenario idx = period_range("2000-01-01", freq=freq, periods=4) df = DataFrame( np.array([0, 1, 0, 1]), @@ -82,18 +83,12 @@ def test_period_range_content(self, freq): ) ax = df.plot() - lines = ax.get_lines()[0].get_xdata() - - # Convert idx and lines to lists of strings representing dates - idx_dates = [str(period) for period in idx] - lines_dates = [str(period) for period in lines] - - assert idx_dates == lines_dates + _check_inputdata_equals_outputdata(idx=idx, ax=ax) - #TODO: Add more tests for different frequency formats - @pytest.mark.parametrize("freq", ["1YE", "YE", "3YE", "10YE"]) + # TODO: Add more tests for different frequency formats + @pytest.mark.parametrize("freq", ["20s","3s","60min","5min","7h","4D","8W","11ME","2QE","YE", "3YE", "10YE"]) def test_date_range_content(self, freq): - # Setup your DataFrame as in your scenario + # Setup your DataFrame as in your scenario idx = date_range("2000/01/01", freq=freq, periods=4) df = DataFrame( np.array([0, 1, 0, 1]), @@ -101,13 +96,7 @@ def test_date_range_content(self, freq): columns=["A"], ) ax = df.plot() - lines = ax.get_lines()[0].get_xdata() - # Convert idx and lines to lists of strings representing dates - idx_dates = [str(period).split("-")[0] for period in idx] - lines_dates = [str(period) for period in lines] - assert idx_dates == lines_dates - - + _check_inputdata_equals_outputdata(idx=idx, ax=ax) def test_frame_inferred(self): # inferred freq From d6eb450355568adccc1f67c22626e9598ac79d91 Mon Sep 17 00:00:00 2001 From: Gustaf Larsson Date: Sat, 2 Mar 2024 12:49:42 +0100 Subject: [PATCH 4/8] fix: #4 - Plotting PeriodIndexes now correctly aligns with the start of the period --- pandas/plotting/_matplotlib/timeseries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/plotting/_matplotlib/timeseries.py b/pandas/plotting/_matplotlib/timeseries.py index d4587a6ccf90a..15a07e056c4be 100644 --- a/pandas/plotting/_matplotlib/timeseries.py +++ b/pandas/plotting/_matplotlib/timeseries.py @@ -310,7 +310,7 @@ def maybe_convert_index(ax: Axes, data: NDFrameT) -> NDFrameT: if isinstance(data.index, ABCDatetimeIndex): data = data.tz_localize(None).to_period(freq=freq_str) elif isinstance(data.index, ABCPeriodIndex): - data.index = data.index.asfreq(freq=freq_str) + data.index = data.index.asfreq(freq=freq_str, how = "S") return data From e7e73e9fcb5ba4bd5f9e29d48375d620dcbc101e Mon Sep 17 00:00:00 2001 From: andrefred Date: Sun, 3 Mar 2024 13:38:46 +0100 Subject: [PATCH 5/8] #2 Refactor: Updated test_construction_from_string::test_period_range.py to test frequencies with koefficient > 1. Also removed redundant test called test_construction_from_string_monthly since the updated test_construction_from_string covers the same thing. --- .../tests/indexes/period/test_period_range.py | 38 ++++--------------- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/pandas/tests/indexes/period/test_period_range.py b/pandas/tests/indexes/period/test_period_range.py index 6f8e6d07da8bf..369900afb6dec 100644 --- a/pandas/tests/indexes/period/test_period_range.py +++ b/pandas/tests/indexes/period/test_period_range.py @@ -79,10 +79,16 @@ class TestPeriodRange: @pytest.mark.parametrize( "freq_offset, freq_period", [ + ("h", "h"), + ("7h", "7h"), ("D", "D"), - ("W", "W"), - ("QE", "Q"), + ("15D", "15D"), + ("ME", "M"), + ("3ME", "3M"), ("YE", "Y"), + ("8YE", "8Y"), + ("20s", "20s"), + ("2QE", "2Q"), ], ) def test_construction_from_string(self, freq_offset, freq_period): @@ -113,34 +119,6 @@ def test_construction_from_string(self, freq_offset, freq_period): result = period_range(start=end, end=start, freq=freq_period, name="foo") tm.assert_index_equal(result, expected) - def test_construction_from_string_monthly(self): - # non-empty - expected = date_range( - start="2017-01-01", periods=5, freq="ME", name="foo" - ).to_period() - start, end = str(expected[0]), str(expected[-1]) - - result = period_range(start=start, end=end, freq="M", name="foo") - tm.assert_index_equal(result, expected) - - result = period_range(start=start, periods=5, freq="M", name="foo") - tm.assert_index_equal(result, expected) - - result = period_range(end=end, periods=5, freq="M", name="foo") - tm.assert_index_equal(result, expected) - - # empty - expected = PeriodIndex([], freq="M", name="foo") - - result = period_range(start=start, periods=0, freq="M", name="foo") - tm.assert_index_equal(result, expected) - - result = period_range(end=end, periods=0, freq="M", name="foo") - tm.assert_index_equal(result, expected) - - result = period_range(start=end, end=start, freq="M", name="foo") - tm.assert_index_equal(result, expected) - def test_construction_from_period(self): # upsampling start, end = Period("2017Q1", freq="Q"), Period("2018Q1", freq="Q") From b3d4ff16fae45171baeba56a6ff6723fedf88881 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 3 Mar 2024 16:07:28 +0100 Subject: [PATCH 6/8] Docs: added comments to bug fix #10 --- pandas/plotting/_matplotlib/timeseries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/plotting/_matplotlib/timeseries.py b/pandas/plotting/_matplotlib/timeseries.py index 15a07e056c4be..da395197737b7 100644 --- a/pandas/plotting/_matplotlib/timeseries.py +++ b/pandas/plotting/_matplotlib/timeseries.py @@ -310,7 +310,7 @@ def maybe_convert_index(ax: Axes, data: NDFrameT) -> NDFrameT: if isinstance(data.index, ABCDatetimeIndex): data = data.tz_localize(None).to_period(freq=freq_str) elif isinstance(data.index, ABCPeriodIndex): - data.index = data.index.asfreq(freq=freq_str, how = "S") + data.index = data.index.asfreq(freq=freq_str, how = "S") #Lineplot alignes to the start of period return data From 6e22a86cf420cb5e6d138171833d511c16cf2a08 Mon Sep 17 00:00:00 2001 From: Gustaf Larsson <94399312+Gustaf-Larsson@users.noreply.github.com> Date: Mon, 4 Mar 2024 13:36:58 +0100 Subject: [PATCH 7/8] fix: Removed TODO comments --- pandas/tests/plotting/test_datetimelike.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 6b3cc7b011092..402b5eada7d86 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -1,5 +1,4 @@ """ Test cases for time series specific (freq conversion, etc) """ - from datetime import ( date, datetime, @@ -71,7 +70,6 @@ def test_fontsize_set_correctly(self): for label in ax.get_xticklabels() + ax.get_yticklabels(): assert label.get_fontsize() == 2 - # TODO: Add more tests for different frequencies @pytest.mark.parametrize("freq", ["20s","3s","60min","5min","7h","4D","8W","11M","2Q","Y", "3Y", "10Y"]) def test_period_range_content(self, freq): # Setup your DataFrame as in your scenario @@ -85,7 +83,6 @@ def test_period_range_content(self, freq): ax = df.plot() _check_inputdata_equals_outputdata(idx=idx, ax=ax) - # TODO: Add more tests for different frequency formats @pytest.mark.parametrize("freq", ["20s","3s","60min","5min","7h","4D","8W","11ME","2QE","YE", "3YE", "10YE"]) def test_date_range_content(self, freq): # Setup your DataFrame as in your scenario From 6a209303b08dfbf3cb44d2ffa2a31d71778ebe56 Mon Sep 17 00:00:00 2001 From: Gustaf Larsson <94399312+Gustaf-Larsson@users.noreply.github.com> Date: Mon, 4 Mar 2024 13:41:27 +0100 Subject: [PATCH 8/8] fix: Updated documentation --- pandas/tests/plotting/common.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index 60c7eb3c83aac..de52edab53d62 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -548,13 +548,13 @@ def _check_inputdata_equals_outputdata(idx, ax): ) """ - Check that the input data is equal to the output data + Check that the input dates is equal to the plotted dates Parameters ---------- - idx : PeriodIndex + idx : PeriodIndex , DatetimeIndex The input data based on freq ax : matplotlib Axes object - The input data after plotting + The plotted data """ #Convert to periodIndex to use same formatting as the output