Repository: pandas-dev/pandas

Issue:
API: use show_dimensions default to decide whether to show Series length
rather than `display.max_rows` directly

for considency with the new 'truncate' option



Discussion:
cc @bjonen if you have time

So you are referring to changing this line? 
https://github.com/pydata/pandas/blob/master/pandas/core/series.py#L831
Right now, the dimensions are only printed if we produce a `tidy_repr`. 

And you would like the docs to be implemented?  

```
Whether to print out dimensions at the end of DataFrame repr.
If 'truncate' is specified, only print out the dimensions if the
frame is truncated (e.g. not display all rows and/or columns)
```

would be reworking this to decide if it's truncated
then based on show_dimensions setting shoe the length ( or not)

`show_dimennsions` can be
- `truncate`: In this case we print the dimensions only if the series gets truncated. 
- `True` In this case we print the dimensions (this is not implemented right now) independent of whether the series got truncated. 
- `False` In this case we do not print the dimensions inpependent of whether the series got truncated. 

If that's ok I can make the adjustment. 

that looks right (tests are current in `test_format.py` for the DataFrame impl of this, so maybe add Series to that or below). Further can you update the `show_dimensions` option in `core/config_init.py` to reflect this better?

thanks

Am I right that nothing will change with the default settings? (as in 0.14 the length of the series is only shown when truncated, and the `show_dimensions` option is `'truncate'` by default) 
So only if a user would set `show_dimensions` to True or False the display behaviour will change (and always or never show the series length)?

Just asking because I was doubting if this would warrant a change in the default display behaviour (but AFAIU, this is not the case so no problem).

BTW, while testing I saw another issue: #7508

@jorisvandenbossche the user facing API shouldn't change (as the default is basically 'truncate' with Series now). but will be consistent if the user DOES change it.


Resolving patch:
diff --git a/pandas/core/series.py b/pandas/core/series.py
--- a/pandas/core/series.py
+++ b/pandas/core/series.py
@@ -980,9 +980,10 @@ def __unicode__(self):
         width, height = get_terminal_size()
         max_rows = (height if get_option("display.max_rows") == 0 else
                     get_option("display.max_rows"))
+        show_dimensions = get_option("display.show_dimensions")
 
         self.to_string(buf=buf, name=self.name, dtype=self.dtype,
-                       max_rows=max_rows)
+                       max_rows=max_rows, length=show_dimensions)
         result = buf.getvalue()
 
         return result
@@ -1021,31 +1022,6 @@ def to_string(self, buf=None, na_rep='NaN', float_format=None, header=True,
         formatted : string (if not buffer passed)
         """
 
-        the_repr = self._get_repr(float_format=float_format, na_rep=na_rep,
-                                  header=header, index=index, length=length,
-                                  dtype=dtype, name=name, max_rows=max_rows)
-
-        # catch contract violations
-        if not isinstance(the_repr, compat.text_type):
-            raise AssertionError("result must be of type unicode, type"
-                                 " of result is {0!r}"
-                                 "".format(the_repr.__class__.__name__))
-
-        if buf is None:
-            return the_repr
-        else:
-            try:
-                buf.write(the_repr)
-            except AttributeError:
-                with open(buf, 'w') as f:
-                    f.write(the_repr)
-
-    def _get_repr(self, name=False, header=True, index=True, length=True,
-                  dtype=True, na_rep='NaN', float_format=None, max_rows=None):
-        """
-
-        Internal function, should always return unicode string
-        """
         formatter = fmt.SeriesFormatter(self, name=name, length=length,
                                         header=header, index=index,
                                         dtype=dtype, na_rep=na_rep,
@@ -1053,12 +1029,20 @@ def _get_repr(self, name=False, header=True, index=True, length=True,
                                         max_rows=max_rows)
         result = formatter.to_string()
 
-        # TODO: following check prob. not neces.
+        # catch contract violations
         if not isinstance(result, compat.text_type):
             raise AssertionError("result must be of type unicode, type"
                                  " of result is {0!r}"
                                  "".format(result.__class__.__name__))
-        return result
+
+        if buf is None:
+            return result
+        else:
+            try:
+                buf.write(result)
+            except AttributeError:
+                with open(buf, 'w') as f:
+                    f.write(result)
 
     def __iter__(self):
         """ provide iteration over the values of the Series
diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py
--- a/pandas/io/formats/format.py
+++ b/pandas/io/formats/format.py
@@ -199,7 +199,8 @@ def _get_footer(self):
                                        escape_chars=('\t', '\r', '\n'))
             footer += ("Name: %s" % series_name) if name is not None else ""
 
-        if self.length:
+        if (self.length is True or
+                (self.length == 'truncate' and self.truncate_v)):
             if footer:
                 footer += ', '
             footer += 'Length: %d' % len(self.series)


Test patch:
diff --git a/pandas/tests/io/formats/test_format.py b/pandas/tests/io/formats/test_format.py
--- a/pandas/tests/io/formats/test_format.py
+++ b/pandas/tests/io/formats/test_format.py
@@ -1770,12 +1770,14 @@ def test_east_asian_unicode_series(self):
                        name=u'おおおおおおお')
 
             expected = (u"0       あ\n     ... \n"
-                        u"3    ええええ\nName: おおおおおおお, dtype: object")
+                        u"3    ええええ\n"
+                        u"Name: おおおおおおお, Length: 4, dtype: object")
             self.assertEqual(_rep(s), expected)
 
             s.index = [u'ああ', u'いいいい', u'う', u'えええ']
             expected = (u"ああ        あ\n       ... \n"
-                        u"えええ    ええええ\nName: おおおおおおお, dtype: object")
+                        u"えええ    ええええ\n"
+                        u"Name: おおおおおおお, Length: 4, dtype: object")
             self.assertEqual(_rep(s), expected)
 
         # Emable Unicode option -----------------------------------------
@@ -1846,14 +1848,15 @@ def test_east_asian_unicode_series(self):
                 s = Series([u'あ', u'いい', u'ううう', u'ええええ'],
                            name=u'おおおおおおお')
                 expected = (u"0          あ\n       ...   \n"
-                            u"3    ええええ\nName: おおおおおおお, dtype: object")
+                            u"3    ええええ\n"
+                            u"Name: おおおおおおお, Length: 4, dtype: object")
                 self.assertEqual(_rep(s), expected)
 
                 s.index = [u'ああ', u'いいいい', u'う', u'えええ']
                 expected = (u"ああ            あ\n"
                             u"            ...   \n"
                             u"えええ    ええええ\n"
-                            u"Name: おおおおおおお, dtype: object")
+                            u"Name: おおおおおおお, Length: 4, dtype: object")
                 self.assertEqual(_rep(s), expected)
 
             # ambiguous unicode
@@ -2021,7 +2024,8 @@ def test_max_multi_index_display(self):
     # Make sure #8532 is fixed
     def test_consistent_format(self):
         s = pd.Series([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.9999, 1, 1] * 10)
-        with option_context("display.max_rows", 10):
+        with option_context("display.max_rows", 10,
+                            "display.show_dimensions", False):
             res = repr(s)
         exp = ('0      1.0000\n1      1.0000\n2      1.0000\n3      '
                '1.0000\n4      1.0000\n        ...  \n125    '
@@ -2040,7 +2044,8 @@ def chck_ncols(self, s):
 
     def test_format_explicit(self):
         test_sers = gen_series_formatting()
-        with option_context("display.max_rows", 4):
+        with option_context("display.max_rows", 4,
+                            "display.show_dimensions", False):
             res = repr(test_sers['onel'])
             exp = '0     a\n1     a\n     ..\n98    a\n99    a\ndtype: object'
             self.assertEqual(exp, res)
@@ -2087,6 +2092,22 @@ def getndots(s):
             strrepr = repr(s).replace('\n', '')
         self.assertEqual(getndots(strrepr), 3)
 
+    def test_show_dimensions(self):
+        # gh-7117
+        s = Series(range(5))
+
+        assert 'Length' not in repr(s)
+
+        with option_context("display.max_rows", 4):
+            assert 'Length' in repr(s)
+
+        with option_context("display.show_dimensions", True):
+            assert 'Length' in repr(s)
+
+        with option_context("display.max_rows", 4,
+                            "display.show_dimensions", False):
+            assert 'Length' not in repr(s)
+
     def test_to_string_name(self):
         s = Series(range(100), dtype='int64')
         s.name = 'myser'
diff --git a/pandas/tests/sparse/test_format.py b/pandas/tests/sparse/test_format.py
--- a/pandas/tests/sparse/test_format.py
+++ b/pandas/tests/sparse/test_format.py
@@ -33,7 +33,7 @@ def test_sparse_max_row(self):
             # GH 10560
             result = repr(s)
             exp = ("0    1.0\n    ... \n4    NaN\n"
-                   "dtype: float64\nBlockIndex\n"
+                   "Length: 5, dtype: float64\nBlockIndex\n"
                    "Block locations: array([0, 3]{0})\n"
                    "Block lengths: array([1, 1]{0})".format(dfm))
             self.assertEqual(result, exp)
@@ -52,7 +52,8 @@ def test_sparse_mi_max_row(self):
                "Block lengths: array([1, 1]{0})".format(dfm))
         self.assertEqual(result, exp)
 
-        with option_context("display.max_rows", 3):
+        with option_context("display.max_rows", 3,
+                            "display.show_dimensions", False):
             # GH 13144
             result = repr(s)
             exp = ("A  0    1.0\n       ... \nC  2    NaN\n"
@@ -77,7 +78,7 @@ def test_sparse_bool(self):
         with option_context("display.max_rows", 3):
             result = repr(s)
             exp = ("0     True\n     ...  \n5    False\n"
-                   "dtype: bool\nBlockIndex\n"
+                   "Length: 6, dtype: bool\nBlockIndex\n"
                    "Block locations: array([0, 3]{0})\n"
                    "Block lengths: array([1, 1]{0})".format(dtype))
             self.assertEqual(result, exp)
@@ -94,7 +95,8 @@ def test_sparse_int(self):
                "Block lengths: array([1, 1]{0})".format(dtype))
         self.assertEqual(result, exp)
 
-        with option_context("display.max_rows", 3):
+        with option_context("display.max_rows", 3,
+                            "display.show_dimensions", False):
             result = repr(s)
             exp = ("0    0\n    ..\n5    0\n"
                    "dtype: int64\nBlockIndex\n"
diff --git a/pandas/tests/test_categorical.py b/pandas/tests/test_categorical.py
--- a/pandas/tests/test_categorical.py
+++ b/pandas/tests/test_categorical.py
@@ -2088,7 +2088,7 @@ def test_repr(self):
 
         a = pd.Series(pd.Categorical(["a", "b"] * 25))
         exp = u("0     a\n1     b\n" + "     ..\n" + "48    a\n49    b\n" +
-                "dtype: category\nCategories (2, object): [a, b]")
+                "Length: 50, dtype: category\nCategories (2, object): [a, b]")
         with option_context("display.max_rows", 5):
             self.assertEqual(exp, repr(a))