Updated the style and color options to use Enums.

This commit is contained in:
Teal Dulcet 2023-03-10 05:15:01 -08:00
parent 1d6c53c985
commit 73411c18cb
10 changed files with 903 additions and 726 deletions

View File

@ -33,6 +33,8 @@ jobs:
./graphs
- name: Cppcheck
run: cppcheck --enable=all .
- name: Clang-Tidy
run: clang-tidy -checks='bugprone-*,-bugprone-easily-swappable-parameters,cert-*,clang-analyzer-*,misc-const-correctness,misc-redundant-expression,misc-unused-*,modernize-*,-modernize-use-trailing-return-type,performance-*,portability-*,readability-const-return-type,readability-container-*,readability-duplicate-include,readability-else-after-return,readability-non-const-parameter,readability-redundant-*,readability-simplify-*,readability-string-compare,readability-use-anyofallof' -header-filter='.*' *.cpp -- -Wall -O3 -std=c++17
Python:
name: Linux Python

103
README.md
View File

@ -22,9 +22,8 @@ Requires support for C++14. See the [tables.hpp](tables.hpp) file for full usage
Complete versions of all of the examples below and more can be found in the [tables.cpp](tables.cpp) file.
Compile with:
GCC: `g++ -std=c++14 -Wall -g -O3 tables.cpp -o tables`\
Clang: `clang++ -std=c++14 -Wall -g -O3 tables.cpp -o tables`
* GCC: `g++ -std=c++14 -Wall -g -O3 tables.cpp -o tables`
* Clang: `clang++ -std=c++14 -Wall -g -O3 tables.cpp -o tables`
Run with: `./tables`
@ -313,12 +312,12 @@ int main()
{
double xmin = -10;
double xmax = 10;
double xscl = 2;
double xstep = 0.5;
tables::options aoptions;
aoptions.headerrow = true;
tables::function(xmin, xmax, xscl, afunction, aoptions);
tables::function(xmin, xmax, xstep, afunction, aoptions);
return 0;
}
@ -335,7 +334,7 @@ int main()
{
double xmin = -10;
double xmax = 10;
double xscl = 2;
double xstep = 0.5;
function<double(double)> afunction = [](auto x)
{ return x + 1; };
@ -343,7 +342,7 @@ int main()
tables::options aoptions;
aoptions.headerrow = true;
tables::function(xmin, xmax, xscl, afunction, aoptions);
tables::function(xmin, xmax, xstep, afunction, aoptions);
return 0;
}
@ -375,7 +374,7 @@ int main()
{
double xmin = -10;
double xmax = 10;
double xscl = 2;
double xstep = 0.5;
size_t numfunctions = 2;
@ -385,7 +384,7 @@ int main()
tables::options aoptions;
aoptions.headerrow = true;
tables::functions(xmin, xmax, xscl, numfunctions, functions, aoptions);
tables::functions(xmin, xmax, xstep, numfunctions, functions, aoptions);
return 0;
}
@ -403,7 +402,7 @@ int main()
{
double xmin = -10;
double xmax = 10;
double xscl = 2;
double xstep = 0.5;
size_t numfunctions = 2;
@ -416,7 +415,7 @@ int main()
tables::options aoptions;
aoptions.headerrow = true;
tables::functions(xmin, xmax, xscl, numfunctions, functions, aoptions);
tables::functions(xmin, xmax, xstep, numfunctions, functions, aoptions);
return 0;
}
@ -460,8 +459,10 @@ Default value: `1`
Option: `alignment`\
Values:
* `nullptr`
* `left` (default)
* `right`
* `internal` (integer and floating-point types only)
#### bool to alpha
@ -480,28 +481,35 @@ The title is word wrapped based on the current width of the terminal, using [thi
Option: `style`\
Values:
0. ASCII
0. `style_ASCII`: ASCII
![](images/ASCII%20table.png)
1. Basic
1. `style_basic`: Basic
![](images/basic%20table.png)
2. Light (default)
2. `style_light`: Light (default)
![](images/light%20table.png)
3. Heavy
3. `style_heavy`: Heavy
![](images/heavy%20table.png)
4. Double
4. `style_double`: Double
![](images/double%20table.png)
5. Light Dashed
5. `style_light_dashed`: Light Dashed
![](images/light%20dashed%20table.png)
6. Heavy Dashed
6. `style_heavy_dashed`: Heavy Dashed
![](images/heavy%20dashed%20table.png)
#### Check size
Option: `check`\
Default value: `true`
Check that the width of the table is not greater then the width of the terminal.
### Other C++ Console Tables Libraries
* [C++ Text Table](https://github.com/haarcuba/cpp-text-table) (must specify every cell individually in their data structure, limited options, no Unicode support, no header row or column support)
@ -517,8 +525,8 @@ Requires support for C++14. See the [graphs.hpp](graphs.hpp) file for full usage
Complete versions of all of the examples below and more can be found in the [graphs.cpp](graphs.cpp) file.
Compile with:
GCC: `g++ -std=c++14 -Wall -g -O3 graphs.cpp -o graphs`\
Clang: `clang++ -std=c++14 -Wall -g -O3 graphs.cpp -o graphs`
* GCC: `g++ -std=c++14 -Wall -g -O3 graphs.cpp -o graphs`
* Clang: `clang++ -std=c++14 -Wall -g -O3 graphs.cpp -o graphs`
Run with: `./graphs`
@ -756,25 +764,25 @@ The title is word wrapped based on the current width of the terminal, using [thi
Option: `style`\
Values:
0. ASCII
0. `style_ASCII`: ASCII
![](images/ASCII%20graph.png)
1. Basic
1. `style_basic`: Basic
![](images/basic%20graph.png)
2. Light (default)
2. `style_light`: Light (default)
![](images/light%20graph.png)
3. Heavy
3. `style_heavy`: Heavy
![](images/heavy%20graph.png)
4. Double
4. `style_double`: Double
![](images/double%20graph.png)
5. Light Dashed
5. `style_light_dashed`: Light Dashed
![](images/light%20dashed%20graph.png)
6. Heavy Dashed
6. `style_heavy_dashed`: Heavy Dashed
![](images/heavy%20dashed%20graph.png)
@ -783,27 +791,25 @@ Values:
Option: `color`\
Values:
0. System default
1. Black
2. Red (default)
3. Green
4. Yellow
5. Blue
6. Cyan
7. Light gray
8. Dark gray
9. Light red
10. Light green
11. Light yellow
12. Light blue
13. Light cyan
14. White
0. `color_default`: System default
1. `color_black`: Black
2. `color_red`: Red (default)
3. `color_green`: Green
4. `color_yellow`: Yellow
5. `color_blue`: Blue
6. `color_cyan`: Cyan
7. `color_light_gray`: Light gray
8. `color_dark_gray`: Dark gray
9. `color_light_red`: Light red
10. `color_light_green`: Light green
11. `color_light_yellow`: Light yellow
12. `color_light_blue`: Light blue
13. `color_light_cyan`: Light cyan
14. `color_white`: White
See [here](https://misc.flogisoft.com/bash/tip_colors_and_formatting#foreground_text) for examples of the colors.
Only used for plots and when graphing a single function.
When graphing multiple functions, colors `2` - `14` are used inorder. Color `0` is used where the functions cross.
Only used when plotting a single array and when graphing a single function. When plotting multiple arrays or graphing multiple functions, colors 2 - 14 are used inorder. The system default color is used where the plots cross.
##### Plot
@ -813,6 +819,13 @@ When graphing multiple functions, colors `2` - `14` are used inorder. Color `0`
![](images/graph%20colors.png)
#### Check size
Option: `check`\
Default value: `true`
Check that the width and height of the graph are not greater then the respective width and height of the terminal.
### Other C++ Console Graphs/Plots Libraries
* [C++ terminal plotting library](https://github.com/fbbdev/plot) (requires C++14, based on [UnicodePlots.jl](https://github.com/Evizero/UnicodePlots.jl), no documentation and very difficult to use, although supports animations)

View File

@ -68,14 +68,14 @@ int main()
graphs::options aoptions;
for (unsigned int k = 0; k < graphs::size(graphs::styles); ++k)
for (const graphs::style_type style : graphs::style_types)
{
aoptions.style = k;
aoptions.style = style;
graphs::array(height, width, xmin, xmax, ymin, ymax, rows, array, aoptions);
}
if (array != nullptr)
if (array)
{
for (unsigned int i = 0; i < rows; ++i)
delete[] array[i];
@ -92,9 +92,9 @@ int main()
graphs::options aoptions;
for (unsigned int k = 0; k < graphs::size(graphs::styles); ++k)
for (const graphs::style_type style : graphs::style_types)
{
aoptions.style = k;
aoptions.style = style;
graphs::array(height, width, xmin, xmax, ymin, ymax, aarray, aoptions);
}
@ -108,9 +108,9 @@ int main()
graphs::options aoptions;
for (unsigned int k = 0; k < graphs::size(graphs::styles); ++k)
for (const graphs::style_type style : graphs::style_types)
{
aoptions.style = k;
aoptions.style = style;
graphs::array(height, width, xmin, xmax, ymin, ymax, array, aoptions);
}
@ -120,9 +120,9 @@ int main()
{
graphs::options aoptions;
for (unsigned int k = 0; k < graphs::size(graphs::styles); ++k)
for (const graphs::style_type style : graphs::style_types)
{
aoptions.style = k;
aoptions.style = style;
graphs::function(height, width, xmin, xmax, ymin, ymax, afunction, aoptions);
}
@ -133,9 +133,9 @@ int main()
graphs::options aoptions;
for (unsigned int k = 0; k < graphs::size(graphs::styles); ++k)
for (const graphs::style_type style : graphs::style_types)
{
aoptions.style = k;
aoptions.style = style;
graphs::function(height, width, xmin, xmax, ymin, ymax, afunction, aoptions);
}
@ -147,11 +147,11 @@ int main()
graphs::options aoptions;
for (unsigned int k = 0; k < graphs::size(graphs::styles); ++k)
for (const graphs::style_type style : graphs::style_types)
{
aoptions.style = k;
aoptions.style = style;
graphs::functions(height, width, xmin, xmax, ymin, ymax, 2, functions, aoptions);
graphs::functions(height, width, xmin, xmax, ymin, ymax, graphs::size(functions), functions, aoptions);
}
}
{
@ -162,11 +162,11 @@ int main()
graphs::options aoptions;
for (unsigned int k = 0; k < graphs::size(graphs::styles); ++k)
for (const graphs::style_type style : graphs::style_types)
{
aoptions.style = k;
aoptions.style = style;
graphs::functions(height, width, xmin, xmax, ymin, ymax, 2, functions, aoptions);
graphs::functions(height, width, xmin, xmax, ymin, ymax, graphs::size(functions), functions, aoptions);
}
}
{
@ -181,11 +181,11 @@ int main()
aoptions.axisunitslabel = false;
// graphs::options aoptions{.axisunitslabel = false};
for (unsigned int k = 0; k < graphs::size(graphs::styles); ++k)
for (const graphs::style_type style : graphs::style_types)
{
aoptions.style = k;
aoptions.style = style;
graphs::functions(height, width, xmin, xmax, ymin, ymax, 3, functions, aoptions);
graphs::functions(height, width, xmin, xmax, ymin, ymax, graphs::size(functions), functions, aoptions);
}
/* aoptions.style = 2;
@ -195,7 +195,7 @@ int main()
cout << "\e[1;1H"
<< "\e[2J";
graphs::functions(k, k, xmin, xmax, ymin, ymax, 3, functions, aoptions);
graphs::functions(k, k, xmin, xmax, ymin, ymax, graphs::size(functions), functions, aoptions);
usleep(200000);
} */

View File

@ -22,6 +22,19 @@ namespace graphs
{
using namespace std;
enum style_type
{
style_ASCII,
style_basic,
style_light,
style_heavy,
style_double,
style_light_dashed,
style_heavy_dashed
};
enum style_type const style_types[] = {style_ASCII, style_basic, style_light, style_heavy, style_double, style_light_dashed, style_heavy_dashed};
const char *const styles[][11] = {
{"-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // ASCII
{"", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // Basic
@ -33,6 +46,27 @@ namespace graphs
};
// {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}};//No border
enum color_type
{
color_default,
color_black,
color_red,
color_green,
color_yellow,
color_blue,
color_cyan,
color_light_gray,
color_dark_gray,
color_light_red,
color_light_green,
color_light_yellow,
color_light_blue,
color_light_cyan,
color_white
};
enum color_type const color_types[] = {color_default, color_black, color_red, color_green, color_yellow, color_blue, color_cyan, color_light_gray, color_dark_gray, color_light_red, color_light_green, color_light_yellow, color_light_blue, color_light_cyan, color_white};
const char *const colors[] = {"\e[39m", "\e[30m", "\e[31m", "\e[32m", "\e[33m", "\e[34m", "\e[35m", "\e[36m", "\e[37m", "\e[90m", "\e[91m", "\e[92m", "\e[93m", "\e[94m", "\e[95m", "\e[96m", "\e[97m"};
const char *const dots[] = {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
@ -40,23 +74,29 @@ namespace graphs
const int values[][4] = {{0x1, 0x2, 0x4, 0x40}, {0x8, 0x10, 0x20, 0x80}};
const char *const fractions[] = {"¼", "½", "¾", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
const long double fractionvalues[] = {1.0L / 4.0L, 1.0L / 2.0L, 3.0L / 4.0L, 1.0L / 7.0L, 1.0L / 9.0L, 1.0L / 10.0L, 1.0L / 3.0L, 2.0L / 3.0L, 1.0L / 5.0L, 2.0L / 5.0L, 3.0L / 5.0L, 4.0L / 5.0L, 1.0L / 6.0L, 5.0L / 6.0L, 1.0L / 8.0L, 3.0L / 8.0L, 5.0L / 8.0L, 7.0L / 8.0L};
const char *const constants[] = {"π", "e"};
const long double constantvalues[] = {M_PI, M_E};
const long double max_bit = scalbn(1.0L, LDBL_MANT_DIG - 1);
const long double MAX = max_bit + (max_bit - 1);
struct options
{
bool border = true;
bool axislabel = true;
bool axisunitslabel = true;
const char *title = nullptr;
unsigned int style = 2;
unsigned int color = 2;
style_type style = style_light;
color_type color = color_red;
bool check = true;
};
const options defaultoptions;
template <typename T>
auto size(const T &array)
constexpr size_t size(const T &array)
{
return distance(begin(array), end(array));
}
@ -81,11 +121,11 @@ namespace graphs
}
++length;
wchar_t *wcstring = new wchar_t[length];
auto *wcstring = new wchar_t[length];
if (mbstowcs(wcstring, str, length) == static_cast<size_t>(-1))
{
if (wcstring != nullptr)
if (wcstring)
delete[] wcstring;
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n";
@ -99,7 +139,7 @@ namespace graphs
exit(1);
}
if (wcstring != nullptr)
if (wcstring)
delete[] wcstring;
return width;
@ -110,8 +150,7 @@ namespace graphs
// Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734
string wrap(const char *const str, const size_t line_length)
{
char words[strlen(str) + 1];
strcpy(words, str);
string words = str;
string wrapped;
size_t index = 0;
@ -134,7 +173,7 @@ namespace graphs
}
char temp[templinelen + 1];
strncpy(temp, words + (index - linelen), templinelen);
strncpy(temp, words.data() + (index - linelen), templinelen);
temp[templinelen] = '\0';
size_t width = strcol(temp);
@ -158,62 +197,54 @@ namespace graphs
}
// Convert fractions and constants to Unicode characters
size_t outputlabel(const long double label, ostringstream &strm)
size_t outputfraction(const long double number, ostringstream &strm)
{
bool output = false;
long double intpart = 0;
long double fractionpart = abs(modf(label, &intpart));
for (unsigned int i = 0; i < graphs::size(fractions) and !output; ++i)
const long double n = abs(number);
if (n <= MAX)
{
if (abs(fractionpart - fractionvalues[i]) < DBL_EPSILON)
long double intpart = 0;
long double fractionpart = abs(modf(number, &intpart));
for (size_t i = 0; i < graphs::size(fractions) and !output; ++i)
{
if (intpart != 0)
strm << intpart;
if (abs(fractionpart - fractionvalues[i]) <= DBL_EPSILON * n)
{
if (intpart == 0 and number < 0)
strm << "-";
else if (intpart != 0)
strm << setprecision(LDBL_DIG) << intpart;
strm << fractions[i];
strm << fractions[i];
output = true;
output = true;
}
}
}
if (abs(label) >= DBL_EPSILON)
{
if (!output and fmod(label, M_PI) == 0)
if (n > DBL_EPSILON)
{
const char symbol[] = "π";
for (size_t i = 0; i < graphs::size(constants) and !output; ++i)
{
if (abs(fmod(number, constantvalues[i])) <= DBL_EPSILON * n)
{
intpart = number / constantvalues[i];
intpart = label / M_PI;
if (intpart == -1)
strm << "-";
else if (intpart != 1)
strm << setprecision(LDBL_DIG) << intpart;
if (intpart == -1)
strm << "-";
else if (intpart != 1)
strm << intpart;
strm << constants[i];
strm << symbol;
output = true;
}
else if (!output and fmod(label, M_E) == 0)
{
const char symbol[] = "e";
intpart = label / M_E;
if (intpart == -1)
strm << "-";
else if (intpart != 1)
strm << intpart;
strm << symbol;
output = true;
output = true;
}
}
}
}
if (!output)
strm << label;
strm << number;
size_t length = strcol(strm.str().c_str());
@ -230,10 +261,7 @@ namespace graphs
const bool axislabel = aoptions.axislabel;
const bool axisunitslabel = aoptions.axisunitslabel;
const char *const title = aoptions.title;
const unsigned int style = aoptions.style;
if (style >= graphs::size(styles))
return 1;
const style_type style = aoptions.style;
if (height == 0)
return 1;
@ -244,19 +272,22 @@ namespace graphs
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
const int aheight = height / 4;
const int awidth = width / 2;
if (aheight > w.ws_row)
if (aoptions.check)
{
cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
return 1;
}
const size_t aheight = height / 4;
const size_t awidth = width / 2;
if (awidth > w.ws_col)
{
cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
return 1;
if (aheight > w.ws_row)
{
cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
return 1;
}
if (awidth > w.ws_col)
{
cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
return 1;
}
}
if (xmin >= xmax)
@ -271,38 +302,39 @@ namespace graphs
return 1;
}
const long double xscl = width / (xmax - xmin);
const long double yscl = height / (ymax - ymin);
const long double xaxis = width - (xmax * xscl);
const long double yaxis = ymax * yscl;
const int divisor = 2 * 4 * ((width / 160.0) > 1 ? (width / 160) + 1 : 1);
const long double xstep = (xmax - xmin) / width;
const long double ystep = (ymax - ymin) / height;
const long double xaxis = xmin > 0 ? 0 : xmax < 0 ? width
: width - (xmax / xstep);
const long double yaxis = ymin > 0 ? height : ymax < 0 ? 0
: ymax / ystep;
const int xdivisor = 2 * 4 * ((width / 160) + 2);
const int ydivisor = 2 * 4 * ((height / 160) + 2);
setlocale(LC_CTYPE, "");
setlocale(LC_ALL, "");
if (title != nullptr and title[0] != '\0')
cout << wrap(title, w.ws_col) << "\n";
if (title and title[0] != '\0')
cout << wrap(title, width / 2) << "\n";
for (unsigned int i = 0; i < height; i += 4)
for (size_t i = 0; i < height; i += 4)
{
const bool ayaxis = (i <= yaxis and (i + 4) > yaxis);
const bool yaxislabel = (i <= (yaxis + 4) and (i + 4) > (yaxis + 4));
const bool ayaxis = yaxis <= (height - 4) ? i <= yaxis and (i + 4) > yaxis : i < yaxis and (i + 4) >= yaxis;
const bool yaxislabel = yaxis <= (height - 4) ? i <= (yaxis + 4) and (i + 4) > (yaxis + 4) : i < (yaxis - 4) and (i + 4) >= (yaxis - 4);
ostringstream ylabelstrm;
size_t ylabellength = 0;
if (border and axislabel and axisunitslabel)
if (border and axislabel and axisunitslabel and yaxis >= 0 and yaxis <= height)
{
bool output = false;
long double label = 0;
int adivisor = divisor;
if (i < yaxis)
adivisor = -adivisor;
int adivisor = i < yaxis ? -ydivisor : ydivisor;
for (long double k = yaxis + adivisor; ((i < yaxis and k >= i) or (i > yaxis and k < (i + 4))) and i >= 4 and !output; k += adivisor)
for (long double k = yaxis + adivisor; (i < yaxis ? k >= i : k < (i + 4)) and i >= 4 and !output; k += adivisor)
{
if (i <= k and (i + 4) > k)
{
label = ymax - (k / yscl);
label = ymax - ((k > height ? height : k) * ystep);
output = true;
}
@ -310,15 +342,15 @@ namespace graphs
if (output)
{
ylabellength = outputlabel(label, ylabelstrm);
ylabellength = outputfraction(label, ylabelstrm);
ylabellength *= 2;
}
}
for (unsigned int j = 0; j < width; j += 2)
for (size_t j = 0; j < width; j += 2)
{
const bool axaxis = (j <= xaxis and (j + 2) > xaxis);
const bool xaxislabel = (j <= (xaxis - 2) and (j + 2) > (xaxis - 2));
const bool axaxis = xaxis >= 2 ? j < xaxis and (j + 2) >= xaxis : j <= xaxis and (j + 2) > xaxis;
const bool xaxislabel = xaxis >= 2 ? j < (xaxis - 2) and (j + 2) >= (xaxis - 2) : j <= (xaxis + 2) and (j + 2) > (xaxis + 2);
bool output = false;
@ -331,66 +363,72 @@ namespace graphs
}
else if (axaxis)
{
if (axislabel and axisunitslabel)
if (i == 0)
{
int adivisor = divisor;
if (i < yaxis)
adivisor = -adivisor;
cout << styles[style][4];
output = true;
}
else if (i >= (height - 4))
{
cout << styles[style][10];
output = true;
}
else if (axislabel and axisunitslabel)
{
int adivisor = i < yaxis ? -ydivisor : ydivisor;
for (long double k = yaxis + adivisor; ((i < yaxis and k >= i) or (i > yaxis and k < (i + 4))) and i >= 4 and !output; k += adivisor)
for (long double k = yaxis + adivisor; (i < yaxis ? k >= i : k < (i + 4)) and i >= 4 and !output; k += adivisor)
{
if (i <= k and (i + 4) > k)
{
cout << styles[style][7];
cout << styles[style][xaxis >= 2 ? 7 : 5];
output = true;
}
}
}
if (!output)
{
if (i == 0)
cout << styles[style][4];
else if (i >= (height - 4))
cout << styles[style][10];
else
cout << styles[style][1];
cout << styles[style][1];
output = true;
}
}
else if (ayaxis)
{
if (axislabel and axisunitslabel)
if (j == 0)
{
int adivisor = divisor;
if (j < xaxis)
adivisor = -adivisor;
cout << styles[style][2];
output = true;
}
else if (j >= (width - 2))
{
cout << styles[style][4];
output = true;
}
else if (axislabel and axisunitslabel)
{
int adivisor = j < xaxis ? -xdivisor : xdivisor;
for (long double k = xaxis + adivisor; ((j < xaxis and k >= j) or (j > xaxis and k < (j + 2))) and j < (width - 4) and !output; k += adivisor)
for (long double k = xaxis + adivisor; (j < xaxis ? k >= j : k < (j + 2)) and j < (width - (2 * 2)) and !output; k += adivisor)
{
if (j <= k and (j + 2) > k)
{
cout << styles[style][3];
cout << styles[style][yaxis <= (height - 4) ? 3 : 9];
output = true;
}
}
}
if (!output)
{
if (j == 0)
cout << styles[style][2];
else if (j >= (width - 2))
cout << styles[style][4];
else
cout << styles[style][0];
cout << styles[style][0];
output = true;
}
}
else if (yaxislabel and xaxislabel and axislabel and axisunitslabel)
else if (yaxislabel and xaxislabel and axislabel and axisunitslabel and ymin <= 0 and ymax >= 0 and xmin <= 0 and xmax >= 0)
{
cout << "0";
output = true;
}
else if (j >= (width - 2) and yaxislabel and axislabel)
else if ((xaxis <= (width - 2) ? j >= (width - 2) : j == 0) and yaxislabel and axislabel)
{
cout << "x";
output = true;
@ -398,18 +436,15 @@ namespace graphs
else if (yaxislabel and axislabel and axisunitslabel)
{
long double label = 0;
int adivisor = divisor;
int adivisor = j < xaxis ? -xdivisor : xdivisor;
if (j < xaxis)
{
adivisor = -adivisor;
j += 2;
}
for (long double k = xaxis + adivisor; ((j < xaxis and k >= j) or (j > xaxis and k < (j + 2))) and j < (width - 2) and !output; k += adivisor)
for (long double k = xaxis + adivisor; (j < xaxis ? k >= j : k < (j + 2)) and j < (width - 2) and !output; k += adivisor)
{
if (j <= k and (j + 2) > k)
{
label = (k / xscl) + xmin;
label = ((k > width ? width : k) * xstep) + xmin;
output = true;
}
@ -423,9 +458,9 @@ namespace graphs
output = false;
ostringstream strm;
size_t length = outputlabel(label, strm);
size_t length = outputfraction(label, strm);
length *= 2;
if ((j >= xaxis or (j + length) < (xaxis - 4)) and (j + length) < (width - 2))
if ((j >= xaxis or (j + length) < (ymin <= 0 and ymax >= 0 and xmin <= 0 and xmax >= 0 ? xaxis - 4 : xaxis)) and (j + length) < (width - 2) and (xaxis <= (width - 2) or j > 2))
{
cout << strm.str();
@ -439,12 +474,12 @@ namespace graphs
}
}
}
else if (i == 0 and xaxislabel and axislabel)
else if ((yaxis >= 4 ? i == 0 : i >= (height - 4)) and xaxislabel and axislabel)
{
cout << "y";
output = true;
}
else if ((j <= (xaxis - ylabellength) and (j + 2) > (xaxis - ylabellength)) and axislabel and axisunitslabel)
else if (ylabellength and (xaxis < 2 ? xaxislabel : j < (xaxis - ylabellength) and (j + 2) >= (xaxis - ylabellength)) and (yaxis >= 4 or i < (height - 4)) and axislabel and axisunitslabel)
{
cout << ylabelstrm.str();
output = true;
@ -455,21 +490,23 @@ namespace graphs
if (!output)
{
unsigned int dot = 0;
size_t dot = 0;
unsigned short color = 0;
for (unsigned int k = 0; k < 2 and k < (width - j); ++k)
for (size_t k = 0; k < 2 and k < (width - j); ++k)
{
for (unsigned int l = 0; l < 4 and l < (height - i); ++l)
for (size_t l = 0; l < 4 and l < (height - i); ++l)
{
dot += (array[j + k][i + l] ? 1 : 0) * values[k][l];
const unsigned short value = array[j + k][i + l];
if (value)
dot += values[k][l];
if (color)
{
if (array[j + k][i + l] and color != array[j + k][i + l])
if (value and color != value)
color = 1;
}
else
color = array[j + k][i + l];
color = value;
}
}
@ -479,14 +516,15 @@ namespace graphs
if (color)
cout << colors[color];
cout << "\e[1m" << dots[dot] << "\e[22m";
cout << dots[dot];
if (color)
cout << colors[0];
}
}
cout << "\n";
if (i < (height - 4))
cout << "\n";
}
cout << endl;
@ -505,14 +543,11 @@ namespace graphs
{ return all_of(begin(array), end(array), [](const auto &x)
{ return graphs::size(x) == 2; }); }))
{
cerr << "Error: The arrays must have two columns.";
cerr << "Error: The arrays must have two columns.\n";
return 1;
}
const unsigned int color = aoptions.color;
if (color >= graphs::size(colors))
return 1;
const color_type color = aoptions.color;
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
@ -523,19 +558,22 @@ namespace graphs
if (width == 0)
width = w.ws_col * 2;
const int aheight = height / 4;
const int awidth = width / 2;
if (aheight > w.ws_row)
if (aoptions.check)
{
cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
return 1;
}
const size_t aheight = height / 4;
const size_t awidth = width / 2;
if (awidth > w.ws_col)
{
cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
return 1;
if (aheight > w.ws_row)
{
cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
return 1;
}
if (awidth > w.ws_col)
{
cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
return 1;
}
}
if (xmin == 0 and xmax == 0)
@ -570,32 +608,34 @@ namespace graphs
return 1;
}
const long double xscl = width / (xmax - xmin);
const long double yscl = height / (ymax - ymin);
const long double xaxis = width - (xmax * xscl);
const long double yaxis = ymax * yscl;
const long double xstep = (xmax - xmin) / width;
const long double ystep = (ymax - ymin) / height;
const long double xaxis = width - (xmax / xstep);
const long double yaxis = ymax / ystep;
vector<vector<unsigned short>> aarray(width, vector<unsigned short>(height, 0));
for (unsigned int j = 0; j < graphs::size(arrays); ++j)
for (size_t j = 0; j < graphs::size(arrays); ++j)
{
auto array = arrays[j];
const unsigned int color = (j % (graphs::size(colors) - 2)) + 3;
const auto &array = arrays[j];
const unsigned int acolor = graphs::size(arrays) == 1 ? color + 1 : (j % (graphs::size(colors) - 2)) + 3;
for (unsigned int i = 0; i < graphs::size(array); ++i)
for (size_t i = 0; i < graphs::size(array); ++i)
{
if (array[i][0] >= xmin and array[i][0] < xmax and array[i][1] >= ymin and array[i][1] < ymax)
const auto &x = array[i][0], &y = array[i][1];
if (x >= xmin and x < xmax and y >= ymin and y < ymax)
{
const long long x = (array[i][0] * xscl) + xaxis;
const long long y = (yaxis - (array[i][1] * yscl)) - 1;
const size_t ax = (x / xstep) + xaxis;
const size_t ay = (yaxis - (y / ystep)) - 1;
if (aarray[x][y])
if (aarray[ax][ay])
{
if (aarray[x][y] != color)
aarray[x][y] = 1;
if (aarray[ax][ay] != acolor)
aarray[ax][ay] = 1;
}
else
aarray[x][y] = color;
aarray[ax][ay] = acolor;
}
}
}
@ -621,7 +661,7 @@ namespace graphs
const size_t columns = 2;
vector<std::array<T, columns>> aaarray(rows);
for (unsigned int i = 0; i < rows; ++i)
for (size_t i = 0; i < rows; ++i)
copy(aarray[i], aarray[i] + columns, aaarray[i].begin());
return array(height, width, xmin, xmax, ymin, ymax, aaarray, aoptions);
@ -631,10 +671,7 @@ namespace graphs
template <typename T>
int functions(size_t height, size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, const size_t numfunctions, function<T(T)> functions[], const options &aoptions = defaultoptions)
{
const unsigned int color = aoptions.color;
if (color >= graphs::size(colors))
return 1;
const color_type color = aoptions.color;
if (numfunctions == 0)
return 1;
@ -648,19 +685,22 @@ namespace graphs
if (width == 0)
width = w.ws_col * 2;
const int aheight = height / 4;
const int awidth = width / 2;
if (aheight > w.ws_row)
if (aoptions.check)
{
cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
return 1;
}
const size_t aheight = height / 4;
const size_t awidth = width / 2;
if (awidth > w.ws_col)
{
cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
return 1;
if (aheight > w.ws_row)
{
cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
return 1;
}
if (awidth > w.ws_col)
{
cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
return 1;
}
}
if (xmin >= xmax)
@ -677,26 +717,27 @@ namespace graphs
const size_t rows = width;
const long double xscl = width / (xmax - xmin);
const long double yscl = height / (ymax - ymin);
const long double xaxis = width - (xmax * xscl);
const long double yaxis = ymax * yscl;
const long double xstep = (xmax - xmin) / width;
const long double ystep = (ymax - ymin) / height;
const long double xaxis = width - (xmax / xstep);
const long double yaxis = ymax / ystep;
const size_t xres = 2;
vector<vector<unsigned short>> array(width, vector<unsigned short>(height, 0));
for (unsigned int j = 0; j < numfunctions; ++j)
for (size_t j = 0; j < numfunctions; ++j)
{
unsigned short acolor = numfunctions == 1 ? color + 1 : (j % (graphs::size(colors) - 2)) + 3;
for (long double i = 0; i < rows; i += 0.5)
for (size_t i = 0; i < rows * xres; ++i)
{
T x = (i / xscl) + xmin;
T x = ((i / (long double)xres) * xstep) + xmin;
T y = (functions[j])(x);
if (x >= xmin and x < xmax and y >= ymin and y < ymax)
{
const long long ax = (x * xscl) + xaxis;
const long long ay = (yaxis - (y * yscl)) - 1;
const size_t ax = (x / xstep) + xaxis;
const size_t ay = (yaxis - (y / ystep)) - 1;
if (array[ax][ay])
{

View File

@ -2,7 +2,7 @@
### Usage
Requires Python 3.5 or greater and the [wcwidth library](https://pypi.org/project/wcwidth/), which users can install with: `pip3 install wcwidth`. See the [tables.py](tables.py) file for full usage information.
Requires Python 3.6 or greater and the [wcwidth library](https://pypi.org/project/wcwidth/), which users can install with: `pip3 install wcwidth`. See the [tables.py](tables.py) file for full usage information.
Complete versions of all of the examples below and more can be found in the [test.py](test.py) file.
@ -75,9 +75,9 @@ def afunction(x):
xmin = -10
xmax = 10
xscl = 2
xstep = 0.5
tables.function(xmin, xmax, xscl, afunction, headerrow=True)
tables.function(xmin, xmax, xstep, afunction, headerrow=True)
```
![](../images/function%20to%20table.png)
@ -89,11 +89,11 @@ import tables
xmin = -10
xmax = 10
xscl = 2
xstep = 0.5
afunction = lambda x: x + 1
tables.function(xmin, xmax, xscl, afunction, headerrow=True)
tables.function(xmin, xmax, xstep, afunction, headerrow=True)
```
Output same as example above.
@ -111,12 +111,12 @@ def function2(x):
xmin = -10
xmax = 10
xscl = 2
xstep = 0.5
# Function parameter and return value can be any data type, as long as they are the same
functions = [function1, function2]
tables.functions(xmin, xmax, xscl, functions, headerrow=True)
tables.functions(xmin, xmax, xstep, functions, headerrow=True)
```
![](../images/multiple%20functions%20to%20table.png)
@ -128,12 +128,12 @@ import tables
xmin = -10
xmax = 10
xscl = 2
xstep = 0.5
# Function parameter and return value can be any data type, as long as they are the same
functions = [lambda x: 2 * x, lambda x: x ** 2]
tables.functions(xmin, xmax, xscl, functions, headerrow=True)
tables.functions(xmin, xmax, xstep, functions, headerrow=True)
```
Output same as example above.
@ -174,7 +174,8 @@ Default value: `1`
Option: `alignment`\
Values:
* `False` (left, default)
* `None` (default)
* `False` (left)
* `True` (right)
#### Title
@ -189,33 +190,40 @@ The title is word wrapped based on the current width of the terminal. Handles ne
Option: `style`\
Values:
0. ASCII
0. `style_types.ASCII`: ASCII
![](../images/ASCII%20table.png)
1. Basic
1. `style_types.basic`: Basic
![](../images/basic%20table.png)
2. Light (default)
2. `style_types.light`: Light (default)
![](../images/light%20table.png)
3. Heavy
3. `style_types.heavy`: Heavy
![](../images/heavy%20table.png)
4. Double
4. `style_types.double`: Double
![](../images/double%20table.png)
5. Light Dashed
5. `style_types.light_dashed`: Light Dashed
![](../images/light%20dashed%20table.png)
6. Heavy Dashed
6. `style_types.heavy_dashed`: Heavy Dashed
![](../images/heavy%20dashed%20table.png)
#### Check size
Option: `check`\
Default value: `True`
Check that the width of the table is not greater then the width of the terminal.
## Graphs/Plots
### Usage
Requires Python 3.5 or greater and the [wcwidth library](https://pypi.org/project/wcwidth/), which users can install with: `pip3 install wcwidth`. See the [graphs.py](graphs.py) file for full usage information.
Requires Python 3.6 or greater and the [wcwidth library](https://pypi.org/project/wcwidth/), which users can install with: `pip3 install wcwidth`. See the [graphs.py](graphs.py) file for full usage information.
Complete versions of all of the examples below and more can be found in the [test.py](test.py) file.
@ -369,25 +377,25 @@ The title is word wrapped based on the current width of the terminal. Handles ne
Option: `style`\
Values:
0. ASCII
0. `style_types.ASCII`: ASCII
![](../images/ASCII%20graph.png)
1. Basic
1. `style_types.basic`: Basic
![](../images/basic%20graph.png)
2. Light (default)
2. `style_types.light`: Light (default)
![](../images/light%20graph.png)
3. Heavy
3. `style_types.heavy`: Heavy
![](../images/heavy%20graph.png)
4. Double
4. `style_types.double`: Double
![](../images/double%20graph.png)
5. Light Dashed
5. `style_types.light_dashed`: Light Dashed
![](../images/light%20dashed%20graph.png)
6. Heavy Dashed
6. `style_types.heavy_dashed`: Heavy Dashed
![](../images/heavy%20dashed%20graph.png)
@ -396,27 +404,25 @@ Values:
Option: `color`\
Values:
0. System default
1. Black
2. Red (default)
3. Green
4. Yellow
5. Blue
6. Cyan
7. Light gray
8. Dark gray
9. Light red
10. Light green
11. Light yellow
12. Light blue
13. Light cyan
14. White
0. `color_types.default`: System default
1. `color_types.black`: Black
2. `color_types.red`: Red (default)
3. `color_types.green`: Green
4. `color_types.yellow`: Yellow
5. `color_types.blue`: Blue
6. `color_types.cyan`: Cyan
7. `color_types.dark_gray`: Light gray
8. `color_types.dark_gray`: Dark gray
9. `color_types.light_red`: Light red
10. `color_types.light_green`: Light green
11. `color_types.light_yellow`: Light yellow
12. `color_types.light_blue`: Light blue
13. `color_types.light_cyan`: Light cyan
14. `color_types.white`: White
See [here](https://misc.flogisoft.com/bash/tip_colors_and_formatting#foreground_text) for examples of the colors.
Only used for plots and when graphing a single function.
When graphing multiple functions, colors `2` - `14` are used inorder. Color `0` is used where the functions cross.
Only used when plotting a single array and when graphing a single function. When plotting multiple arrays or graphing multiple functions, colors 2 - 14 are used inorder. The system default color is used where the plots cross.
##### Plot
@ -425,3 +431,10 @@ When graphing multiple functions, colors `2` - `14` are used inorder. Color `0`
##### Graph
![](../images/graph%20colors.png)
#### Check size
Option: `check`\
Default value: `True`
Check that the width and height of the graph are not greater then the respective width and height of the terminal.

View File

@ -7,13 +7,26 @@ from __future__ import division, print_function, unicode_literals
import sys
import math
import shutil
from fractions import Fraction
import textwrap
from enum import Enum, IntEnum, auto
from wcwidth import wcswidth
from typing import List, Tuple, Optional, Sequence, Callable
import locale
locale.setlocale(locale.LC_ALL, '')
class style_types(IntEnum):
ASCII = 0
basic = auto()
light = auto()
heavy = auto()
double = auto()
light_dashed = auto()
heavy_dashed = auto()
styles = [
["-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"], # ASCII
["", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"], # Basic
@ -25,33 +38,71 @@ styles = [
]
# [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]] #No border
colors = ["\033[39m", "\033[30m", "\033[31m", "\033[32m", "\033[33m", "\033[34m", "\033[35m", "\033[36m",
"\033[37m", "\033[90m", "\033[91m", "\033[92m", "\033[93m", "\033[94m", "\033[95m", "\033[96m", "\033[97m"]
dots = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
class color_types(IntEnum):
default = 0
black = auto()
red = auto()
green = auto()
yellow = auto()
blue = auto()
cyan = auto()
light_gray = auto()
dark_gray = auto()
light_red = auto()
light_green = auto()
light_yellow = auto()
light_blue = auto()
light_cyan = auto()
white = auto()
colors = ["\033[39m", "\033[30m", "\033[31m", "\033[32m", "\033[33m",
"\033[34m", "\033[35m", "\033[36m", "\033[37m", "\033[90m",
"\033[91m", "\033[92m", "\033[93m", "\033[94m", "\033[95m",
"\033[96m", "\033[97m"]
dots = [
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
""]
values = [[0x1, 0x2, 0x4, 0x40], [0x8, 0x10, 0x20, 0x80]]
fractions = {
"¼": 1.0 / 4.0,
"½": 1.0 / 2.0,
"¾": 3.0 / 4.0,
"": 1.0 / 7.0,
"": 1.0 / 9.0,
"": 1.0 / 10.0,
"": 1.0 / 3.0,
"": 2.0 / 3.0,
"": 1.0 / 5.0,
"": 2.0 / 5.0,
"": 3.0 / 5.0,
"": 4.0 / 5.0,
"": 1.0 / 6.0,
"": 5.0 / 6.0,
"": 1.0 / 8.0,
"": 3.0 / 8.0,
"": 5.0 / 8.0,
"": 7.0 / 8.0
"¼": Fraction(1, 4),
"½": Fraction(1, 2),
"¾": Fraction(3, 4),
"": Fraction(1, 7),
"": Fraction(1, 9),
"": Fraction(1, 10),
"": Fraction(1, 3),
"": Fraction(2, 3),
"": Fraction(1, 5),
"": Fraction(2, 5),
"": Fraction(3, 5),
"": Fraction(4, 5),
"": Fraction(1, 6),
"": Fraction(5, 6),
"": Fraction(1, 8),
"": Fraction(3, 8),
"": Fraction(5, 8),
"": Fraction(7, 8)
}
constants = {
@ -59,68 +110,75 @@ constants = {
"e": math.e
}
MAX = sys.float_info.radix ** sys.float_info.mant_dig - 1
def strcol(str: str) -> int:
def strcol(astr: str) -> int:
"""Returns the number of columns that the given string would take up if printed."""
width = wcswidth(str)
width = wcswidth(astr)
if width == -1:
print("\nError! wcswidth failed. Nonprintable wide character.", file=sys.stderr)
print(
"\nError! wcswidth failed. Nonprintable wide character.",
file=sys.stderr)
sys.exit(1)
return width
# return len(str)
# return len(astr)
def outputlabel(label: float) -> Tuple[int, str]:
"""Outputs a label in a nice, human readable format."""
def outputfraction(number: float) -> Tuple[int, str]:
"""Convert fractions and constants to Unicode characters"""
output = False
fractionpart, intpart = math.modf(label)
fractionpart = abs(fractionpart)
strm = ""
for fraction in fractions:
if abs(fractionpart - fractions[fraction]) < sys.float_info.epsilon:
if intpart != 0:
strm += str(intpart)
n = abs(number)
strm += fraction
if n <= MAX:
# fractionpart, intpart = math.modf(number)
# fractionpart = abs(fractionpart)
intpart, fractionpart = divmod(Fraction(number).limit_denominator(), 1)
output = True
break
if abs(label) >= sys.float_info.epsilon and not output:
for constant in constants:
if not output and label % constants[constant] == 0:
intpart = label / constants[constant]
if intpart == -1:
for fraction, value in fractions.items():
if abs(fractionpart - value) <= sys.float_info.epsilon * n:
if intpart == 0 and number < 0:
strm += "-"
elif intpart != 1:
strm += str(intpart)
elif intpart != 0:
strm += "{0:n}".format(intpart)
strm += constant
strm += fraction
output = True
break
if n > sys.float_info.epsilon and not output:
for constant, value in constants.items():
if not output and number % value <= sys.float_info.epsilon * n:
intpart = number / value
if intpart == -1:
strm += "-"
elif intpart != 1:
strm += "{0:.{prec}n}".format(intpart,
prec=sys.float_info.dig)
strm += constant
output = True
break
if not output:
strm += "{0:n}".format(label)
strm += "{0:n}".format(number)
length = strcol(strm)
return length, strm
def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, array: List[List[int]], border: bool = True, axislabel: bool = True, axisunitslabel: bool = True, style: int = 2, title: Optional[str] = None) -> int:
def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, array: List[List[int]], border: bool = True, axislabel: bool = True, axisunitslabel: bool = True, style: style_types = style_types.light, title: Optional[str] = None, check: bool = True) -> int:
"""Output graph"""
if not array:
return 1
if not (0 <= style < len(styles)):
return 1
if height == 0:
return 1
@ -129,18 +187,19 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
w = shutil.get_terminal_size()
aheight = height // 4
awidth = width // 2
if check:
aheight = height // 4
awidth = width // 2
if aheight > w.lines:
print("The height of the graph ({0}) is greater then the height of the terminal ({1}).".format(
aheight, w.lines), file=sys.stderr)
return 1
if aheight > w.lines:
print("The height of the graph ({0}) is greater then the height of the terminal ({1}).".format(
aheight, w.lines), file=sys.stderr)
return 1
if awidth > w.columns:
print("The width of the graph ({0}) is greater then the width of the terminal ({1}).".format(
awidth, w.columns), file=sys.stderr)
return 1
if awidth > w.columns:
print("The width of the graph ({0}) is greater then the width of the terminal ({1}).".format(
awidth, w.columns), file=sys.stderr)
return 1
if xmin >= xmax:
print("xmin must be less than xmax.", file=sys.stderr)
@ -150,46 +209,51 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
print("ymin must be less than ymax.", file=sys.stderr)
return 1
xscl = width / (xmax - xmin)
yscl = height / (ymax - ymin)
xaxis = width - (xmax * xscl)
yaxis = ymax * yscl
divisor = 2 * 4 * ((width // 160) + 1 if (width / 160.0) > 1 else 1)
xstep = (xmax - xmin) / width
ystep = (ymax - ymin) / height
xaxis = 0 if xmin > 0 else width if xmax < 0 else width - (xmax / xstep)
yaxis = height if ymin > 0 else 0 if ymax < 0 else ymax / ystep
xdivisor = 2 * 4 * ((width // 160) + 2)
ydivisor = 2 * 4 * ((height // 160) + 2)
if title:
print(textwrap.fill(title, width=w.columns))
print(textwrap.fill(title, width=width // 2))
strm = ""
i = 0
while i < height:
ayaxis = i <= yaxis and (i + 4) > yaxis
yaxislabel = i <= (yaxis + 4) and (i + 4) > (yaxis + 4)
ayaxis = i <= yaxis and (
i + 4) > yaxis if yaxis <= (height - 4) else i < yaxis and (i + 4) >= yaxis
yaxislabel = i <= (yaxis + 4) and (i + 4) > (yaxis + 4) if yaxis <= (
height - 4) else i < (yaxis - 4) and (i + 4) >= (yaxis - 4)
ylabelstrm = ""
ylabellength = 0
if border and axislabel and axisunitslabel:
if border and axislabel and axisunitslabel and yaxis >= 0 and yaxis <= height:
output = False
label = 0.0
adivisor = -divisor if i < yaxis else divisor
adivisor = -ydivisor if i < yaxis else ydivisor
k = yaxis + adivisor
while ((i < yaxis and k >= i) or (i > yaxis and k < (i + 4))) and i >= 4 and not output:
while (k >= i if i < yaxis else k < (i + 4)) and i >= 4 and not output:
if (i <= k and (i + 4) > k):
label = ymax - (k / yscl)
label = ymax - ((height if k > height else k) * ystep)
output = True
k += adivisor
if (output):
ylabellength, ylabelstrm = outputlabel(label)
ylabellength, ylabelstrm = outputfraction(label)
ylabellength *= 2
j = 0
while j < width:
axaxis = j <= xaxis and (j + 2) > xaxis
xaxislabel = j <= (xaxis - 2) and (j + 2) > (xaxis - 2)
axaxis = j < xaxis and (
j + 2) >= xaxis if xaxis >= 2 else j <= xaxis and (j + 2) > xaxis
xaxislabel = j < (xaxis - 2) and (j + 2) >= (
xaxis - 2) if xaxis >= 2 else j <= (xaxis + 2) and (j + 2) > (xaxis + 2)
output = False
@ -198,57 +262,61 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
strm += styles[style][6]
output = True
elif axaxis:
if axislabel and axisunitslabel:
adivisor = -divisor if i < yaxis else divisor
if i == 0:
strm += styles[style][4]
output = True
elif i >= (height - 4):
strm += styles[style][10]
output = True
elif axislabel and axisunitslabel:
adivisor = -ydivisor if i < yaxis else ydivisor
k = yaxis + adivisor
while ((i < yaxis and k >= i) or (i > yaxis and k < (i + 4))) and i >= 4 and not output:
while (k >= i if i < yaxis else k < (i + 4)) and i >= 4 and not output:
if i <= k and (i + 4) > k:
strm += styles[style][7]
strm += styles[style][7 if xaxis >= 2 else 5]
output = True
k += adivisor
if not output:
if i == 0:
strm += styles[style][4]
elif i >= (height - 4):
strm += styles[style][10]
else:
strm += styles[style][1]
strm += styles[style][1]
output = True
elif ayaxis:
if axislabel and axisunitslabel:
adivisor = -divisor if j < xaxis else divisor
if j == 0:
strm += styles[style][2]
output = True
elif j >= (width - 2):
strm += styles[style][4]
output = True
elif axislabel and axisunitslabel:
adivisor = -xdivisor if j < xaxis else xdivisor
k = xaxis + adivisor
while ((j < xaxis and k >= j) or (j > xaxis and k < (j + 2))) and j < (width - 4) and not output:
while (k >= j if j < xaxis else k < (j + 2)) and j < (width - 4) and not output:
if j <= k and (j + 2) > k:
strm += styles[style][3]
strm += styles[style][3 if yaxis <=
(height - 4) else 9]
output = True
k += adivisor
if not output:
if j == 0:
strm += styles[style][2]
elif j >= (width - 2):
strm += styles[style][4]
else:
strm += styles[style][0]
strm += styles[style][0]
output = True
elif yaxislabel and xaxislabel and axislabel and axisunitslabel:
elif yaxislabel and xaxislabel and axislabel and axisunitslabel and ymin <= 0 and ymax >= 0 and xmin <= 0 and xmax >= 0:
strm += "0"
output = True
elif j >= (width - 2) and yaxislabel and axislabel:
elif (j >= (width - 2) if xaxis <= (width - 2) else j == 0) and yaxislabel and axislabel:
strm += "x"
output = True
elif yaxislabel and axislabel and axisunitslabel:
label = 0.0
adivisor = -divisor if j < xaxis else divisor
adivisor = -xdivisor if j < xaxis else xdivisor
if j < xaxis:
j += 2
k = xaxis + adivisor
while ((j < xaxis and k >= j) or (j > xaxis and k < (j + 2))) and j < (width - 2) and not output:
while (k >= j if j < xaxis else k < (j + 2)) and j < (width - 2) and not output:
if j <= k and (j + 2) > k:
label = (k / xscl) + xmin
label = ((width if k > width else k)
* xstep) + xmin
output = True
k += adivisor
@ -259,7 +327,7 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
if output:
output = False
length, astrm = outputlabel(label)
length, astrm = outputfraction(label)
length *= 2
if (j >= xaxis or (j + length) < (xaxis - 4)) and (j + length) < (width - 2):
strm += astrm
@ -271,10 +339,10 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
output = True
else:
j += 2
elif i == 0 and xaxislabel and axislabel:
elif (i == 0 if yaxis >= 4 else i >= (height - 4)) and xaxislabel and axislabel:
strm += "y"
output = True
elif (j <= (xaxis - ylabellength) and (j + 2) > (xaxis - ylabellength)) and axislabel and axisunitslabel:
elif ylabellength and (xaxislabel if xaxis < 2 else j < (xaxis - ylabellength) and (j + 2) >= (xaxis - ylabellength)) and (yaxis >= 4 or i < (height - 4)) and axislabel and axisunitslabel:
strm += ylabelstrm
output = True
if ylabellength > 2:
@ -299,14 +367,15 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
if color:
strm += colors[color]
strm += "\033[1m" + dots[dot] + "\033[22m"
strm += dots[dot]
if color:
strm += colors[0]
j += 2
strm += "\n"
if i < (height - 4):
strm += "\n"
i += 4
print(strm)
@ -314,7 +383,7 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
return 0
def arrays(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarrays: Sequence[Sequence[Sequence[float]]], border: bool = True, axislabel: bool = True, axisunitslabel: bool = True, style: int = 2, color: int = 2, title: Optional[str] = None) -> int:
def arrays(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarrays: Sequence[Sequence[Sequence[float]]], border: bool = True, axislabel: bool = True, axisunitslabel: bool = True, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, check: bool = True) -> int:
"""Convert one or more arrays to graph and output"""
if not aarrays:
return 1
@ -323,9 +392,6 @@ def arrays(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
print("Error: The arrays must have two columns.")
return 1
if color < 0 or color >= len(colors):
return 1
w = shutil.get_terminal_size()
if height == 0:
@ -334,18 +400,19 @@ def arrays(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
if width == 0:
width = w.columns * 2
aheight = height // 4
awidth = width // 2
if check:
aheight = height // 4
awidth = width // 2
if aheight > w.lines:
print("The height of the graph ({0}) is greater then the height of the terminal ({1}).".format(
aheight, w.lines), file=sys.stderr)
return 1
if aheight > w.lines:
print("The height of the graph ({0}) is greater then the height of the terminal ({1}).".format(
aheight, w.lines), file=sys.stderr)
return 1
if awidth > w.columns:
print("The width of the graph ({0}) is greater then the width of the terminal ({1}).".format(
awidth, w.columns), file=sys.stderr)
return 1
if awidth > w.columns:
print("The width of the graph ({0}) is greater then the width of the terminal ({1}).".format(
awidth, w.columns), file=sys.stderr)
return 1
if xmin == 0 and xmax == 0:
xmin = min(i[0] for aarray in aarrays for i in aarray)
@ -363,10 +430,10 @@ def arrays(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
print("ymin must be less than ymax.", file=sys.stderr)
return 1
xscl = width / (xmax - xmin)
yscl = height / (ymax - ymin)
xaxis = width - (xmax * xscl)
yaxis = ymax * yscl
xstep = (xmax - xmin) / width
ystep = (ymax - ymin) / height
xaxis = width - (xmax / xstep)
yaxis = ymax / ystep
aaarray = [[0 for j in range(height)] for i in range(width)]
@ -376,8 +443,8 @@ def arrays(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
for i in aarray:
if i[0] >= xmin and i[0] < xmax and i[1] >= ymin and i[1] < ymax:
x = int((i[0] * xscl) + xaxis)
y = int((yaxis - (i[1] * yscl)) - 1)
x = int((i[0] / xstep) + xaxis)
y = int((yaxis - (i[1] / ystep)) - 1)
if aaarray[x][y]:
if aaarray[x][y] != acolor:
@ -385,19 +452,18 @@ def arrays(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
else:
aaarray[x][y] = acolor
return graph(height, width, xmin, xmax, ymin, ymax, aaarray, border=border, axislabel=axislabel, axisunitslabel=axisunitslabel, style=style, title=title)
return graph(height, width, xmin, xmax, ymin, ymax, aaarray, border=border,
axislabel=axislabel, axisunitslabel=axisunitslabel, style=style, title=title)
def array(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarray: Sequence[Sequence[float]], border: bool = True, axislabel: bool = True, axisunitslabel: bool = True, style: int = 2, color: int = 2, title: Optional[str] = None) -> int:
def array(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarray: Sequence[Sequence[float]], border: bool = True, axislabel: bool = True, axisunitslabel: bool = True, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None) -> int:
"""Convert single array to graph and output"""
return arrays(height, width, xmin, xmax, ymin, ymax, [aarray], border=border, axislabel=axislabel, axisunitslabel=axisunitslabel, style=style, color=color, title=title)
return arrays(height, width, xmin, xmax, ymin, ymax, [
aarray], border=border, axislabel=axislabel, axisunitslabel=axisunitslabel, style=style, color=color, title=title)
def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, afunctions: Sequence[Callable[[float], float]], border: bool = True, axislabel: bool = True, axisunitslabel: bool = True, style: int = 2, color: int = 2, title: Optional[str] = None) -> int:
def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, afunctions: Sequence[Callable[[float], float]], border: bool = True, axislabel: bool = True, axisunitslabel: bool = True, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, check: bool = True) -> int:
"""Convert one or more functions to graph and output"""
if color < 0 or color >= len(colors):
return 1
if not afunctions:
return 1
@ -409,18 +475,19 @@ def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
if width == 0:
width = w.columns * 2
aheight = height // 4
awidth = width // 2
if check:
aheight = height // 4
awidth = width // 2
if aheight > w.lines:
print("The height of the graph ({0}) is greater then the height of the terminal ({1}).".format(
aheight, w.lines), file=sys.stderr)
return 1
if aheight > w.lines:
print("The height of the graph ({0}) is greater then the height of the terminal ({1}).".format(
aheight, w.lines), file=sys.stderr)
return 1
if awidth > w.columns:
print("The width of the graph ({0}) is greater then the width of the terminal ({1}).".format(
awidth, w.columns), file=sys.stderr)
return 1
if awidth > w.columns:
print("The width of the graph ({0}) is greater then the width of the terminal ({1}).".format(
awidth, w.columns), file=sys.stderr)
return 1
if xmin >= xmax:
print("xmin must be less than xmax.", file=sys.stderr)
@ -432,10 +499,11 @@ def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
rows = width
xscl = width / (xmax - xmin)
yscl = height / (ymax - ymin)
xaxis = width - (xmax * xscl)
yaxis = ymax * yscl
xstep = (xmax - xmin) / width
ystep = (ymax - ymin) / height
xaxis = width - (xmax / xstep)
yaxis = ymax / ystep
xres = 2
array = [[0 for j in range(height)] for i in range(width)]
@ -443,13 +511,13 @@ def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
acolor = color + 1 if len(afunctions) == 1 else (j %
(len(colors) - 2)) + 3
for i in (x / 2 for x in range(rows * 2)):
x = (i / xscl) + xmin
for i in (x / xres for x in range(rows * xres)):
x = (i * xstep) + xmin
y = function(x)
if x >= xmin and x < xmax and y >= ymin and y < ymax:
ax = int((x * xscl) + xaxis)
ay = int((yaxis - (y * yscl)) - 1)
ax = int((x / xstep) + xaxis)
ay = int((yaxis - (y / ystep)) - 1)
if array[ax][ay]:
if array[ax][ay] != acolor:
@ -457,9 +525,11 @@ def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
else:
array[ax][ay] = acolor
return graph(height, width, xmin, xmax, ymin, ymax, array, border=border, axislabel=axislabel, axisunitslabel=axisunitslabel, style=style, title=title)
return graph(height, width, xmin, xmax, ymin, ymax, array, border=border,
axislabel=axislabel, axisunitslabel=axisunitslabel, style=style, title=title)
def function(height, width, xmin: float, xmax: float, ymin: float, ymax: float, afunction: Callable[[float], float], border: bool = True, axislabel: bool = True, axisunitslabel: bool = True, style: int = 2, color: int = 2, title: Optional[str] = None) -> int:
def function(height, width, xmin: float, xmax: float, ymin: float, ymax: float, afunction: Callable[[float], float], border: bool = True, axislabel: bool = True, axisunitslabel: bool = True, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None) -> int:
"""Convert single function to function array and output"""
return functions(height, width, xmin, xmax, ymin, ymax, [afunction], border=border, axislabel=axislabel, axisunitslabel=axisunitslabel, style=style, color=color, title=title)
return functions(height, width, xmin, xmax, ymin, ymax, [
afunction], border=border, axislabel=axislabel, axisunitslabel=axisunitslabel, style=style, color=color, title=title)

View File

@ -8,12 +8,24 @@ import sys
import shutil
import re
import textwrap
from enum import IntEnum, auto
from wcwidth import wcswidth
from typing import List, Optional, Any, Sequence, Callable
import locale
locale.setlocale(locale.LC_ALL, '')
class style_types(IntEnum):
ASCII = 0
basic = auto()
light = auto()
heavy = auto()
double = auto()
light_dashed = auto()
heavy_dashed = auto()
styles = [
["-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"], # ASCII
["", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"], # Basic
@ -28,25 +40,24 @@ styles = [
ansi = re.compile(r'\x1B\[(?:[0-9]+(?:;[0-9]+)*)?m')
def strcol(str: str) -> int:
def strcol(astr: str) -> int:
"""Returns the number of columns that the given string would take up if printed."""
str = ansi.sub('', str)
width = wcswidth(str)
astr = ansi.sub('', astr)
width = wcswidth(astr)
if width == -1:
print("\nError! wcswidth failed. Nonprintable wide character.", file=sys.stderr)
print(
"\nError! wcswidth failed. Nonprintable wide character.",
file=sys.stderr)
sys.exit(1)
return width
# return len(str)
# return len(astr)
def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: bool = False, title: Optional[str] = None, style: int = 2) -> int:
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:
"""Output char array as table"""
if not array:
return 1
if not (0 <= style < len(styles)):
return 1
rows = len(array)
columns = len(array[0])
@ -61,13 +72,14 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
else:
width += (2 * padding) * columns
if width > w.columns:
print("The width of the table ({0}) is greater then the width of the terminal ({1}).".format(
width, w.columns), file=sys.stderr)
return 1
if check:
if width > w.columns:
print("The width of the table ({0}) is greater then the width of the terminal ({1}).".format(
width, w.columns), file=sys.stderr)
return 1
if title:
print(textwrap.fill(title, width=w.columns))
print(textwrap.fill(title, width=width))
strm = ""
@ -77,18 +89,22 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
for j in range(columns):
strm += styles[style][0] * ((2 * padding) + columnwidth[j])
if j == (columns - 1):
strm += styles[style][4] + "\n"
elif cellborder or headerrow or (j == 0 and headercolumn):
strm += styles[style][3]
else:
strm += styles[style][0]
if j < (columns - 1):
if cellborder or headerrow or (j == 0 and headercolumn):
strm += styles[style][3]
else:
strm += styles[style][0]
strm += styles[style][4] + "\n"
for i in range(rows):
if tableborder:
strm += styles[style][1]
for j in range(columns):
if (j == 0 and tableborder) or (j > 0 and cellborder) or (i == 0 and j > 0 and headerrow) or (j == 1 and headercolumn):
if (j > 0 and cellborder) or (i == 0 and j > 0 and headerrow) or (j == 1 and headercolumn):
strm += styles[style][1]
elif tableborder or (i > 0 and j > 0 and headerrow) or (j > 1 and headercolumn):
elif j > 0 and (tableborder or (i > 0 and headerrow) or headercolumn):
strm += " "
awidth = columnwidth[j] - (strcol(array[i][j]) - len(array[i][j]))
@ -102,7 +118,9 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
else:
strm += " " * padding
if alignment:
if alignment is None:
strm += "{0:{width}}".format(array[i][j], width=awidth)
elif alignment:
strm += array[i][j].rjust(awidth)
else:
strm += array[i][j].ljust(awidth)
@ -127,17 +145,7 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
elif i < (rows - 1) and headercolumn:
strm += " " * ((2 * padding) + columnwidth[j])
if j == (columns - 1):
if tableborder:
if i == (rows - 1):
strm += styles[style][10]
elif cellborder or (i == 0 and headerrow):
strm += styles[style][7]
elif headercolumn:
strm += styles[style][1]
strm += "\n"
else:
if j < (columns - 1):
if i == (rows - 1) and tableborder:
if cellborder or (j == 0 and headercolumn):
strm += styles[style][9]
@ -153,12 +161,23 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
else:
strm += " "
if tableborder:
if i == (rows - 1):
strm += styles[style][10]
elif cellborder or (i == 0 and headerrow):
strm += styles[style][7]
elif headercolumn:
strm += styles[style][1]
if i < (rows - 1):
strm += "\n"
print(strm)
return 0
def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[Any]] = None, aheadercolumn: Optional[Sequence[Any]] = None, headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: bool = False, title: Optional[str] = None, style: int = 2) -> int:
def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[Any]] = None, aheadercolumn: Optional[Sequence[Any]] = 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:
"""Convert array to char array and output as table"""
if not aarray:
return 1
@ -167,7 +186,9 @@ def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[Any]] =
columns = len(aarray[0])
if not all(len(x) == columns for x in aarray):
print("Error: The rows of the array must have the same number of columns.", file=sys.stderr)
print(
"Error: The rows of the array must have the same number of columns.",
file=sys.stderr)
return 1
if aheaderrow:
@ -177,50 +198,36 @@ def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[Any]] =
columns += 1
if aheaderrow and len(aheaderrow) != columns:
print("Error: The header row must have the same number of columns as the array.", file=sys.stderr)
print(
"Error: The header row must have the same number of columns as the array.",
file=sys.stderr)
return 1
if aheadercolumn and len(aheadercolumn) != (rows - 1 if aheaderrow else rows):
print("Error: The header column must have the same number of rows as the array.", file=sys.stderr)
print(
"Error: The header column must have the same number of rows as the array.",
file=sys.stderr)
return 1
aaarray = [["" for j in range(columns)] for i in range(rows)]
i = 0
if aheaderrow:
for j in range(columns):
aaarray[i][j] = aheaderrow[j]
aaarray[0] = aheaderrow[:columns]
i += 1
for i in range(1 if aheaderrow else 0, rows):
ii = i - 1 if aheaderrow else i
j = 0
ii = 0
for i in range(i, rows):
if aheadercolumn:
aii = i
aaarray[i][0] = aheadercolumn[ii]
if aheaderrow:
aii -= 1
j = 1 if aheadercolumn else 0
aaarray[i][j:] = map(str, aarray[ii][:columns - j])
aaarray[i][j] = aheadercolumn[aii]
j += 1
jj = 0
for j in range(j, columns):
aaarray[i][j] = str(aarray[ii][jj])
jj += 1
j = 0
ii += 1
return table(aaarray, headerrow=headerrow, headercolumn=headercolumn, tableborder=tableborder, cellborder=cellborder, padding=padding, alignment=alignment, title=title, style=style)
return table(aaarray, headerrow=headerrow, headercolumn=headercolumn, tableborder=tableborder,
cellborder=cellborder, padding=padding, alignment=alignment, title=title, style=style)
def functions(xmin: float, xmax: float, xscl: float, afunctions: Sequence[Callable[[float], float]], headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: bool = False, title: Optional[str] = None, style: int = 2) -> 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: Optional[bool] = None, title: Optional[str] = None, style: style_types = style_types.light) -> int:
"""Convert one or more functions to array and output as table"""
if not afunctions:
return 1
@ -229,11 +236,11 @@ def functions(xmin: float, xmax: float, xscl: float, afunctions: Sequence[Callab
print("xmin must be less than xmax.", file=sys.stderr)
return 1
if xscl <= 0:
print("xscl must be greater than zero.", file=sys.stderr)
if xstep <= 0:
print("xstep must be greater than zero.", file=sys.stderr)
return 1
rows = int(((xmax - xmin) * xscl)) + 1
rows = int(((xmax - xmin) / xstep)) + 1
columns = len(afunctions) + 1
aaheaderrow = ["x", "y"]
@ -241,23 +248,24 @@ def functions(xmin: float, xmax: float, xscl: float, afunctions: Sequence[Callab
aheaderrow = [""] * columns
for j in range(columns):
if j < (length - 1) or len(afunctions) == 1:
aheaderrow[j] = aaheaderrow[j]
else:
aheaderrow[j] = aaheaderrow[length - 1] + str(j - length + 2)
if len(afunctions) == 1:
aheaderrow = aaheaderrow
else:
aheaderrow = aaheaderrow[:-1] + [aaheaderrow[-1] +
str(j - length + 2) for j in range(1, columns)]
aarray = [[0 for j in range(columns)] for i in range(rows)]
for i in range(rows):
aarray[i][0] = (i / xscl) + xmin
aarray[i][0] = (i * xstep) + xmin
for j, function in enumerate(afunctions):
aarray[i][j + 1] = function(aarray[i][0])
aarray[i][1:] = [function(aarray[i][0]) for function in afunctions]
return array(aarray, aheaderrow, None, headerrow=headerrow, headercolumn=headercolumn, tableborder=tableborder, cellborder=cellborder, padding=padding, alignment=alignment, title=title, style=style)
return array(aarray, aheaderrow, None, headerrow=headerrow, headercolumn=headercolumn, tableborder=tableborder,
cellborder=cellborder, padding=padding, alignment=alignment, title=title, style=style)
def function(xmin: float, xmax: float, xscl: float, afunction: Callable[[float], float], headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: bool = False, title: Optional[str] = None, style: int = 2) -> 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: Optional[bool] = None, title: Optional[str] = None, style: style_types = style_types.light) -> int:
"""Convert single function to array and output as table"""
return functions(xmin, xmax, xscl, [afunction], headerrow=headerrow, headercolumn=headercolumn, tableborder=tableborder, cellborder=cellborder, padding=padding, alignment=alignment, title=title, style=style)
return functions(xmin, xmax, xstep, [afunction], headerrow=headerrow, headercolumn=headercolumn,
tableborder=tableborder, cellborder=cellborder, padding=padding, alignment=alignment, title=title, style=style)

View File

@ -21,17 +21,17 @@ columns = 5
xmin = -10
xmax = 10
xscl = 2
xstep = 0.5
print("\nOutput array as table\n")
array = [[random.randint(0, sys.maxsize)
for j in range(columns)] for i in range(rows)]
for k in range(len(tables.styles)):
tables.array(array, None, None, style=k)
for style in tables.style_types:
tables.array(array, None, None, style=style)
array = [[random.random() for j in range(columns)] for i in range(rows)]
for k in range(len(tables.styles)):
tables.array(array, None, None, style=k)
for style in tables.style_types:
tables.array(array, None, None, style=style)
print("\nOutput char array as table\n")
array = [["Header row/column 1", "Header row 2", "Header row 3", "Header row 4", "Header row 5"],
@ -39,8 +39,9 @@ array = [["Header row/column 1", "Header row 2", "Header row 3", "Header row 4",
["Header column 3", "Data 5", "Data 6", "Data 7", "Data 8"],
["Header column 4", "Data 9", "Data 10", "Data 11", "Data 12"],
["Header column 5", "Data 13", "Data 14", "Data 15", "Data 16"]]
for k in range(len(tables.styles)):
tables.array(array, None, None, headerrow=True, headercolumn=True, style=k)
for style in tables.style_types:
tables.array(array, None, None, headerrow=True,
headercolumn=True, style=style)
print("\nOutput array as table with separate header row and column\n")
array = [["Data {0:n}".format(i + j) for j in range(4)]
@ -50,44 +51,52 @@ headerrow = ["Header row/column 1", "Header row 2",
headercolumn = ["Header column 2", "Header column 3",
"Header column 4", "Header column 5"]
for k in range(len(tables.styles)):
tables.array(array, headerrow, headercolumn, headerrow=True, headercolumn=True, cellborder=True, style=k)
tables.array(array, headerrow, headercolumn, headerrow=True, headercolumn=True, style=k)
tables.array(array, headerrow[:-1], None, headerrow=True, style=k)
tables.array(array, None, [headerrow[0]] + headercolumn[:-1], headercolumn=True, style=k)
tables.array(array, None, None, cellborder=True, style=k)
tables.array(array, None, None, tableborder=False, style=k)
tables.array(array, headerrow, headercolumn, tableborder=False, headerrow=True, headercolumn=True, style=k)
tables.array(array, headerrow[:-1], None, tableborder=False, headerrow=True, style=k)
tables.array(array, None, [headerrow[0]] + headercolumn[:-1], tableborder=False, headercolumn=True, style=k)
tables.array(array, None, None, tableborder=False, cellborder=True, style=k)
for style in tables.style_types:
tables.array(array, headerrow, headercolumn, headerrow=True,
headercolumn=True, cellborder=True, style=style)
tables.array(array, headerrow, headercolumn,
headerrow=True, headercolumn=True, style=style)
tables.array(array, headerrow[:-1], None, headerrow=True, style=style)
tables.array(array, None, [headerrow[0]] +
headercolumn[:-1], headercolumn=True, style=style)
tables.array(array, None, None, cellborder=True, style=style)
tables.array(array, None, None, tableborder=False, style=style)
tables.array(array, headerrow, headercolumn, tableborder=False,
headerrow=True, headercolumn=True, style=style)
tables.array(array, headerrow[:-1], None,
tableborder=False, headerrow=True, style=style)
tables.array(array, None, [headerrow[0]] + headercolumn[:-1],
tableborder=False, headercolumn=True, style=style)
tables.array(array, None, None, tableborder=False,
cellborder=True, style=style)
array = [[bool(random.getrandbits(1)) for j in range(columns)]
for i in range(rows)]
for k in range(len(tables.styles)):
tables.array(array, None, None, style=k)
for style in tables.style_types:
tables.array(array, None, None, style=style)
print("\nOutput sorted array as table\n")
array = ([random.randint(0, sys.maxsize)
for j in range(columns)] for i in range(rows))
sortdimension = 0
array = sorted(array, key=lambda x: x[sortdimension])
for k in range(len(tables.styles)):
tables.array(array, None, None, style=k)
for style in tables.style_types:
tables.array(array, None, None, style=style)
print("\nOutput single function as table\n")
for k in range(len(tables.styles)):
tables.function(xmin, xmax, xscl, afunction, headerrow=True, style=k)
for k in range(len(tables.styles)):
tables.function(xmin, xmax, xscl, lambda x: x + 1, headerrow=True, style=k)
for style in tables.style_types:
tables.function(xmin, xmax, xstep, afunction, headerrow=True, style=style)
for style in tables.style_types:
tables.function(xmin, xmax, xstep, lambda x: x +
1, headerrow=True, style=style)
print("\nOutput multiple functions as table\n")
for k in range(len(tables.styles)):
tables.functions(xmin, xmax, xscl, [
function1, function2], headerrow=True, style=k)
for k in range(len(tables.styles)):
tables.functions(xmin, xmax, xscl, [
lambda x: 2 * x, lambda x: x ** 2], headerrow=True, style=k)
for style in tables.style_types:
tables.functions(xmin, xmax, xstep, [
function1, function2], headerrow=True, style=style)
for style in tables.style_types:
tables.functions(xmin, xmax, xstep, [
lambda x: 2 * x, lambda x: x ** 2], headerrow=True, style=style)
height = 160
width = 160
@ -99,24 +108,25 @@ ymax = 20
print("\nOutput single array as plot\n")
array = [range(i, i + 2) for i in range(10)]
for k in range(len(graphs.styles)):
graphs.array(height, width, xmin, xmax, ymin, ymax, array, style=k)
for style in graphs.style_types:
graphs.array(height, width, xmin, xmax, ymin, ymax, array, style=style)
print("\nOutput single function as graph\n")
for k in range(len(graphs.styles)):
graphs.function(height, width, xmin, xmax, ymin, ymax, afunction, style=k)
for k in range(len(graphs.styles)):
for style in graphs.style_types:
graphs.function(height, width, xmin, xmax, ymin,
ymax, lambda x: x + 1, style=k)
ymax, afunction, style=style)
for style in graphs.style_types:
graphs.function(height, width, xmin, xmax, ymin,
ymax, lambda x: x + 1, style=style)
print("\nOutput multiple functions as graph\n")
for k in range(len(graphs.styles)):
graphs.functions(height, width, xmin, xmax, ymin,
ymax, [function1, function2], style=k)
for k in range(len(graphs.styles)):
for style in graphs.style_types:
graphs.functions(height, width, xmin, xmax, ymin, ymax,
[function1, function2], style=style)
for style in graphs.style_types:
graphs.functions(height, width, xmin, xmax, ymin, ymax, [
lambda x: 2 * x, lambda x: x ** 2], style=k)
lambda x: 2 * x, lambda x: x ** 2], style=style)
for k in range(len(graphs.styles)):
graphs.functions(height, width, -(2 * math.pi), 2 * math.pi, -4,
4, [math.sin, math.cos, math.tan], axisunitslabel=False, style=k)
for style in graphs.style_types:
graphs.functions(height, width, -(2 * math.pi), 2 * math.pi, -4, 4,
[math.sin, math.cos, math.tan], axisunitslabel=False, style=style)

View File

@ -77,7 +77,7 @@ int main()
const long double xmin = -10;
const long double xmax = 10;
const long double xscl = 2; // 80 / (xmax - xmin);
const long double xstep = 0.5; // (xmax - xmin) / 80;
string *headerrow = nullptr;
string *headercolumn = nullptr;
@ -96,14 +96,14 @@ int main()
tables::options aoptions;
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(rows, columns, array, nullptr, nullptr, aoptions);
}
if (array != nullptr)
if (array)
{
for (unsigned int i = 0; i < rows; ++i)
delete[] array[i];
@ -120,9 +120,9 @@ int main()
tables::options aoptions;
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -136,9 +136,9 @@ int main()
tables::options aoptions;
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(array, headerrow, headercolumn, aoptions);
}
@ -155,14 +155,14 @@ int main()
tables::options aoptions;
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(rows, columns, array, nullptr, nullptr, aoptions);
}
if (array != nullptr)
if (array)
{
for (unsigned int i = 0; i < rows; ++i)
delete[] array[i];
@ -179,9 +179,9 @@ int main()
tables::options aoptions;
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -195,9 +195,9 @@ int main()
tables::options aoptions;
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(array, headerrow, headercolumn, aoptions);
}
@ -217,9 +217,9 @@ int main()
aoptions.headercolumn = true;
// tables::options aoptions{.headerrow = true, .headercolumn = true};
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(array, headerrow, headercolumn, aoptions);
}
@ -236,9 +236,9 @@ int main()
aoptions.headercolumn = true;
// tables::options aoptions{.headerrow = true, .headercolumn = true};
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -263,9 +263,9 @@ int main()
aoptions.headercolumn = true;
// tables::options aoptions{.headerrow = true, .headercolumn = true};
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(array, headerrow, headercolumn, aoptions);
}
@ -286,15 +286,15 @@ int main()
vector<string> aheadercolumn(headerrow, headerrow + 1);
aheadercolumn.insert(aheadercolumn.end(), headercolumn, headercolumn + columns - 1);
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
{
tables::options aoptions;
aoptions.headerrow = true;
aoptions.headercolumn = true;
aoptions.cellborder = true;
aoptions.style = k;
// tables::options aoptions{.headerrow = true, .headercolumn = true, .cellborder = true, .style = k};
aoptions.style = style;
// tables::options aoptions{.headerrow = true, .headercolumn = true, .cellborder = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -302,8 +302,8 @@ int main()
tables::options aoptions;
aoptions.headerrow = true;
aoptions.headercolumn = true;
aoptions.style = k;
// tables::options aoptions{.headerrow = true, .headercolumn = true, .style = k};
aoptions.style = style;
// tables::options aoptions{.headerrow = true, .headercolumn = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -313,8 +313,8 @@ int main()
tables::options aoptions;
aoptions.headerrow = true;
aoptions.style = k;
// tables::options aoptions{.headerrow = true, .style = k};
aoptions.style = style;
// tables::options aoptions{.headerrow = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -324,8 +324,8 @@ int main()
tables::options aoptions;
aoptions.headercolumn = true;
aoptions.style = k;
// tables::options aoptions{.headercolumn = true, .style = k};
aoptions.style = style;
// tables::options aoptions{.headercolumn = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -335,8 +335,8 @@ int main()
tables::options aoptions;
aoptions.cellborder = true;
aoptions.style = k;
// tables::options aoptions{.cellborder = true, .style = k};
aoptions.style = style;
// tables::options aoptions{.cellborder = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -346,8 +346,8 @@ int main()
tables::options aoptions;
aoptions.tableborder = false;
aoptions.style = k;
// tables::options aoptions{.tableborder = false, .style = k};
aoptions.style = style;
// tables::options aoptions{.tableborder = false, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -356,8 +356,8 @@ int main()
aoptions.tableborder = false;
aoptions.headerrow = true;
aoptions.headercolumn = true;
aoptions.style = k;
// tables::options aoptions{.tableborder = false, .headerrow = true, .headercolumn = true, .style = k};
aoptions.style = style;
// tables::options aoptions{.tableborder = false, .headerrow = true, .headercolumn = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -368,8 +368,8 @@ int main()
tables::options aoptions;
aoptions.tableborder = false;
aoptions.headerrow = true;
aoptions.style = k;
// tables::options aoptions{.tableborder = false, .headerrow = true, .style = k};
aoptions.style = style;
// tables::options aoptions{.tableborder = false, .headerrow = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -380,8 +380,8 @@ int main()
tables::options aoptions;
aoptions.tableborder = false;
aoptions.headercolumn = true;
aoptions.style = k;
// tables::options aoptions{.tableborder = false, .headercolumn = true, .style = k};
aoptions.style = style;
// tables::options aoptions{.tableborder = false, .headercolumn = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -392,8 +392,8 @@ int main()
tables::options aoptions;
aoptions.tableborder = false;
aoptions.cellborder = true;
aoptions.style = k;
// tables::options aoptions{.tableborder = false, .cellborder = true, .style = k};
aoptions.style = style;
// tables::options aoptions{.tableborder = false, .cellborder = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -413,14 +413,14 @@ int main()
aoptions.boolalpha = true;
// tables::options aoptions{.boolalpha = true};
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(rows, columns, array, nullptr, nullptr, aoptions);
}
if (array != nullptr)
if (array)
{
for (unsigned int i = 0; i < rows; ++i)
delete[] array[i];
@ -448,14 +448,14 @@ int main()
tables::options aoptions;
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(rows, columns, array, nullptr, nullptr, aoptions);
}
if (array != nullptr)
if (array)
{
for (unsigned int i = 0; i < rows; ++i)
delete[] array[i];
@ -477,9 +477,9 @@ int main()
tables::options aoptions;
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(aarray, headerrow, headercolumn, aoptions);
}
@ -498,9 +498,9 @@ int main()
tables::options aoptions;
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::array(array, headerrow, headercolumn, aoptions);
}
@ -512,11 +512,11 @@ int main()
aoptions.headerrow = true;
// tables::options aoptions{.headerrow = true};
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::function(xmin, xmax, xscl, afunction, aoptions);
tables::function(xmin, xmax, xstep, afunction, aoptions);
}
}
{
@ -527,11 +527,11 @@ int main()
aoptions.headerrow = true;
// tables::options aoptions{.headerrow = true};
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::function(xmin, xmax, xscl, afunction, aoptions);
tables::function(xmin, xmax, xstep, afunction, aoptions);
}
}
// Output multiple functions as table
@ -543,11 +543,11 @@ int main()
aoptions.headerrow = true;
// tables::options aoptions{.headerrow = true};
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::functions(xmin, xmax, xscl, 2, functions, aoptions);
tables::functions(xmin, xmax, xstep, tables::size(functions), functions, aoptions);
}
}
{
@ -560,11 +560,11 @@ int main()
aoptions.headerrow = true;
// tables::options aoptions{.headerrow = true};
for (unsigned int k = 0; k < tables::size(tables::styles); ++k)
for (const tables::style_type style : tables::style_types)
{
aoptions.style = k;
aoptions.style = style;
tables::functions(xmin, xmax, xscl, 2, functions, aoptions);
tables::functions(xmin, xmax, xstep, tables::size(functions), functions, aoptions);
}
}

View File

@ -9,6 +9,7 @@
#include <cstdlib>
#include <vector>
#include <iterator>
#include <numeric>
#include <sys/ioctl.h>
#include <unistd.h>
#include <regex>
@ -17,6 +18,19 @@ namespace tables
{
using namespace std;
enum style_type
{
style_ASCII,
style_basic,
style_light,
style_heavy,
style_double,
style_light_dashed,
style_heavy_dashed
};
enum style_type const style_types[] = {style_ASCII, style_basic, style_light, style_heavy, style_double, style_light_dashed, style_heavy_dashed};
const char *const styles[][11] = {
{"-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // ASCII
{"", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // Basic
@ -28,7 +42,7 @@ namespace tables
};
// {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}};//No border
regex ansi(R"(\x1B\[(?:[0-9]+(?:;[0-9]+)*)?m)");
const regex ansi(R"(\x1B\[(?:[0-9]+(?:;[0-9]+)*)?m)");
struct options
{
@ -40,13 +54,14 @@ namespace tables
ios_base &(*alignment)(ios_base &) = left;
bool boolalpha = false;
const char *title = nullptr;
unsigned int style = 2;
style_type style = style_light;
bool check = true;
};
const options defaultoptions;
template <typename T>
auto size(const T &array)
constexpr size_t size(const T &array)
{
return distance(begin(array), end(array));
}
@ -74,11 +89,11 @@ namespace tables
}
++length;
wchar_t *wcstring = new wchar_t[length];
auto *wcstring = new wchar_t[length];
if (mbstowcs(wcstring, str, length) == static_cast<size_t>(-1))
{
if (wcstring != nullptr)
if (wcstring)
delete[] wcstring;
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n";
@ -92,7 +107,7 @@ namespace tables
exit(1);
}
if (wcstring != nullptr)
if (wcstring)
delete[] wcstring;
return width;
@ -103,8 +118,7 @@ namespace tables
// Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734
string wrap(const char *const str, const size_t line_length)
{
char words[strlen(str) + 1];
strcpy(words, str);
string words = str;
string wrapped;
size_t index = 0;
@ -127,7 +141,7 @@ namespace tables
}
char temp[templinelen + 1];
strncpy(temp, words + (index - linelen), templinelen);
strncpy(temp, words.data() + (index - linelen), templinelen);
temp[templinelen] = '\0';
size_t width = strcol(temp);
@ -163,76 +177,83 @@ namespace tables
const bool cellborder = aoptions.cellborder;
const unsigned int padding = aoptions.padding;
const char *const title = aoptions.title;
const unsigned int style = aoptions.style;
if (style >= tables::size(styles))
return 1;
const style_type style = aoptions.style;
const size_t rows = array.size();
const size_t columns = array[0].size();
int columnwidth[columns];
for (unsigned int j = 0; j < columns; ++j)
for (size_t j = 0; j < columns; ++j)
columnwidth[j] = 0;
int width = 0;
setlocale(LC_ALL, "");
setlocale(LC_CTYPE, "");
for (unsigned int j = 0; j < columns; ++j)
for (size_t j = 0; j < columns; ++j)
{
for (unsigned int i = 0; i < rows; ++i)
for (size_t i = 0; i < rows; ++i)
{
int cellwidth = strcol(array[i][j].c_str());
const int cellwidth = strcol(array[i][j].c_str());
if (cellwidth > columnwidth[j])
columnwidth[j] = cellwidth;
}
width += columnwidth[j];
}
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
size_t width = accumulate(columnwidth, columnwidth + columns, 0ul);
if (tableborder or cellborder or headerrow or headercolumn)
width += (((2 * padding) + 1) * columns) + (tableborder ? 1 : -1);
else
width += (2 * padding) * columns;
if (width > w.ws_col)
if (aoptions.check)
{
cerr << "The width of the table (" << width << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
return 1;
if (width > w.ws_col)
{
cerr << "The width of the table (" << width << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
return 1;
}
}
if (title != nullptr and title[0] != '\0')
cout << wrap(title, w.ws_col) << "\n";
if (title and title[0] != '\0')
cout << wrap(title, width) << "\n";
if (aoptions.alignment)
cout << aoptions.alignment;
if (tableborder)
{
cout << styles[style][2];
for (unsigned int j = 0; j < columns; ++j)
for (size_t j = 0; j < columns; ++j)
{
for (unsigned int k = 0; k < (2 * padding) + columnwidth[j]; ++k)
for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k)
cout << styles[style][0];
if (j == (columns - 1))
cout << styles[style][4] << "\n";
else if (cellborder or headerrow or (j == 0 and headercolumn))
cout << styles[style][3];
else
cout << styles[style][0];
if (j < (columns - 1))
{
if (cellborder or headerrow or (j == 0 and headercolumn))
cout << styles[style][3];
else
cout << styles[style][0];
}
}
cout << styles[style][4] << "\n";
}
for (unsigned int i = 0; i < rows; ++i)
for (size_t i = 0; i < rows; ++i)
{
for (unsigned int j = 0; j < columns; ++j)
if (tableborder)
cout << styles[style][1];
for (size_t j = 0; j < columns; ++j)
{
if ((j == 0 and tableborder) or (j > 0 and cellborder) or (i == 0 and j > 0 and headerrow) or (j == 1 and headercolumn))
if ((j and cellborder) or (i == 0 and j and headerrow) or (j == 1 and headercolumn))
cout << styles[style][1];
else if (tableborder or (i > 0 and j > 0 and headerrow) or (j > 1 and headercolumn))
else if (j and (tableborder or (i and headerrow) or headercolumn))
cout << " ";
const int difference = columnwidth[j] - strcol(array[i][j].c_str());
@ -251,7 +272,7 @@ namespace tables
{
cout << string(padding, ' ');
cout << aoptions.alignment << setw(difference + array[i][j].length()) << array[i][j];
cout << setw(difference + array[i][j].length()) << array[i][j];
cout << string(padding, ' ');
}
@ -272,29 +293,15 @@ namespace tables
if ((i == (rows - 1) and tableborder) or (i < (rows - 1) and cellborder) or (i == 0 and headerrow) or (i < (rows - 1) and headercolumn))
{
for (unsigned int j = 0; j < columns; ++j)
for (size_t j = 0; j < columns; ++j)
{
if ((i == (rows - 1) and tableborder) or (i < (rows - 1) and cellborder) or (i == 0 and headerrow) or (i < (rows - 1) and j == 0 and headercolumn))
for (unsigned int k = 0; k < (2 * padding) + columnwidth[j]; ++k)
for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k)
cout << styles[style][0];
else if (i < (rows - 1) and headercolumn)
cout << string((2 * padding) + columnwidth[j], ' ');
if (j == (columns - 1))
{
if (tableborder)
{
if (i == (rows - 1))
cout << styles[style][10];
else if (cellborder or (i == 0 and headerrow))
cout << styles[style][7];
else if (headercolumn)
cout << styles[style][1];
}
cout << "\n";
}
else
if (j < (columns - 1))
{
if (i == (rows - 1) and tableborder)
{
@ -316,6 +323,19 @@ namespace tables
}
}
}
if (tableborder)
{
if (i == (rows - 1))
cout << styles[style][10];
else if (cellborder or (i == 0 and headerrow))
cout << styles[style][7];
else if (headercolumn)
cout << styles[style][1];
}
if (i < (rows - 1))
cout << "\n";
}
}
@ -331,30 +351,30 @@ namespace tables
if (!tables::size(aarray))
return 1;
unsigned int i = 0;
unsigned int j = 0;
size_t i = 0;
size_t j = 0;
size_t rows = tables::size(aarray);
size_t columns = tables::size(aarray[0]);
if (!all_of(begin(aarray), end(aarray), [columns](auto &x)
if (!all_of(begin(aarray), end(aarray), [columns](const auto &x)
{ return tables::size(x) == columns; }))
{
cerr << "Error: The rows of the array must have the same number of columns.";
cerr << "Error: The rows of the array must have the same number of columns.\n";
return 1;
}
if (headerrow != nullptr)
if (headerrow)
++rows;
if (headercolumn != nullptr)
if (headercolumn)
++columns;
vector<vector<string>> aaarray(rows, vector<string>(columns));
if (headerrow != nullptr)
if (headerrow)
{
for (unsigned int j = 0; j < columns; ++j)
for (size_t j = 0; j < columns; ++j)
{
aaarray[i][j] = headerrow[j];
}
@ -362,13 +382,13 @@ namespace tables
++i;
}
for (unsigned int ii = 0; i < rows; ++i)
for (size_t ii = 0; i < rows; ++i)
{
if (headercolumn != nullptr)
if (headercolumn)
{
unsigned int ii = i;
size_t ii = i;
if (headerrow != nullptr)
if (headerrow)
--ii;
aaarray[i][j] = headercolumn[ii];
@ -376,7 +396,7 @@ namespace tables
++j;
}
for (unsigned int jj = 0; j < columns; ++j)
for (size_t jj = 0; j < columns; ++j)
{
ostringstream strm;
@ -400,7 +420,7 @@ namespace tables
int array(const size_t rows, const size_t columns, T **aarray, const char *const headerrow[] = nullptr, const char *const headercolumn[] = nullptr, const options &aoptions = defaultoptions)
{
vector<vector<T>> aaarray(rows, vector<T>(columns));
for (unsigned int i = 0; i < rows; ++i)
for (size_t i = 0; i < rows; ++i)
copy(aarray[i], aarray[i] + columns, aaarray[i].begin());
string *aheaderrow = nullptr;
@ -434,7 +454,7 @@ namespace tables
// Convert one or more functions to array and output as table
template <typename T>
int functions(const long double xmin, const long double xmax, const long double xscl, const size_t numfunctions, function<T(T)> functions[], const options &aoptions = defaultoptions)
int functions(const long double xmin, const long double xmax, const long double xstep, const size_t numfunctions, function<T(T)> functions[], const options &aoptions = defaultoptions)
{
if (numfunctions == 0)
return 1;
@ -445,13 +465,13 @@ namespace tables
return 1;
}
if (xscl <= 0)
if (xstep <= 0)
{
cerr << "xscl must be greater than zero.\n";
cerr << "xstep must be greater than zero.\n";
return 1;
}
const size_t rows = ((xmax - xmin) * xscl) + 1;
const size_t rows = ((xmax - xmin) / xstep) + 1;
const size_t columns = numfunctions + 1;
const char *const aheaderrow[] = {"x", "y"};
@ -459,9 +479,9 @@ namespace tables
const size_t length = tables::size(aheaderrow);
string *headerrow = new string[columns];
auto *headerrow = new string[columns];
for (unsigned int j = 0; j < columns; ++j)
for (size_t j = 0; j < columns; ++j)
{
if (j < (length - 1) or numfunctions == 1)
{
@ -478,7 +498,7 @@ namespace tables
string *headercolumn = nullptr;
// headercolumn = new string[rows + 1];
// for (unsigned int i = 0; i < rows + 1; ++i)
// for (size_t i = 0; i < rows + 1; ++i)
// {
// ostringstream strm;
// strm << i + 1;
@ -487,22 +507,22 @@ namespace tables
vector<vector<T>> aarray(rows, vector<T>(columns));
for (unsigned int i = 0; i < rows; ++i)
for (size_t i = 0; i < rows; ++i)
{
aarray[i][0] = (i / xscl) + xmin;
aarray[i][0] = (i * xstep) + xmin;
for (unsigned int j = 0; j < numfunctions; ++j)
for (size_t j = 0; j < numfunctions; ++j)
aarray[i][j + 1] = (functions[j])(aarray[i][0]);
}
int code = array(aarray, headerrow, headercolumn, aoptions);
if (headerrow != nullptr)
if (headerrow)
{
delete[] headerrow;
}
// if (headercolumn != nullptr)
// if (headercolumn)
// {
// delete[] headercolumn;
// }
@ -512,20 +532,20 @@ namespace tables
// Convert single function to array and output as table
template <typename T>
int function(const long double xmin, const long double xmax, const long double xscl, const function<T(T)> &afunction, const options &aoptions = defaultoptions)
int function(const long double xmin, const long double xmax, const long double xstep, const function<T(T)> &afunction, const options &aoptions = defaultoptions)
{
std::function<T(T)> afunctions[] = {afunction};
return functions(xmin, xmax, xscl, 1, afunctions, aoptions);
return functions(xmin, xmax, xstep, 1, afunctions, aoptions);
}
// Convert single function to array and output as table
template <typename T>
int function(const long double xmin, const long double xmax, const long double xscl, T afunction(T), const options &aoptions = defaultoptions)
int function(const long double xmin, const long double xmax, const long double xstep, T afunction(T), const options &aoptions = defaultoptions)
{
std::function<T(T)> afunctions[] = {afunction};
return functions(xmin, xmax, xscl, 1, afunctions, aoptions);
return functions(xmin, xmax, xstep, 1, afunctions, aoptions);
}
}