Add option to change output stream/file.

This commit is contained in:
Teal Dulcet 2024-11-22 10:49:10 -08:00
parent 8fa05e23c8
commit ed5d06d08a
7 changed files with 157 additions and 112 deletions

View File

@ -463,20 +463,17 @@ Default value: `false`
Option: `padding`\ Option: `padding`\
Default value: `1` Default value: `1`
#### Alignment #### Format and Alignment
Option: `alignment`\ Option: `alignment`\
Values: Values:
* `nullptr` * (default)
* `left` (default) * `std::ios_base::left`
* `right` * `std::ios_base::right`
* `internal` (integer and floating-point types only) * `std::ios_base::internal` (integer and floating-point types only)
#### bool to alpha See [`ios_base::fmtflags`](https://en.cppreference.com/w/cpp/io/ios_base/fmtflags) for full available options. Use `std::ios_base::boolalpha` for bool to alpha.
Option: `boolalpha`\
Default value: `false`
#### Title #### Title
@ -507,6 +504,17 @@ Values:
7. `style_heavy_dashed`: Heavy Dashed 7. `style_heavy_dashed`: Heavy Dashed
![](images/heavy%20dashed%20table.png) ![](images/heavy%20dashed%20table.png)
#### Output stream
Option: `ostr`\
Values:
* `std::cout` (default)
* `std::cerr`
* `std::clog`
Any other subclass of `ostream`, including `iostream`, `ofstream` and `ostringstream`
#### Check size #### Check size
Option: `check`\ Option: `check`\
@ -949,6 +957,17 @@ This option is only used when plotting a single array and when graphing a single
![](images/graph%20colors.png) ![](images/graph%20colors.png)
#### Output stream
Option: `ostr`\
Values:
* `std::cout` (default)
* `std::cerr`
* `std::clog`
Any other subclass of `ostream`, including `iostream`, `ofstream` and `ostringstream`
#### Check size #### Check size
Option: `check`\ Option: `check`\
@ -967,7 +986,6 @@ Pull requests welcome! Ideas for contributions:
Both: Both:
* Add more options * Add more options
* Add options to word wrap and truncate long text in table cells * Add options to word wrap and truncate long text in table cells
* Add option to center text in table cells
* Add more examples * Add more examples
* Improve the performance * Improve the performance
* Handle newlines and tabs in the tables * Handle newlines and tabs in the tables
@ -979,5 +997,6 @@ Both:
* Port to other languages (C, Java, Rust, etc.) * Port to other languages (C, Java, Rust, etc.)
C++: C++:
* Add option to center text in table cells
* Update the CI to test with more compilers * Update the CI to test with more compilers
* Support tables with the `wchar_t`, `char16_t` and `char32_t` C data types and the `wstring`, `u16string` and `u32string` C++ data types. * Support tables with the `wchar_t`, `char16_t` and `char32_t` C data types and the `wstring`, `u16string` and `u32string` C++ data types.

View File

@ -165,6 +165,7 @@ namespace graphs
const char *title = nullptr; const char *title = nullptr;
style_type style = style_light; style_type style = style_light;
color_type color = color_red; color_type color = color_red;
ostream &ostr = cout;
bool check = true; bool check = true;
}; };
@ -176,7 +177,7 @@ namespace graphs
if (iscntrl(c)) if (iscntrl(c))
{ {
cerr << "\nError: Control character in string.\n"; cerr << "\nError: Control character in string.\n";
cout << "Control character: " << (int)c << '\n'; cerr << "Control character: " << (int)c << '\n';
} }
size_t length = mbstowcs(nullptr, str.c_str(), 0); size_t length = mbstowcs(nullptr, str.c_str(), 0);
@ -493,18 +494,20 @@ namespace graphs
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
if (title and title[0] != '\0') if (title and title[0] != '\0')
cout << wrap(title, awidth) << '\n'; aoptions.ostr << wrap(title, awidth) << '\n';
const char *const *astyle = styles[aoptions.style]; const char *const *astyle = styles[aoptions.style];
ostringstream strm;
if (border) if (border)
{ {
cout << astyle[2]; strm << astyle[2];
for (size_t k = 0; k < awidth; ++k) for (size_t k = 0; k < awidth; ++k)
cout << astyle[0]; strm << astyle[0];
cout << astyle[4] << '\n'; strm << astyle[4] << '\n';
} }
for (size_t i = 0; i < height; i += ai) for (size_t i = 0; i < height; i += ai)
@ -539,7 +542,7 @@ namespace graphs
} }
if (border) if (border)
cout << astyle[1]; strm << astyle[1];
for (size_t j = 0; j < width; j += aj) for (size_t j = 0; j < width; j += aj)
{ {
@ -552,19 +555,19 @@ namespace graphs
{ {
if (axaxis and ayaxis) if (axaxis and ayaxis)
{ {
cout << astyle[6]; strm << astyle[6];
output = true; output = true;
} }
else if (axaxis) else if (axaxis)
{ {
if (!i) if (!i)
{ {
cout << astyle[4]; strm << astyle[4];
output = true; output = true;
} }
else if (i >= (height - ai)) else if (i >= (height - ai))
{ {
cout << astyle[10]; strm << astyle[10];
output = true; output = true;
} }
else if (axistick) else if (axistick)
@ -575,14 +578,14 @@ namespace graphs
{ {
if (i <= k and (i + ai) > k) if (i <= k and (i + ai) > k)
{ {
cout << astyle[xaxis >= aj ? 7 : 5]; strm << astyle[xaxis >= aj ? 7 : 5];
output = true; output = true;
} }
} }
} }
if (!output) if (!output)
{ {
cout << astyle[1]; strm << astyle[1];
output = true; output = true;
} }
} }
@ -590,12 +593,12 @@ namespace graphs
{ {
if (!j) if (!j)
{ {
cout << astyle[2]; strm << astyle[2];
output = true; output = true;
} }
else if (j >= (width - aj)) else if (j >= (width - aj))
{ {
cout << astyle[4]; strm << astyle[4];
output = true; output = true;
} }
else if (axistick) else if (axistick)
@ -606,25 +609,25 @@ namespace graphs
{ {
if (j <= k and (j + aj) > k) if (j <= k and (j + aj) > k)
{ {
cout << astyle[yaxis <= (height - ai) ? 3 : 9]; strm << astyle[yaxis <= (height - ai) ? 3 : 9];
output = true; output = true;
} }
} }
} }
if (!output) if (!output)
{ {
cout << astyle[0]; strm << astyle[0];
output = true; output = true;
} }
} }
else if (yaxislabel and xaxislabel and axistick and axisunitslabel and ymin <= 0 and ymax >= 0 and xmin <= 0 and xmax >= 0) else if (yaxislabel and xaxislabel and axistick and axisunitslabel and ymin <= 0 and ymax >= 0 and xmin <= 0 and xmax >= 0)
{ {
cout << '0'; strm << '0';
output = true; output = true;
} }
else if ((xaxis <= (width - aj) ? j >= (width - aj) : !j) and yaxislabel and axislabel) else if ((xaxis <= (width - aj) ? j >= (width - aj) : !j) and yaxislabel and axislabel)
{ {
cout << 'x'; strm << 'x';
output = true; output = true;
} }
else if (yaxislabel and axistick and axisunitslabel) else if (yaxislabel and axistick and axisunitslabel)
@ -651,12 +654,12 @@ namespace graphs
{ {
output = false; output = false;
ostringstream strm; ostringstream astrm;
size_t length = outputlabel(label, aoptions.xunits, strm); size_t length = outputlabel(label, aoptions.xunits, astrm);
length *= aj; length *= aj;
if ((j >= xaxis or (j + length) < (ymin <= 0 and ymax >= 0 and xmin <= 0 and xmax >= 0 ? xaxis - ai : xaxis)) and (j + length) < (width - aj) and (xaxis <= (width - aj) or j > aj)) if ((j >= xaxis or (j + length) < (ymin <= 0 and ymax >= 0 and xmin <= 0 and xmax >= 0 ? xaxis - ai : xaxis)) and (j + length) < (width - aj) and (xaxis <= (width - aj) or j > aj))
{ {
cout << strm.str(); strm << astrm.str();
if (length > aj) if (length > aj)
j += length - aj; j += length - aj;
@ -670,12 +673,12 @@ namespace graphs
} }
else if ((yaxis >= ai ? !i : i >= (height - ai)) and xaxislabel and axislabel) else if ((yaxis >= ai ? !i : i >= (height - ai)) and xaxislabel and axislabel)
{ {
cout << 'y'; strm << 'y';
output = true; output = true;
} }
else if (ylabellength and (xaxis < aj ? xaxislabel : j < (xaxis - ylabellength) and (j + aj) >= (xaxis - ylabellength)) and (yaxis >= ai or i < (height - ai)) and axistick and axisunitslabel) else if (ylabellength and (xaxis < aj ? xaxislabel : j < (xaxis - ylabellength) and (j + aj) >= (xaxis - ylabellength)) and (yaxis >= ai or i < (height - ai)) and axistick and axisunitslabel)
{ {
cout << ylabelstrm.str(); strm << ylabelstrm.str();
output = true; output = true;
if (ylabellength > aj) if (ylabellength > aj)
j += ylabellength - aj; j += ylabellength - aj;
@ -718,34 +721,35 @@ namespace graphs
--color; --color;
if (color) if (color)
cout << colors[color]; strm << colors[color];
cout << (type == type_histogram ? bars[dot] : type == type_block ? blocks[dot] strm << (type == type_histogram ? bars[dot] : type == type_block ? blocks[dot]
: dots[dot]); : dots[dot]);
if (color) if (color)
cout << colors[0]; strm << colors[0];
} }
} }
if (border) if (border)
cout << astyle[1]; strm << astyle[1];
if (i < (height - ai) or border) if (i < (height - ai) or border)
cout << '\n'; strm << '\n';
} }
if (border) if (border)
{ {
cout << astyle[8]; strm << astyle[8];
for (size_t k = 0; k < awidth; ++k) for (size_t k = 0; k < awidth; ++k)
cout << astyle[0]; strm << astyle[0];
cout << astyle[10]; strm << astyle[10];
} }
cout << '\n'; strm << '\n';
aoptions.ostr << strm.str();
return 0; return 0;
} }

View File

@ -198,14 +198,18 @@ Default value: `False`
Option: `padding`\ Option: `padding`\
Default value: `1` Default value: `1`
#### Alignment #### Format and Alignment
Option: `alignment`\ Option: `alignment`\
Values: Values:
* `None` (default) * `""` (default)
* `False` (left) * `"<"` (left)
* `True` (right) * `">"` (right)
* `"="` (internal, numeric types only)
* `"^"` (center)
See the [Python documentation](https://docs.python.org/3/library/string.html#formatspec) for the full available options.
#### Title #### Title
@ -236,6 +240,16 @@ Values:
7. `style_types.heavy_dashed`: Heavy Dashed 7. `style_types.heavy_dashed`: Heavy Dashed
![](../images/heavy%20dashed%20table.png) ![](../images/heavy%20dashed%20table.png)
#### Output file
Option: `file`\
Values:
* `sys.stdout` (default)
* `sys.stderr`
Any other text [file object](https://docs.python.org/3/glossary.html#term-file-object).
#### Check size #### Check size
Option: `check`\ Option: `check`\
@ -542,6 +556,16 @@ This option is only used when plotting a single array and when graphing a single
![](../images/graph%20colors.png) ![](../images/graph%20colors.png)
#### Output file
Option: `file`\
Values:
* `sys.stdout` (default)
* `sys.stderr`
Any other text [file object](https://docs.python.org/3/glossary.html#term-file-object).
#### Check size #### Check size
Option: `check`\ Option: `check`\

View File

@ -10,7 +10,7 @@ import textwrap
from datetime import datetime, timezone from datetime import datetime, timezone
from enum import Enum, IntEnum, auto from enum import Enum, IntEnum, auto
from fractions import Fraction from fractions import Fraction
from typing import Callable, List, Optional, Sequence, Tuple from typing import Callable, List, Optional, Sequence, TextIO, Tuple
if sys.platform != "win32": if sys.platform != "win32":
import ctypes import ctypes
@ -298,7 +298,7 @@ def outputlabel(label: float, units: units_types) -> Tuple[int, str]:
return length, strm return length, strm
def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, array: List[List[int]], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, style: style_types = style_types.light, title: Optional[str] = None, check: bool = True) -> int: def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, array: List[List[int]], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, style: style_types = style_types.light, title: Optional[str] = None, file: TextIO = sys.stdout, check: bool = True) -> int:
"""Output graph.""" """Output graph."""
if not array: if not array:
return 1 return 1
@ -344,7 +344,7 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
ydivisor = 2 * ai * ((((4 * height) // ai) // 160) + 2) ydivisor = 2 * ai * ((((4 * height) // ai) // 160) + 2)
if title: if title:
print(textwrap.fill(title, width=awidth)) print(textwrap.fill(title, width=awidth), file=file)
astyle = styles[style] astyle = styles[style]
@ -521,12 +521,12 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
if border: if border:
strm += astyle[8] + (astyle[0] * awidth) + astyle[10] strm += astyle[8] + (astyle[0] * awidth) + astyle[10]
print(strm) print(strm, file=file)
return 0 return 0
def histogram(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarray: Sequence[float], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, check: bool = True) -> int: def histogram(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarray: Sequence[float], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, file: TextIO = sys.stdout, check: bool = True) -> int:
"""Convert one or more arrays to graph and output.""" """Convert one or more arrays to graph and output."""
if not aarray: if not aarray:
return 1 return 1
@ -594,10 +594,10 @@ def histogram(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
aaarray[x][y] = acolor aaarray[x][y] = acolor
y += 1 y += 1
return graph(height, width, xmin, xmax, ymin, ymax, aaarray, border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, type_types.histogram, style, title) return graph(height, width, xmin, xmax, ymin, ymax, aaarray, border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, type_types.histogram, style, title, file)
def plots(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarrays: Sequence[Sequence[Sequence[float]]], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, mark: mark_types = mark_types.dot, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, check: bool = True) -> int: def plots(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarrays: Sequence[Sequence[Sequence[float]]], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, mark: mark_types = mark_types.dot, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, file: TextIO = sys.stdout, check: bool = True) -> int:
"""Convert one or more arrays to graph and output.""" """Convert one or more arrays to graph and output."""
if not aarrays: if not aarrays:
return 1 return 1
@ -673,15 +673,15 @@ def plots(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
else: else:
aaarray[x][y] = acolor aaarray[x][y] = acolor
return graph(height, width, xmin, xmax, ymin, ymax, aaarray, border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, atype, style, title) return graph(height, width, xmin, xmax, ymin, ymax, aaarray, border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, atype, style, title, file)
def plot(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarray: Sequence[Sequence[float]], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, mark: mark_types = mark_types.dot, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None) -> int: def plot(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarray: Sequence[Sequence[float]], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, mark: mark_types = mark_types.dot, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, file: TextIO = sys.stdout, check: bool = True) -> int:
"""Convert single array to graph and output.""" """Convert single array to graph and output."""
return plots(height, width, xmin, xmax, ymin, ymax, [aarray], border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, atype, mark, style, color, title) return plots(height, width, xmin, xmax, ymin, ymax, (aarray,), border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, atype, mark, style, color, title, file, check)
def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, afunctions: Sequence[Callable[[float], float]], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, check: bool = True) -> int: def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, afunctions: Sequence[Callable[[float], float]], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, file: TextIO = sys.stdout, check: bool = True) -> int:
"""Convert one or more functions to graph and output.""" """Convert one or more functions to graph and output."""
if not afunctions: if not afunctions:
return 1 return 1
@ -747,9 +747,9 @@ def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
else: else:
array[ax][ay] = acolor array[ax][ay] = acolor
return graph(height, width, xmin, xmax, ymin, ymax, array, border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, atype, style, title) return graph(height, width, xmin, xmax, ymin, ymax, array, border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, atype, style, title, file)
def function(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, afunction: Callable[[float], float], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None) -> int: def function(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, afunction: Callable[[float], float], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, file: TextIO = sys.stdout, check: bool = True) -> int:
"""Convert single function to function array and output.""" """Convert single function to function array and output."""
return functions(height, width, xmin, xmax, ymin, ymax, [afunction], border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, atype, style, color, title) return functions(height, width, xmin, xmax, ymin, ymax, (afunction,), border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, atype, style, color, title, file, check)

View File

@ -8,7 +8,7 @@ import shutil
import sys import sys
import textwrap import textwrap
from enum import IntEnum, auto from enum import IntEnum, auto
from typing import Any, Callable, List, Optional, Sequence from typing import Any, Callable, List, Optional, Sequence, TextIO
if sys.platform != "win32": if sys.platform != "win32":
import ctypes import ctypes
@ -66,7 +66,7 @@ def strcol(astr: str) -> int:
def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False,
padding: int = 1, alignment: Optional[bool] = None, title: Optional[str] = None, style: style_types = style_types.light, check: bool = True) -> int: padding: int = 1, alignment: str = "", title: Optional[str] = None, style: style_types = style_types.light, file: TextIO = sys.stdout, check: bool = True) -> int:
"""Output char array as table.""" """Output char array as table."""
if not array: if not array:
return 1 return 1
@ -91,7 +91,7 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
return 1 return 1
if title: if title:
print(textwrap.fill(title, width=width)) print(textwrap.fill(title, width=width), file=file)
astyle = styles[style] astyle = styles[style]
@ -124,9 +124,9 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
awidth = columnwidth[j] - (strcol(array[i][j]) - len(array[i][j])) awidth = columnwidth[j] - (strcol(array[i][j]) - len(array[i][j]))
if (not i and headerrow) or (not j and headercolumn): if (not i and headerrow) or (not j and headercolumn):
strm += (" " * padding) + "\033[1m" + array[i][j].center(awidth) + "\033[22m" + (" " * padding) strm += (" " * padding) + "\033[1m" + f"{array[i][j]:^{awidth}}" + "\033[22m" + (" " * padding)
else: else:
strm += (" " * padding) + (f"{array[i][j]:{awidth}}" if alignment is None else array[i][j].rjust(awidth) if alignment else array[i][j].ljust(awidth)) + (" " * padding) strm += (" " * padding) + f"{array[i][j]:{alignment}{awidth}}" + (" " * padding)
if tableborder: if tableborder:
strm += astyle[1] strm += astyle[1]
@ -177,12 +177,12 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
strm += astyle[10] strm += astyle[10]
print(strm) print(strm, file=file)
return 0 return 0
def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[str]] = None, aheadercolumn: Optional[Sequence[str]] = None, headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: Optional[bool] = None, title: Optional[str] = None, style: style_types = style_types.light) -> int: def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[str]] = None, aheadercolumn: Optional[Sequence[str]] = None, headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: str = "", title: Optional[str] = None, style: style_types = style_types.light, file: TextIO = sys.stdout, check: bool = True) -> int:
"""Convert array to char array and output as table.""" """Convert array to char array and output as table."""
if not aarray: if not aarray:
return 1 return 1
@ -228,10 +228,10 @@ def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[str]] =
j = 1 if aheadercolumn else 0 j = 1 if aheadercolumn else 0
aaarray[i][j:] = map(str, aarray[ii][:columns - j]) aaarray[i][j:] = map(str, aarray[ii][:columns - j])
return table(aaarray, headerrow, headercolumn, tableborder, cellborder, padding, alignment, title, style) return table(aaarray, headerrow, headercolumn, tableborder, cellborder, padding, alignment, title, style, file, check)
def functions(xmin: float, xmax: float, xstep: float, afunctions: Sequence[Callable[[float], float]], headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: Optional[bool] = None, title: Optional[str] = None, style: style_types = style_types.light) -> int: def functions(xmin: float, xmax: float, xstep: float, afunctions: Sequence[Callable[[float], float]], headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: str = "", title: Optional[str] = None, style: style_types = style_types.light, file: TextIO = sys.stdout, check: bool = True) -> int:
"""Convert one or more functions to array and output as table.""" """Convert one or more functions to array and output as table."""
if not afunctions: if not afunctions:
return 1 return 1
@ -261,9 +261,9 @@ def functions(xmin: float, xmax: float, xstep: float, afunctions: Sequence[Calla
aarray[i][1:] = [function(temp) for function in afunctions] aarray[i][1:] = [function(temp) for function in afunctions]
return array(aarray, aheaderrow, None, headerrow, headercolumn, tableborder, cellborder, padding, alignment, title, style) return array(aarray, aheaderrow, None, headerrow, headercolumn, tableborder, cellborder, padding, alignment, title, style, file, check)
def function(xmin: float, xmax: float, xstep: float, afunction: Callable[[float], float], headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: Optional[bool] = None, title: Optional[str] = None, style: style_types = style_types.light) -> int: def function(xmin: float, xmax: float, xstep: float, afunction: Callable[[float], float], headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: str = "", title: Optional[str] = None, style: style_types = style_types.light, file: TextIO = sys.stdout, check: bool = True) -> int:
"""Convert single function to array and output as table.""" """Convert single function to array and output as table."""
return functions(xmin, xmax, xstep, [afunction], headerrow, headercolumn, tableborder, cellborder, padding, alignment, title, style) return functions(xmin, xmax, xstep, (afunction,), headerrow, headercolumn, tableborder, cellborder, padding, alignment, title, style, file, check)

View File

@ -405,8 +405,8 @@ int main()
array[i][j] = rand() % 2; array[i][j] = rand() % 2;
tables::options aoptions; tables::options aoptions;
aoptions.boolalpha = true; aoptions.alignment |= ios_base::boolalpha;
// tables::options aoptions = {.boolalpha = true}; // tables::options aoptions = {.alignment |= ios_base::boolalpha};
for (const tables::style_type style : tables::style_types) for (const tables::style_type style : tables::style_types)
{ {

View File

@ -58,10 +58,10 @@ namespace tables
bool tableborder = true; bool tableborder = true;
bool cellborder = false; bool cellborder = false;
unsigned padding = 1; unsigned padding = 1;
ios_base &(*alignment)(ios_base &) = left; ios_base::fmtflags alignment;
bool boolalpha = false;
const char *title = nullptr; const char *title = nullptr;
style_type style = style_light; style_type style = style_light;
ostream &ostr = cout;
bool check = true; bool check = true;
}; };
@ -75,7 +75,7 @@ namespace tables
if (iscntrl(c)) if (iscntrl(c))
{ {
cerr << "\nError: Control character in string.\n"; cerr << "\nError: Control character in string.\n";
cout << "Control character: " << (int)c << '\n'; cerr << "Control character: " << (int)c << '\n';
} }
size_t length = mbstowcs(nullptr, str.c_str(), 0); size_t length = mbstowcs(nullptr, str.c_str(), 0);
@ -92,7 +92,6 @@ namespace tables
if (width == -1) if (width == -1)
throw range_error("Error: wcswidth failed. Nonprintable wide character."); throw range_error("Error: wcswidth failed. Nonprintable wide character.");
return width; return width;
} }
@ -194,45 +193,45 @@ namespace tables
} }
if (title and title[0] != '\0') if (title and title[0] != '\0')
cout << wrap(title, width) << '\n'; aoptions.ostr << wrap(title, width) << '\n';
if (aoptions.alignment)
cout << aoptions.alignment;
const char *const *astyle = styles[aoptions.style]; const char *const *astyle = styles[aoptions.style];
ostringstream strm;
strm << setiosflags(aoptions.alignment);
if (tableborder) if (tableborder)
{ {
cout << astyle[2]; strm << astyle[2];
for (size_t j = 0; j < columns; ++j) for (size_t j = 0; j < columns; ++j)
{ {
for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k) for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k)
cout << astyle[0]; strm << astyle[0];
if (j < (columns - 1)) if (j < (columns - 1))
{ {
if (cellborder or headerrow or (!j and headercolumn)) if (cellborder or headerrow or (!j and headercolumn))
cout << astyle[3]; strm << astyle[3];
else else
cout << astyle[0]; strm << astyle[0];
} }
} }
cout << astyle[4] << '\n'; strm << astyle[4] << '\n';
} }
for (size_t i = 0; i < rows; ++i) for (size_t i = 0; i < rows; ++i)
{ {
if (tableborder) if (tableborder)
cout << astyle[1]; strm << astyle[1];
for (size_t j = 0; j < columns; ++j) for (size_t j = 0; j < columns; ++j)
{ {
if ((j and cellborder) or (!i and j and headerrow) or (j == 1 and headercolumn)) if ((j and cellborder) or (!i and j and headerrow) or (j == 1 and headercolumn))
cout << astyle[1]; strm << astyle[1];
else if (j and (tableborder or (i and headerrow) or headercolumn)) else if (j and (tableborder or (i and headerrow) or headercolumn))
cout << ' '; strm << ' ';
const int difference = columnwidth[j] - strcol(array[i][j]); const int difference = columnwidth[j] - strcol(array[i][j]);
@ -240,48 +239,48 @@ namespace tables
{ {
const int apadding = (difference / 2); const int apadding = (difference / 2);
cout << string(padding + apadding, ' ') << "\e[1m" << array[i][j] << "\e[22m" << string(padding + (difference - apadding), ' '); strm << string(padding + apadding, ' ') << "\e[1m" << array[i][j] << "\e[22m" << string(padding + (difference - apadding), ' ');
} }
else else
{ {
cout << string(padding, ' ') << setw(difference + array[i][j].length()) << array[i][j] << string(padding, ' '); strm << string(padding, ' ') << setw(difference + array[i][j].length()) << array[i][j] << string(padding, ' ');
} }
} }
if (tableborder) if (tableborder)
cout << astyle[1]; strm << astyle[1];
if (i < (rows - 1) or tableborder) if (i < (rows - 1) or tableborder)
cout << '\n'; strm << '\n';
if ((i < (rows - 1) and cellborder) or (!i and headerrow) or (i < (rows - 1) and headercolumn)) if ((i < (rows - 1) and cellborder) or (!i and headerrow) or (i < (rows - 1) and headercolumn))
{ {
if (tableborder) if (tableborder)
{ {
if (cellborder or (!i and headerrow) or headercolumn) if (cellborder or (!i and headerrow) or headercolumn)
cout << astyle[5]; strm << astyle[5];
} }
for (size_t j = 0; j < columns; ++j) for (size_t j = 0; j < columns; ++j)
{ {
if (cellborder or (!i and headerrow) or (!j and headercolumn)) if (cellborder or (!i and headerrow) or (!j and headercolumn))
for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k) for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k)
cout << astyle[0]; strm << astyle[0];
else if (headercolumn) else if (headercolumn)
cout << string((2 * padding) + columnwidth[j], ' '); strm << string((2 * padding) + columnwidth[j], ' ');
if (j < (columns - 1)) if (j < (columns - 1))
{ {
if (cellborder or ((!i and headerrow) and (!j and headercolumn))) if (cellborder or ((!i and headerrow) and (!j and headercolumn)))
cout << astyle[6]; strm << astyle[6];
else if (!i and headerrow) else if (!i and headerrow)
cout << astyle[9]; strm << astyle[9];
else if (headercolumn) else if (headercolumn)
{ {
if (!j) if (!j)
cout << astyle[7]; strm << astyle[7];
else else
cout << ' '; strm << ' ';
} }
} }
} }
@ -289,37 +288,38 @@ namespace tables
if (tableborder) if (tableborder)
{ {
if (cellborder or (!i and headerrow)) if (cellborder or (!i and headerrow))
cout << astyle[7]; strm << astyle[7];
else if (headercolumn) else if (headercolumn)
cout << astyle[1]; strm << astyle[1];
} }
cout << '\n'; strm << '\n';
} }
} }
if (tableborder) if (tableborder)
{ {
cout << astyle[8]; strm << astyle[8];
for (size_t j = 0; j < columns; ++j) for (size_t j = 0; j < columns; ++j)
{ {
for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k) for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k)
cout << astyle[0]; strm << astyle[0];
if (j < (columns - 1)) if (j < (columns - 1))
{ {
if (cellborder or (!j and headercolumn)) if (cellborder or (!j and headercolumn))
cout << astyle[9]; strm << astyle[9];
else else
cout << astyle[0]; strm << astyle[0];
} }
} }
cout << astyle[10]; strm << astyle[10];
} }
cout << '\n'; strm << '\n';
aoptions.ostr << strm.str();
return 0; return 0;
} }
@ -379,9 +379,7 @@ namespace tables
for (size_t jj = 0; j < columns; ++j) for (size_t jj = 0; j < columns; ++j)
{ {
ostringstream strm; ostringstream strm;
strm << setiosflags(aoptions.alignment);
if (aoptions.boolalpha)
strm << boolalpha;
strm << aarray[ii][jj]; strm << aarray[ii][jj];
aaarray[i][j] = strm.str(); aaarray[i][j] = strm.str();