Skip to content

Commit 5771612

Browse files
committed
BUG: fix to_html justify and index args, close #1728
1 parent eec8a83 commit 5771612

File tree

3 files changed

+157
-36
lines changed

3 files changed

+157
-36
lines changed

pandas/core/format.py

+35-14
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
multiindex key at each row, default True
4444
justify : {'left', 'right'}, default None
4545
Left or right-justify the column labels. If None uses the option from
46-
the configuration in pandas.core.common, 'left' out of the box
46+
the print configuration (controlled by set_printoptions), 'right' out
47+
of the box.
4748
index_names : bool, optional
4849
Prints the names of the indexes, default True
4950
force_unicode : bool, default False
@@ -275,8 +276,11 @@ def write_th(s, indent=0):
275276
def write_td(s, indent=0):
276277
write('<td>%s</td>' % _str(s), indent)
277278

278-
def write_tr(l, indent=0, indent_delta=4, header=False):
279-
write('<tr>', indent)
279+
def write_tr(l, indent=0, indent_delta=4, header=False, align=None):
280+
if align is None:
281+
write('<tr>', indent)
282+
else:
283+
write('<tr style="text-align: %s;">' % align, indent)
280284
indent += indent_delta
281285
if header:
282286
for s in l:
@@ -294,16 +298,22 @@ def write_tr(l, indent=0, indent_delta=4, header=False):
294298
write('<table border="1">', indent)
295299

296300
def _column_header():
297-
row = [''] * (frame.index.nlevels - 1)
301+
if self.index:
302+
row = [''] * (frame.index.nlevels - 1)
303+
else:
304+
row = []
298305

299306
if isinstance(self.columns, MultiIndex):
300-
if self.has_column_names:
307+
if self.has_column_names and self.index:
301308
row.append(single_column_table(self.columns.names))
302309
else:
303310
row.append('')
304-
row.extend([single_column_table(c) for c in self.columns])
311+
style = "text-align: %s;" % self.justify
312+
row.extend([single_column_table(c, self.justify, style) for
313+
c in self.columns])
305314
else:
306-
row.append(self.columns.name or '')
315+
if self.index:
316+
row.append(self.columns.name or '')
307317
row.extend(self.columns)
308318
return row
309319

@@ -324,7 +334,12 @@ def _column_header():
324334

325335
col_row = _column_header()
326336
indent += indent_delta
327-
write_tr(col_row, indent, indent_delta, header=True)
337+
if isinstance(self.columns, MultiIndex):
338+
align = None
339+
else:
340+
align = self.justify
341+
write_tr(col_row, indent, indent_delta, header=True,
342+
align=align)
328343
if self.has_index_names:
329344
row = frame.index.names + [''] * len(self.columns)
330345
write_tr(row, indent, indent_delta, header=True)
@@ -351,10 +366,11 @@ def _maybe_bold_row(x):
351366
# write values
352367
for i in range(len(frame)):
353368
row = []
354-
if isinstance(frame.index, MultiIndex):
355-
row.extend(_maybe_bold_row(frame.index[i]))
356-
else:
357-
row.append(_maybe_bold_row(frame.index[i]))
369+
if self.index:
370+
if isinstance(frame.index, MultiIndex):
371+
row.extend(_maybe_bold_row(frame.index[i]))
372+
else:
373+
row.append(_maybe_bold_row(frame.index[i]))
358374
for j in range(len(self.columns)):
359375
row.append(fmt_values[j][i])
360376
write_tr(row, indent, indent_delta)
@@ -655,8 +671,13 @@ def _cond(values):
655671
return [x[:-1] if x.endswith('.') and x != na_rep else x for x in trimmed]
656672

657673

658-
def single_column_table(column):
659-
table = '<table><tbody>'
674+
def single_column_table(column, align=None, style=None):
675+
table = '<table'
676+
if align is not None:
677+
table += (' align="%s"' % align)
678+
if style is not None:
679+
table += (' style="%s"' % style)
680+
table += '><tbody>'
660681
for i in column:
661682
table += ('<tr><td>%s</td></tr>' % str(i))
662683
table += '</tbody></table>'

pandas/core/frame.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -1240,7 +1240,7 @@ def to_string(self, buf=None, columns=None, col_space=None, colSpace=None,
12401240
def to_html(self, buf=None, columns=None, col_space=None, colSpace=None,
12411241
header=True, index=True, na_rep='NaN', formatters=None,
12421242
float_format=None, sparsify=None, index_names=True,
1243-
bold_rows=True):
1243+
justify=None, force_unicode=False, bold_rows=True):
12441244
"""
12451245
to_html-specific options
12461246
bold_rows : boolean, default True
@@ -1257,12 +1257,13 @@ def to_html(self, buf=None, columns=None, col_space=None, colSpace=None,
12571257

12581258
formatter = fmt.DataFrameFormatter(self, buf=buf, columns=columns,
12591259
col_space=col_space, na_rep=na_rep,
1260-
header=header, index=index,
12611260
formatters=formatters,
12621261
float_format=float_format,
1263-
bold_rows=bold_rows,
12641262
sparsify=sparsify,
1265-
index_names=index_names)
1263+
justify=justify,
1264+
index_names=index_names,
1265+
header=header, index=index,
1266+
bold_rows=bold_rows)
12661267
formatter.to_html()
12671268

12681269
if buf is None:

pandas/tests/test_format.py

+117-18
Original file line numberDiff line numberDiff line change
@@ -412,20 +412,24 @@ def test_to_html_multiindex(self):
412412
np.mod(range(4), 2)),
413413
names=['CL0', 'CL1'])
414414
df = pandas.DataFrame([list('abcd'), list('efgh')], columns=columns)
415-
result = df.to_html()
415+
result = df.to_html(justify='left')
416416
expected = ('<table border="1">\n'
417417
' <thead>\n'
418418
' <tr>\n'
419419
' <th><table><tbody><tr><td>CL0</td></tr><tr>'
420420
'<td>CL1</td></tr></tbody></table></th>\n'
421-
' <th><table><tbody><tr><td>0</td></tr><tr>'
422-
'<td>0</td></tr></tbody></table></th>\n'
423-
' <th><table><tbody><tr><td>1</td></tr><tr>'
424-
'<td>1</td></tr></tbody></table></th>\n'
425-
' <th><table><tbody><tr><td>2</td></tr><tr>'
426-
'<td>0</td></tr></tbody></table></th>\n'
427-
' <th><table><tbody><tr><td>3</td></tr><tr>'
428-
'<td>1</td></tr></tbody></table></th>\n'
421+
' <th><table align="left" style="text-align: left;">'
422+
'<tbody><tr><td>0</td></tr><tr><td>0</td></tr></tbody>'
423+
'</table></th>\n'
424+
' <th><table align="left" style="text-align: left;">'
425+
'<tbody><tr><td>1</td></tr><tr><td>1</td></tr></tbody>'
426+
'</table></th>\n'
427+
' <th><table align="left" style="text-align: left;">'
428+
'<tbody><tr><td>2</td></tr><tr><td>0</td></tr></tbody>'
429+
'</table></th>\n'
430+
' <th><table align="left" style="text-align: left;">'
431+
'<tbody><tr><td>3</td></tr><tr><td>1</td></tr></tbody>'
432+
'</table></th>\n'
429433
' </tr>\n'
430434
' </thead>\n'
431435
' <tbody>\n'
@@ -445,24 +449,29 @@ def test_to_html_multiindex(self):
445449
' </tr>\n'
446450
' </tbody>\n'
447451
'</table>')
452+
448453
self.assertEqual(result, expected)
449454

450455
columns = pandas.MultiIndex.from_tuples(zip(range(4),
451456
np.mod(range(4), 2)))
452457
df = pandas.DataFrame([list('abcd'), list('efgh')], columns=columns)
453-
result = df.to_html()
458+
result = df.to_html(justify='right')
454459
expected = ('<table border="1">\n'
455460
' <thead>\n'
456461
' <tr>\n'
457462
' <th></th>\n'
458-
' <th><table><tbody><tr><td>0</td></tr>'
459-
'<tr><td>0</td></tr></tbody></table></th>\n'
460-
' <th><table><tbody><tr><td>1</td></tr>'
461-
'<tr><td>1</td></tr></tbody></table></th>\n'
462-
' <th><table><tbody><tr><td>2</td></tr>'
463-
'<tr><td>0</td></tr></tbody></table></th>\n'
464-
' <th><table><tbody><tr><td>3</td></tr>'
465-
'<tr><td>1</td></tr></tbody></table></th>\n'
463+
' <th><table align="right" style="text-align:'
464+
' right;"><tbody><tr><td>0</td></tr><tr><td>0</td></tr>'
465+
'</tbody></table></th>\n'
466+
' <th><table align="right" style="text-align:'
467+
' right;"><tbody><tr><td>1</td></tr><tr><td>1</td></tr>'
468+
'</tbody></table></th>\n'
469+
' <th><table align="right" style="text-align:'
470+
' right;"><tbody><tr><td>2</td></tr><tr><td>0</td></tr>'
471+
'</tbody></table></th>\n'
472+
' <th><table align="right" style="text-align:'
473+
' right;"><tbody><tr><td>3</td></tr><tr><td>1</td></tr>'
474+
'</tbody></table></th>\n'
466475
' </tr>\n'
467476
' </thead>\n'
468477
' <tbody>\n'
@@ -482,8 +491,98 @@ def test_to_html_multiindex(self):
482491
' </tr>\n'
483492
' </tbody>\n'
484493
'</table>')
494+
495+
self.assertEqual(result, expected)
496+
497+
def test_to_html_justify(self):
498+
df = pandas.DataFrame({'A': [6, 30000, 2],
499+
'B': [1, 2, 70000],
500+
'C': [223442, 0, 1]},
501+
columns=['A', 'B', 'C'])
502+
result = df.to_html(justify='left')
503+
expected = ('<table border="1">\n'
504+
' <thead>\n'
505+
' <tr style="text-align: left;">\n'
506+
' <th></th>\n'
507+
' <th>A</th>\n'
508+
' <th>B</th>\n'
509+
' <th>C</th>\n'
510+
' </tr>\n'
511+
' </thead>\n'
512+
' <tbody>\n'
513+
' <tr>\n'
514+
' <td><strong>0</strong></td>\n'
515+
' <td> 6</td>\n'
516+
' <td> 1</td>\n'
517+
' <td> 223442</td>\n'
518+
' </tr>\n'
519+
' <tr>\n'
520+
' <td><strong>1</strong></td>\n'
521+
' <td> 30000</td>\n'
522+
' <td> 2</td>\n'
523+
' <td> 0</td>\n'
524+
' </tr>\n'
525+
' <tr>\n'
526+
' <td><strong>2</strong></td>\n'
527+
' <td> 2</td>\n'
528+
' <td> 70000</td>\n'
529+
' <td> 1</td>\n'
530+
' </tr>\n'
531+
' </tbody>\n'
532+
'</table>')
533+
534+
self.assertEqual(result, expected)
535+
536+
result = df.to_html(justify='right')
537+
expected = ('<table border="1">\n'
538+
' <thead>\n'
539+
' <tr style="text-align: right;">\n'
540+
' <th></th>\n'
541+
' <th>A</th>\n'
542+
' <th>B</th>\n'
543+
' <th>C</th>\n'
544+
' </tr>\n'
545+
' </thead>\n'
546+
' <tbody>\n'
547+
' <tr>\n'
548+
' <td><strong>0</strong></td>\n'
549+
' <td> 6</td>\n'
550+
' <td> 1</td>\n'
551+
' <td> 223442</td>\n'
552+
' </tr>\n'
553+
' <tr>\n'
554+
' <td><strong>1</strong></td>\n'
555+
' <td> 30000</td>\n'
556+
' <td> 2</td>\n'
557+
' <td> 0</td>\n'
558+
' </tr>\n'
559+
' <tr>\n'
560+
' <td><strong>2</strong></td>\n'
561+
' <td> 2</td>\n'
562+
' <td> 70000</td>\n'
563+
' <td> 1</td>\n'
564+
' </tr>\n'
565+
' </tbody>\n'
566+
'</table>')
485567
self.assertEqual(result, expected)
486568

569+
def test_to_html_index(self):
570+
index = ['foo', 'bar', 'baz']
571+
df = pandas.DataFrame({'A': [1, 2, 3],
572+
'B': [1.2, 3.4, 5.6],
573+
'C': ['one', 'two', np.NaN]},
574+
columns=['A', 'B', 'C'],
575+
index = index)
576+
result = df.to_html(index=False)
577+
for i in index:
578+
self.assert_(i not in result)
579+
580+
tuples = [('foo', 'car'), ('foo', 'bike'), ('bar' ,'car')]
581+
df.index = pandas.MultiIndex.from_tuples(tuples)
582+
result = df.to_html(index=False)
583+
for i in ['foo', 'bar', 'car', 'bike']:
584+
self.assert_(i not in result)
585+
487586
def test_repr_html(self):
488587
self.frame._repr_html_()
489588

0 commit comments

Comments
 (0)