1
""" ReStructured Text utilities
2

3
* Make ReST table given array of values
4
"""
5

6 33
import numpy as np
7

8

9 33
def rst_table(cell_values,
10
              row_names=None,
11
              col_names=None,
12
              title='',
13
              val_fmt='{0:5.2f}',
14
              format_chars=None
15
              ):
16
    """ Return string for ReST table with entries `cell_values`
17

18
    Parameters
19
    ----------
20
    cell_values : (R, C) array-like
21
        At least 2D.  Can be greater than 2D, in which case you should adapt
22
        the `val_fmt` to deal with the multiple entries that will go in each
23
        cell
24
    row_names : None or (R,) length sequence, optional
25
        Row names.  If None, use ``row[0]`` etc.
26
    col_names : None or (C,) length sequence, optional
27
        Column names.  If None, use ``col[0]`` etc.
28
    title : str, optional
29
        Title for table.  Add as heading above table
30
    val_fmt : str, optional
31
        Format string using string ``format`` method mini-language. Converts
32
        the result of ``cell_values[r, c]`` to a string to make the cell
33
        contents. Default assumes a floating point value in a 2D `cell_values`.
34
    format_chars : None or dict, optional
35
        With keys 'down', 'along', 'thick_long', 'cross' and 'title_heading'.
36
        Values are characters for: lines going down; lines going along; thick
37
        lines along; two lines crossing; and the title overline / underline.
38
        All missing values filled with rst defaults.
39

40
    Returns
41
    -------
42
    table_str : str
43
        Multiline string with ascii table, suitable for printing
44
    """
45
    # formatting
46 33
    if format_chars is None:
47 33
        format_chars = {}
48 33
    down = format_chars.pop('down', '|')
49 33
    along = format_chars.pop('along', '-')
50 33
    thick_long = format_chars.pop('thick_long', '=')
51 33
    cross = format_chars.pop('cross', '+')
52 33
    title_heading = format_chars.pop('title_heading', '*')
53 33
    if len(format_chars) != 0:
54 33
        raise ValueError(f"Unexpected ``format_char`` keys {', '.join(format_chars)}")
55 33
    down_joiner = ' ' + down + ' '
56 33
    down_starter = down + ' '
57 33
    down_ender = ' ' + down
58 33
    cross_joiner = along + cross + along
59 33
    cross_starter = cross + along
60 33
    cross_ender = along + cross
61 33
    cross_thick_joiner = thick_long + cross + thick_long
62 33
    cross_thick_starter = cross + thick_long
63 33
    cross_thick_ender = thick_long + cross
64
    # lengths of row names, column names and values
65 33
    cell_values = np.asarray(cell_values)
66 33
    R, C = cell_values.shape[:2]
67 33
    if row_names is None:
68 33
        row_names = [f'row[{r}]' for r in range(R)]
69 33
    elif len(row_names) != R:
70 33
        raise ValueError('len(row_names) != number of rows')
71 33
    if col_names is None:
72 33
        col_names = [f'col[{c}]' for c in range(C)]
73 33
    elif len(col_names) != C:
74 33
        raise ValueError('len(col_names) != number of columns')
75 33
    row_len = max(len(name) for name in row_names)
76 33
    col_len = max(len(name) for name in col_names)
77
    # Compile row value strings, find longest, extend col length to match
78 33
    row_str_list = []
79 33
    for row_no in range(R):
80 33
        row_strs = [val_fmt.format(val) for val in cell_values[row_no]]
81 33
        max_len = max(len(s) for s in row_strs)
82 33
        if max_len > col_len:
83 33
            col_len = max_len
84 33
        row_str_list.append(row_strs)
85 33
    row_name_fmt = "{0:<" + str(row_len) + "}"
86 33
    row_names = [row_name_fmt.format(name) for name in row_names]
87 33
    col_name_fmt = "{0:^" + str(col_len) + "}"
88 33
    col_names = [col_name_fmt.format(name) for name in col_names]
89 33
    col_headings = [' ' * row_len] + col_names
90 33
    col_header = down_joiner.join(col_headings)
91 33
    row_val_fmt = '{0:<' + str(col_len) + '}'
92 33
    table_strs = []
93 33
    if title != '':
94 33
        table_strs += [title_heading * len(title),
95
                       title,
96
                       title_heading * len(title),
97
                       '']
98 33
    along_headings = [along * len(h) for h in col_headings]
99 33
    crossed_line = (cross_starter +
100
                    cross_joiner.join(along_headings) +
101
                    cross_ender)
102 33
    thick_long_headings = [thick_long * len(h) for h in col_headings]
103 33
    crossed_thick_line = (cross_thick_starter +
104
                          cross_thick_joiner.join(thick_long_headings) +
105
                          cross_thick_ender)
106 33
    table_strs += [crossed_line,
107
                   down_starter + col_header + down_ender,
108
                   crossed_thick_line]
109 33
    for row_no, row_name in enumerate(row_names):
110 33
        row_vals = [row_val_fmt.format(row_str)
111
                    for row_str in row_str_list[row_no]]
112 33
        row_line = (down_starter +
113
                    down_joiner.join([row_name] + row_vals) +
114
                    down_ender)
115 33
        table_strs.append(row_line)
116 33
    table_strs.append(crossed_line)
117 33
    return '\n'.join(table_strs)

Read our documentation on viewing source code .

Loading