yiningmao's picture
Upload 34 files
c5db72e
import numpy as np
from collections import OrderedDict
class ResultTable:
"""
Class to save and show result neatly.
First column is always 'NAME' column.
"""
def __init__(self, table_name='table', header=None, splitter='||', int_formatter='%3d', float_formatter='%.4f'):
"""
Initialize table setting.
:param list header: list of string, table headers.
:param str splitter:
:param str int_formatter:
:param str float_formatter:
"""
self.table_name = table_name
self.header = header
if self.header is not None:
self.set_headers(self.header)
self.num_rows = 0
self.splitter = splitter
self.int_formatter = int_formatter
self.float_formatter = float_formatter
def set_headers(self, header):
"""
Set table headers as given and clear all data.
:param list header: list of header strings
:return: None
"""
self.header = header
if 'NAME' not in header:
self.header = ['NAME'] + self.header
self.data = OrderedDict([(h, []) for h in self.header])
self.max_len = OrderedDict([(h, len(h)) for h in self.header])
# {h: len(h) for h in self.header}
def add_row(self, row_name, row_dict):
"""
Add new row into the table.
:param str row_name: name of the row, which will be the first column
:param dict row_dict: dictionary containing column name as a key and column value as value.
:return: None
"""
# If header is not defined, fetch from input dict
if self.header is None:
self.set_headers(list(row_dict.keys()))
# If input dict has new column, make one
for key in row_dict:
if key not in self.data:
self.set_headers(self.header + [key])
for h in self.header:
if h == 'NAME':
self.data['NAME'].append(row_name)
self.max_len[h] = max(self.max_len['NAME'], len(row_name))
else:
# If input dict doesn't have values for table header, make empty value.
if h not in row_dict:
row_dict[h] = '-'
# convert input dict to string
d = row_dict[h]
if isinstance(d, (int, np.integer)):
d_str = self.int_formatter % d
elif isinstance(d, (float, np.float)):
d_str = self.float_formatter % d
elif isinstance(d, str):
d_str = d
elif isinstance(d, list):
d_str = str(d)
else:
raise NotImplementedError('data type currently not supported. %s' % str(type(d)))
self.data[h].append(d_str)
self.max_len[h] = max(self.max_len[h], len(d_str))
self.num_rows += 1
def row_to_line(self, row_values):
"""
Convert a row into string form
:param list row_values: list of row values as string
:return: string form of a row
"""
value_str = []
for i, header in enumerate(self.header):
max_length = self.max_len[header]
length = len(row_values[i])
diff = max_length - length
# Center align
# left_space = diff // 2
# right_space = diff - left_space
# s = ' ' * left_space + row_values[i] + ' ' * right_space
# Left align
s = row_values[i] + ' ' * diff
value_str.append(s)
# for i, max_length in enumerate(self.max_len.values()):
# length = len(row_values[i])
# diff = max_length - length
#
# # Center align
# # left_space = diff // 2
# # right_space = diff - left_space
# # s = ' ' * left_space + row_values[i] + ' ' * right_space
#
# # Left align
# s = row_values[i] + ' ' * diff
# value_str.append(s)
return self.splitter + ' ' + (' %s ' % self.splitter).join(value_str) + ' ' + self.splitter
def to_string(self):
"""
Convert a table into string form
:return: string form of the table
"""
size_per_col = {h: self.max_len[h] + 2 + len(self.splitter) for h in self.header}
line_len = sum([size_per_col[c] for c in size_per_col]) + len(self.splitter)
table_str = '\n'
# TABLE NAME
table_str += self.table_name + '\n'
# HEADER
line = self.row_to_line(self.header)
table_str += '=' * line_len + '\n'
table_str += line + '\n'
table_str += self.splitter + '-' * (line_len - len(self.splitter) * 2) + self.splitter + '\n'
# DATA
for row_values in zip(*self.data.values()):
line = self.row_to_line(row_values)
table_str += line + '\n'
table_str += '=' * line_len + '\n'
return table_str
def show(self):
print(self.to_string())
@property
def shape(self):
return (self.num_rows, self.num_cols)
@property
def num_cols(self):
return len(self.header)