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 ./graphs
- name: Cppcheck - name: Cppcheck
run: cppcheck --enable=all . 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: Python:
name: Linux 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. Complete versions of all of the examples below and more can be found in the [tables.cpp](tables.cpp) file.
Compile with: Compile with:
* GCC: `g++ -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`
Clang: `clang++ -std=c++14 -Wall -g -O3 tables.cpp -o tables`
Run with: `./tables` Run with: `./tables`
@ -313,12 +312,12 @@ int main()
{ {
double xmin = -10; double xmin = -10;
double xmax = 10; double xmax = 10;
double xscl = 2; double xstep = 0.5;
tables::options aoptions; tables::options aoptions;
aoptions.headerrow = true; aoptions.headerrow = true;
tables::function(xmin, xmax, xscl, afunction, aoptions); tables::function(xmin, xmax, xstep, afunction, aoptions);
return 0; return 0;
} }
@ -335,7 +334,7 @@ int main()
{ {
double xmin = -10; double xmin = -10;
double xmax = 10; double xmax = 10;
double xscl = 2; double xstep = 0.5;
function<double(double)> afunction = [](auto x) function<double(double)> afunction = [](auto x)
{ return x + 1; }; { return x + 1; };
@ -343,7 +342,7 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.headerrow = true; aoptions.headerrow = true;
tables::function(xmin, xmax, xscl, afunction, aoptions); tables::function(xmin, xmax, xstep, afunction, aoptions);
return 0; return 0;
} }
@ -375,7 +374,7 @@ int main()
{ {
double xmin = -10; double xmin = -10;
double xmax = 10; double xmax = 10;
double xscl = 2; double xstep = 0.5;
size_t numfunctions = 2; size_t numfunctions = 2;
@ -385,7 +384,7 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.headerrow = true; aoptions.headerrow = true;
tables::functions(xmin, xmax, xscl, numfunctions, functions, aoptions); tables::functions(xmin, xmax, xstep, numfunctions, functions, aoptions);
return 0; return 0;
} }
@ -403,7 +402,7 @@ int main()
{ {
double xmin = -10; double xmin = -10;
double xmax = 10; double xmax = 10;
double xscl = 2; double xstep = 0.5;
size_t numfunctions = 2; size_t numfunctions = 2;
@ -416,7 +415,7 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.headerrow = true; aoptions.headerrow = true;
tables::functions(xmin, xmax, xscl, numfunctions, functions, aoptions); tables::functions(xmin, xmax, xstep, numfunctions, functions, aoptions);
return 0; return 0;
} }
@ -460,8 +459,10 @@ Default value: `1`
Option: `alignment`\ Option: `alignment`\
Values: Values:
* `nullptr`
* `left` (default) * `left` (default)
* `right` * `right`
* `internal` (integer and floating-point types only)
#### bool to alpha #### bool to alpha
@ -480,28 +481,35 @@ The title is word wrapped based on the current width of the terminal, using [thi
Option: `style`\ Option: `style`\
Values: Values:
0. ASCII 0. `style_ASCII`: ASCII
![](images/ASCII%20table.png) ![](images/ASCII%20table.png)
1. Basic 1. `style_basic`: Basic
![](images/basic%20table.png) ![](images/basic%20table.png)
2. Light (default) 2. `style_light`: Light (default)
![](images/light%20table.png) ![](images/light%20table.png)
3. Heavy 3. `style_heavy`: Heavy
![](images/heavy%20table.png) ![](images/heavy%20table.png)
4. Double 4. `style_double`: Double
![](images/double%20table.png) ![](images/double%20table.png)
5. Light Dashed 5. `style_light_dashed`: Light Dashed
![](images/light%20dashed%20table.png) ![](images/light%20dashed%20table.png)
6. Heavy Dashed 6. `style_heavy_dashed`: Heavy Dashed
![](images/heavy%20dashed%20table.png) ![](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 ### 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) * [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. Complete versions of all of the examples below and more can be found in the [graphs.cpp](graphs.cpp) file.
Compile with: Compile with:
GCC: `g++ -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` * Clang: `clang++ -std=c++14 -Wall -g -O3 graphs.cpp -o graphs`
Run with: `./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`\ Option: `style`\
Values: Values:
0. ASCII 0. `style_ASCII`: ASCII
![](images/ASCII%20graph.png) ![](images/ASCII%20graph.png)
1. Basic 1. `style_basic`: Basic
![](images/basic%20graph.png) ![](images/basic%20graph.png)
2. Light (default) 2. `style_light`: Light (default)
![](images/light%20graph.png) ![](images/light%20graph.png)
3. Heavy 3. `style_heavy`: Heavy
![](images/heavy%20graph.png) ![](images/heavy%20graph.png)
4. Double 4. `style_double`: Double
![](images/double%20graph.png) ![](images/double%20graph.png)
5. Light Dashed 5. `style_light_dashed`: Light Dashed
![](images/light%20dashed%20graph.png) ![](images/light%20dashed%20graph.png)
6. Heavy Dashed 6. `style_heavy_dashed`: Heavy Dashed
![](images/heavy%20dashed%20graph.png) ![](images/heavy%20dashed%20graph.png)
@ -783,27 +791,25 @@ Values:
Option: `color`\ Option: `color`\
Values: Values:
0. System default 0. `color_default`: System default
1. Black 1. `color_black`: Black
2. Red (default) 2. `color_red`: Red (default)
3. Green 3. `color_green`: Green
4. Yellow 4. `color_yellow`: Yellow
5. Blue 5. `color_blue`: Blue
6. Cyan 6. `color_cyan`: Cyan
7. Light gray 7. `color_light_gray`: Light gray
8. Dark gray 8. `color_dark_gray`: Dark gray
9. Light red 9. `color_light_red`: Light red
10. Light green 10. `color_light_green`: Light green
11. Light yellow 11. `color_light_yellow`: Light yellow
12. Light blue 12. `color_light_blue`: Light blue
13. Light cyan 13. `color_light_cyan`: Light cyan
14. White 14. `color_white`: White
See [here](https://misc.flogisoft.com/bash/tip_colors_and_formatting#foreground_text) for examples of the colors. 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. 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.
When graphing multiple functions, colors `2` - `14` are used inorder. Color `0` is used where the functions cross.
##### Plot ##### Plot
@ -813,6 +819,13 @@ When graphing multiple functions, colors `2` - `14` are used inorder. Color `0`
![](images/graph%20colors.png) ![](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 ### 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) * [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; 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); graphs::array(height, width, xmin, xmax, ymin, ymax, rows, array, aoptions);
} }
if (array != nullptr) if (array)
{ {
for (unsigned int i = 0; i < rows; ++i) for (unsigned int i = 0; i < rows; ++i)
delete[] array[i]; delete[] array[i];
@ -92,9 +92,9 @@ int main()
graphs::options aoptions; 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); graphs::array(height, width, xmin, xmax, ymin, ymax, aarray, aoptions);
} }
@ -108,9 +108,9 @@ int main()
graphs::options aoptions; 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); graphs::array(height, width, xmin, xmax, ymin, ymax, array, aoptions);
} }
@ -120,9 +120,9 @@ int main()
{ {
graphs::options aoptions; 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); graphs::function(height, width, xmin, xmax, ymin, ymax, afunction, aoptions);
} }
@ -133,9 +133,9 @@ int main()
graphs::options aoptions; 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); graphs::function(height, width, xmin, xmax, ymin, ymax, afunction, aoptions);
} }
@ -147,11 +147,11 @@ int main()
graphs::options aoptions; 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; 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; aoptions.axisunitslabel = false;
// graphs::options 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; /* aoptions.style = 2;
@ -195,7 +195,7 @@ int main()
cout << "\e[1;1H" cout << "\e[1;1H"
<< "\e[2J"; << "\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); usleep(200000);
} */ } */

View File

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

View File

@ -2,7 +2,7 @@
### Usage ### 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. 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 xmin = -10
xmax = 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) ![](../images/function%20to%20table.png)
@ -89,11 +89,11 @@ import tables
xmin = -10 xmin = -10
xmax = 10 xmax = 10
xscl = 2 xstep = 0.5
afunction = lambda x: x + 1 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. Output same as example above.
@ -111,12 +111,12 @@ def function2(x):
xmin = -10 xmin = -10
xmax = 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 # Function parameter and return value can be any data type, as long as they are the same
functions = [function1, function2] 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) ![](../images/multiple%20functions%20to%20table.png)
@ -128,12 +128,12 @@ import tables
xmin = -10 xmin = -10
xmax = 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 # 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] 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. Output same as example above.
@ -174,7 +174,8 @@ Default value: `1`
Option: `alignment`\ Option: `alignment`\
Values: Values:
* `False` (left, default) * `None` (default)
* `False` (left)
* `True` (right) * `True` (right)
#### Title #### Title
@ -189,33 +190,40 @@ The title is word wrapped based on the current width of the terminal. Handles ne
Option: `style`\ Option: `style`\
Values: Values:
0. ASCII 0. `style_types.ASCII`: ASCII
![](../images/ASCII%20table.png) ![](../images/ASCII%20table.png)
1. Basic 1. `style_types.basic`: Basic
![](../images/basic%20table.png) ![](../images/basic%20table.png)
2. Light (default) 2. `style_types.light`: Light (default)
![](../images/light%20table.png) ![](../images/light%20table.png)
3. Heavy 3. `style_types.heavy`: Heavy
![](../images/heavy%20table.png) ![](../images/heavy%20table.png)
4. Double 4. `style_types.double`: Double
![](../images/double%20table.png) ![](../images/double%20table.png)
5. Light Dashed 5. `style_types.light_dashed`: Light Dashed
![](../images/light%20dashed%20table.png) ![](../images/light%20dashed%20table.png)
6. Heavy Dashed 6. `style_types.heavy_dashed`: Heavy Dashed
![](../images/heavy%20dashed%20table.png) ![](../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 ## Graphs/Plots
### Usage ### 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. 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`\ Option: `style`\
Values: Values:
0. ASCII 0. `style_types.ASCII`: ASCII
![](../images/ASCII%20graph.png) ![](../images/ASCII%20graph.png)
1. Basic 1. `style_types.basic`: Basic
![](../images/basic%20graph.png) ![](../images/basic%20graph.png)
2. Light (default) 2. `style_types.light`: Light (default)
![](../images/light%20graph.png) ![](../images/light%20graph.png)
3. Heavy 3. `style_types.heavy`: Heavy
![](../images/heavy%20graph.png) ![](../images/heavy%20graph.png)
4. Double 4. `style_types.double`: Double
![](../images/double%20graph.png) ![](../images/double%20graph.png)
5. Light Dashed 5. `style_types.light_dashed`: Light Dashed
![](../images/light%20dashed%20graph.png) ![](../images/light%20dashed%20graph.png)
6. Heavy Dashed 6. `style_types.heavy_dashed`: Heavy Dashed
![](../images/heavy%20dashed%20graph.png) ![](../images/heavy%20dashed%20graph.png)
@ -396,27 +404,25 @@ Values:
Option: `color`\ Option: `color`\
Values: Values:
0. System default 0. `color_types.default`: System default
1. Black 1. `color_types.black`: Black
2. Red (default) 2. `color_types.red`: Red (default)
3. Green 3. `color_types.green`: Green
4. Yellow 4. `color_types.yellow`: Yellow
5. Blue 5. `color_types.blue`: Blue
6. Cyan 6. `color_types.cyan`: Cyan
7. Light gray 7. `color_types.dark_gray`: Light gray
8. Dark gray 8. `color_types.dark_gray`: Dark gray
9. Light red 9. `color_types.light_red`: Light red
10. Light green 10. `color_types.light_green`: Light green
11. Light yellow 11. `color_types.light_yellow`: Light yellow
12. Light blue 12. `color_types.light_blue`: Light blue
13. Light cyan 13. `color_types.light_cyan`: Light cyan
14. White 14. `color_types.white`: White
See [here](https://misc.flogisoft.com/bash/tip_colors_and_formatting#foreground_text) for examples of the colors. 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. 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.
When graphing multiple functions, colors `2` - `14` are used inorder. Color `0` is used where the functions cross.
##### Plot ##### Plot
@ -425,3 +431,10 @@ When graphing multiple functions, colors `2` - `14` are used inorder. Color `0`
##### Graph ##### Graph
![](../images/graph%20colors.png) ![](../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 sys
import math import math
import shutil import shutil
from fractions import Fraction
import textwrap import textwrap
from enum import Enum, IntEnum, auto
from wcwidth import wcswidth from wcwidth import wcswidth
from typing import List, Tuple, Optional, Sequence, Callable from typing import List, Tuple, Optional, Sequence, Callable
import locale import locale
locale.setlocale(locale.LC_ALL, '') 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 = [ styles = [
["-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"], # ASCII ["-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"], # ASCII
["", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"], # Basic ["", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"], # Basic
@ -25,33 +38,71 @@ styles = [
] ]
# [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]] #No border # [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]] #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]] values = [[0x1, 0x2, 0x4, 0x40], [0x8, 0x10, 0x20, 0x80]]
fractions = { fractions = {
"¼": 1.0 / 4.0, "¼": Fraction(1, 4),
"½": 1.0 / 2.0, "½": Fraction(1, 2),
"¾": 3.0 / 4.0, "¾": Fraction(3, 4),
"": 1.0 / 7.0, "": Fraction(1, 7),
"": 1.0 / 9.0, "": Fraction(1, 9),
"": 1.0 / 10.0, "": Fraction(1, 10),
"": 1.0 / 3.0, "": Fraction(1, 3),
"": 2.0 / 3.0, "": Fraction(2, 3),
"": 1.0 / 5.0, "": Fraction(1, 5),
"": 2.0 / 5.0, "": Fraction(2, 5),
"": 3.0 / 5.0, "": Fraction(3, 5),
"": 4.0 / 5.0, "": Fraction(4, 5),
"": 1.0 / 6.0, "": Fraction(1, 6),
"": 5.0 / 6.0, "": Fraction(5, 6),
"": 1.0 / 8.0, "": Fraction(1, 8),
"": 3.0 / 8.0, "": Fraction(3, 8),
"": 5.0 / 8.0, "": Fraction(5, 8),
"": 7.0 / 8.0 "": Fraction(7, 8)
} }
constants = { constants = {
@ -59,68 +110,75 @@ constants = {
"e": math.e "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.""" """Returns the number of columns that the given string would take up if printed."""
width = wcswidth(str) width = wcswidth(astr)
if width == -1: 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) sys.exit(1)
return width return width
# return len(str) # return len(astr)
def outputlabel(label: float) -> Tuple[int, str]: def outputfraction(number: float) -> Tuple[int, str]:
"""Outputs a label in a nice, human readable format."""
"""Convert fractions and constants to Unicode characters""" """Convert fractions and constants to Unicode characters"""
output = False output = False
fractionpart, intpart = math.modf(label)
fractionpart = abs(fractionpart)
strm = "" strm = ""
for fraction in fractions: n = abs(number)
if abs(fractionpart - fractions[fraction]) < sys.float_info.epsilon:
if intpart != 0:
strm += str(intpart)
strm += fraction if n <= MAX:
# fractionpart, intpart = math.modf(number)
# fractionpart = abs(fractionpart)
intpart, fractionpart = divmod(Fraction(number).limit_denominator(), 1)
output = True for fraction, value in fractions.items():
break if abs(fractionpart - value) <= sys.float_info.epsilon * n:
if intpart == 0 and number < 0:
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:
strm += "-" strm += "-"
elif intpart != 1: elif intpart != 0:
strm += str(intpart) strm += "{0:n}".format(intpart)
strm += constant strm += fraction
output = True output = True
break 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: if not output:
strm += "{0:n}".format(label) strm += "{0:n}".format(number)
length = strcol(strm) length = strcol(strm)
return length, strm return length, strm
def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, array: List[List[int]], border: bool = 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""" """Output graph"""
if not array: if not array:
return 1 return 1
if not (0 <= style < len(styles)):
return 1
if height == 0: if height == 0:
return 1 return 1
@ -129,18 +187,19 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
w = shutil.get_terminal_size() w = shutil.get_terminal_size()
aheight = height // 4 if check:
awidth = width // 2 aheight = height // 4
awidth = width // 2
if aheight > w.lines: if aheight > w.lines:
print("The height of the graph ({0}) is greater then the height of the terminal ({1}).".format( print("The height of the graph ({0}) is greater then the height of the terminal ({1}).".format(
aheight, w.lines), file=sys.stderr) aheight, w.lines), file=sys.stderr)
return 1 return 1
if awidth > w.columns: if awidth > w.columns:
print("The width of the graph ({0}) is greater then the width of the terminal ({1}).".format( print("The width of the graph ({0}) is greater then the width of the terminal ({1}).".format(
awidth, w.columns), file=sys.stderr) awidth, w.columns), file=sys.stderr)
return 1 return 1
if xmin >= xmax: if xmin >= xmax:
print("xmin must be less than xmax.", file=sys.stderr) 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) print("ymin must be less than ymax.", file=sys.stderr)
return 1 return 1
xscl = width / (xmax - xmin) xstep = (xmax - xmin) / width
yscl = height / (ymax - ymin) ystep = (ymax - ymin) / height
xaxis = width - (xmax * xscl) xaxis = 0 if xmin > 0 else width if xmax < 0 else width - (xmax / xstep)
yaxis = ymax * yscl yaxis = height if ymin > 0 else 0 if ymax < 0 else ymax / ystep
divisor = 2 * 4 * ((width // 160) + 1 if (width / 160.0) > 1 else 1) xdivisor = 2 * 4 * ((width // 160) + 2)
ydivisor = 2 * 4 * ((height // 160) + 2)
if title: if title:
print(textwrap.fill(title, width=w.columns)) print(textwrap.fill(title, width=width // 2))
strm = "" strm = ""
i = 0 i = 0
while i < height: while i < height:
ayaxis = i <= yaxis and (i + 4) > yaxis ayaxis = i <= yaxis and (
yaxislabel = i <= (yaxis + 4) and (i + 4) > (yaxis + 4) 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 = "" ylabelstrm = ""
ylabellength = 0 ylabellength = 0
if border and axislabel and axisunitslabel: if border and axislabel and axisunitslabel and yaxis >= 0 and yaxis <= height:
output = False output = False
label = 0.0 label = 0.0
adivisor = -divisor if i < yaxis else divisor adivisor = -ydivisor if i < yaxis else ydivisor
k = yaxis + adivisor 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): if (i <= k and (i + 4) > k):
label = ymax - (k / yscl) label = ymax - ((height if k > height else k) * ystep)
output = True output = True
k += adivisor k += adivisor
if (output): if (output):
ylabellength, ylabelstrm = outputlabel(label) ylabellength, ylabelstrm = outputfraction(label)
ylabellength *= 2 ylabellength *= 2
j = 0 j = 0
while j < width: while j < width:
axaxis = j <= xaxis and (j + 2) > xaxis axaxis = j < xaxis and (
xaxislabel = j <= (xaxis - 2) and (j + 2) > (xaxis - 2) 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 output = False
@ -198,57 +262,61 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
strm += styles[style][6] strm += styles[style][6]
output = True output = True
elif axaxis: elif axaxis:
if axislabel and axisunitslabel: if i == 0:
adivisor = -divisor if i < yaxis else divisor 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 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: if i <= k and (i + 4) > k:
strm += styles[style][7] strm += styles[style][7 if xaxis >= 2 else 5]
output = True output = True
k += adivisor k += adivisor
if not output: if not output:
if i == 0: strm += styles[style][1]
strm += styles[style][4]
elif i >= (height - 4):
strm += styles[style][10]
else:
strm += styles[style][1]
output = True output = True
elif ayaxis: elif ayaxis:
if axislabel and axisunitslabel: if j == 0:
adivisor = -divisor if j < xaxis else divisor 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 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: if j <= k and (j + 2) > k:
strm += styles[style][3] strm += styles[style][3 if yaxis <=
(height - 4) else 9]
output = True output = True
k += adivisor k += adivisor
if not output: if not output:
if j == 0: strm += styles[style][0]
strm += styles[style][2]
elif j >= (width - 2):
strm += styles[style][4]
else:
strm += styles[style][0]
output = True 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" strm += "0"
output = True 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" strm += "x"
output = True output = True
elif yaxislabel and axislabel and axisunitslabel: elif yaxislabel and axislabel and axisunitslabel:
label = 0.0 label = 0.0
adivisor = -divisor if j < xaxis else divisor adivisor = -xdivisor if j < xaxis else xdivisor
if j < xaxis: if j < xaxis:
j += 2 j += 2
k = xaxis + adivisor 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: if j <= k and (j + 2) > k:
label = (k / xscl) + xmin label = ((width if k > width else k)
* xstep) + xmin
output = True output = True
k += adivisor k += adivisor
@ -259,7 +327,7 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
if output: if output:
output = False output = False
length, astrm = outputlabel(label) length, astrm = outputfraction(label)
length *= 2 length *= 2
if (j >= xaxis or (j + length) < (xaxis - 4)) and (j + length) < (width - 2): if (j >= xaxis or (j + length) < (xaxis - 4)) and (j + length) < (width - 2):
strm += astrm strm += astrm
@ -271,10 +339,10 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
output = True output = True
else: else:
j += 2 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" strm += "y"
output = True 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 strm += ylabelstrm
output = True output = True
if ylabellength > 2: if ylabellength > 2:
@ -299,14 +367,15 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
if color: if color:
strm += colors[color] strm += colors[color]
strm += "\033[1m" + dots[dot] + "\033[22m" strm += dots[dot]
if color: if color:
strm += colors[0] strm += colors[0]
j += 2 j += 2
strm += "\n" if i < (height - 4):
strm += "\n"
i += 4 i += 4
print(strm) print(strm)
@ -314,7 +383,7 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
return 0 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""" """Convert one or more arrays to graph and output"""
if not aarrays: if not aarrays:
return 1 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.") print("Error: The arrays must have two columns.")
return 1 return 1
if color < 0 or color >= len(colors):
return 1
w = shutil.get_terminal_size() w = shutil.get_terminal_size()
if height == 0: if height == 0:
@ -334,18 +400,19 @@ def arrays(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
if width == 0: if width == 0:
width = w.columns * 2 width = w.columns * 2
aheight = height // 4 if check:
awidth = width // 2 aheight = height // 4
awidth = width // 2
if aheight > w.lines: if aheight > w.lines:
print("The height of the graph ({0}) is greater then the height of the terminal ({1}).".format( print("The height of the graph ({0}) is greater then the height of the terminal ({1}).".format(
aheight, w.lines), file=sys.stderr) aheight, w.lines), file=sys.stderr)
return 1 return 1
if awidth > w.columns: if awidth > w.columns:
print("The width of the graph ({0}) is greater then the width of the terminal ({1}).".format( print("The width of the graph ({0}) is greater then the width of the terminal ({1}).".format(
awidth, w.columns), file=sys.stderr) awidth, w.columns), file=sys.stderr)
return 1 return 1
if xmin == 0 and xmax == 0: if xmin == 0 and xmax == 0:
xmin = min(i[0] for aarray in aarrays for i in aarray) 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) print("ymin must be less than ymax.", file=sys.stderr)
return 1 return 1
xscl = width / (xmax - xmin) xstep = (xmax - xmin) / width
yscl = height / (ymax - ymin) ystep = (ymax - ymin) / height
xaxis = width - (xmax * xscl) xaxis = width - (xmax / xstep)
yaxis = ymax * yscl yaxis = ymax / ystep
aaarray = [[0 for j in range(height)] for i in range(width)] 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: for i in aarray:
if i[0] >= xmin and i[0] < xmax and i[1] >= ymin and i[1] < ymax: if i[0] >= xmin and i[0] < xmax and i[1] >= ymin and i[1] < ymax:
x = int((i[0] * xscl) + xaxis) x = int((i[0] / xstep) + xaxis)
y = int((yaxis - (i[1] * yscl)) - 1) y = int((yaxis - (i[1] / ystep)) - 1)
if aaarray[x][y]: if aaarray[x][y]:
if aaarray[x][y] != acolor: if aaarray[x][y] != acolor:
@ -385,19 +452,18 @@ def arrays(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
else: else:
aaarray[x][y] = acolor aaarray[x][y] = acolor
return graph(height, width, xmin, xmax, ymin, ymax, aaarray, border=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""" """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""" """Convert one or more functions to graph and output"""
if color < 0 or color >= len(colors):
return 1
if not afunctions: if not afunctions:
return 1 return 1
@ -409,18 +475,19 @@ def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
if width == 0: if width == 0:
width = w.columns * 2 width = w.columns * 2
aheight = height // 4 if check:
awidth = width // 2 aheight = height // 4
awidth = width // 2
if aheight > w.lines: if aheight > w.lines:
print("The height of the graph ({0}) is greater then the height of the terminal ({1}).".format( print("The height of the graph ({0}) is greater then the height of the terminal ({1}).".format(
aheight, w.lines), file=sys.stderr) aheight, w.lines), file=sys.stderr)
return 1 return 1
if awidth > w.columns: if awidth > w.columns:
print("The width of the graph ({0}) is greater then the width of the terminal ({1}).".format( print("The width of the graph ({0}) is greater then the width of the terminal ({1}).".format(
awidth, w.columns), file=sys.stderr) awidth, w.columns), file=sys.stderr)
return 1 return 1
if xmin >= xmax: if xmin >= xmax:
print("xmin must be less than xmax.", file=sys.stderr) 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 rows = width
xscl = width / (xmax - xmin) xstep = (xmax - xmin) / width
yscl = height / (ymax - ymin) ystep = (ymax - ymin) / height
xaxis = width - (xmax * xscl) xaxis = width - (xmax / xstep)
yaxis = ymax * yscl yaxis = ymax / ystep
xres = 2
array = [[0 for j in range(height)] for i in range(width)] 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 % acolor = color + 1 if len(afunctions) == 1 else (j %
(len(colors) - 2)) + 3 (len(colors) - 2)) + 3
for i in (x / 2 for x in range(rows * 2)): for i in (x / xres for x in range(rows * xres)):
x = (i / xscl) + xmin x = (i * xstep) + xmin
y = function(x) y = function(x)
if x >= xmin and x < xmax and y >= ymin and y < ymax: if x >= xmin and x < xmax and y >= ymin and y < ymax:
ax = int((x * xscl) + xaxis) ax = int((x / xstep) + xaxis)
ay = int((yaxis - (y * yscl)) - 1) ay = int((yaxis - (y / ystep)) - 1)
if array[ax][ay]: if array[ax][ay]:
if array[ax][ay] != acolor: if array[ax][ay] != acolor:
@ -457,9 +525,11 @@ def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
else: else:
array[ax][ay] = acolor array[ax][ay] = acolor
return graph(height, width, xmin, xmax, ymin, ymax, array, border=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""" """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 shutil
import re import re
import textwrap import textwrap
from enum import IntEnum, auto
from wcwidth import wcswidth from wcwidth import wcswidth
from typing import List, Optional, Any, Sequence, Callable from typing import List, Optional, Any, Sequence, Callable
import locale import locale
locale.setlocale(locale.LC_ALL, '') 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 = [ styles = [
["-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"], # ASCII ["-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"], # ASCII
["", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"], # Basic ["", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"], # Basic
@ -28,25 +40,24 @@ styles = [
ansi = re.compile(r'\x1B\[(?:[0-9]+(?:;[0-9]+)*)?m') 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.""" """Returns the number of columns that the given string would take up if printed."""
str = ansi.sub('', str) astr = ansi.sub('', astr)
width = wcswidth(str) width = wcswidth(astr)
if width == -1: 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) sys.exit(1)
return width 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""" """Output char array as table"""
if not array: if not array:
return 1 return 1
if not (0 <= style < len(styles)):
return 1
rows = len(array) rows = len(array)
columns = len(array[0]) columns = len(array[0])
@ -61,13 +72,14 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
else: else:
width += (2 * padding) * columns width += (2 * padding) * columns
if width > w.columns: if check:
print("The width of the table ({0}) is greater then the width of the terminal ({1}).".format( if width > w.columns:
width, w.columns), file=sys.stderr) print("The width of the table ({0}) is greater then the width of the terminal ({1}).".format(
return 1 width, w.columns), file=sys.stderr)
return 1
if title: if title:
print(textwrap.fill(title, width=w.columns)) print(textwrap.fill(title, width=width))
strm = "" strm = ""
@ -77,18 +89,22 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
for j in range(columns): for j in range(columns):
strm += styles[style][0] * ((2 * padding) + columnwidth[j]) strm += styles[style][0] * ((2 * padding) + columnwidth[j])
if j == (columns - 1): if j < (columns - 1):
strm += styles[style][4] + "\n" if cellborder or headerrow or (j == 0 and headercolumn):
elif cellborder or headerrow or (j == 0 and headercolumn): strm += styles[style][3]
strm += styles[style][3] else:
else: strm += styles[style][0]
strm += styles[style][0]
strm += styles[style][4] + "\n"
for i in range(rows): for i in range(rows):
if tableborder:
strm += styles[style][1]
for j in range(columns): 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] 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 += " " strm += " "
awidth = columnwidth[j] - (strcol(array[i][j]) - len(array[i][j])) 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: else:
strm += " " * padding 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) strm += array[i][j].rjust(awidth)
else: else:
strm += array[i][j].ljust(awidth) 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: elif i < (rows - 1) and headercolumn:
strm += " " * ((2 * padding) + columnwidth[j]) strm += " " * ((2 * padding) + columnwidth[j])
if j == (columns - 1): 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 i == (rows - 1) and tableborder: if i == (rows - 1) and tableborder:
if cellborder or (j == 0 and headercolumn): if cellborder or (j == 0 and headercolumn):
strm += styles[style][9] strm += styles[style][9]
@ -153,12 +161,23 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
else: else:
strm += " " 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) print(strm)
return 0 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""" """Convert array to char array and output as table"""
if not aarray: if not aarray:
return 1 return 1
@ -167,7 +186,9 @@ def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[Any]] =
columns = len(aarray[0]) columns = len(aarray[0])
if not all(len(x) == columns for x in aarray): 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 return 1
if aheaderrow: if aheaderrow:
@ -177,50 +198,36 @@ def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[Any]] =
columns += 1 columns += 1
if aheaderrow and len(aheaderrow) != columns: 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 return 1
if aheadercolumn and len(aheadercolumn) != (rows - 1 if aheaderrow else rows): 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 return 1
aaarray = [["" for j in range(columns)] for i in range(rows)] aaarray = [["" for j in range(columns)] for i in range(rows)]
i = 0
if aheaderrow: if aheaderrow:
for j in range(columns): aaarray[0] = aheaderrow[:columns]
aaarray[i][j] = aheaderrow[j]
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: if aheadercolumn:
aii = i aaarray[i][0] = aheadercolumn[ii]
if aheaderrow: j = 1 if aheadercolumn else 0
aii -= 1 aaarray[i][j:] = map(str, aarray[ii][:columns - j])
aaarray[i][j] = aheadercolumn[aii] return table(aaarray, headerrow=headerrow, headercolumn=headercolumn, tableborder=tableborder,
cellborder=cellborder, padding=padding, alignment=alignment, title=title, style=style)
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)
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""" """Convert one or more functions to array and output as table"""
if not afunctions: if not afunctions:
return 1 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) print("xmin must be less than xmax.", file=sys.stderr)
return 1 return 1
if xscl <= 0: if xstep <= 0:
print("xscl must be greater than zero.", file=sys.stderr) print("xstep must be greater than zero.", file=sys.stderr)
return 1 return 1
rows = int(((xmax - xmin) * xscl)) + 1 rows = int(((xmax - xmin) / xstep)) + 1
columns = len(afunctions) + 1 columns = len(afunctions) + 1
aaheaderrow = ["x", "y"] aaheaderrow = ["x", "y"]
@ -241,23 +248,24 @@ def functions(xmin: float, xmax: float, xscl: float, afunctions: Sequence[Callab
aheaderrow = [""] * columns aheaderrow = [""] * columns
for j in range(columns): if len(afunctions) == 1:
if j < (length - 1) or len(afunctions) == 1: aheaderrow = aaheaderrow
aheaderrow[j] = aaheaderrow[j] else:
else: aheaderrow = aaheaderrow[:-1] + [aaheaderrow[-1] +
aheaderrow[j] = aaheaderrow[length - 1] + str(j - length + 2) str(j - length + 2) for j in range(1, columns)]
aarray = [[0 for j in range(columns)] for i in range(rows)] aarray = [[0 for j in range(columns)] for i in range(rows)]
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][1:] = [function(aarray[i][0]) for function in afunctions]
aarray[i][j + 1] = function(aarray[i][0])
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""" """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 xmin = -10
xmax = 10 xmax = 10
xscl = 2 xstep = 0.5
print("\nOutput array as table\n") print("\nOutput array as table\n")
array = [[random.randint(0, sys.maxsize) array = [[random.randint(0, sys.maxsize)
for j in range(columns)] for i in range(rows)] for j in range(columns)] for i in range(rows)]
for k in range(len(tables.styles)): for style in tables.style_types:
tables.array(array, None, None, style=k) tables.array(array, None, None, style=style)
array = [[random.random() for j in range(columns)] for i in range(rows)] array = [[random.random() for j in range(columns)] for i in range(rows)]
for k in range(len(tables.styles)): for style in tables.style_types:
tables.array(array, None, None, style=k) tables.array(array, None, None, style=style)
print("\nOutput char array as table\n") print("\nOutput char array as table\n")
array = [["Header row/column 1", "Header row 2", "Header row 3", "Header row 4", "Header row 5"], 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 3", "Data 5", "Data 6", "Data 7", "Data 8"],
["Header column 4", "Data 9", "Data 10", "Data 11", "Data 12"], ["Header column 4", "Data 9", "Data 10", "Data 11", "Data 12"],
["Header column 5", "Data 13", "Data 14", "Data 15", "Data 16"]] ["Header column 5", "Data 13", "Data 14", "Data 15", "Data 16"]]
for k in range(len(tables.styles)): for style in tables.style_types:
tables.array(array, None, None, headerrow=True, headercolumn=True, style=k) tables.array(array, None, None, headerrow=True,
headercolumn=True, style=style)
print("\nOutput array as table with separate header row and column\n") print("\nOutput array as table with separate header row and column\n")
array = [["Data {0:n}".format(i + j) for j in range(4)] 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", headercolumn = ["Header column 2", "Header column 3",
"Header column 4", "Header column 5"] "Header column 4", "Header column 5"]
for k in range(len(tables.styles)): for style in tables.style_types:
tables.array(array, headerrow, headercolumn, headerrow=True, headercolumn=True, cellborder=True, style=k) tables.array(array, headerrow, headercolumn, headerrow=True,
tables.array(array, headerrow, headercolumn, headerrow=True, headercolumn=True, style=k) headercolumn=True, cellborder=True, style=style)
tables.array(array, headerrow[:-1], None, headerrow=True, style=k) tables.array(array, headerrow, headercolumn,
tables.array(array, None, [headerrow[0]] + headercolumn[:-1], headercolumn=True, style=k) headerrow=True, headercolumn=True, style=style)
tables.array(array, None, None, cellborder=True, style=k) tables.array(array, headerrow[:-1], None, headerrow=True, style=style)
tables.array(array, None, None, tableborder=False, style=k) tables.array(array, None, [headerrow[0]] +
tables.array(array, headerrow, headercolumn, tableborder=False, headerrow=True, headercolumn=True, style=k) headercolumn[:-1], headercolumn=True, style=style)
tables.array(array, headerrow[:-1], None, tableborder=False, headerrow=True, style=k) tables.array(array, None, None, cellborder=True, style=style)
tables.array(array, None, [headerrow[0]] + headercolumn[:-1], tableborder=False, headercolumn=True, style=k) tables.array(array, None, None, tableborder=False, style=style)
tables.array(array, None, None, tableborder=False, cellborder=True, style=k) 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)] array = [[bool(random.getrandbits(1)) for j in range(columns)]
for i in range(rows)] for i in range(rows)]
for k in range(len(tables.styles)): for style in tables.style_types:
tables.array(array, None, None, style=k) tables.array(array, None, None, style=style)
print("\nOutput sorted array as table\n") print("\nOutput sorted array as table\n")
array = ([random.randint(0, sys.maxsize) array = ([random.randint(0, sys.maxsize)
for j in range(columns)] for i in range(rows)) for j in range(columns)] for i in range(rows))
sortdimension = 0 sortdimension = 0
array = sorted(array, key=lambda x: x[sortdimension]) array = sorted(array, key=lambda x: x[sortdimension])
for k in range(len(tables.styles)): for style in tables.style_types:
tables.array(array, None, None, style=k) tables.array(array, None, None, style=style)
print("\nOutput single function as table\n") print("\nOutput single function as table\n")
for k in range(len(tables.styles)): for style in tables.style_types:
tables.function(xmin, xmax, xscl, afunction, headerrow=True, style=k) tables.function(xmin, xmax, xstep, afunction, headerrow=True, style=style)
for k in range(len(tables.styles)): for style in tables.style_types:
tables.function(xmin, xmax, xscl, lambda x: x + 1, headerrow=True, style=k) tables.function(xmin, xmax, xstep, lambda x: x +
1, headerrow=True, style=style)
print("\nOutput multiple functions as table\n") print("\nOutput multiple functions as table\n")
for k in range(len(tables.styles)): for style in tables.style_types:
tables.functions(xmin, xmax, xscl, [ tables.functions(xmin, xmax, xstep, [
function1, function2], headerrow=True, style=k) function1, function2], headerrow=True, style=style)
for k in range(len(tables.styles)): for style in tables.style_types:
tables.functions(xmin, xmax, xscl, [ tables.functions(xmin, xmax, xstep, [
lambda x: 2 * x, lambda x: x ** 2], headerrow=True, style=k) lambda x: 2 * x, lambda x: x ** 2], headerrow=True, style=style)
height = 160 height = 160
width = 160 width = 160
@ -99,24 +108,25 @@ ymax = 20
print("\nOutput single array as plot\n") print("\nOutput single array as plot\n")
array = [range(i, i + 2) for i in range(10)] array = [range(i, i + 2) for i in range(10)]
for k in range(len(graphs.styles)): for style in graphs.style_types:
graphs.array(height, width, xmin, xmax, ymin, ymax, array, style=k) graphs.array(height, width, xmin, xmax, ymin, ymax, array, style=style)
print("\nOutput single function as graph\n") print("\nOutput single function as graph\n")
for k in range(len(graphs.styles)): for style in graphs.style_types:
graphs.function(height, width, xmin, xmax, ymin, ymax, afunction, style=k)
for k in range(len(graphs.styles)):
graphs.function(height, width, xmin, xmax, ymin, 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") print("\nOutput multiple functions as graph\n")
for k in range(len(graphs.styles)): for style in graphs.style_types:
graphs.functions(height, width, xmin, xmax, ymin, graphs.functions(height, width, xmin, xmax, ymin, ymax,
ymax, [function1, function2], style=k) [function1, function2], style=style)
for k in range(len(graphs.styles)): for style in graphs.style_types:
graphs.functions(height, width, xmin, xmax, ymin, ymax, [ 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)): for style in graphs.style_types:
graphs.functions(height, width, -(2 * math.pi), 2 * math.pi, -4, graphs.functions(height, width, -(2 * math.pi), 2 * math.pi, -4, 4,
4, [math.sin, math.cos, math.tan], axisunitslabel=False, style=k) [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 xmin = -10;
const long double xmax = 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 *headerrow = nullptr;
string *headercolumn = nullptr; string *headercolumn = nullptr;
@ -96,14 +96,14 @@ int main()
tables::options aoptions; 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); tables::array(rows, columns, array, nullptr, nullptr, aoptions);
} }
if (array != nullptr) if (array)
{ {
for (unsigned int i = 0; i < rows; ++i) for (unsigned int i = 0; i < rows; ++i)
delete[] array[i]; delete[] array[i];
@ -120,9 +120,9 @@ int main()
tables::options aoptions; 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); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -136,9 +136,9 @@ int main()
tables::options aoptions; 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); tables::array(array, headerrow, headercolumn, aoptions);
} }
@ -155,14 +155,14 @@ int main()
tables::options aoptions; 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); tables::array(rows, columns, array, nullptr, nullptr, aoptions);
} }
if (array != nullptr) if (array)
{ {
for (unsigned int i = 0; i < rows; ++i) for (unsigned int i = 0; i < rows; ++i)
delete[] array[i]; delete[] array[i];
@ -179,9 +179,9 @@ int main()
tables::options aoptions; 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); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -195,9 +195,9 @@ int main()
tables::options aoptions; 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); tables::array(array, headerrow, headercolumn, aoptions);
} }
@ -217,9 +217,9 @@ int main()
aoptions.headercolumn = true; aoptions.headercolumn = true;
// tables::options aoptions{.headerrow = true, .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); tables::array(array, headerrow, headercolumn, aoptions);
} }
@ -236,9 +236,9 @@ int main()
aoptions.headercolumn = true; aoptions.headercolumn = true;
// tables::options aoptions{.headerrow = true, .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); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -263,9 +263,9 @@ int main()
aoptions.headercolumn = true; aoptions.headercolumn = true;
// tables::options aoptions{.headerrow = true, .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); tables::array(array, headerrow, headercolumn, aoptions);
} }
@ -286,15 +286,15 @@ int main()
vector<string> aheadercolumn(headerrow, headerrow + 1); vector<string> aheadercolumn(headerrow, headerrow + 1);
aheadercolumn.insert(aheadercolumn.end(), headercolumn, headercolumn + columns - 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; tables::options aoptions;
aoptions.headerrow = true; aoptions.headerrow = true;
aoptions.headercolumn = true; aoptions.headercolumn = true;
aoptions.cellborder = true; aoptions.cellborder = true;
aoptions.style = k; aoptions.style = style;
// tables::options aoptions{.headerrow = true, .headercolumn = true, .cellborder = true, .style = k}; // tables::options aoptions{.headerrow = true, .headercolumn = true, .cellborder = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -302,8 +302,8 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.headerrow = true; aoptions.headerrow = true;
aoptions.headercolumn = true; aoptions.headercolumn = true;
aoptions.style = k; aoptions.style = style;
// tables::options aoptions{.headerrow = true, .headercolumn = true, .style = k}; // tables::options aoptions{.headerrow = true, .headercolumn = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -313,8 +313,8 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.headerrow = true; aoptions.headerrow = true;
aoptions.style = k; aoptions.style = style;
// tables::options aoptions{.headerrow = true, .style = k}; // tables::options aoptions{.headerrow = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -324,8 +324,8 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.headercolumn = true; aoptions.headercolumn = true;
aoptions.style = k; aoptions.style = style;
// tables::options aoptions{.headercolumn = true, .style = k}; // tables::options aoptions{.headercolumn = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -335,8 +335,8 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.cellborder = true; aoptions.cellborder = true;
aoptions.style = k; aoptions.style = style;
// tables::options aoptions{.cellborder = true, .style = k}; // tables::options aoptions{.cellborder = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -346,8 +346,8 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.tableborder = false; aoptions.tableborder = false;
aoptions.style = k; aoptions.style = style;
// tables::options aoptions{.tableborder = false, .style = k}; // tables::options aoptions{.tableborder = false, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -356,8 +356,8 @@ int main()
aoptions.tableborder = false; aoptions.tableborder = false;
aoptions.headerrow = true; aoptions.headerrow = true;
aoptions.headercolumn = true; aoptions.headercolumn = true;
aoptions.style = k; aoptions.style = style;
// tables::options aoptions{.tableborder = false, .headerrow = true, .headercolumn = true, .style = k}; // tables::options aoptions{.tableborder = false, .headerrow = true, .headercolumn = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -368,8 +368,8 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.tableborder = false; aoptions.tableborder = false;
aoptions.headerrow = true; aoptions.headerrow = true;
aoptions.style = k; aoptions.style = style;
// tables::options aoptions{.tableborder = false, .headerrow = true, .style = k}; // tables::options aoptions{.tableborder = false, .headerrow = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -380,8 +380,8 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.tableborder = false; aoptions.tableborder = false;
aoptions.headercolumn = true; aoptions.headercolumn = true;
aoptions.style = k; aoptions.style = style;
// tables::options aoptions{.tableborder = false, .headercolumn = true, .style = k}; // tables::options aoptions{.tableborder = false, .headercolumn = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -392,8 +392,8 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.tableborder = false; aoptions.tableborder = false;
aoptions.cellborder = true; aoptions.cellborder = true;
aoptions.style = k; aoptions.style = style;
// tables::options aoptions{.tableborder = false, .cellborder = true, .style = k}; // tables::options aoptions{.tableborder = false, .cellborder = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -413,14 +413,14 @@ int main()
aoptions.boolalpha = true; aoptions.boolalpha = true;
// tables::options 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); tables::array(rows, columns, array, nullptr, nullptr, aoptions);
} }
if (array != nullptr) if (array)
{ {
for (unsigned int i = 0; i < rows; ++i) for (unsigned int i = 0; i < rows; ++i)
delete[] array[i]; delete[] array[i];
@ -448,14 +448,14 @@ int main()
tables::options aoptions; 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); tables::array(rows, columns, array, nullptr, nullptr, aoptions);
} }
if (array != nullptr) if (array)
{ {
for (unsigned int i = 0; i < rows; ++i) for (unsigned int i = 0; i < rows; ++i)
delete[] array[i]; delete[] array[i];
@ -477,9 +477,9 @@ int main()
tables::options aoptions; 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); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -498,9 +498,9 @@ int main()
tables::options aoptions; 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); tables::array(array, headerrow, headercolumn, aoptions);
} }
@ -512,11 +512,11 @@ int main()
aoptions.headerrow = true; aoptions.headerrow = true;
// tables::options 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; aoptions.headerrow = true;
// tables::options 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 // Output multiple functions as table
@ -543,11 +543,11 @@ int main()
aoptions.headerrow = true; aoptions.headerrow = true;
// tables::options 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; aoptions.headerrow = true;
// tables::options 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 <cstdlib>
#include <vector> #include <vector>
#include <iterator> #include <iterator>
#include <numeric>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <unistd.h> #include <unistd.h>
#include <regex> #include <regex>
@ -17,6 +18,19 @@ namespace tables
{ {
using namespace std; 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] = { const char *const styles[][11] = {
{"-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // ASCII {"-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // ASCII
{"", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // Basic {"", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // Basic
@ -28,7 +42,7 @@ namespace tables
}; };
// {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}};//No border // {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}};//No border
regex ansi(R"(\x1B\[(?:[0-9]+(?:;[0-9]+)*)?m)"); const regex ansi(R"(\x1B\[(?:[0-9]+(?:;[0-9]+)*)?m)");
struct options struct options
{ {
@ -40,13 +54,14 @@ namespace tables
ios_base &(*alignment)(ios_base &) = left; ios_base &(*alignment)(ios_base &) = left;
bool boolalpha = false; bool boolalpha = false;
const char *title = nullptr; const char *title = nullptr;
unsigned int style = 2; style_type style = style_light;
bool check = true;
}; };
const options defaultoptions; const options defaultoptions;
template <typename T> template <typename T>
auto size(const T &array) constexpr size_t size(const T &array)
{ {
return distance(begin(array), end(array)); return distance(begin(array), end(array));
} }
@ -74,11 +89,11 @@ namespace tables
} }
++length; ++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 (mbstowcs(wcstring, str, length) == static_cast<size_t>(-1))
{ {
if (wcstring != nullptr) if (wcstring)
delete[] wcstring; delete[] wcstring;
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n";
@ -92,7 +107,7 @@ namespace tables
exit(1); exit(1);
} }
if (wcstring != nullptr) if (wcstring)
delete[] wcstring; delete[] wcstring;
return width; return width;
@ -103,8 +118,7 @@ namespace tables
// Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734 // Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734
string wrap(const char *const str, const size_t line_length) string wrap(const char *const str, const size_t line_length)
{ {
char words[strlen(str) + 1]; string words = str;
strcpy(words, str);
string wrapped; string wrapped;
size_t index = 0; size_t index = 0;
@ -127,7 +141,7 @@ namespace tables
} }
char temp[templinelen + 1]; char temp[templinelen + 1];
strncpy(temp, words + (index - linelen), templinelen); strncpy(temp, words.data() + (index - linelen), templinelen);
temp[templinelen] = '\0'; temp[templinelen] = '\0';
size_t width = strcol(temp); size_t width = strcol(temp);
@ -163,76 +177,83 @@ namespace tables
const bool cellborder = aoptions.cellborder; const bool cellborder = aoptions.cellborder;
const unsigned int padding = aoptions.padding; const unsigned int padding = aoptions.padding;
const char *const title = aoptions.title; const char *const title = aoptions.title;
const unsigned int style = aoptions.style; const style_type style = aoptions.style;
if (style >= tables::size(styles))
return 1;
const size_t rows = array.size(); const size_t rows = array.size();
const size_t columns = array[0].size(); const size_t columns = array[0].size();
int columnwidth[columns]; int columnwidth[columns];
for (unsigned int j = 0; j < columns; ++j) for (size_t j = 0; j < columns; ++j)
columnwidth[j] = 0; columnwidth[j] = 0;
int width = 0; setlocale(LC_ALL, "");
setlocale(LC_CTYPE, ""); for (size_t j = 0; j < columns; ++j)
for (unsigned int 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]) if (cellwidth > columnwidth[j])
columnwidth[j] = cellwidth; columnwidth[j] = cellwidth;
} }
width += columnwidth[j];
} }
struct winsize w; struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
size_t width = accumulate(columnwidth, columnwidth + columns, 0ul);
if (tableborder or cellborder or headerrow or headercolumn) if (tableborder or cellborder or headerrow or headercolumn)
width += (((2 * padding) + 1) * columns) + (tableborder ? 1 : -1); width += (((2 * padding) + 1) * columns) + (tableborder ? 1 : -1);
else else
width += (2 * padding) * columns; 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"; if (width > w.ws_col)
return 1; {
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') if (title and title[0] != '\0')
cout << wrap(title, w.ws_col) << "\n"; cout << wrap(title, width) << "\n";
if (aoptions.alignment)
cout << aoptions.alignment;
if (tableborder) if (tableborder)
{ {
cout << styles[style][2]; 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]; cout << styles[style][0];
if (j == (columns - 1)) if (j < (columns - 1))
cout << styles[style][4] << "\n"; {
else if (cellborder or headerrow or (j == 0 and headercolumn)) if (cellborder or headerrow or (j == 0 and headercolumn))
cout << styles[style][3]; cout << styles[style][3];
else else
cout << styles[style][0]; 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]; 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 << " "; cout << " ";
const int difference = columnwidth[j] - strcol(array[i][j].c_str()); const int difference = columnwidth[j] - strcol(array[i][j].c_str());
@ -251,7 +272,7 @@ namespace tables
{ {
cout << string(padding, ' '); 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, ' '); 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)) 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)) 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]; cout << styles[style][0];
else if (i < (rows - 1) and headercolumn) else if (i < (rows - 1) and headercolumn)
cout << string((2 * padding) + columnwidth[j], ' '); cout << string((2 * padding) + columnwidth[j], ' ');
if (j == (columns - 1)) 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 (i == (rows - 1) and tableborder) 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)) if (!tables::size(aarray))
return 1; return 1;
unsigned int i = 0; size_t i = 0;
unsigned int j = 0; size_t j = 0;
size_t rows = tables::size(aarray); size_t rows = tables::size(aarray);
size_t columns = tables::size(aarray[0]); 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; })) { 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; return 1;
} }
if (headerrow != nullptr) if (headerrow)
++rows; ++rows;
if (headercolumn != nullptr) if (headercolumn)
++columns; ++columns;
vector<vector<string>> aaarray(rows, vector<string>(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]; aaarray[i][j] = headerrow[j];
} }
@ -362,13 +382,13 @@ namespace tables
++i; ++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; --ii;
aaarray[i][j] = headercolumn[ii]; aaarray[i][j] = headercolumn[ii];
@ -376,7 +396,7 @@ namespace tables
++j; ++j;
} }
for (unsigned int jj = 0; j < columns; ++j) for (size_t jj = 0; j < columns; ++j)
{ {
ostringstream strm; 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) 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)); 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()); copy(aarray[i], aarray[i] + columns, aaarray[i].begin());
string *aheaderrow = nullptr; string *aheaderrow = nullptr;
@ -434,7 +454,7 @@ namespace tables
// Convert one or more functions to array and output as table // Convert one or more functions to array and output as table
template <typename T> 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) if (numfunctions == 0)
return 1; return 1;
@ -445,13 +465,13 @@ namespace tables
return 1; 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; 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 size_t columns = numfunctions + 1;
const char *const aheaderrow[] = {"x", "y"}; const char *const aheaderrow[] = {"x", "y"};
@ -459,9 +479,9 @@ namespace tables
const size_t length = tables::size(aheaderrow); 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) if (j < (length - 1) or numfunctions == 1)
{ {
@ -478,7 +498,7 @@ namespace tables
string *headercolumn = nullptr; string *headercolumn = nullptr;
// headercolumn = new string[rows + 1]; // 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; // ostringstream strm;
// strm << i + 1; // strm << i + 1;
@ -487,22 +507,22 @@ namespace tables
vector<vector<T>> aarray(rows, vector<T>(columns)); 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]); aarray[i][j + 1] = (functions[j])(aarray[i][0]);
} }
int code = array(aarray, headerrow, headercolumn, aoptions); int code = array(aarray, headerrow, headercolumn, aoptions);
if (headerrow != nullptr) if (headerrow)
{ {
delete[] headerrow; delete[] headerrow;
} }
// if (headercolumn != nullptr) // if (headercolumn)
// { // {
// delete[] headercolumn; // delete[] headercolumn;
// } // }
@ -512,20 +532,20 @@ namespace tables
// Convert single function to array and output as table // Convert single function to array and output as table
template <typename T> 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}; 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 // Convert single function to array and output as table
template <typename T> 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}; std::function<T(T)> afunctions[] = {afunction};
return functions(xmin, xmax, xscl, 1, afunctions, aoptions); return functions(xmin, xmax, xstep, 1, afunctions, aoptions);
} }
} }