Skip to content

Commit

Permalink
Merge d296879 into 85c4430
Browse files Browse the repository at this point in the history
  • Loading branch information
agroener committed Mar 26, 2015
2 parents 85c4430 + d296879 commit 05665e1
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Expand Up @@ -570,6 +570,8 @@ New Features
- ``astropy.tests``

- Added a new Quantity-aware ``assert_quantity_allclose``. [#3273]
- Added column alignment formatting for better pprint viewing
experience. [#3037]

- ``astropy.time``

Expand Down
97 changes: 84 additions & 13 deletions astropy/table/pprint.py
Expand Up @@ -185,7 +185,7 @@ def _get_pprint_size(max_lines=None, max_width=None):


def _pformat_col(self, col, max_lines=None, show_name=True, show_unit=None,
show_dtype=False, show_length=None, html=False):
show_dtype=False, show_length=None, html=False, align=None):
"""Return a list of formatted string representation of column values.
Parameters
Expand All @@ -211,6 +211,11 @@ def _pformat_col(self, col, max_lines=None, show_name=True, show_unit=None,
html : bool
Output column as HTML
align : str or list
Left/right alignment of a column. Default is 'right'. A list
of strings can be provided for alignment of tables with multiple
columns.
Returns
-------
lines : list
Expand All @@ -224,10 +229,14 @@ def _pformat_col(self, col, max_lines=None, show_name=True, show_unit=None,
show_unit = getattr(col, 'unit', None) is not None

outs = {} # Some values from _pformat_col_iter iterator that are needed here
col_strs_iter = self._pformat_col_iter(col, max_lines, show_name=show_name, show_unit=show_unit,
show_dtype=show_dtype, show_length=show_length,
col_strs_iter = self._pformat_col_iter(col, max_lines, show_name=show_name,
show_unit=show_unit,
show_dtype=show_dtype,
show_length=show_length,
outs=outs)
col_strs = list(col_strs_iter)
if len(col_strs) > 0:
col_width = max(len(x) for x in col_strs)

if html:
from ..utils.xml.writer import xml_escape
Expand All @@ -249,6 +258,7 @@ def _pformat_col(self, col, max_lines=None, show_name=True, show_unit=None,
col_strs.insert(0, '<table>')
col_strs.append('</table>')

# Now bring all the column string values to the same fixed width
else:
col_width = max(len(x) for x in col_strs) if col_strs else 1

Expand All @@ -258,10 +268,46 @@ def _pformat_col(self, col, max_lines=None, show_name=True, show_unit=None,
if outs['i_dashes'] is not None:
col_strs[outs['i_dashes']] = '-' * col_width

# Now bring all the column string values to the same fixed width
# Format columns according to alignment
justify_methods = {'<': 'ljust', '^': 'center', '>': 'rjust'}
for i, col_str in enumerate(col_strs):
col_strs[i] = col_str.rjust(col_width)

if align is None:
try:
if col.format[:2] == '0=':
justify = (lambda col_str, col_width:
getattr(col_str, 'zfill')(col_width))
else:
justify_method = justify_methods.get(col.format[0], None)
if justify_method is None:
justify_method = justify_methods[col.format[1]]
justify = (lambda col_str, col_width:
getattr(col_str, justify_method)(col_width,
col.format[0]))
else:
justify = (lambda col_str, col_width:
getattr(col_str, justify_method)(col_width))
except:
justify = (lambda col_str, col_width:
getattr(col_str, 'rjust')(col_width))
else:
if align == '0=':
justify = (lambda col_str, col_width:
getattr(col_str, 'zfill')(col_width))
elif align in ['<','^','>']:
justify_method = justify_methods.get(align, None)
if justify_method is None:
justify_method = justify_methods[col.format[1]]
justify = (lambda col_str, col_width:
getattr(col_str, justify_method)(col_width,
col.format[0]))
else:
justify = (lambda col_str, col_width:
getattr(col_str, justify_method)(col_width))
else:
justify = (lambda col_str, col_width:
getattr(col_str, 'rjust')(col_width))
col_strs[i] = justify(col_str, col_width)

if outs['show_length']:
col_strs.append('Length = {0} rows'.format(len(col)))

Expand Down Expand Up @@ -376,7 +422,7 @@ def _pformat_col_iter(self, col, max_lines, show_name, show_unit, outs,

def _pformat_table(self, table, max_lines=None, max_width=None, show_name=True,
show_unit=None, show_dtype=False,
html=False, tableid=None):
html=False, tableid=None, align='right'):
"""Return a list of lines for the formatted string representation of
the table.
Expand Down Expand Up @@ -407,6 +453,11 @@ def _pformat_table(self, table, max_lines=None, max_width=None, show_name=True,
"table{id}", where id is the unique integer id of the table object,
id(table)
align : str or list
Left/right alignment of a column. Default is 'right'. A list
of strings can be provided for alignment of tables with multiple
columns.
Returns
-------
out : str
Expand All @@ -423,12 +474,32 @@ def _pformat_table(self, table, max_lines=None, max_width=None, show_name=True,
if show_unit is None:
show_unit = any([getattr(col, 'unit', None) for col in six.itervalues(table.columns)])

for col in six.itervalues(table.columns):
lines, outs = self._pformat_col(col, max_lines, show_name=show_name,
show_unit=show_unit, show_dtype=show_dtype)
if outs['show_length']:
lines = lines[:-1]
cols.append(lines)
# Figure out align
if isinstance(align,str):
align = align
elif isinstance(align,list) and len(align) == 1:
align = align[0]
elif isinstance(align,list) and len(align) == len(table.columns.values()):
align = align
else:
align = 'right'

# If align remains a list, need to loop over values
if type(align) == list:
for i,col in enumerate(table.columns.values()):
lines, outs = self._pformat_col(col, max_lines, show_name=show_name,
show_unit=show_unit, show_dtype=show_dtype,
align=align[i])
if outs['show_length']:
lines = lines[:-1]
cols.append(lines)
else:
for col in six.itervalues(table.columns):
lines, outs = self._pformat_col(col, max_lines, show_name=show_name,
show_unit=show_unit, show_dtype=show_dtype)
if outs['show_length']:
lines = lines[:-1]
cols.append(lines)

if not cols:
return ['<No columns>'], {'show_length': False}
Expand Down
17 changes: 13 additions & 4 deletions astropy/table/table.py
Expand Up @@ -635,7 +635,7 @@ def _is_mixin_column(self, col, quantity_is_mixin=False):
return is_mixin

def pprint(self, max_lines=None, max_width=None, show_name=True,
show_unit=None, show_dtype=False):
show_unit=None, show_dtype=False, align='right'):
"""Print a formatted string representation of the table.
If no value of ``max_lines`` is supplied then the height of the
Expand Down Expand Up @@ -666,14 +666,18 @@ def pprint(self, max_lines=None, max_width=None, show_name=True,
show_dtype : bool
Include a header row for column dtypes (default=True)
align : str
Left/right alignment of a column. Default is 'right'.
"""
lines, outs = self.formatter._pformat_table(self, max_lines, max_width,
show_name=show_name, show_unit=show_unit,
show_dtype=show_dtype)
show_dtype=show_dtype, align=align)
if outs['show_length']:
lines.append('Length = {0} rows'.format(len(self)))

n_header = outs['n_header']

for i, line in enumerate(lines):
if i < n_header:
color_print(line, 'red')
Expand Down Expand Up @@ -740,7 +744,8 @@ def show_in_browser(self,
webbrowser.get(browser).open("file://" + path)

def pformat(self, max_lines=None, max_width=None, show_name=True,
show_unit=None, show_dtype=False, html=False, tableid=None):
show_unit=None, show_dtype=False, html=False, tableid=None,
align='right'):
"""Return a list of lines for the formatted string representation of
the table.
Expand Down Expand Up @@ -781,16 +786,20 @@ def pformat(self, max_lines=None, max_width=None, show_name=True,
"table{id}", where id is the unique integer id of the table object,
id(self)
align : str
Left/right alignment of a column. Default is 'right'.
Returns
-------
lines : list
Formatted table as a list of strings
"""

lines, outs = self.formatter._pformat_table(self, max_lines, max_width,
show_name=show_name, show_unit=show_unit,
show_dtype=show_dtype, html=html,
tableid=tableid)
tableid=tableid, align=align)

if outs['show_length']:
lines.append('Length = {0} rows'.format(len(self)))
Expand Down
13 changes: 13 additions & 0 deletions astropy/table/tests/test_pprint.py
Expand Up @@ -370,6 +370,19 @@ def test_column_format_func_not_str(self, table_type):
with pytest.raises(ValueError):
str(t['a'])

def test_column_alignment(self, table_type):
t = table_type([[1], [2], [3], [4]],
names=('long title a', 'long title b',
'long title c', 'long title d'))
t['long title a'].format = '<'
t['long title b'].format = '^'
t['long title c'].format = '>'
t['long title d'].format = '0='
assert str(t['long title a']) == 'long title a\n------------\n1 '
assert str(t['long title b']) == 'long title b\n------------\n 2 '
assert str(t['long title c']) == 'long title c\n------------\n 3'
assert str(t['long title d']) == 'long title d\n------------\n000000000004'


class TestFormatWithMaskedElements():

Expand Down
2 changes: 1 addition & 1 deletion astropy_helpers
Submodule astropy_helpers updated 37 files
+19 −34 .travis.yml
+3 −48 CHANGES.rst
+30 −79 ah_bootstrap.py
+0 −52 appveyor.yml
+2 −6 astropy_helpers/commands/build_ext.py
+2 −2 astropy_helpers/commands/build_sphinx.py
+0 −4 astropy_helpers/commands/setup_package.py
+1 −1 astropy_helpers/distutils_helpers.py
+7 −40 astropy_helpers/git_helpers.py
+3 −3 astropy_helpers/setup_helpers.py
+0 −1 astropy_helpers/sphinx/conf.py
+2 −17 astropy_helpers/sphinx/ext/astropyautosummary.py
+0 −56 astropy_helpers/sphinx/ext/autodoc_enhancements.py
+2 −2 astropy_helpers/sphinx/ext/automodapi.py
+3 −14 astropy_helpers/sphinx/ext/automodsumm.py
+0 −56 astropy_helpers/sphinx/ext/tests/test_autodoc_enhancements.py
+6 −6 astropy_helpers/sphinx/ext/tests/test_automodapi.py
+1 −1 astropy_helpers/sphinx/ext/viewcode.py
+ astropy_helpers/sphinx/local/python3links.inv
+0 −7 astropy_helpers/sphinx/local/python3links.txt
+0 −0 astropy_helpers/src/__init__.py
+0 −0 astropy_helpers/src/compiler.c
+2 −0 astropy_helpers/src/setup_package.py
+0 −36 astropy_helpers/tests/__init__.py
+2 −11 astropy_helpers/tests/test_ah_bootstrap.py
+26 −85 astropy_helpers/tests/test_git_helpers.py
+44 −102 astropy_helpers/tests/test_setup_helpers.py
+23 −321 astropy_helpers/utils.py
+55 −127 astropy_helpers/version_helpers.py
+0 −71 continuous-integration/appveyor/install-miniconda.ps1
+0 −47 continuous-integration/appveyor/windows_sdk.cmd
+0 −7 continuous-integration/travis/install_conda_linux.sh
+0 −7 continuous-integration/travis/install_conda_osx.sh
+0 −4 continuous-integration/travis/install_graphviz_linux.sh
+0 −4 continuous-integration/travis/install_graphviz_osx.sh
+3 −6 setup.py
+2 −7 tox.ini
43 changes: 43 additions & 0 deletions docs/table/access_table.rst
Expand Up @@ -374,6 +374,49 @@ For columns the syntax and behavior of
2973.0
Length = 100 rows

Column alignment
''''''''''''''''

Individual columns have the ability to be aligned in a number of different
ways, for an enhanced viewing experience.

>>> t1 = Table()
>>> t1['long column name 1'] = [1,2,3]
>>> t1['long column name 2'] = [4,5,6]
>>> t1['long column name 3'] = [7,8,9]
>>> t1['long column name 4'] = [700000,800000,900000]
>>> t1['long column name 2'].format = '<'
>>> t1['long column name 3'].format = '0='
>>> t1['long column name 4'].format = '^'
>>> t1.pprint()
long column name 1 long column name 2 long column name 3 long column name 4
------------------ ------------------ ------------------ ------------------
1 4 000000000000000007 700000
2 5 000000000000000008 800000
3 6 000000000000000009 900000

Conveniently, alignment can be handled another way, by passing a list to the
keyword argument ``align``.

>>> t1 = Table()
>>> t1['column1'] = [1,2,3,4,5]
>>> t1['column2'] = [2,4,6,8,10]
>>> t1.pprint(align=['<','0='])
column1 column2
------- -------
1 0000002
2 0000004
3 0000006
4 0000008
5 0000010

By default, if the length of the list does not match the number of columns
within the table, alignment defaults to right-aligned columns. This default
behavior also holds true even if a single alignment character is passed in as a
list (e.g., align=['^']), where global alignment of all columns within a table
is intended. For very large tables, this can be a nuissance, and so looping is the
recommended solution for this task.

pformat() method
''''''''''''''''

Expand Down

0 comments on commit 05665e1

Please sign in to comment.