From 7e461a18d9f6928132afec6f48ce968b3e989ba6 Mon Sep 17 00:00:00 2001 From: Kaiqi Dong Date: Mon, 3 Dec 2018 17:43:52 +0100 Subject: [PATCH 01/20] remove \n from docstring --- pandas/core/arrays/datetimes.py | 26 +++++++++++++------------- pandas/core/arrays/timedeltas.py | 16 ++++++++-------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index cfe3afcf3730a..b3df505d56d78 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -82,7 +82,7 @@ def f(self): return result f.__name__ = name - f.__doc__ = docstring + f.__doc__ = "\n{}\n".format(docstring) return property(f) @@ -1072,19 +1072,19 @@ def date(self): return tslib.ints_to_pydatetime(timestamps, box="date") - year = _field_accessor('year', 'Y', "\n The year of the datetime\n") + year = _field_accessor('year', 'Y', "The year of the datetime") month = _field_accessor('month', 'M', - "\n The month as January=1, December=12 \n") - day = _field_accessor('day', 'D', "\nThe days of the datetime\n") - hour = _field_accessor('hour', 'h', "\nThe hours of the datetime\n") - minute = _field_accessor('minute', 'm', "\nThe minutes of the datetime\n") - second = _field_accessor('second', 's', "\nThe seconds of the datetime\n") + "The month as January=1, December=12") + day = _field_accessor('day', 'D', "The days of the datetime") + hour = _field_accessor('hour', 'h', "The hours of the datetime") + minute = _field_accessor('minute', 'm', "The minutes of the datetime") + second = _field_accessor('second', 's', "The seconds of the datetime") microsecond = _field_accessor('microsecond', 'us', - "\nThe microseconds of the datetime\n") + "The microseconds of the datetime") nanosecond = _field_accessor('nanosecond', 'ns', - "\nThe nanoseconds of the datetime\n") + "The nanoseconds of the datetime") weekofyear = _field_accessor('weekofyear', 'woy', - "\nThe week ordinal of the year\n") + "The week ordinal of the year") week = weekofyear _dayofweek_doc = """ The day of the week with Monday=0, Sunday=6. @@ -1129,12 +1129,12 @@ def date(self): "The name of day in a week (ex: Friday)\n\n.. deprecated:: 0.23.0") dayofyear = _field_accessor('dayofyear', 'doy', - "\nThe ordinal day of the year\n") - quarter = _field_accessor('quarter', 'q', "\nThe quarter of the date\n") + "The ordinal day of the year") + quarter = _field_accessor('quarter', 'q', "The quarter of the date") days_in_month = _field_accessor( 'days_in_month', 'dim', - "\nThe number of days in the month\n") + "The number of days in the month") daysinmonth = days_in_month _is_month_doc = """ Indicates whether the date is the {first_or_last} day of the month. diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index 830283d31a929..4afc9f5483c2a 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -59,7 +59,7 @@ def f(self): return result f.__name__ = name - f.__doc__ = docstring + f.__doc__ = "\n{}\n".format(docstring) return property(f) @@ -684,16 +684,16 @@ def to_pytimedelta(self): return tslibs.ints_to_pytimedelta(self.asi8) days = _field_accessor("days", "days", - "\nNumber of days for each element.\n") + "Number of days for each element.") seconds = _field_accessor("seconds", "seconds", - "\nNumber of seconds (>= 0 and less than 1 day) " - "for each element.\n") + "Number of seconds (>= 0 and less than 1 day) " + "for each element.") microseconds = _field_accessor("microseconds", "microseconds", - "\nNumber of microseconds (>= 0 and less " - "than 1 second) for each element.\n") + "Number of microseconds (>= 0 and less " + "than 1 second) for each element.") nanoseconds = _field_accessor("nanoseconds", "nanoseconds", - "\nNumber of nanoseconds (>= 0 and less " - "than 1 microsecond) for each element.\n") + "Number of nanoseconds (>= 0 and less " + "than 1 microsecond) for each element.") @property def components(self): From dea38f24c0067ae3fe9484b837c9649714213bba Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Tue, 14 Jan 2020 21:26:31 +0100 Subject: [PATCH 02/20] fix issue 17038 --- pandas/core/reshape/pivot.py | 4 +++- pandas/tests/reshape/test_pivot.py | 20 ++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/pandas/core/reshape/pivot.py b/pandas/core/reshape/pivot.py index b443ba142369c..9743d90f4dd04 100644 --- a/pandas/core/reshape/pivot.py +++ b/pandas/core/reshape/pivot.py @@ -117,7 +117,9 @@ def pivot_table( agged[v] = maybe_downcast_to_dtype(agged[v], data[v].dtype) table = agged - if table.index.nlevels > 1: + + # GH 17038, this check should only happen if index is specified + if table.index.nlevels > 1 and index: # Related GH #17123 # If index_names are integers, determine whether the integers refer # to the level position or name. diff --git a/pandas/tests/reshape/test_pivot.py b/pandas/tests/reshape/test_pivot.py index 743fc50c87e96..46a05123c9fdd 100644 --- a/pandas/tests/reshape/test_pivot.py +++ b/pandas/tests/reshape/test_pivot.py @@ -896,12 +896,6 @@ def _check_output( totals = table.loc[("All", ""), value_col] assert totals == self.data[value_col].mean() - # no rows - rtable = self.data.pivot_table( - columns=["AA", "BB"], margins=True, aggfunc=np.mean - ) - assert isinstance(rtable, Series) - table = self.data.pivot_table(index=["AA", "BB"], margins=True, aggfunc="mean") for item in ["DD", "EE", "FF"]: totals = table.loc[("All", ""), item] @@ -972,6 +966,20 @@ def test_pivot_integer_columns(self): tm.assert_frame_equal(table, table2, check_names=False) + @pytest.mark.parametrize("cols", [(1, 2), ("a", "b"), (1, "b"), ("a", 1)]) + def test_pivot_table_multiindex_only(self, cols): + # GH 17038 + df2 = DataFrame({cols[0]: [1, 2, 3], cols[1]: [1, 2, 3], "v": [4, 5, 6]}) + + result = df2.pivot_table(values="v", columns=cols) + expected = DataFrame( + [[4, 5, 6]], + columns=MultiIndex.from_tuples([(1, 1), (2, 2), (3, 3)], names=cols), + index=Index(["v"]), + ) + + tm.assert_frame_equal(result, expected) + def test_pivot_no_level_overlap(self): # GH #1181 From cd9e7ac3f31ffaf95cd628863df911dea9fa1248 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Tue, 14 Jan 2020 21:29:43 +0100 Subject: [PATCH 03/20] revert change --- pandas/core/reshape/pivot.py | 3 +-- pandas/tests/reshape/test_pivot.py | 20 ++++++-------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/pandas/core/reshape/pivot.py b/pandas/core/reshape/pivot.py index 9743d90f4dd04..a7cdbb0da7a4e 100644 --- a/pandas/core/reshape/pivot.py +++ b/pandas/core/reshape/pivot.py @@ -118,8 +118,7 @@ def pivot_table( table = agged - # GH 17038, this check should only happen if index is specified - if table.index.nlevels > 1 and index: + if table.index.nlevels > 1: # Related GH #17123 # If index_names are integers, determine whether the integers refer # to the level position or name. diff --git a/pandas/tests/reshape/test_pivot.py b/pandas/tests/reshape/test_pivot.py index 46a05123c9fdd..743fc50c87e96 100644 --- a/pandas/tests/reshape/test_pivot.py +++ b/pandas/tests/reshape/test_pivot.py @@ -896,6 +896,12 @@ def _check_output( totals = table.loc[("All", ""), value_col] assert totals == self.data[value_col].mean() + # no rows + rtable = self.data.pivot_table( + columns=["AA", "BB"], margins=True, aggfunc=np.mean + ) + assert isinstance(rtable, Series) + table = self.data.pivot_table(index=["AA", "BB"], margins=True, aggfunc="mean") for item in ["DD", "EE", "FF"]: totals = table.loc[("All", ""), item] @@ -966,20 +972,6 @@ def test_pivot_integer_columns(self): tm.assert_frame_equal(table, table2, check_names=False) - @pytest.mark.parametrize("cols", [(1, 2), ("a", "b"), (1, "b"), ("a", 1)]) - def test_pivot_table_multiindex_only(self, cols): - # GH 17038 - df2 = DataFrame({cols[0]: [1, 2, 3], cols[1]: [1, 2, 3], "v": [4, 5, 6]}) - - result = df2.pivot_table(values="v", columns=cols) - expected = DataFrame( - [[4, 5, 6]], - columns=MultiIndex.from_tuples([(1, 1), (2, 2), (3, 3)], names=cols), - index=Index(["v"]), - ) - - tm.assert_frame_equal(result, expected) - def test_pivot_no_level_overlap(self): # GH #1181 From e5e912be0f596943067a7df812442764d311a086 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Tue, 14 Jan 2020 21:30:16 +0100 Subject: [PATCH 04/20] revert change --- pandas/core/reshape/pivot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/core/reshape/pivot.py b/pandas/core/reshape/pivot.py index a7cdbb0da7a4e..b443ba142369c 100644 --- a/pandas/core/reshape/pivot.py +++ b/pandas/core/reshape/pivot.py @@ -117,7 +117,6 @@ def pivot_table( agged[v] = maybe_downcast_to_dtype(agged[v], data[v].dtype) table = agged - if table.index.nlevels > 1: # Related GH #17123 # If index_names are integers, determine whether the integers refer From bc7bad46a2db6fb3dba709f1b4c0c050ee7b4024 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 17 May 2020 13:41:15 +0200 Subject: [PATCH 05/20] allow xlabel ylabel --- pandas/plotting/_core.py | 12 ++++++++++++ pandas/plotting/_matplotlib/core.py | 13 +++++++++++++ pandas/tests/plotting/test_frame.py | 30 +++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 467bdf7e0745d..e99fc7cc327bc 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -653,6 +653,14 @@ class PlotAccessor(PandasObject): Set the x limits of the current axes. ylim : 2-tuple/list Set the y limits of the current axes. + xlabel: string, default will use the index name. + Name to use for the xlabel on x-axis. + + .. versionadded:: 1.1.0 + ylabel: string, default is None which is not showing ylabel now. + Name to use for the ylabel on y-axis. + + .. versionadded:: 1.1.0 rot : int, default None Rotation for ticks (xticks for vertical, yticks for horizontal plots). @@ -759,6 +767,8 @@ def _get_call_args(backend_name, data, args, kwargs): ("xerr", None), ("label", None), ("secondary_y", False), + ("xlabel", None), + ("ylabel", None), ] elif isinstance(data, ABCDataFrame): arg_def = [ @@ -791,6 +801,8 @@ def _get_call_args(backend_name, data, args, kwargs): ("xerr", None), ("secondary_y", False), ("sort_columns", False), + ("xlabel", None), + ("ylabel", None), ] else: raise TypeError( diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 19a75eb151782..3aa8718555173 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -95,6 +95,8 @@ def __init__( ylim=None, xticks=None, yticks=None, + xlabel=None, + ylabel=None, sort_columns=False, fontsize=None, secondary_y=False, @@ -136,6 +138,8 @@ def __init__( self.ylim = ylim self.title = title self.use_index = use_index + self.xlabel = xlabel + self.ylabel = ylabel self.fontsize = fontsize @@ -480,6 +484,11 @@ def _adorn_subplots(self): if self.xlim is not None: ax.set_xlim(self.xlim) + # GH9093, currently Pandas does not show ylabel, so if users provide + # ylabel will set it as ylabel in the plot. + if self.ylabel is not None: + ax.set_ylabel(self.ylabel) + ax.grid(self.grid) if self.title: @@ -666,6 +675,10 @@ def _get_index_name(self): if name is not None: name = pprint_thing(name) + # GH 9093, override the default xlabel if xlabel is provided. + if self.xlabel is not None: + name = pprint_thing(self.xlabel) + return name @classmethod diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index c84a09f21f46b..26c9fefd0c249 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -3350,6 +3350,36 @@ def test_colors_of_columns_with_same_name(self): for legend, line in zip(result.get_legend().legendHandles, result.lines): assert legend.get_color() == line.get_color() + @pytest.mark.parametrize( + "index_name, xlabel", [(None, ""), ("new_name", "new_name")] + ) + @pytest.mark.parametrize("kind", ["line", "area", "bar"]) + def test_xlabel_single_plot(self, kind, index_name, xlabel): + # GH 9093 + df = pd.DataFrame([[1, 2], [2, 5]], columns=["Type A", "Type B"]) + df.index.name = index_name + + # default is the index name is being used if not None, otherwise no xlabel is shown + ax = df.plot(kind=kind) + assert ax.get_xlabel() == xlabel + + ax = df.plot(kind=kind, xlabel="new label") + assert ax.get_xlabel() == "new label" + + @pytest.mark.parametrize("index_name, ylabel", [(None, ""), ("new_name", "")]) + @pytest.mark.parametrize("kind", ["line", "area", "bar"]) + def test_ylabel_single_plot(self, kind, index_name, ylabel): + # GH 9093 + df = pd.DataFrame([[1, 2], [2, 5]], columns=["Type A", "Type B"]) + df.index.name = index_name + + # default is the ylabel is not shown + ax = df.plot(kind=kind) + assert ax.get_ylabel() == ylabel + + ax = df.plot(kind=kind, ylabel="new label") + assert ax.get_ylabel() == "new label" + def _generate_4_axes_via_gridspec(): import matplotlib.pyplot as plt From 4ae4f176b17b5b20c0ba8e2e0b41c22070db7386 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 17 May 2020 17:41:36 +0200 Subject: [PATCH 06/20] fixup --- pandas/tests/plotting/test_frame.py | 38 ++++++++++++++--------------- pandas/tests/plotting/test_misc.py | 2 +- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index 26c9fefd0c249..589ff38ca3b01 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -3351,34 +3351,32 @@ def test_colors_of_columns_with_same_name(self): assert legend.get_color() == line.get_color() @pytest.mark.parametrize( - "index_name, xlabel", [(None, ""), ("new_name", "new_name")] + "index_name, old_xlabel, new_xlabel, old_ylabel, new_ylabel", + [ + (None, "", "new_x", "", ""), + ("old_x", "old_x", "new_x", "", ""), + (None, "", "", "", ""), + (None, "", "new_x", "", "new_y"), + ("old_x", "old_x", "new_x", "", "new_y"), + ], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) - def test_xlabel_single_plot(self, kind, index_name, xlabel): - # GH 9093 - df = pd.DataFrame([[1, 2], [2, 5]], columns=["Type A", "Type B"]) - df.index.name = index_name - - # default is the index name is being used if not None, otherwise no xlabel is shown - ax = df.plot(kind=kind) - assert ax.get_xlabel() == xlabel - - ax = df.plot(kind=kind, xlabel="new label") - assert ax.get_xlabel() == "new label" - - @pytest.mark.parametrize("index_name, ylabel", [(None, ""), ("new_name", "")]) - @pytest.mark.parametrize("kind", ["line", "area", "bar"]) - def test_ylabel_single_plot(self, kind, index_name, ylabel): + def test_xlabel_ylabel_single_plot( + self, kind, index_name, old_xlabel, old_ylabel, new_xlabel, new_ylabel + ): # GH 9093 df = pd.DataFrame([[1, 2], [2, 5]], columns=["Type A", "Type B"]) df.index.name = index_name - # default is the ylabel is not shown + # default is the ylabel is not shown and xlabel is index name ax = df.plot(kind=kind) - assert ax.get_ylabel() == ylabel + assert ax.get_ylabel() == old_ylabel + assert ax.get_xlabel() == old_xlabel - ax = df.plot(kind=kind, ylabel="new label") - assert ax.get_ylabel() == "new label" + # old xlabel will be overriden and assigned ylabel will be used as ylabel + ax = df.plot(kind=kind, ylabel=new_ylabel, xlabel=new_xlabel) + assert ax.get_ylabel() == new_ylabel + assert ax.get_xlabel() == new_xlabel def _generate_4_axes_via_gridspec(): diff --git a/pandas/tests/plotting/test_misc.py b/pandas/tests/plotting/test_misc.py index 27039948dfc16..81add4beabfd2 100644 --- a/pandas/tests/plotting/test_misc.py +++ b/pandas/tests/plotting/test_misc.py @@ -54,7 +54,7 @@ def test_get_accessor_args(): assert x is None assert y is None assert kind == "line" - assert len(kwargs) == 22 + assert len(kwargs) == 24 @td.skip_if_no_mpl From 0d32836c5bc23633b36270947dcdf163d9554050 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 17 May 2020 18:05:13 +0200 Subject: [PATCH 07/20] add more tests and fix docs --- pandas/plotting/_core.py | 10 ++++++---- pandas/tests/plotting/test_frame.py | 30 +++++++++++++++++++++++++++- pandas/tests/plotting/test_series.py | 28 ++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index e99fc7cc327bc..2b95653721ea3 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -653,14 +653,16 @@ class PlotAccessor(PandasObject): Set the x limits of the current axes. ylim : 2-tuple/list Set the y limits of the current axes. - xlabel: string, default will use the index name. - Name to use for the xlabel on x-axis. + xlabel : str, default None + Name to use for the xlabel on x-axis. Default uses index name as xlabel. .. versionadded:: 1.1.0 - ylabel: string, default is None which is not showing ylabel now. - Name to use for the ylabel on y-axis. + + ylabel : str, default None + Name to use for the ylabel on y-axis. Default will show no ylabel. .. versionadded:: 1.1.0 + rot : int, default None Rotation for ticks (xticks for vertical, yticks for horizontal plots). diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index 589ff38ca3b01..9ae7d80934d0f 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -3361,7 +3361,7 @@ def test_colors_of_columns_with_same_name(self): ], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) - def test_xlabel_ylabel_single_plot( + def test_xlabel_ylabel_dataframe_single_plot( self, kind, index_name, old_xlabel, old_ylabel, new_xlabel, new_ylabel ): # GH 9093 @@ -3378,6 +3378,34 @@ def test_xlabel_ylabel_single_plot( assert ax.get_ylabel() == new_ylabel assert ax.get_xlabel() == new_xlabel + @pytest.mark.parametrize( + "index_name, old_xlabel, new_xlabel, old_ylabel, new_ylabel", + [ + (None, "", "new_x", "", ""), + ("old_x", "old_x", "new_x", "", ""), + (None, "", "", "", ""), + (None, "", "new_x", "", "new_y"), + ("old_x", "old_x", "new_x", "", "new_y"), + ], + ) + @pytest.mark.parametrize("kind", ["line", "area", "bar"]) + def test_xlabel_ylabel_dataframe_subplots( + self, kind, index_name, old_xlabel, old_ylabel, new_xlabel, new_ylabel + ): + # GH 9093 + df = pd.DataFrame([[1, 2], [2, 5]], columns=["Type A", "Type B"]) + df.index.name = index_name + + # default is the ylabel is not shown and xlabel is index name + axes = df.plot(kind=kind, subplots=True) + assert all([ax.get_ylabel() == old_ylabel for ax in axes]) + assert all([ax.get_xlabel() == old_xlabel for ax in axes]) + + # old xlabel will be overriden and assigned ylabel will be used as ylabel + axes = df.plot(kind=kind, ylabel=new_ylabel, xlabel=new_xlabel, subplots=True) + assert all([ax.get_ylabel() == new_ylabel for ax in axes]) + assert all([ax.get_xlabel() == new_xlabel for ax in axes]) + def _generate_4_axes_via_gridspec(): import matplotlib.pyplot as plt diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index 5341878d4986e..be82f0c30a928 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -934,3 +934,31 @@ def test_style_single_ok(self): s = pd.Series([1, 2]) ax = s.plot(style="s", color="C3") assert ax.lines[0].get_color() == ["C3"] + + @pytest.mark.parametrize( + "index_name, old_xlabel, new_xlabel, old_ylabel, new_ylabel", + [ + (None, "", "new_x", "", ""), + ("old_x", "old_x", "new_x", "", ""), + (None, "", "", "", ""), + (None, "", "new_x", "", "new_y"), + ("old_x", "old_x", "new_x", "", "new_y"), + ], + ) + @pytest.mark.parametrize("kind", ["line", "area", "bar"]) + def test_xlabel_ylabel_series( + self, kind, index_name, old_xlabel, old_ylabel, new_xlabel, new_ylabel + ): + # GH 9093 + ser = pd.Series([1, 2, 3, 4]) + ser.index.name = index_name + + # default is the ylabel is not shown and xlabel is index name + ax = ser.plot(kind=kind) + assert ax.get_ylabel() == old_ylabel + assert ax.get_xlabel() == old_xlabel + + # old xlabel will be overriden and assigned ylabel will be used as ylabel + ax = ser.plot(kind=kind, ylabel=new_ylabel, xlabel=new_xlabel) + assert ax.get_ylabel() == new_ylabel + assert ax.get_xlabel() == new_xlabel From 4d7216b381ebd7fba6c17f8d403e6df1493474f7 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 17 May 2020 18:07:29 +0200 Subject: [PATCH 08/20] annotation --- pandas/plotting/_matplotlib/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 3aa8718555173..542fcec4842c0 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -95,8 +95,8 @@ def __init__( ylim=None, xticks=None, yticks=None, - xlabel=None, - ylabel=None, + xlabel: str = None, + ylabel: str = None, sort_columns=False, fontsize=None, secondary_y=False, From cc1b6d68170a1c303cfa45e1c4bff8c27d812763 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 17 May 2020 18:16:34 +0200 Subject: [PATCH 09/20] add whatsnew --- doc/source/whatsnew/v1.1.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 73892da2cbf71..41e7b1334624e 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -235,6 +235,7 @@ Other enhancements :class:`~pandas.io.stata.StataWriter`, :class:`~pandas.io.stata.StataWriter117`, and :class:`~pandas.io.stata.StataWriterUTF8` (:issue:`26599`). - :meth:`HDFStore.put` now accepts `track_times` parameter. Parameter is passed to ``create_table`` method of ``PyTables`` (:issue:`32682`). +- :meth:`Series.plot` and :meth:`DataFrame.plot` now accepts `xlabel` and `ylabel` parameters to present labels on x and y axis (:issue:`9093`). .. --------------------------------------------------------------------------- From dbf8f1ad81f4be0ca7e8986cbf93c87f0316f7d1 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 17 May 2020 18:34:17 +0200 Subject: [PATCH 10/20] linting --- pandas/tests/plotting/test_frame.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index 9ae7d80934d0f..4fd5b79da3743 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -3398,13 +3398,13 @@ def test_xlabel_ylabel_dataframe_subplots( # default is the ylabel is not shown and xlabel is index name axes = df.plot(kind=kind, subplots=True) - assert all([ax.get_ylabel() == old_ylabel for ax in axes]) - assert all([ax.get_xlabel() == old_xlabel for ax in axes]) + assert all(ax.get_ylabel() == old_ylabel for ax in axes) + assert all(ax.get_xlabel() == old_xlabel for ax in axes) # old xlabel will be overriden and assigned ylabel will be used as ylabel axes = df.plot(kind=kind, ylabel=new_ylabel, xlabel=new_xlabel, subplots=True) - assert all([ax.get_ylabel() == new_ylabel for ax in axes]) - assert all([ax.get_xlabel() == new_xlabel for ax in axes]) + assert all(ax.get_ylabel() == new_ylabel for ax in axes) + assert all(ax.get_xlabel() == new_xlabel for ax in axes) def _generate_4_axes_via_gridspec(): From 3fb1faab9ae436273f31ff8fa1eaf6925d734c32 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 17 May 2020 19:09:01 +0200 Subject: [PATCH 11/20] fix annotation --- pandas/plotting/_matplotlib/core.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 542fcec4842c0..a3936f0456990 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -1,5 +1,5 @@ import re -from typing import Optional +from typing import List, Optional import warnings import numpy as np @@ -95,8 +95,8 @@ def __init__( ylim=None, xticks=None, yticks=None, - xlabel: str = None, - ylabel: str = None, + xlabel: Optional[str] = None, + ylabel: Optional[str] = None, sort_columns=False, fontsize=None, secondary_y=False, @@ -157,8 +157,8 @@ def __init__( self.grid = grid self.legend = legend - self.legend_handles = [] - self.legend_labels = [] + self.legend_handles: List = [] + self.legend_labels: List = [] for attr in self._pop_attributes: value = kwds.pop(attr, self._attr_defaults.get(attr, None)) From 3f3409908802c04a50c6779289839e24b9248f5b Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Mon, 25 May 2020 19:11:22 +0200 Subject: [PATCH 12/20] allow number as labels --- pandas/plotting/_core.py | 4 ++-- pandas/plotting/_matplotlib/core.py | 5 +++-- pandas/tests/plotting/test_frame.py | 12 ++++++++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 2b95653721ea3..77c10a68e3685 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -653,12 +653,12 @@ class PlotAccessor(PandasObject): Set the x limits of the current axes. ylim : 2-tuple/list Set the y limits of the current axes. - xlabel : str, default None + xlabel : label, default None Name to use for the xlabel on x-axis. Default uses index name as xlabel. .. versionadded:: 1.1.0 - ylabel : str, default None + ylabel : label, default None Name to use for the ylabel on y-axis. Default will show no ylabel. .. versionadded:: 1.1.0 diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index a3936f0456990..6f778190b1fd2 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -4,6 +4,7 @@ import numpy as np +from pandas._typing import Label from pandas.errors import AbstractMethodError from pandas.util._decorators import cache_readonly @@ -95,8 +96,8 @@ def __init__( ylim=None, xticks=None, yticks=None, - xlabel: Optional[str] = None, - ylabel: Optional[str] = None, + xlabel: Optional[Label] = None, + ylabel: Optional[Label] = None, sort_columns=False, fontsize=None, secondary_y=False, diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index 4fd5b79da3743..fe6ec198b4753 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -3358,6 +3358,8 @@ def test_colors_of_columns_with_same_name(self): (None, "", "", "", ""), (None, "", "new_x", "", "new_y"), ("old_x", "old_x", "new_x", "", "new_y"), + (None, "", 1, "", ""), + (None, "", 1, "", 2), ], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) @@ -3375,8 +3377,8 @@ def test_xlabel_ylabel_dataframe_single_plot( # old xlabel will be overriden and assigned ylabel will be used as ylabel ax = df.plot(kind=kind, ylabel=new_ylabel, xlabel=new_xlabel) - assert ax.get_ylabel() == new_ylabel - assert ax.get_xlabel() == new_xlabel + assert ax.get_ylabel() == str(new_ylabel) + assert ax.get_xlabel() == str(new_xlabel) @pytest.mark.parametrize( "index_name, old_xlabel, new_xlabel, old_ylabel, new_ylabel", @@ -3386,6 +3388,8 @@ def test_xlabel_ylabel_dataframe_single_plot( (None, "", "", "", ""), (None, "", "new_x", "", "new_y"), ("old_x", "old_x", "new_x", "", "new_y"), + (None, "", 1, "", ""), + (None, "", 1, "", 2), ], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) @@ -3403,8 +3407,8 @@ def test_xlabel_ylabel_dataframe_subplots( # old xlabel will be overriden and assigned ylabel will be used as ylabel axes = df.plot(kind=kind, ylabel=new_ylabel, xlabel=new_xlabel, subplots=True) - assert all(ax.get_ylabel() == new_ylabel for ax in axes) - assert all(ax.get_xlabel() == new_xlabel for ax in axes) + assert all(ax.get_ylabel() == str(new_ylabel) for ax in axes) + assert all(ax.get_xlabel() == str(new_xlabel) for ax in axes) def _generate_4_axes_via_gridspec(): From 408d08faffc5fe49fd67a7a6e10e6fa73ef7290a Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 14 Jun 2020 12:14:18 +0200 Subject: [PATCH 13/20] simplify test --- pandas/plotting/_matplotlib/core.py | 5 +-- pandas/tests/plotting/test_frame.py | 48 ++++++++++------------------ pandas/tests/plotting/test_series.py | 24 +++++--------- 3 files changed, 27 insertions(+), 50 deletions(-) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 499c5d7565e80..bb15902cc5e53 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -2,6 +2,7 @@ from typing import List, Optional import warnings +from matplotlib.artist import Artist import numpy as np from pandas._typing import Label @@ -159,8 +160,8 @@ def __init__( self.grid = grid self.legend = legend - self.legend_handles: List = [] - self.legend_labels: List = [] + self.legend_handles: List[Artist] = [] + self.legend_labels: List[Label] = [] for attr in self._pop_attributes: value = kwds.pop(attr, self._attr_defaults.get(attr, None)) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index fe6ec198b4753..617f1c532b94c 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -3351,20 +3351,12 @@ def test_colors_of_columns_with_same_name(self): assert legend.get_color() == line.get_color() @pytest.mark.parametrize( - "index_name, old_xlabel, new_xlabel, old_ylabel, new_ylabel", - [ - (None, "", "new_x", "", ""), - ("old_x", "old_x", "new_x", "", ""), - (None, "", "", "", ""), - (None, "", "new_x", "", "new_y"), - ("old_x", "old_x", "new_x", "", "new_y"), - (None, "", 1, "", ""), - (None, "", 1, "", 2), - ], + "index_name, old_label, new_label", + [(None, "", "new"), ("old", "old", "new"), (None, "", ""), (None, "", 1),], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) def test_xlabel_ylabel_dataframe_single_plot( - self, kind, index_name, old_xlabel, old_ylabel, new_xlabel, new_ylabel + self, kind, index_name, old_label, new_label ): # GH 9093 df = pd.DataFrame([[1, 2], [2, 5]], columns=["Type A", "Type B"]) @@ -3372,29 +3364,21 @@ def test_xlabel_ylabel_dataframe_single_plot( # default is the ylabel is not shown and xlabel is index name ax = df.plot(kind=kind) - assert ax.get_ylabel() == old_ylabel - assert ax.get_xlabel() == old_xlabel + assert ax.get_xlabel() == old_label + assert ax.get_ylabel() == "" # old xlabel will be overriden and assigned ylabel will be used as ylabel - ax = df.plot(kind=kind, ylabel=new_ylabel, xlabel=new_xlabel) - assert ax.get_ylabel() == str(new_ylabel) - assert ax.get_xlabel() == str(new_xlabel) + ax = df.plot(kind=kind, ylabel=new_label, xlabel=new_label) + assert ax.get_ylabel() == str(new_label) + assert ax.get_xlabel() == str(new_label) @pytest.mark.parametrize( - "index_name, old_xlabel, new_xlabel, old_ylabel, new_ylabel", - [ - (None, "", "new_x", "", ""), - ("old_x", "old_x", "new_x", "", ""), - (None, "", "", "", ""), - (None, "", "new_x", "", "new_y"), - ("old_x", "old_x", "new_x", "", "new_y"), - (None, "", 1, "", ""), - (None, "", 1, "", 2), - ], + "index_name, old_label, new_label", + [(None, "", "new"), ("old", "old", "new"), (None, "", ""), (None, "", 1),], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) def test_xlabel_ylabel_dataframe_subplots( - self, kind, index_name, old_xlabel, old_ylabel, new_xlabel, new_ylabel + self, kind, index_name, old_label, new_label ): # GH 9093 df = pd.DataFrame([[1, 2], [2, 5]], columns=["Type A", "Type B"]) @@ -3402,13 +3386,13 @@ def test_xlabel_ylabel_dataframe_subplots( # default is the ylabel is not shown and xlabel is index name axes = df.plot(kind=kind, subplots=True) - assert all(ax.get_ylabel() == old_ylabel for ax in axes) - assert all(ax.get_xlabel() == old_xlabel for ax in axes) + assert all(ax.get_ylabel() == "" for ax in axes) + assert all(ax.get_xlabel() == old_label for ax in axes) # old xlabel will be overriden and assigned ylabel will be used as ylabel - axes = df.plot(kind=kind, ylabel=new_ylabel, xlabel=new_xlabel, subplots=True) - assert all(ax.get_ylabel() == str(new_ylabel) for ax in axes) - assert all(ax.get_xlabel() == str(new_xlabel) for ax in axes) + axes = df.plot(kind=kind, ylabel=new_label, xlabel=new_label, subplots=True) + assert all(ax.get_ylabel() == str(new_label) for ax in axes) + assert all(ax.get_xlabel() == str(new_label) for ax in axes) def _generate_4_axes_via_gridspec(): diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index be82f0c30a928..5b569b79b7295 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -936,29 +936,21 @@ def test_style_single_ok(self): assert ax.lines[0].get_color() == ["C3"] @pytest.mark.parametrize( - "index_name, old_xlabel, new_xlabel, old_ylabel, new_ylabel", - [ - (None, "", "new_x", "", ""), - ("old_x", "old_x", "new_x", "", ""), - (None, "", "", "", ""), - (None, "", "new_x", "", "new_y"), - ("old_x", "old_x", "new_x", "", "new_y"), - ], + "index_name, old_label, new_label", + [(None, "", "new"), ("old", "old", "new"), (None, "", ""),], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) - def test_xlabel_ylabel_series( - self, kind, index_name, old_xlabel, old_ylabel, new_xlabel, new_ylabel - ): + def test_xlabel_ylabel_series(self, kind, index_name, old_label, new_label): # GH 9093 ser = pd.Series([1, 2, 3, 4]) ser.index.name = index_name # default is the ylabel is not shown and xlabel is index name ax = ser.plot(kind=kind) - assert ax.get_ylabel() == old_ylabel - assert ax.get_xlabel() == old_xlabel + assert ax.get_ylabel() == "" + assert ax.get_xlabel() == old_label # old xlabel will be overriden and assigned ylabel will be used as ylabel - ax = ser.plot(kind=kind, ylabel=new_ylabel, xlabel=new_xlabel) - assert ax.get_ylabel() == new_ylabel - assert ax.get_xlabel() == new_xlabel + ax = ser.plot(kind=kind, ylabel=new_label, xlabel=new_label) + assert ax.get_ylabel() == new_label + assert ax.get_xlabel() == new_label From 54824ab97957deff5865b6f7b85359b65e7c4762 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 14 Jun 2020 12:58:37 +0200 Subject: [PATCH 14/20] fix linting --- pandas/tests/plotting/test_frame.py | 4 ++-- pandas/tests/plotting/test_series.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index 617f1c532b94c..6d61da030057d 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -3352,7 +3352,7 @@ def test_colors_of_columns_with_same_name(self): @pytest.mark.parametrize( "index_name, old_label, new_label", - [(None, "", "new"), ("old", "old", "new"), (None, "", ""), (None, "", 1),], + [(None, "", "new"), ("old", "old", "new"), (None, "", ""), (None, "", 1), ], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) def test_xlabel_ylabel_dataframe_single_plot( @@ -3374,7 +3374,7 @@ def test_xlabel_ylabel_dataframe_single_plot( @pytest.mark.parametrize( "index_name, old_label, new_label", - [(None, "", "new"), ("old", "old", "new"), (None, "", ""), (None, "", 1),], + [(None, "", "new"), ("old", "old", "new"), (None, "", ""), (None, "", 1), ], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) def test_xlabel_ylabel_dataframe_subplots( diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index 5b569b79b7295..937c7d2c18784 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -937,7 +937,7 @@ def test_style_single_ok(self): @pytest.mark.parametrize( "index_name, old_label, new_label", - [(None, "", "new"), ("old", "old", "new"), (None, "", ""),], + [(None, "", "new"), ("old", "old", "new"), (None, "", ""), ], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) def test_xlabel_ylabel_series(self, kind, index_name, old_label, new_label): From 8a24a4005da4f924e289762966725da138c7b8bb Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 14 Jun 2020 14:40:26 +0200 Subject: [PATCH 15/20] fix linting --- pandas/tests/plotting/test_frame.py | 4 ++-- pandas/tests/plotting/test_series.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index 6d61da030057d..528b4611a9ceb 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -3352,7 +3352,7 @@ def test_colors_of_columns_with_same_name(self): @pytest.mark.parametrize( "index_name, old_label, new_label", - [(None, "", "new"), ("old", "old", "new"), (None, "", ""), (None, "", 1), ], + [(None, "", "new"), ("old", "old", "new"), (None, "", ""), (None, "", 1)], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) def test_xlabel_ylabel_dataframe_single_plot( @@ -3374,7 +3374,7 @@ def test_xlabel_ylabel_dataframe_single_plot( @pytest.mark.parametrize( "index_name, old_label, new_label", - [(None, "", "new"), ("old", "old", "new"), (None, "", ""), (None, "", 1), ], + [(None, "", "new"), ("old", "old", "new"), (None, "", ""), (None, "", 1)], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) def test_xlabel_ylabel_dataframe_subplots( diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index 937c7d2c18784..b3bc150c4a243 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -937,7 +937,7 @@ def test_style_single_ok(self): @pytest.mark.parametrize( "index_name, old_label, new_label", - [(None, "", "new"), ("old", "old", "new"), (None, "", ""), ], + [(None, "", "new"), ("old", "old", "new"), (None, "", "")], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) def test_xlabel_ylabel_series(self, kind, index_name, old_label, new_label): From 31c8ccfce2787b58ca1d6d6b1fbf4d7d42eddcf0 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sat, 20 Jun 2020 18:34:09 +0200 Subject: [PATCH 16/20] add user guide --- doc/source/user_guide/visualization.rst | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/doc/source/user_guide/visualization.rst b/doc/source/user_guide/visualization.rst index 305221b767aff..723b3db64b776 100644 --- a/doc/source/user_guide/visualization.rst +++ b/doc/source/user_guide/visualization.rst @@ -1108,6 +1108,34 @@ shown by default. plt.close('all') + +Controlling the labels +~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.1.0 + +You may set the ``xlabel`` and ``ylabel`` arguments to give the plot custom labels +for x and y axis. By default, Pandas will pick up index name as xlabel, while leaving +it empty for ylabel. + +.. ipython:: python + :suppress: + + plt.figure() + +.. ipython:: python + + df = pd.DataFrame([[1, 2], [2, 5]], columns=["A", "B"]) + + df.plot() # default setting + + df.plot(xlabel="new A", ylabel="Y column") + +.. ipython:: python + :suppress: + + plt.close('all') + Scales ~~~~~~ From 9d1d94294d4e29c07f7326ea66c945e3b98ce1f9 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sat, 20 Jun 2020 19:38:28 +0200 Subject: [PATCH 17/20] fix test --- doc/source/user_guide/visualization.rst | 41 +++++++++++++------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/doc/source/user_guide/visualization.rst b/doc/source/user_guide/visualization.rst index 723b3db64b776..620f1bd6fbd2a 100644 --- a/doc/source/user_guide/visualization.rst +++ b/doc/source/user_guide/visualization.rst @@ -1083,25 +1083,27 @@ keywords are passed along to the corresponding matplotlib function :meth:`ax.scatter() `). These can be used to control additional styling, beyond what pandas provides. -Controlling the legend + +Controlling the labels ~~~~~~~~~~~~~~~~~~~~~~ -You may set the ``legend`` argument to ``False`` to hide the legend, which is -shown by default. +.. versionadded:: 1.1.0 + +You may set the ``xlabel`` and ``ylabel`` arguments to give the plot custom labels +for x and y axis. By default, Pandas will pick up index name as xlabel, while leaving +it empty for ylabel. .. ipython:: python :suppress: - np.random.seed(123456) + plt.figure() .. ipython:: python - df = pd.DataFrame(np.random.randn(1000, 4), - index=ts.index, columns=list('ABCD')) - df = df.cumsum() + df_labels = pd.DataFrame([[1, 2], [2, 5]], columns=["A", "B"]) - @savefig frame_plot_basic_noleg.png - df.plot(legend=False) + @savefig plot_xlabel_ylabel.png + df_labels.plot(xlabel="new A", ylabel="Y column") .. ipython:: python :suppress: @@ -1109,33 +1111,32 @@ shown by default. plt.close('all') -Controlling the labels +Controlling the legend ~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 1.1.0 - -You may set the ``xlabel`` and ``ylabel`` arguments to give the plot custom labels -for x and y axis. By default, Pandas will pick up index name as xlabel, while leaving -it empty for ylabel. +You may set the ``legend`` argument to ``False`` to hide the legend, which is +shown by default. .. ipython:: python :suppress: - plt.figure() + np.random.seed(123456) .. ipython:: python - df = pd.DataFrame([[1, 2], [2, 5]], columns=["A", "B"]) - - df.plot() # default setting + df = pd.DataFrame(np.random.randn(1000, 4), + index=ts.index, columns=list('ABCD')) + df = df.cumsum() - df.plot(xlabel="new A", ylabel="Y column") + @savefig frame_plot_basic_noleg.png + df.plot(legend=False) .. ipython:: python :suppress: plt.close('all') + Scales ~~~~~~ From 5335de8e226308164f88514961762b9642e141e8 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sat, 20 Jun 2020 20:20:07 +0200 Subject: [PATCH 18/20] use current df --- doc/source/user_guide/visualization.rst | 38 ++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/doc/source/user_guide/visualization.rst b/doc/source/user_guide/visualization.rst index 620f1bd6fbd2a..8619b6c3c7f97 100644 --- a/doc/source/user_guide/visualization.rst +++ b/doc/source/user_guide/visualization.rst @@ -1084,26 +1084,25 @@ keywords are passed along to the corresponding matplotlib function to control additional styling, beyond what pandas provides. -Controlling the labels +Controlling the legend ~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 1.1.0 - -You may set the ``xlabel`` and ``ylabel`` arguments to give the plot custom labels -for x and y axis. By default, Pandas will pick up index name as xlabel, while leaving -it empty for ylabel. +You may set the ``legend`` argument to ``False`` to hide the legend, which is +shown by default. .. ipython:: python :suppress: - plt.figure() + np.random.seed(123456) .. ipython:: python - df_labels = pd.DataFrame([[1, 2], [2, 5]], columns=["A", "B"]) + df = pd.DataFrame(np.random.randn(1000, 4), + index=ts.index, columns=list('ABCD')) + df = df.cumsum() - @savefig plot_xlabel_ylabel.png - df_labels.plot(xlabel="new A", ylabel="Y column") + @savefig frame_plot_basic_noleg.png + df.plot(legend=False) .. ipython:: python :suppress: @@ -1111,25 +1110,26 @@ it empty for ylabel. plt.close('all') -Controlling the legend +Controlling the labels ~~~~~~~~~~~~~~~~~~~~~~ -You may set the ``legend`` argument to ``False`` to hide the legend, which is -shown by default. +.. versionadded:: 1.1.0 + +You may set the ``xlabel`` and ``ylabel`` arguments to give the plot custom labels +for x and y axis. By default, Pandas will pick up index name as xlabel, while leaving +it empty for ylabel. .. ipython:: python :suppress: - np.random.seed(123456) + plt.figure() .. ipython:: python - df = pd.DataFrame(np.random.randn(1000, 4), - index=ts.index, columns=list('ABCD')) - df = df.cumsum() + df.plot() - @savefig frame_plot_basic_noleg.png - df.plot(legend=False) + @savefig plot_xlabel_ylabel.png + df_labels.plot(xlabel="new x", ylabel="new y") .. ipython:: python :suppress: From 8f12150059e11bb949f4795fd13883ef9763ee3c Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sat, 20 Jun 2020 21:15:43 +0200 Subject: [PATCH 19/20] fix typo --- doc/source/user_guide/visualization.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/source/user_guide/visualization.rst b/doc/source/user_guide/visualization.rst index 7c544f94d16fe..c6f098bc8f78a 100644 --- a/doc/source/user_guide/visualization.rst +++ b/doc/source/user_guide/visualization.rst @@ -1083,7 +1083,6 @@ keywords are passed along to the corresponding matplotlib function :meth:`ax.scatter() `). These can be used to control additional styling, beyond what pandas provides. - Controlling the legend ~~~~~~~~~~~~~~~~~~~~~~ @@ -1129,7 +1128,7 @@ it empty for ylabel. df.plot() @savefig plot_xlabel_ylabel.png - df_labels.plot(xlabel="new x", ylabel="new y") + df.plot(xlabel="new x", ylabel="new y") .. ipython:: python :suppress: From e1ade5360501a7e6116241dc7d557f1888b442ae Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Thu, 25 Jun 2020 17:57:14 +0200 Subject: [PATCH 20/20] code change on reviews --- doc/source/user_guide/visualization.rst | 2 +- pandas/plotting/_core.py | 4 ++-- pandas/plotting/_matplotlib/core.py | 2 +- pandas/tests/plotting/test_frame.py | 16 ++++++++++++++-- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/doc/source/user_guide/visualization.rst b/doc/source/user_guide/visualization.rst index c6f098bc8f78a..27826e7cde9e1 100644 --- a/doc/source/user_guide/visualization.rst +++ b/doc/source/user_guide/visualization.rst @@ -1115,7 +1115,7 @@ Controlling the labels .. versionadded:: 1.1.0 You may set the ``xlabel`` and ``ylabel`` arguments to give the plot custom labels -for x and y axis. By default, Pandas will pick up index name as xlabel, while leaving +for x and y axis. By default, pandas will pick up index name as xlabel, while leaving it empty for ylabel. .. ipython:: python diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 9fcb78792e384..2da8864c5a295 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -653,12 +653,12 @@ class PlotAccessor(PandasObject): Set the x limits of the current axes. ylim : 2-tuple/list Set the y limits of the current axes. - xlabel : label, default None + xlabel : label, optional Name to use for the xlabel on x-axis. Default uses index name as xlabel. .. versionadded:: 1.1.0 - ylabel : label, default None + ylabel : label, optional Name to use for the ylabel on y-axis. Default will show no ylabel. .. versionadded:: 1.1.0 diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 8d465e7b76486..e510f7140519a 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -491,7 +491,7 @@ def _adorn_subplots(self): # GH9093, currently Pandas does not show ylabel, so if users provide # ylabel will set it as ylabel in the plot. if self.ylabel is not None: - ax.set_ylabel(self.ylabel) + ax.set_ylabel(pprint_thing(self.ylabel)) ax.grid(self.grid) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index d100f2a3b0d92..3d85e79b15c4c 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -3365,7 +3365,13 @@ def test_colors_of_columns_with_same_name(self): @pytest.mark.parametrize( "index_name, old_label, new_label", - [(None, "", "new"), ("old", "old", "new"), (None, "", ""), (None, "", 1)], + [ + (None, "", "new"), + ("old", "old", "new"), + (None, "", ""), + (None, "", 1), + (None, "", [1, 2]), + ], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) def test_xlabel_ylabel_dataframe_single_plot( @@ -3387,7 +3393,13 @@ def test_xlabel_ylabel_dataframe_single_plot( @pytest.mark.parametrize( "index_name, old_label, new_label", - [(None, "", "new"), ("old", "old", "new"), (None, "", ""), (None, "", 1)], + [ + (None, "", "new"), + ("old", "old", "new"), + (None, "", ""), + (None, "", 1), + (None, "", [1, 2]), + ], ) @pytest.mark.parametrize("kind", ["line", "area", "bar"]) def test_xlabel_ylabel_dataframe_subplots(