mirror of
				https://github.com/KevinMidboe/tableprint.git
				synced 2025-10-29 18:00:16 +00:00 
			
		
		
		
	Adds support for custom table styles
- Defines a few tablestyles which specify the different box characters to use - Modifies the table, header, and hr functions to take a key that is the name of one of these styles (instead of fixed characters) - Renames frame to dataframe - Adds some helper functions (top, bottom, and banner) for printing just the top or bottom row, or a banner with a given message, using a styled table
This commit is contained in:
		
							
								
								
									
										252
									
								
								tableprint.py
									
									
									
									
									
								
							
							
						
						
									
										252
									
								
								tableprint.py
									
									
									
									
									
								
							| @@ -1,131 +1,158 @@ | |||||||
| """ | """ | ||||||
| Tableprint | Tableprint | ||||||
|  |  | ||||||
| A module to print and display ASCII formatted tables of data | A module to print and display formatted tables of data | ||||||
|  |  | ||||||
| Usage | Usage | ||||||
| ----- | ----- | ||||||
| >>> data = np.random.randn(10,3) | >>> data = np.random.randn(10, 3) | ||||||
| >>> headers = ['Column A', 'Column B', 'Column C'] | >>> headers = ['Column A', 'Column B', 'Column C'] | ||||||
| >>> tableprint.table(data, headers) | >>> tableprint.table(data, headers) | ||||||
| """ | """ | ||||||
| from __future__ import print_function, unicode_literals | from __future__ import print_function, unicode_literals | ||||||
| from six import string_types | from six import string_types | ||||||
|  | from collections import namedtuple | ||||||
|  | from numbers import Number | ||||||
|  | import sys | ||||||
| import numpy as np | import numpy as np | ||||||
|  |  | ||||||
| __all__ = ['table', 'row', 'header', 'hr', 'humantime', 'frame'] | __all__ = ['table', 'row', 'header', 'hr', 'humantime', 'dataframe'] | ||||||
| __version__ = '0.2.1' | __version__ = '0.3.0' | ||||||
|  |  | ||||||
|  | # set up table styles | ||||||
|  | LineStyle = namedtuple('LineStyle', ('begin', 'hline', 'sep', 'end')) | ||||||
|  | TableStyle = namedtuple('TableStyle', ('top', 'below_header', 'bottom', 'row')) | ||||||
|  | DEFAULT_STYLES = { | ||||||
|  |     'grid': TableStyle( | ||||||
|  |         top=LineStyle('+', '-', '+', '+'), | ||||||
|  |         below_header=LineStyle('+', '-', '+', '+'), | ||||||
|  |         bottom=LineStyle('+', '-', '+', '+'), | ||||||
|  |         row=LineStyle('|', '', '|', '|'), | ||||||
|  |     ), | ||||||
|  |     'fancy_grid': TableStyle( | ||||||
|  |         top=LineStyle('╒', '═', '╤', '╕'), | ||||||
|  |         below_header=LineStyle('╞', '═', '╪', '╡'), | ||||||
|  |         bottom=LineStyle("╘", "═", "╧", "╛"), | ||||||
|  |         row=LineStyle('│', '', '│', '│'), | ||||||
|  |     ), | ||||||
|  |     'clean': TableStyle( | ||||||
|  |         top=LineStyle(' ', '─', ' ', ' '), | ||||||
|  |         below_header=LineStyle(' ', '─', ' ', ' '), | ||||||
|  |         bottom=LineStyle(" ", "─", " ", " "), | ||||||
|  |         row=LineStyle(' ', '', ' ', ' '), | ||||||
|  |     ), | ||||||
|  |     'banner': TableStyle( | ||||||
|  |         top=LineStyle('╒', '═', '╤', '╕'), | ||||||
|  |         below_header=LineStyle("╘", "═", "╧", "╛"), | ||||||
|  |         bottom=LineStyle("╘", "═", "╧", "╛"), | ||||||
|  |         row=LineStyle('│', '', '│', '│'), | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  | STYLE = 'fancy_grid' | ||||||
|  | WIDTH = 11 | ||||||
|  | FMT = '5g' | ||||||
|  |  | ||||||
|  |  | ||||||
| def table(data, headers, format_spec='5g', column_width=10, | def table(data, headers=None, format_spec=FMT, width=WIDTH, style=STYLE, out=sys.stdout): | ||||||
|           outer_char='\u2502', corner_char='\u253C', line_char='\u2500'): |     """Print a table with the given data | ||||||
|     """ |  | ||||||
|     Print an ASCII table with the given data |  | ||||||
|  |  | ||||||
|     Parameters |     Parameters | ||||||
|     ---------- |     ---------- | ||||||
|     data : array_like |     data : array_like | ||||||
|         An (m x n) array containing the data to print (m rows of n columns) |         An (m x n) array containing the data to print (m rows of n columns) | ||||||
|  |  | ||||||
|     headers : list |     headers : list, optional | ||||||
|         A list of n strings consisting of the header of each of the n columns |         A list of n strings consisting of the header of each of the n columns (Default: None) | ||||||
|  |  | ||||||
|     column_width : int, optional |  | ||||||
|         The width of each column in the table (Default: 10) |  | ||||||
|  |  | ||||||
|     outer_char : string, optional |  | ||||||
|         The character defining the outer border of the table (Default: '|') |  | ||||||
|  |  | ||||||
|     corner_char : string, optional |  | ||||||
|         Printed at the junctions of the table lines (Default: '+') |  | ||||||
|  |  | ||||||
|     line_char : string, optional |  | ||||||
|         Character as part of each horizontal rule (Default: '-') |  | ||||||
|  |  | ||||||
|     format_spec : string, optional |     format_spec : string, optional | ||||||
|         Format specification for formatting numbers (Default: '5g') |         Format specification for formatting numbers (Default: '5g') | ||||||
|  |  | ||||||
|  |     width : int, optional | ||||||
|  |         The width of each column in the table (Default: 11) | ||||||
|  |  | ||||||
|  |     style : string or tuple, optional | ||||||
|  |         A formatting style. (Default: 'fancy_grid') | ||||||
|  |  | ||||||
|  |     out : writer, optional | ||||||
|  |         A file handle or object that has write() and flush() methods (Default: sys.stdout) | ||||||
|     """ |     """ | ||||||
|  |     ncols = len(data[0]) if headers is None else len(headers) | ||||||
|  |     tablestyle = DEFAULT_STYLES[style] | ||||||
|  |  | ||||||
|     # get the header string |     # Initialize with a hr or the header | ||||||
|     headerstr = header(headers, column_width=column_width, outer_char=outer_char) |     tablestr = [hr(ncols, width, tablestyle.top)] \ | ||||||
|  |         if headers is None else [header(headers, width, style)] | ||||||
|  |  | ||||||
|     # parse each row |     # parse each row | ||||||
|     tablestr = [headerstr] + [row(d, column_width=column_width, format_spec=format_spec, |     tablestr += [row(d, width, format_spec, style) for d in data] | ||||||
|                               outer_char=outer_char) for d in data] |  | ||||||
|  |  | ||||||
|     # only add the final border if there was data in the table |     # only add the final border if there was data in the table | ||||||
|     if len(data) > 0: |     if len(data) > 0: | ||||||
|         tablestr += [hr(len(headers), column_width=column_width, |         tablestr += [hr(ncols, width, tablestyle.bottom)] | ||||||
|                         corner_char=corner_char, line_char=line_char)] |  | ||||||
|  |  | ||||||
|     # print the table |     # print the table | ||||||
|     print('\n'.join(tablestr)) |     out.write('\n'.join(tablestr) + '\n') | ||||||
|  |     out.flush() | ||||||
|  |  | ||||||
|  |  | ||||||
| def header(headers, column_width=10, outer_char='\u2502', add_hr=True): | def header(headers, width=WIDTH, style=STYLE, add_hr=True): | ||||||
|     """ |     """Returns a formatted row of column header strings | ||||||
|     Returns a formatted ASCII row of column header strings |  | ||||||
|  |  | ||||||
|     Parameters |     Parameters | ||||||
|     ---------- |     ---------- | ||||||
|     headers : list of strings |     headers : list of strings | ||||||
|         A list of n strings, the column headers |         A list of n strings, the column headers | ||||||
|  |  | ||||||
|     column_width : int |     width : int | ||||||
|         The width of each column (Default: 10) |         The width of each column (Default: 11) | ||||||
|  |  | ||||||
|     outer_char : string |     style : string or tuple, optional | ||||||
|         A character printed at the edges of each column (Default: '|') |         A formatting style (see DEFAULT_STYLES) | ||||||
|  |  | ||||||
|     Returns |     Returns | ||||||
|     ------- |     ------- | ||||||
|     headerstr : string |     headerstr : string | ||||||
|         A string consisting of the full header row to print |         A string consisting of the full header row to print | ||||||
|  |  | ||||||
|     """ |     """ | ||||||
|  |     tablestyle = DEFAULT_STYLES[style] | ||||||
|  |  | ||||||
|     # string formatter |     # string formatter | ||||||
|     fmt = map(lambda x: '{:<' + str(column_width) + '}', headers) |     data = map(lambda x: ('{:^%d}' % width).format(x), headers) | ||||||
|  |  | ||||||
|     # build the base string |  | ||||||
|     basestr = (' %s ' % outer_char).join(fmt) |  | ||||||
|  |  | ||||||
|     # build the formatted str |     # build the formatted str | ||||||
|     headerstr = outer_char + basestr.format(*headers) + outer_char |     headerstr = _format_line(data, tablestyle.row) | ||||||
|  |  | ||||||
|     if add_hr: |     if add_hr: | ||||||
|         hr_string = hr(len(headers), column_width=column_width) |         upper = hr(len(headers), width, tablestyle.top) | ||||||
|         headerstr = '\n'.join([hr_string, headerstr, hr_string]) |         lower = hr(len(headers), width, tablestyle.below_header) | ||||||
|  |         headerstr = '\n'.join([upper, headerstr, lower]) | ||||||
|  |  | ||||||
|     return headerstr |     return headerstr | ||||||
|  |  | ||||||
|  |  | ||||||
| def row(values, column_width=10, format_spec='5g', outer_char='\u2502'): | def row(values, width=WIDTH, format_spec=FMT, style=STYLE): | ||||||
|     """ |     """Returns a formatted row of data | ||||||
|     Returns a formatted ASCII row of data |  | ||||||
|  |  | ||||||
|     Parameters |     Parameters | ||||||
|     ---------- |     ---------- | ||||||
|     values : array_like |     values : array_like | ||||||
|         An iterable array of data (numbers of strings), each value is printed in a separate column |         An iterable array of data (numbers of strings), each value is printed in a separate column | ||||||
|  |  | ||||||
|     column_width : int |     width : int | ||||||
|         The width of each column (Default: 10) |         The width of each column (Default: 11) | ||||||
|  |  | ||||||
|     format_spec : string |     format_spec : string | ||||||
|         The precision format string used to format numbers in the values array (Default: '5g') |         The precision format string used to format numbers in the values array (Default: '5g') | ||||||
|  |  | ||||||
|     outer_char : string |     style : namedtuple, optional | ||||||
|         A character printed at the edges of each column (Default : '|') |         A line formatting style | ||||||
|  |  | ||||||
|     Returns |     Returns | ||||||
|     ------- |     ------- | ||||||
|     rowstr : string |     rowstr : string | ||||||
|         A string consisting of the full row of data to print |         A string consisting of the full row of data to print | ||||||
|  |  | ||||||
|     """ |     """ | ||||||
|  |     tablestyle = DEFAULT_STYLES[style] | ||||||
|  |  | ||||||
|     assert isinstance(format_spec, string_types) | (type(format_spec) is list), \ |     assert isinstance(format_spec, string_types) | (type(format_spec) is list), \ | ||||||
|         "format_spec must be a string or list of strings" |         "format_spec must be a string or list of strings" | ||||||
| @@ -137,60 +164,92 @@ def row(values, column_width=10, format_spec='5g', outer_char='\u2502'): | |||||||
|     def mapdata(val): |     def mapdata(val): | ||||||
|  |  | ||||||
|         # unpack |         # unpack | ||||||
|         d, prec = val |         datum, prec = val | ||||||
|  |  | ||||||
|         if isinstance(d, string_types): |         if isinstance(datum, string_types): | ||||||
|             return ('{:>%i}' % column_width).format(d) |             return ('{:>%i}' % width).format(datum) | ||||||
|  |  | ||||||
|         elif isinstance(d, (int, float, np.integer, np.float)): |         elif isinstance(datum, Number): | ||||||
|             return ('{:>%i.%s}' % (column_width, prec)).format(d) |             return ('{:>%i.%s}' % (width, prec)).format(datum) | ||||||
|  |  | ||||||
|         else: |         else: | ||||||
|             raise ValueError('Elements in the values array must be strings, ints, or floats') |             raise ValueError('Elements in the values array must be strings, ints, or floats') | ||||||
|  |  | ||||||
|     # string formatter |     # string formatter | ||||||
|     fmt = map(mapdata, zip(values, format_spec)) |     data = map(mapdata, zip(values, format_spec)) | ||||||
|  |  | ||||||
|     # build the base string |     # build the row string | ||||||
|     basestr = (' %s ' % outer_char).join(fmt) |     return _format_line(data, tablestyle.row) | ||||||
|  |  | ||||||
|     # build the formatted string |  | ||||||
|     rowstr = outer_char + basestr + outer_char |  | ||||||
|  |  | ||||||
|     return rowstr |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def hr(ncols, column_width=10, corner_char='\u253C', line_char='\u2500'): | def hr(n, width=WIDTH, linestyle=LineStyle('|', '-', '+', '|')): | ||||||
|     """ |     """Returns a formatted string used as a border between table rows | ||||||
|     Returns a formatted string used as a border between table rows |  | ||||||
|  |  | ||||||
|     Parameters |     Parameters | ||||||
|     ---------- |     ---------- | ||||||
|     ncols : int |     n : int | ||||||
|         The number of columns in the table |         The number of columns in the table | ||||||
|  |  | ||||||
|     column_width : int |     width : int | ||||||
|         The width of each column (Default: 10) |         The width of each column (Default: 11) | ||||||
|  |  | ||||||
|     corner_char : string |     linestyle : tuple | ||||||
|         A character printed at the intersection of column edges and the row border (Default: '+') |         A LineStyle namedtuple containing the characters for (begin, hr, sep, end). | ||||||
|  |         (Default: ('|', '-', '+', '|')) | ||||||
|     line_char : string |  | ||||||
|         A character printed in between column edges, defines the row border (Default: '-') |  | ||||||
|  |  | ||||||
|     Returns |     Returns | ||||||
|     ------- |     ------- | ||||||
|     rowstr : string |     rowstr : string | ||||||
|         A string consisting of the row border to print |         A string consisting of the row border to print | ||||||
|  |  | ||||||
|     """ |     """ | ||||||
|     hrstr = corner_char.join([('{:%s^%i}' % (line_char, column_width + 2)).format('') for _ in range(ncols)]) |     hrstr = linestyle.sep.join([('{:%s^%i}' % (linestyle.hline, width)).format('')] * n) | ||||||
|     return corner_char + hrstr[1:-1] + corner_char |     return linestyle.begin + hrstr + linestyle.end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def top(n, width=WIDTH, style=STYLE): | ||||||
|  |     """Prints the top row of a table""" | ||||||
|  |     return hr(n, width, linestyle=DEFAULT_STYLES[style].top) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def bottom(n, width=WIDTH, style=STYLE): | ||||||
|  |     """Prints the top row of a table""" | ||||||
|  |     return hr(n, width, linestyle=DEFAULT_STYLES[style].bottom) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def banner(message, width=30, style='banner', out=sys.stdout): | ||||||
|  |     """Prints a banner message | ||||||
|  |  | ||||||
|  |     Parameters | ||||||
|  |     ---------- | ||||||
|  |     message : string | ||||||
|  |         The message to print in the banner | ||||||
|  |  | ||||||
|  |     width : int | ||||||
|  |         The width of each column (Default: 11) | ||||||
|  |  | ||||||
|  |     style : string | ||||||
|  |         A line formatting style (Default: 'banner') | ||||||
|  |  | ||||||
|  |     out : writer | ||||||
|  |         An object that has write() and flush() methods (Default: sys.stdout) | ||||||
|  |     """ | ||||||
|  |     out.write(header([message], width, style) + '\n') | ||||||
|  |     out.flush() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def dataframe(df, **kwargs): | ||||||
|  |     """Print table with data from the given pandas DataFrame | ||||||
|  |  | ||||||
|  |     Parameters | ||||||
|  |     ---------- | ||||||
|  |     df : DataFrame | ||||||
|  |         A pandas DataFrame with the table to print | ||||||
|  |     """ | ||||||
|  |     table(np.array(df), list(df.columns), **kwargs) | ||||||
|  |  | ||||||
|  |  | ||||||
| def humantime(t): | def humantime(t): | ||||||
|     """ |     """Converts a time in seconds to a reasonable human readable time | ||||||
|     Converts a time in seconds to a reasonable human readable time |  | ||||||
|  |  | ||||||
|     Parameters |     Parameters | ||||||
|     ---------- |     ---------- | ||||||
| @@ -201,9 +260,7 @@ def humantime(t): | |||||||
|     ------- |     ------- | ||||||
|     time : string |     time : string | ||||||
|         The human readable formatted value of the given time |         The human readable formatted value of the given time | ||||||
|  |  | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         t = float(t) |         t = float(t) | ||||||
|     except (ValueError, TypeError): |     except (ValueError, TypeError): | ||||||
| @@ -248,29 +305,6 @@ def humantime(t): | |||||||
|     return timestr |     return timestr | ||||||
|  |  | ||||||
|  |  | ||||||
| def frame(dataframe, **kwargs): | def _format_line(data, linestyle): | ||||||
|     """ |     """Formats a list of elements using the given line style""" | ||||||
|     Print an ASCII table using the given pandas DataFrame |     return linestyle.begin + linestyle.sep.join(data) + linestyle.end | ||||||
|  |  | ||||||
|     Parameters |  | ||||||
|     ---------- |  | ||||||
|     dataframe : DataFrame |  | ||||||
|         A pandas DataFrame with consisting of the table to print |  | ||||||
|  |  | ||||||
|     column_width : int, optional |  | ||||||
|         The width of each column in the table (Default: 10) |  | ||||||
|  |  | ||||||
|     outer_char : string, optional |  | ||||||
|         The character defining the outer border of the table (Default: '|') |  | ||||||
|  |  | ||||||
|     corner_char : string, optional |  | ||||||
|         Printed at the junctions of the table lines (Default: '+') |  | ||||||
|  |  | ||||||
|     line_char : string, optional |  | ||||||
|         Character as part of each horizontal rule (Default: '-') |  | ||||||
|  |  | ||||||
|     format_spec : string, optional |  | ||||||
|         Format specification for formatting numbers (Default: '5g') |  | ||||||
|  |  | ||||||
|     """ |  | ||||||
|     table(np.array(dataframe), list(dataframe.columns), **kwargs) |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user