Skip to content

Commit 5933782

Browse files
committed
Add repr footer showing total number of rows and columns
1 parent 6cee3e1 commit 5933782

File tree

3 files changed

+36
-14
lines changed

3 files changed

+36
-14
lines changed

pandas/core/format.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#coding: utf-8
12
from __future__ import print_function
23
# pylint: disable=W0141
34

@@ -264,7 +265,7 @@ def __init__(self, frame, buf=None, columns=None, col_space=None,
264265
header=True, index=True, na_rep='NaN', formatters=None,
265266
justify=None, float_format=None, sparsify=None,
266267
index_names=True, line_width=None, max_rows=None, max_cols=None,
267-
**kwds):
268+
show_dimensions=False, **kwds):
268269
self.frame = frame
269270
self.buf = buf if buf is not None else StringIO()
270271
self.show_index_names = index_names
@@ -283,6 +284,7 @@ def __init__(self, frame, buf=None, columns=None, col_space=None,
283284
self.line_width = line_width
284285
self.max_rows = max_rows
285286
self.max_cols = max_cols
287+
self.show_dimensions = show_dimensions
286288

287289
if justify is None:
288290
self.justify = get_option("display.colheader_justify")
@@ -311,6 +313,7 @@ def _to_str_columns(self):
311313
cols_to_show = self.columns[:self.max_cols]
312314
truncate_h = self.max_cols and (len(self.columns) > self.max_cols)
313315
truncate_v = self.max_rows and (len(self.frame) > self.max_rows)
316+
self.truncated_v = truncate_v
314317
if truncate_h:
315318
cols_to_show = self.columns[:self.max_cols]
316319
else:
@@ -377,6 +380,10 @@ def to_string(self, force_unicode=None):
377380

378381
self.buf.writelines(text)
379382

383+
if self.show_dimensions:
384+
self.buf.write("\n\n[%d rows x %d columns]" \
385+
% (len(frame), len(frame.columns)) )
386+
380387
def _join_multiline(self, *strcols):
381388
lwidth = self.line_width
382389
adjoin_width = 1
@@ -671,6 +678,8 @@ def write_result(self, buf):
671678
'not %s') % type(self.classes))
672679
_classes.extend(self.classes)
673680

681+
682+
674683
self.write('<table border="1" class="%s">' % ' '.join(_classes),
675684
indent)
676685

@@ -687,6 +696,10 @@ def write_result(self, buf):
687696
indent = self._write_body(indent)
688697

689698
self.write('</table>', indent)
699+
if self.fmt.show_dimensions:
700+
by = chr(215) if compat.PY3 else unichr(215) # ×
701+
self.write(u('<p>%d rows %s %d columns</p>') %
702+
(len(frame), by, len(frame.columns)) )
690703
_put_lines(buf, self.elements)
691704

692705
def _write_header(self, indent):

pandas/core/frame.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ def __unicode__(self):
454454
else:
455455
width = None
456456
self.to_string(buf=buf, max_rows=max_rows, max_cols=max_cols,
457-
line_width=width)
457+
line_width=width, show_dimensions=True)
458458

459459
return buf.getvalue()
460460

@@ -485,7 +485,8 @@ def _repr_html_(self):
485485

486486
return ('<div style="max-height:1000px;'
487487
'max-width:1500px;overflow:auto;">\n' +
488-
self.to_html(max_rows=max_rows, max_cols=max_cols) \
488+
self.to_html(max_rows=max_rows, max_cols=max_cols,
489+
show_dimensions=True) \
489490
+ '\n</div>')
490491
else:
491492
return None
@@ -1254,7 +1255,8 @@ def to_string(self, buf=None, columns=None, col_space=None, colSpace=None,
12541255
header=True, index=True, na_rep='NaN', formatters=None,
12551256
float_format=None, sparsify=None, nanRep=None,
12561257
index_names=True, justify=None, force_unicode=None,
1257-
line_width=None, max_rows=None, max_cols=None):
1258+
line_width=None, max_rows=None, max_cols=None,
1259+
show_dimensions=False):
12581260
"""
12591261
Render a DataFrame to a console-friendly tabular output.
12601262
"""
@@ -1281,7 +1283,8 @@ def to_string(self, buf=None, columns=None, col_space=None, colSpace=None,
12811283
index_names=index_names,
12821284
header=header, index=index,
12831285
line_width=line_width,
1284-
max_rows=max_rows, max_cols=max_cols)
1286+
max_rows=max_rows, max_cols=max_cols,
1287+
show_dimensions=show_dimensions)
12851288
formatter.to_string()
12861289

12871290
if buf is None:
@@ -1293,7 +1296,8 @@ def to_html(self, buf=None, columns=None, col_space=None, colSpace=None,
12931296
header=True, index=True, na_rep='NaN', formatters=None,
12941297
float_format=None, sparsify=None, index_names=True,
12951298
justify=None, force_unicode=None, bold_rows=True,
1296-
classes=None, escape=True, max_rows=None, max_cols=None):
1299+
classes=None, escape=True, max_rows=None, max_cols=None,
1300+
show_dimensions=False):
12971301
"""
12981302
Render a DataFrame as an HTML table.
12991303
@@ -1332,7 +1336,8 @@ def to_html(self, buf=None, columns=None, col_space=None, colSpace=None,
13321336
header=header, index=index,
13331337
bold_rows=bold_rows,
13341338
escape=escape,
1335-
max_rows=max_rows, max_cols=max_cols)
1339+
max_rows=max_rows, max_cols=max_cols,
1340+
show_dimensions=show_dimensions)
13361341
formatter.to_html(classes=classes)
13371342

13381343
if buf is None:

pandas/tests/test_format.py

+11-7
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def has_horizontally_truncated_repr(df):
4141

4242
def has_vertically_truncated_repr(df):
4343
r = repr(df)
44-
return '..' in r.splitlines()[-1]
44+
return '..' in r.splitlines()[-3]
4545

4646
def has_truncated_repr(df):
4747
return has_horizontally_truncated_repr(df) or has_vertically_truncated_repr(df)
@@ -128,16 +128,16 @@ def test_repr_truncation(self):
128128
def test_repr_chop_threshold(self):
129129
df = DataFrame([[0.1, 0.5],[0.5, -0.1]])
130130
pd.reset_option("display.chop_threshold") # default None
131-
self.assertEqual(repr(df), ' 0 1\n0 0.1 0.5\n1 0.5 -0.1')
131+
self.assertEqual(repr(df), ' 0 1\n0 0.1 0.5\n1 0.5 -0.1\n\n[2 rows x 2 columns]')
132132

133133
with option_context("display.chop_threshold", 0.2 ):
134-
self.assertEqual(repr(df), ' 0 1\n0 0.0 0.5\n1 0.5 0.0')
134+
self.assertEqual(repr(df), ' 0 1\n0 0.0 0.5\n1 0.5 0.0\n\n[2 rows x 2 columns]')
135135

136136
with option_context("display.chop_threshold", 0.6 ):
137-
self.assertEqual(repr(df), ' 0 1\n0 0 0\n1 0 0')
137+
self.assertEqual(repr(df), ' 0 1\n0 0 0\n1 0 0\n\n[2 rows x 2 columns]')
138138

139139
with option_context("display.chop_threshold", None ):
140-
self.assertEqual(repr(df), ' 0 1\n0 0.1 0.5\n1 0.5 -0.1')
140+
self.assertEqual(repr(df), ' 0 1\n0 0.1 0.5\n1 0.5 -0.1\n\n[2 rows x 2 columns]')
141141

142142
def test_repr_obeys_max_seq_limit(self):
143143
import pandas.core.common as com
@@ -775,6 +775,8 @@ def test_wide_repr(self):
775775
df = DataFrame([col(max_cols-1, 25) for _ in range(10)])
776776
set_option('display.expand_frame_repr', False)
777777
rep_str = repr(df)
778+
print(rep_str)
779+
assert "10 rows x %d columns" % (max_cols-1) in rep_str
778780
set_option('display.expand_frame_repr', True)
779781
wide_repr = repr(df)
780782
self.assert_(rep_str != wide_repr)
@@ -790,7 +792,7 @@ def test_wide_repr_wide_columns(self):
790792
df = DataFrame(randn(5, 3), columns=['a' * 90, 'b' * 90, 'c' * 90])
791793
rep_str = repr(df)
792794

793-
self.assert_(len(rep_str.splitlines()) == 20)
795+
self.assertEqual(len(rep_str.splitlines()), 22)
794796

795797
def test_wide_repr_named(self):
796798
with option_context('mode.sim_interactive', True):
@@ -1450,6 +1452,8 @@ def test_repr_html_long(self):
14501452
long_repr = df._repr_html_()
14511453
assert '...' in long_repr
14521454
assert str(40 + h) not in long_repr
1455+
assert u('%d rows ') % h in long_repr
1456+
assert u('2 columns') in long_repr
14531457

14541458
def test_repr_html_long_multiindex(self):
14551459
max_rows = get_option('display.max_rows')
@@ -1565,7 +1569,7 @@ def test_float_trim_zeros(self):
15651569
vals = [2.08430917305e+10, 3.52205017305e+10, 2.30674817305e+10,
15661570
2.03954217305e+10, 5.59897817305e+10]
15671571
skip = True
1568-
for line in repr(DataFrame({'A': vals})).split('\n'):
1572+
for line in repr(DataFrame({'A': vals})).split('\n')[:-2]:
15691573
if line.startswith('dtype:'):
15701574
continue
15711575
if _three_digit_exp():

0 commit comments

Comments
 (0)