Merge branch 'tdulcet:master' into pixel-intermediate

This commit is contained in:
Jan Kuhlmann 2025-01-15 11:06:52 +01:00 committed by GitHub
commit 95b2f7aad0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 749 additions and 360 deletions

View File

@ -11,6 +11,7 @@ jobs:
name: Linux C++
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.cxx == 'clang++' && matrix.os == 'ubuntu-20.04' }}
strategy:
matrix:
os: [ubuntu-20.04, ubuntu-22.04, ubuntu-24.04]
@ -68,7 +69,7 @@ jobs:
python3 -m pip install --upgrade pip
python3 -m pip install ruff
- name: Script
run: ruff check --output-format=github --target-version py37 --select F,E4,E7,E9,W,I,D,UP,YTT,ANN,S,BLE,B,A,COM819,C4,T10,EM,EXE,ISC,ICN,G,PIE,PYI,Q,RSE,RET,SLF,SLOT,SIM,TID,TCH,ARG,PGH,PL,TRY,FLY,PERF,FURB,LOG,RUF --preview --ignore W191,D211,D213,D401,PLR09,PLR1702,PLR2004,FURB101,FURB167,RUF001,RUF002,RUF003,RUF023 .
run: ruff check --output-format=github --target-version py37 --select F,E4,E7,E9,W,I,D,UP,YTT,ANN,S,BLE,B,A,COM819,C4,T10,EM,EXE,ISC,ICN,G,PIE,PYI,Q,RSE,RET,SLF,SLOT,SIM,TID,TC,ARG,PGH,PL,TRY,FLY,PERF,FURB,LOG,RUF --preview --ignore W191,D211,D213,D401,PLR09,PLR1702,PLR2004,FURB101,FURB167,RUF001,RUF002,RUF003,RUF023 .
continue-on-error: true
Python:
@ -92,4 +93,4 @@ jobs:
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Script
run: |
python -X dev python/test.py
python -X dev python/

View File

@ -544,7 +544,7 @@ Other compilers should work as well, but are not (yet) tested.
Run with: `./graphs`
If `height` is `0`, it will be set to the current height of the terminal (number of rows times four). If `width` is `0`, it will be set to the current width of the terminal (number of columns times two).
If `height` is `0`, it will be set to the current height of the terminal (number of rows). If `width` is `0`, it will be set to the current width of the terminal (number of columns).
#### Output array as histogram
@ -557,8 +557,8 @@ using namespace std;
int main()
{
size_t height = 160;
size_t width = 160;
size_t height = 40;
size_t width = 80;
long double xmin = -20;
long double xmax = 20;
@ -588,8 +588,8 @@ using namespace std;
int main()
{
size_t height = 160;
size_t width = 160;
size_t height = 40;
size_t width = 80;
long double xmin = -20;
long double xmax = 20;
@ -623,8 +623,8 @@ using namespace std;
int main()
{
size_t height = 160;
size_t width = 160;
size_t height = 40;
size_t width = 80;
long double xmin = -20;
long double xmax = 20;
@ -654,8 +654,8 @@ using namespace std;
int main()
{
size_t height = 160;
size_t width = 160;
size_t height = 40;
size_t width = 80;
long double xmin = -20;
long double xmax = 20;
@ -696,8 +696,8 @@ double afunction(double x)
int main()
{
size_t height = 160;
size_t width = 160;
size_t height = 40;
size_t width = 80;
long double xmin = -20;
long double xmax = 20;
@ -719,8 +719,8 @@ using namespace std;
int main()
{
size_t height = 160;
size_t width = 160;
size_t height = 40;
size_t width = 80;
long double xmin = -20;
long double xmax = 20;
@ -759,8 +759,8 @@ double function2(double x)
int main()
{
size_t height = 160;
size_t width = 160;
size_t height = 40;
size_t width = 80;
long double xmin = -20;
long double xmax = 20;
@ -787,8 +787,8 @@ using namespace std;
int main()
{
size_t height = 160;
size_t width = 160;
size_t height = 40;
size_t width = 80;
long double xmin = -20;
long double xmax = 20;
@ -875,9 +875,16 @@ Values:
1. `type_braille`: Braille (default)
![](images/type%20braille%20graph.png)
2. `type_block`: Block
3. `type_block_quadrant`: Block quadrant
![](images/type%20block%20graph.png)
4. `type_separated_block_quadrant`: Separated block quadrant
5. `type_block_sextant`: Block sextant
6. `type_separated_block_sextant`: Separated block sextant
7. `type_block_octant`: Block octant
The Braille type has the highest resolution of 2×4 pixels per character, while the block type uses 2×2. This option is only used for plots and graphs. Histograms use 1×8 pixels per character.
The Braille and block octant types have the highest density of 2×4 pixels per character, while the two block sextant types use 2×3, the two block quadrant types use 2×2 and the block type uses 1×1. This option is only used for plots and graphs. Histograms use 1×8 pixels per character.
The block sextant type requires support for Unicode 13.0, while the separated block quadrant, separated block sextant and block octant types require support for Unicode 16.0.
#### Mark type

View File

@ -45,8 +45,8 @@ constexpr long double function5(long double x)
int main()
{
const size_t height = 160;
const size_t width = 160;
const size_t height = 40;
const size_t width = 80;
const long double xmin = -20;
const long double xmax = 20;

View File

@ -80,24 +80,40 @@ namespace graphs
enum color_type const color_types[] = {color_default, color_black, color_red, color_green, color_yellow, color_blue, color_magenta, color_cyan, color_white, color_gray, color_bright_red, color_bright_green, color_bright_yellow, color_bright_blue, color_bright_magenta, color_bright_cyan, color_bright_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 unsigned char colors[] = {39, 30, 31, 32, 33, 34, 35, 36, 37, 90, 91, 92, 93, 94, 95, 96, 97};
const char *const dots[] = {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
const int dotvalues[][4] = {{0x1, 0x2, 0x4, 0x40}, {0x8, 0x10, 0x20, 0x80}};
const char *const blocks[] = {" ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
const int blockvalues[][2] = {{4, 1}, {8, 2}};
const char *const blocks[] = {"\u00A0", ""};
const char *const bars[] = {" ", "", "", "", "", "", "", "", ""};
const char *const blocks_quadrant[] = {"\u00A0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
const char *const separated_blocks_quadrant[] = {"\u00A0", "𜰡", "𜰢", "𜰣", "𜰤", "𜰥", "𜰦", "𜰧", "𜰨", "𜰩", "𜰪", "𜰫", "𜰬", "𜰭", "𜰮", "𜰯"};
const char *const blocks_sextant[] = {"\u00A0", "🬀", "🬁", "🬂", "🬃", "🬄", "🬅", "🬆", "🬇", "🬈", "🬉", "🬊", "🬋", "🬌", "🬍", "🬎", "🬏", "🬐", "🬑", "🬒", "🬓", "", "🬔", "🬕", "🬖", "🬗", "🬘", "🬙", "🬚", "🬛", "🬜", "🬝", "🬞", "🬟", "🬠", "🬡", "🬢", "🬣", "🬤", "🬥", "🬦", "🬧", "", "🬨", "🬩", "🬪", "🬫", "🬬", "🬭", "🬮", "🬯", "🬰", "🬱", "🬲", "🬳", "🬴", "🬵", "🬶", "🬷", "🬸", "🬹", "🬺", "🬻", ""};
const char *const separated_blocks_sextant[] = {"\u00A0", "𜹑", "𜹒", "𜹓", "𜹔", "𜹕", "𜹖", "𜹗", "𜹘", "𜹙", "𜹚", "𜹛", "𜹜", "𜹝", "𜹞", "𜹟", "𜹠", "𜹡", "𜹢", "𜹣", "𜹤", "𜹥", "𜹦", "𜹧", "𜹨", "𜹩", "𜹪", "𜹫", "𜹬", "𜹭", "𜹮", "𜹯", "𜹰", "𜹱", "𜹲", "𜹳", "𜹴", "𜹵", "𜹶", "𜹷", "𜹸", "𜹹", "𜹺", "𜹻", "𜹼", "𜹽", "𜹾", "𜹿", "𜺀", "𜺁", "𜺂", "𜺃", "𜺄", "𜺅", "𜺆", "𜺇", "𜺈", "𜺉", "𜺊", "𜺋", "𜺌", "𜺍", "𜺎", "𜺏"};
const char *const blocks_octant[] = {"\u00A0", "𜺨", "𜺫", "🮂", "𜴀", "", "𜴁", "𜴂", "𜴃", "𜴄", "", "𜴅", "𜴆", "𜴇", "𜴈", "", "𜴉", "𜴊", "𜴋", "𜴌", "🯦", "𜴍", "𜴎", "𜴏", "𜴐", "𜴑", "𜴒", "𜴓", "𜴔", "𜴕", "𜴖", "𜴗", "𜴘", "𜴙", "𜴚", "𜴛", "𜴜", "𜴝", "𜴞", "𜴟", "🯧", "𜴠", "𜴡", "𜴢", "𜴣", "𜴤", "𜴥", "𜴦", "𜴧", "𜴨", "𜴩", "𜴪", "𜴫", "𜴬", "𜴭", "𜴮", "𜴯", "𜴰", "𜴱", "𜴲", "𜴳", "𜴴", "𜴵", "🮅", "𜺣", "𜴶", "𜴷", "𜴸", "𜴹", "𜴺", "𜴻", "𜴼", "𜴽", "𜴾", "𜴿", "𜵀", "𜵁", "𜵂", "𜵃", "𜵄", "", "𜵅", "𜵆", "𜵇", "𜵈", "", "𜵉", "𜵊", "𜵋", "𜵌", "", "𜵍", "𜵎", "𜵏", "𜵐", "", "𜵑", "𜵒", "𜵓", "𜵔", "𜵕", "𜵖", "𜵗", "𜵘", "𜵙", "𜵚", "𜵛", "𜵜", "𜵝", "𜵞", "𜵟", "𜵠", "𜵡", "𜵢", "𜵣", "𜵤", "𜵥", "𜵦", "𜵧", "𜵨", "𜵩", "𜵪", "𜵫", "𜵬", "𜵭", "𜵮", "𜵯", "𜵰", "𜺠", "𜵱", "𜵲", "𜵳", "𜵴", "𜵵", "𜵶", "𜵷", "𜵸", "𜵹", "𜵺", "𜵻", "𜵼", "𜵽", "𜵾", "𜵿", "𜶀", "𜶁", "𜶂", "𜶃", "𜶄", "𜶅", "𜶆", "𜶇", "𜶈", "𜶉", "𜶊", "𜶋", "𜶌", "𜶍", "𜶎", "𜶏", "", "𜶐", "𜶑", "𜶒", "𜶓", "", "𜶔", "𜶕", "𜶖", "𜶗", "", "𜶘", "𜶙", "𜶚", "𜶛", "", "𜶜", "𜶝", "𜶞", "𜶟", "𜶠", "𜶡", "𜶢", "𜶣", "𜶤", "𜶥", "𜶦", "𜶧", "𜶨", "𜶩", "𜶪", "𜶫", "", "𜶬", "𜶭", "𜶮", "𜶯", "𜶰", "𜶱", "𜶲", "𜶳", "𜶴", "𜶵", "𜶶", "𜶷", "𜶸", "𜶹", "𜶺", "𜶻", "𜶼", "𜶽", "𜶾", "𜶿", "𜷀", "𜷁", "𜷂", "𜷃", "𜷄", "𜷅", "𜷆", "𜷇", "𜷈", "𜷉", "𜷊", "𜷋", "𜷌", "𜷍", "𜷎", "𜷏", "𜷐", "𜷑", "𜷒", "𜷓", "𜷔", "𜷕", "𜷖", "𜷗", "𜷘", "𜷙", "𜷚", "", "𜷛", "𜷜", "𜷝", "𜷞", "", "𜷟", "𜷠", "𜷡", "𜷢", "", "𜷣", "", "𜷤", "𜷥", ""};
const char *const bars[] = {"\u00A0", "", "", "", "", "", "", "", ""};
enum type_type
{
type_braille,
type_block,
type_block_quadrant,
type_separated_block_quadrant,
type_block_sextant,
type_separated_block_sextant,
type_block_octant,
type_histogram // Set automatically by the histogram() function
};
enum type_type const type_types[] = {type_braille, type_block /* , type_histogram */};
enum type_type const type_types[] = {type_braille, type_block, type_block_quadrant, type_separated_block_quadrant, type_block_sextant, type_separated_block_sextant, type_block_octant /* , type_histogram */};
const unsigned short densities[][2] = {{4, 2}, {1, 1}, {2, 2}, {2, 2}, {3, 2}, {3, 2}, {4, 2}, {8, 1}};
enum plot_type
{
@ -107,7 +123,7 @@ namespace graphs
enum plot_type const plot_types[] = {plot_scatter, plot_line};
const short marks[][8][2] = {{{0, 0}}, {{0, 1}, {-1, 0}, {0, 0}, {1, 0}, {0, -1}}, {{-1, 1}, {0, 1}, {1, 1}, {-1, 0}, {1, 0}, {-1, -1}, {0, -1}, {1, -1}}};
const vector<vector<pair<short, short>>> marks = {{{0, 0}}, {{0, 1}, {-1, 0}, {0, 0}, {1, 0}, {0, -1}}, {{-1, 1}, {0, 1}, {1, 1}, {-1, 0}, {1, 0}, {-1, -1}, {0, -1}, {1, -1}}};
enum mark_type
{
@ -381,8 +397,9 @@ namespace graphs
strm << number;
}
inline size_t outputlabel(const long double label, const units_type units, ostringstream &strm)
inline size_t outputlabel(const long double label, const units_type units, string &str)
{
ostringstream strm;
strm.imbue(locale(""));
switch (units)
@ -423,11 +440,21 @@ namespace graphs
break;
}
const size_t length = strcol(strm.str());
str = strm.str();
const size_t length = strcol(str);
return length;
}
inline string outputcolor(const color_type color)
{
ostringstream strm;
strm << "\e[" << int(colors[color]) << "m";
return strm.str();
}
// Output graph
inline int graph(const size_t height, const size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, const vector<vector<unsigned short>> &array, const options &aoptions)
{
@ -440,7 +467,6 @@ namespace graphs
const bool axistick = aoptions.axistick;
const bool axisunitslabel = aoptions.axisunitslabel;
const type_type type = aoptions.type;
const char *const title = aoptions.title;
if (!height)
return 1;
@ -451,9 +477,7 @@ namespace graphs
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
const size_t ai = type == type_histogram ? 8 : type == type_block ? 2
: 4;
const size_t aj = type == type_histogram ? 1 : 2;
const auto [ai, aj] = densities[type];
const size_t aheight = height / ai;
const size_t awidth = width / aj;
@ -496,8 +520,8 @@ namespace graphs
setlocale(LC_ALL, "");
if (title and title[0] != '\0')
aoptions.ostr << wrap(title, awidth) << '\n';
if (aoptions.title and aoptions.title[0] != '\0')
aoptions.ostr << wrap(aoptions.title, awidth) << '\n';
const char *const *astyle = styles[aoptions.style];
@ -518,7 +542,7 @@ namespace graphs
const bool ayaxis = yaxis <= (height - ai) ? i <= yaxis and (i + ai) > yaxis : i < yaxis and (i + ai) >= yaxis;
const bool yaxislabel = yaxis <= (height - ai) ? i <= (yaxis + ai) and (i + ai) > (yaxis + ai) : i < (yaxis - ai) and (i + ai) >= (yaxis - ai);
ostringstream ylabelstrm;
string ylabelstr;
size_t ylabellength = 0;
if (axis and axistick and axisunitslabel and yaxis >= 0 and yaxis <= height)
@ -539,7 +563,7 @@ namespace graphs
if (output)
{
ylabellength = outputlabel(label, aoptions.yunits, ylabelstrm);
ylabellength = outputlabel(label, aoptions.yunits, ylabelstr);
ylabellength *= aj;
}
}
@ -657,12 +681,12 @@ namespace graphs
{
output = false;
ostringstream astrm;
size_t length = outputlabel(label, aoptions.xunits, astrm);
string astr;
size_t length = outputlabel(label, aoptions.xunits, astr);
length *= aj;
if ((j >= xaxis or (j + length) < (ymin <= 0 and ymax >= 0 and xmin <= 0 and xmax >= 0 ? xaxis - ai : xaxis)) and (j + length) < (width - aj) and (xaxis <= (width - aj) or j > aj))
{
strm << astrm.str();
strm << astr;
if (length > aj)
j += length - aj;
@ -681,7 +705,7 @@ namespace graphs
}
else if (ylabellength and (xaxis < aj ? xaxislabel : j < (xaxis - ylabellength) and (j + aj) >= (xaxis - ylabellength)) and (yaxis >= ai or i < (height - ai)) and axistick and axisunitslabel)
{
strm << ylabelstrm.str();
strm << ylabelstr;
output = true;
if (ylabellength > aj)
j += ylabellength - aj;
@ -700,15 +724,24 @@ namespace graphs
const unsigned short value = array[j + k][i + l];
if (value)
{
if (type == type_histogram)
switch (type)
{
case type_braille:
dot += dotvalues[k][l];
break;
case type_block:
case type_block_quadrant:
case type_separated_block_quadrant:
case type_block_sextant:
case type_separated_block_sextant:
case type_block_octant:
dot += 1 << (l * aj + k);
break;
case type_histogram:
if (!dot)
dot = (size(bars) - l) - 1;
break;
}
else if (type == type_block)
dot += blockvalues[k][l];
else
dot += dotvalues[k][l];
}
if (color)
{
@ -724,13 +757,38 @@ namespace graphs
--color;
if (color)
strm << colors[color];
strm << outputcolor(color_type(color));
strm << (type == type_histogram ? bars[dot] : type == type_block ? blocks[dot]
: dots[dot]);
switch (type)
{
case type_braille:
strm << dots[dot];
break;
case type_block:
strm << blocks[dot];
break;
case type_block_quadrant:
strm << blocks_quadrant[dot];
break;
case type_separated_block_quadrant:
strm << separated_blocks_quadrant[dot];
break;
case type_block_sextant:
strm << blocks_sextant[dot];
break;
case type_separated_block_sextant:
strm << separated_blocks_sextant[dot];
break;
case type_block_octant:
strm << blocks_octant[dot];
break;
case type_histogram:
strm << bars[dot];
break;
}
if (color)
strm << colors[0];
strm << outputcolor(color_default);
}
}
@ -931,31 +989,30 @@ namespace graphs
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (!height)
height = w.ws_row * 4;
height = w.ws_row;
if (!width)
width = w.ws_col * 2;
width = w.ws_col;
if (aoptions.check)
{
const size_t aheight = height / 4;
const size_t awidth = width / 2;
if (aheight > w.ws_row)
if (height > w.ws_row)
{
cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
cerr << "The height of the graph (" << height << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
return 1;
}
if (awidth > w.ws_col)
if (width > w.ws_col)
{
cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
cerr << "The width of the graph (" << width << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
return 1;
}
}
height *= 2;
width /= 2;
const auto [ai, aj] = densities[type_histogram];
height *= ai;
width *= aj;
if (!xmin and !xmax)
{
@ -1055,31 +1112,30 @@ namespace graphs
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (!height)
height = w.ws_row * 4;
height = w.ws_row;
if (!width)
width = w.ws_col * 2;
width = w.ws_col;
if (aoptions.check)
{
const size_t aheight = height / 4;
const size_t awidth = width / 2;
if (aheight > w.ws_row)
if (height > w.ws_row)
{
cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
cerr << "The height of the graph (" << height << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
return 1;
}
if (awidth > w.ws_col)
if (width > w.ws_col)
{
cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
cerr << "The width of the graph (" << width << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
return 1;
}
}
if (aoptions.type == type_block)
height /= 2;
const auto [ai, aj] = densities[aoptions.type];
height *= ai;
width *= aj;
if (!xmin and !xmax)
{
@ -1194,31 +1250,30 @@ namespace graphs
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (!height)
height = w.ws_row * 4;
height = w.ws_row;
if (!width)
width = w.ws_col * 2;
width = w.ws_col;
if (aoptions.check)
{
const size_t aheight = height / 4;
const size_t awidth = width / 2;
if (aheight > w.ws_row)
if (height > w.ws_row)
{
cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
cerr << "The height of the graph (" << height << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
return 1;
}
if (awidth > w.ws_col)
if (width > w.ws_col)
{
cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
cerr << "The width of the graph (" << width << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
return 1;
}
}
if (aoptions.type == type_block)
height /= 2;
const auto [ai, aj] = densities[aoptions.type];
height *= ai;
width *= aj;
if (xmin >= xmax)
{

View File

@ -33,9 +33,9 @@ python3 -m pip 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 [`__main__.py`](__main__.py) file.
Run with: `python3 -OO test.py`.
Run with: `python3 -OO .`.
#### Output str array as table
@ -269,19 +269,19 @@ python3 -m pip 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 [`__main__.py`](__main__.py) file.
Run with: `python3 -OO test.py`.
Run with: `python3 -OO .`.
If `height` is `0`, it will be set to the current height of the terminal (number of rows times four). If `width` is `0`, it will be set to the current width of the terminal (number of columns times two).
If `height` is `0`, it will be set to the current height of the terminal (number of rows). If `width` is `0`, it will be set to the current width of the terminal (number of columns).
#### Output array as histogram
```py
import graphs
height = 160
width = 160
height = 40
width = 80
xmin = -20
xmax = 20
@ -302,8 +302,8 @@ If `xmin` and `xmax` are both `0`, they will be set to the respective minimum an
```py
import graphs
height = 160
width = 160
height = 40
width = 80
xmin = -20
xmax = 20
@ -329,8 +329,8 @@ import graphs
def afunction(x):
return x + 1
height = 160
width = 160
height = 40
width = 80
xmin = -20
xmax = 20
@ -347,8 +347,8 @@ graphs.function(height, width, xmin, xmax, ymin, ymax, afunction)
```py
import graphs
height = 160
width = 160
height = 40
width = 80
xmin = -20
xmax = 20
@ -373,8 +373,8 @@ def function1(x):
def function2(x):
return x ** 2
height = 160
width = 160
height = 40
width = 80
xmin = -20
xmax = 20
@ -394,8 +394,8 @@ graphs.functions(height, width, xmin, xmax, ymin, ymax, functions)
```py
import graphs
height = 160
width = 160
height = 40
width = 80
xmin = -20
xmax = 20
@ -474,9 +474,16 @@ Values:
1. `type_types.braille`: Braille (default)
![](../images/type%20braille%20graph.png)
2. `type_types.block`: Block
3. `type_types.block_quadrant`: Block quadrant
![](../images/type%20block%20graph.png)
4. `type_types.separated_block_quadrant`: Separated block quadrant
5. `type_types.block_sextant`: Block sextant
6. `type_types.separated_block_sextant`: Separated block sextant
7. `type_types.block_octant`: Block octant
The Braille type has the highest resolution of 2×4 pixels per character, while the block type uses 2×2. This option is only used for plots and graphs. Histograms use 1×8 pixels per character.
The Braille and block octant types have the highest density of 2×4 pixels per character, while the two block sextant types use 2×3, the two block quadrant types use 2×2 and the block type uses 1×1. This option is only used for plots and graphs. Histograms use 1×8 pixels per character.
The block sextant type requires support for Unicode 13.0, while the separated block quadrant, separated block sextant and block octant types require support for Unicode 16.0.
#### Mark type

130
python/__main__.py Normal file
View File

@ -0,0 +1,130 @@
#!/usr/bin/env python3
# Teal Dulcet, CS546
# Run: python3 -OO .
import math
import operator
import random
import sys
import graphs
import tables
def afunction(x: float) -> float:
return x + 1
def function1(x: float) -> float:
return 2 * x
def function2(x: float) -> float:
return x**2
rows = 5
columns = 5
xmin = -10
xmax = 10
xstep = 0.5
print("\nOutput array as table\n")
array = [[random.randint(0, sys.maxsize) for j in range(columns)] for i in range(rows)]
for style in tables.style_types:
tables.array(array, None, None, style=style)
array = [[random.random() for j in range(columns)] for i in range(rows)]
for style in tables.style_types:
tables.array(array, None, None, style=style)
print("\nOutput char array as table\n")
array = [
["Header row/column 1", "Header row 2", "Header row 3", "Header row 4", "Header row 5"],
["Header column 2", "Data 1", "Data 2", "Data 3", "Data 4"],
["Header column 3", "Data 5", "Data 6", "Data 7", "Data 8"],
["Header column 4", "Data 9", "Data 10", "Data 11", "Data 12"],
["Header column 5", "Data 13", "Data 14", "Data 15", "Data 16"],
]
for style in tables.style_types:
tables.array(array, None, None, headerrow=True, headercolumn=True, style=style)
print("\nOutput array as table with separate header row and column\n")
array = [[f"Data {i + j:n}" for j in range(4)] for i in range(1, 4 * 4 + 1, 4)]
headerrow = ["Header row/column 1", "Header row 2", "Header row 3", "Header row 4", "Header row 5"]
headercolumn = ["Header column 2", "Header column 3", "Header column 4", "Header column 5"]
for style in tables.style_types:
tables.array(array, headerrow, headercolumn, headerrow=True, headercolumn=True, cellborder=True, style=style)
tables.array(array, headerrow, headercolumn, headerrow=True, headercolumn=True, style=style)
tables.array(array, headerrow[:-1], None, headerrow=True, style=style)
tables.array(array, None, [headerrow[0]] + headercolumn[:-1], headercolumn=True, style=style)
tables.array(array, None, None, cellborder=True, style=style)
tables.array(array, None, None, tableborder=False, style=style)
tables.array(array, headerrow, headercolumn, tableborder=False, headerrow=True, headercolumn=True, style=style)
tables.array(array, headerrow[:-1], None, tableborder=False, headerrow=True, style=style)
tables.array(array, None, [headerrow[0]] + headercolumn[:-1], tableborder=False, headercolumn=True, style=style)
tables.array(array, None, None, tableborder=False, cellborder=True, style=style)
array = [[bool(random.getrandbits(1)) for j in range(columns)] for i in range(rows)]
for style in tables.style_types:
tables.array(array, None, None, style=style)
print("\nOutput sorted array as table\n")
array = ([random.randint(0, sys.maxsize) for j in range(columns)] for i in range(rows))
sortdimension = 0
array = sorted(array, key=operator.itemgetter(sortdimension))
for style in tables.style_types:
tables.array(array, None, None, style=style)
print("\nOutput single function as table\n")
for style in tables.style_types:
tables.function(xmin, xmax, xstep, afunction, headerrow=True, style=style)
for style in tables.style_types:
tables.function(xmin, xmax, xstep, lambda x: x + 1, headerrow=True, style=style)
print("\nOutput multiple functions as table\n")
for style in tables.style_types:
tables.functions(xmin, xmax, xstep, [function1, function2], headerrow=True, style=style)
for style in tables.style_types:
tables.functions(xmin, xmax, xstep, [lambda x: 2 * x, lambda x: x**2], headerrow=True, style=style)
height = 40
width = 80
xmin = -20
xmax = 20
ymin = -20
ymax = 20
print("\nOutput array as histogram\n")
array = [random.gauss(0, 1) for i in range(100)]
for style in graphs.style_types:
graphs.histogram(height, width, xmin, xmax, ymin, ymax, array, style=style)
print("\nOutput single array as plot\n")
array = [range(i, i + 2) for i in range(10)]
for atype in graphs.atype_types:
for mark in graphs.mark_types:
for style in graphs.style_types:
graphs.plot(height, width, xmin, xmax, ymin, ymax, array, atype=atype, mark=mark, style=style)
print("\nOutput single function as graph\n")
for style in graphs.style_types:
graphs.function(height, width, xmin, xmax, ymin, ymax, afunction, style=style)
for style in graphs.style_types:
graphs.function(height, width, xmin, xmax, ymin, ymax, lambda x: x + 1, style=style)
print("\nOutput multiple functions as graph\n")
for style in graphs.style_types:
graphs.functions(height, width, xmin, xmax, ymin, ymax, [function1, function2], style=style)
for style in graphs.style_types:
graphs.functions(height, width, xmin, xmax, ymin, ymax, [lambda x: 2 * x, lambda x: x**2], style=style)
for style in graphs.style_types:
graphs.functions(
height, width, -(2 * math.pi), 2 * math.pi, -4, 4, [math.sin, math.cos, math.tan], axisunitslabel=False, style=style
)

View File

@ -24,6 +24,7 @@ if sys.platform != "win32":
def wcswidth(astr: str) -> int:
return libc.wcswidth(astr, len(astr))
else:
from wcwidth import wcswidth
@ -49,7 +50,7 @@ styles = (
("", "", "", "", "", "", "", "", "", "", ""), # Double
("", "", "", "", "", "", "", "", "", "", ""), # Light Arc
("", "", "", "", "", "", "", "", "", "", ""), # Light Dashed
("", "", "", "", "", "", "", "", "", "", "") # Heavy Dashed
("", "", "", "", "", "", "", "", "", "", ""), # Heavy Dashed
# (" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ")) #No border
)
@ -74,11 +75,9 @@ class color_types(IntEnum):
bright_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")
colors = (39, 30, 31, 32, 33, 34, 35, 36, 37, 90, 91, 92, 93, 94, 95, 96, 97)
# fmt: off
dots = (
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
@ -100,22 +99,50 @@ dots = (
"")
dotvalues = ((0x1, 0x2, 0x4, 0x40), (0x8, 0x10, 0x20, 0x80))
blocks = (" ", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "")
blockvalues = ((4, 1), (8, 2))
blocks = ("\xA0", "")
bars = (" ", "", "", "", "", "", "", "", "")
blocks_quadrant = ("\xA0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "")
separated_blocks_quadrant = ("\xA0", "𜰡", "𜰢", "𜰣", "𜰤", "𜰥", "𜰦", "𜰧", "𜰨", "𜰩", "𜰪", "𜰫", "𜰬", "𜰭", "𜰮", "𜰯")
blocks_sextant = ("\xA0", "🬀", "🬁", "🬂", "🬃", "🬄", "🬅", "🬆", "🬇", "🬈", "🬉", "🬊", "🬋", "🬌", "🬍", "🬎", "🬏", "🬐", "🬑", "🬒", "🬓", "", "🬔", "🬕", "🬖", "🬗", "🬘", "🬙", "🬚", "🬛", "🬜", "🬝", "🬞", "🬟", "🬠", "🬡", "🬢", "🬣", "🬤", "🬥", "🬦", "🬧", "", "🬨", "🬩", "🬪", "🬫", "🬬", "🬭", "🬮", "🬯", "🬰", "🬱", "🬲", "🬳", "🬴", "🬵", "🬶", "🬷", "🬸", "🬹", "🬺", "🬻", "")
separated_blocks_sextant = ("\xA0", "𜹑", "𜹒", "𜹓", "𜹔", "𜹕", "𜹖", "𜹗", "𜹘", "𜹙", "𜹚", "𜹛", "𜹜", "𜹝", "𜹞", "𜹟", "𜹠", "𜹡", "𜹢", "𜹣", "𜹤", "𜹥", "𜹦", "𜹧", "𜹨", "𜹩", "𜹪", "𜹫", "𜹬", "𜹭", "𜹮", "𜹯", "𜹰", "𜹱", "𜹲", "𜹳", "𜹴", "𜹵", "𜹶", "𜹷", "𜹸", "𜹹", "𜹺", "𜹻", "𜹼", "𜹽", "𜹾", "𜹿", "𜺀", "𜺁", "𜺂", "𜺃", "𜺄", "𜺅", "𜺆", "𜺇", "𜺈", "𜺉", "𜺊", "𜺋", "𜺌", "𜺍", "𜺎", "𜺏")
blocks_octant = ("\xA0", "𜺨", "𜺫", "🮂", "𜴀", "", "𜴁", "𜴂", "𜴃", "𜴄", "", "𜴅", "𜴆", "𜴇", "𜴈", "", "𜴉", "𜴊", "𜴋", "𜴌", "🯦", "𜴍", "𜴎", "𜴏", "𜴐", "𜴑", "𜴒", "𜴓", "𜴔", "𜴕", "𜴖", "𜴗", "𜴘", "𜴙", "𜴚", "𜴛", "𜴜", "𜴝", "𜴞", "𜴟", "🯧", "𜴠", "𜴡", "𜴢", "𜴣", "𜴤", "𜴥", "𜴦", "𜴧", "𜴨", "𜴩", "𜴪", "𜴫", "𜴬", "𜴭", "𜴮", "𜴯", "𜴰", "𜴱", "𜴲", "𜴳", "𜴴", "𜴵", "🮅", "𜺣", "𜴶", "𜴷", "𜴸", "𜴹", "𜴺", "𜴻", "𜴼", "𜴽", "𜴾", "𜴿", "𜵀", "𜵁", "𜵂", "𜵃", "𜵄", "", "𜵅", "𜵆", "𜵇", "𜵈", "", "𜵉", "𜵊", "𜵋", "𜵌", "", "𜵍", "𜵎", "𜵏", "𜵐", "", "𜵑", "𜵒", "𜵓", "𜵔", "𜵕", "𜵖", "𜵗", "𜵘", "𜵙", "𜵚", "𜵛", "𜵜", "𜵝", "𜵞", "𜵟", "𜵠", "𜵡", "𜵢", "𜵣", "𜵤", "𜵥", "𜵦", "𜵧", "𜵨", "𜵩", "𜵪", "𜵫", "𜵬", "𜵭", "𜵮", "𜵯", "𜵰", "𜺠", "𜵱", "𜵲", "𜵳", "𜵴", "𜵵", "𜵶", "𜵷", "𜵸", "𜵹", "𜵺", "𜵻", "𜵼", "𜵽", "𜵾", "𜵿", "𜶀", "𜶁", "𜶂", "𜶃", "𜶄", "𜶅", "𜶆", "𜶇", "𜶈", "𜶉", "𜶊", "𜶋", "𜶌", "𜶍", "𜶎", "𜶏", "", "𜶐", "𜶑", "𜶒", "𜶓", "", "𜶔", "𜶕", "𜶖", "𜶗", "", "𜶘", "𜶙", "𜶚", "𜶛", "", "𜶜", "𜶝", "𜶞", "𜶟", "𜶠", "𜶡", "𜶢", "𜶣", "𜶤", "𜶥", "𜶦", "𜶧", "𜶨", "𜶩", "𜶪", "𜶫", "", "𜶬", "𜶭", "𜶮", "𜶯", "𜶰", "𜶱", "𜶲", "𜶳", "𜶴", "𜶵", "𜶶", "𜶷", "𜶸", "𜶹", "𜶺", "𜶻", "𜶼", "𜶽", "𜶾", "𜶿", "𜷀", "𜷁", "𜷂", "𜷃", "𜷄", "𜷅", "𜷆", "𜷇", "𜷈", "𜷉", "𜷊", "𜷋", "𜷌", "𜷍", "𜷎", "𜷏", "𜷐", "𜷑", "𜷒", "𜷓", "𜷔", "𜷕", "𜷖", "𜷗", "𜷘", "𜷙", "𜷚", "", "𜷛", "𜷜", "𜷝", "𜷞", "", "𜷟", "𜷠", "𜷡", "𜷢", "", "𜷣", "", "𜷤", "𜷥", "")
bars = ("\xA0", "", "", "", "", "", "", "", "")
# fmt: on
class type_types(IntEnum):
braille = 0
block = auto()
histogram = auto() # Set automatically by the histogram() function
block_quadrant = auto()
separated_block_quadrant = auto()
block_sextant = auto()
separated_block_sextant = auto()
block_octant = auto()
histogram = auto() # Set automatically by the histogram() function
atype_types = (type_types.braille, type_types.block)
marks = (((0, 0),), ((0, 1), (-1, 0), (0, 0), (1, 0), (0, -1)),
((-1, 1), (0, 1), (1, 1), (-1, 0), (1, 0), (-1, -1), (0, -1), (1, -1)))
atype_types = (
type_types.braille,
type_types.block,
type_types.block_quadrant,
type_types.separated_block_quadrant,
type_types.block_sextant,
type_types.separated_block_sextant,
type_types.block_octant,
)
densities = ((4, 2), (1, 1), (2, 2), (2, 2), (3, 2), (3, 2), (4, 2), (8, 1))
marks = (
((0, 0),),
((0, 1), (-1, 0), (0, 0), (1, 0), (0, -1)),
((-1, 1), (0, 1), (1, 1), (-1, 0), (1, 0), (-1, -1), (0, -1), (1, -1)),
)
class mark_types(IntEnum):
@ -142,13 +169,10 @@ fractions = {
"": Fraction(1, 8),
"": Fraction(3, 8),
"": Fraction(5, 8),
"": Fraction(7, 8)
"": Fraction(7, 8),
}
constants = {
"π": math.pi,
"e": math.e
}
constants = {"π": math.pi, "e": math.e}
class units_types(Enum):
@ -166,7 +190,7 @@ class units_types(Enum):
suffix_power_char = ("", "K", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q")
MAX = sys.float_info.radix ** sys.float_info.mant_dig - 1
MAX = sys.float_info.radix**sys.float_info.mant_dig - 1
def strcol(astr: str) -> int:
@ -221,8 +245,7 @@ def outputunit(number: float, scale: units_types) -> str:
strm = locale.format_string("%.0f", number, grouping=True)
# "k" if power == 1 and scale == scale_SI else
strm += suffix_power_char[power] if power < len(
suffix_power_char) else "(error)"
strm += suffix_power_char[power] if power < len(suffix_power_char) else "(error)"
if scale == units_types.scale_IEC_I and power > 0:
strm += "i"
@ -298,7 +321,31 @@ def outputlabel(label: float, units: units_types) -> Tuple[int, str]:
return length, strm
def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, array: List[List[int]], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, style: style_types = style_types.light, title: Optional[str] = None, file: TextIO = sys.stdout, check: bool = True) -> int:
def outputcolor(color: color_types) -> str:
return f"\033[{colors[color]}m"
def graph(
height: int,
width: int,
xmin: float,
xmax: float,
ymin: float,
ymax: float,
array: List[List[int]],
border: bool = False,
axis: bool = True,
axislabel: bool = True,
axistick: bool = True,
axisunitslabel: bool = True,
xunits: units_types = units_types.fracts,
yunits: units_types = units_types.fracts,
atype: type_types = type_types.braille,
style: style_types = style_types.light,
title: Optional[str] = None,
file: TextIO = sys.stdout,
check: bool = True,
) -> int:
"""Output graph."""
if not array:
return 1
@ -311,21 +358,18 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
w = shutil.get_terminal_size()
ai = 8 if atype == type_types.histogram else 2 if atype == type_types.block else 4
aj = 1 if atype == type_types.histogram else 2
ai, aj = densities[atype]
aheight = height // ai
awidth = width // aj
if check:
if aheight > w.lines:
print(
f"The height of the graph ({aheight}) is greater then the height of the terminal ({w.lines}).", file=sys.stderr)
print(f"The height of the graph ({aheight}) is greater then the height of the terminal ({w.lines}).", file=sys.stderr)
return 1
if awidth > w.columns:
print(
f"The width of the graph ({awidth}) is greater then the width of the terminal ({w.columns}).", file=sys.stderr)
print(f"The width of the graph ({awidth}) is greater then the width of the terminal ({w.columns}).", file=sys.stderr)
return 1
if xmin >= xmax:
@ -471,7 +515,13 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
elif (not i if yaxis >= ai else i >= height - ai) and xaxislabel and axislabel:
strm += "y"
output = True
elif ylabellength and (xaxislabel if xaxis < aj else j < xaxis - ylabellength and j + aj >= xaxis - ylabellength) and (yaxis >= ai or i < height - ai) and axistick and axisunitslabel:
elif (
ylabellength
and (xaxislabel if xaxis < aj else j < xaxis - ylabellength and j + aj >= xaxis - ylabellength)
and (yaxis >= ai or i < height - ai)
and axistick
and axisunitslabel
):
strm += ylabelstrm
output = True
if ylabellength > aj:
@ -485,13 +535,20 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
for l in range(min(ai, height - i)):
value = array[j + k][i + l]
if value:
if atype == type_types.histogram:
if atype == type_types.braille:
dot += dotvalues[k][l]
elif atype in {
type_types.block,
type_types.block_quadrant,
type_types.separated_block_quadrant,
type_types.block_sextant,
type_types.separated_block_sextant,
type_types.block_octant,
}:
dot += 1 << (l * aj + k)
elif atype == type_types.histogram:
if not dot:
dot = (len(bars) - l) - 1
elif atype == type_types.block:
dot += blockvalues[k][l]
else:
dot += dotvalues[k][l]
if color:
if value and color != value:
color = 1
@ -502,12 +559,27 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
color -= 1
if color:
strm += colors[color]
strm += outputcolor(color)
strm += bars[dot] if atype == type_types.histogram else blocks[dot] if atype == type_types.block else dots[dot]
if atype == type_types.braille:
strm += dots[dot]
elif atype == type_types.block:
strm += blocks[dot]
elif atype == type_types.block_quadrant:
strm += blocks_quadrant[dot]
elif atype == type_types.separated_block_quadrant:
strm += separated_blocks_quadrant[dot]
elif atype == type_types.block_sextant:
strm += blocks_sextant[dot]
elif atype == type_types.separated_block_sextant:
strm += separated_blocks_sextant[dot]
elif atype == type_types.block_octant:
strm += blocks_octant[dot]
elif atype == type_types.histogram:
strm += bars[dot]
if color:
strm += colors[0]
strm += outputcolor(color_types.default)
j += aj
@ -526,7 +598,27 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
return 0
def histogram(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarray: Sequence[float], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, file: TextIO = sys.stdout, check: bool = True) -> int:
def histogram(
height: int,
width: int,
xmin: float,
xmax: float,
ymin: float,
ymax: float,
aarray: Sequence[float],
border: bool = False,
axis: bool = True,
axislabel: bool = True,
axistick: bool = True,
axisunitslabel: bool = True,
xunits: units_types = units_types.fracts,
yunits: units_types = units_types.fracts,
style: style_types = style_types.light,
color: color_types = color_types.red,
title: Optional[str] = None,
file: TextIO = sys.stdout,
check: bool = True,
) -> int:
"""Convert one or more arrays to graph and output."""
if not aarray:
return 1
@ -534,27 +626,24 @@ def histogram(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
w = shutil.get_terminal_size()
if not height:
height = w.lines * 4
height = w.lines
if not width:
width = w.columns * 2
width = w.columns
if check:
aheight = height // 4
awidth = width // 2
if aheight > w.lines:
print(
f"The height of the graph ({aheight}) is greater then the height of the terminal ({w.lines}).", file=sys.stderr)
if height > w.lines:
print(f"The height of the graph ({height}) is greater then the height of the terminal ({w.lines}).", file=sys.stderr)
return 1
if awidth > w.columns:
print(
f"The width of the graph ({awidth}) is greater then the width of the terminal ({w.columns}).", file=sys.stderr)
if width > w.columns:
print(f"The width of the graph ({width}) is greater then the width of the terminal ({w.columns}).", file=sys.stderr)
return 1
height *= 2
width //= 2
ai, aj = densities[type_types.histogram]
height *= ai
width *= aj
if not xmin and not xmax:
xmin = min(aarray)
@ -594,10 +683,51 @@ def histogram(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
aaarray[x][y] = acolor
y += 1
return graph(height, width, xmin, xmax, ymin, ymax, aaarray, border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, type_types.histogram, style, title, file)
return graph(
height,
width,
xmin,
xmax,
ymin,
ymax,
aaarray,
border,
axis,
axislabel,
axistick,
axisunitslabel,
xunits,
yunits,
type_types.histogram,
style,
title,
file,
)
def plots(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarrays: Sequence[Sequence[Sequence[float]]], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, mark: mark_types = mark_types.dot, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, file: TextIO = sys.stdout, check: bool = True) -> int:
def plots(
height: int,
width: int,
xmin: float,
xmax: float,
ymin: float,
ymax: float,
aarrays: Sequence[Sequence[Sequence[float]]],
border: bool = False,
axis: bool = True,
axislabel: bool = True,
axistick: bool = True,
axisunitslabel: bool = True,
xunits: units_types = units_types.fracts,
yunits: units_types = units_types.fracts,
atype: type_types = type_types.braille,
mark: mark_types = mark_types.dot,
style: style_types = style_types.light,
color: color_types = color_types.red,
title: Optional[str] = None,
file: TextIO = sys.stdout,
check: bool = True,
) -> int:
"""Convert one or more arrays to graph and output."""
if not aarrays:
return 1
@ -609,27 +739,24 @@ def plots(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
w = shutil.get_terminal_size()
if not height:
height = w.lines * 4
height = w.lines
if not width:
width = w.columns * 2
width = w.columns
if check:
aheight = height // 4
awidth = width // 2
if aheight > w.lines:
print(
f"The height of the graph ({aheight}) is greater then the height of the terminal ({w.lines}).", file=sys.stderr)
if height > w.lines:
print(f"The height of the graph ({height}) is greater then the height of the terminal ({w.lines}).", file=sys.stderr)
return 1
if awidth > w.columns:
print(
f"The width of the graph ({awidth}) is greater then the width of the terminal ({w.columns}).", file=sys.stderr)
if width > w.columns:
print(f"The width of the graph ({width}) is greater then the width of the terminal ({w.columns}).", file=sys.stderr)
return 1
if atype == type_types.block:
height //= 2
ai, aj = densities[atype]
height *= ai
width *= aj
if not xmin and not xmax:
xmin = min(x for aarray in aarrays for x, y in aarray)
@ -673,15 +800,99 @@ def plots(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
else:
aaarray[x][y] = acolor
return graph(height, width, xmin, xmax, ymin, ymax, aaarray, border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, atype, style, title, file)
return graph(
height,
width,
xmin,
xmax,
ymin,
ymax,
aaarray,
border,
axis,
axislabel,
axistick,
axisunitslabel,
xunits,
yunits,
atype,
style,
title,
file,
)
def plot(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, aarray: Sequence[Sequence[float]], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, mark: mark_types = mark_types.dot, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, file: TextIO = sys.stdout, check: bool = True) -> int:
def plot(
height: int,
width: int,
xmin: float,
xmax: float,
ymin: float,
ymax: float,
aarray: Sequence[Sequence[float]],
border: bool = False,
axis: bool = True,
axislabel: bool = True,
axistick: bool = True,
axisunitslabel: bool = True,
xunits: units_types = units_types.fracts,
yunits: units_types = units_types.fracts,
atype: type_types = type_types.braille,
mark: mark_types = mark_types.dot,
style: style_types = style_types.light,
color: color_types = color_types.red,
title: Optional[str] = None,
file: TextIO = sys.stdout,
check: bool = True,
) -> int:
"""Convert single array to graph and output."""
return plots(height, width, xmin, xmax, ymin, ymax, (aarray,), border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, atype, mark, style, color, title, file, check)
return plots(
height,
width,
xmin,
xmax,
ymin,
ymax,
(aarray,),
border,
axis,
axislabel,
axistick,
axisunitslabel,
xunits,
yunits,
atype,
mark,
style,
color,
title,
file,
check,
)
def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, afunctions: Sequence[Callable[[float], float]], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, file: TextIO = sys.stdout, check: bool = True) -> int:
def functions(
height: int,
width: int,
xmin: float,
xmax: float,
ymin: float,
ymax: float,
afunctions: Sequence[Callable[[float], float]],
border: bool = False,
axis: bool = True,
axislabel: bool = True,
axistick: bool = True,
axisunitslabel: bool = True,
xunits: units_types = units_types.fracts,
yunits: units_types = units_types.fracts,
atype: type_types = type_types.braille,
style: style_types = style_types.light,
color: color_types = color_types.red,
title: Optional[str] = None,
file: TextIO = sys.stdout,
check: bool = True,
) -> int:
"""Convert one or more functions to graph and output."""
if not afunctions:
return 1
@ -689,27 +900,24 @@ def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
w = shutil.get_terminal_size()
if not height:
height = w.lines * 4
height = w.lines
if not width:
width = w.columns * 2
width = w.columns
if check:
aheight = height // 4
awidth = width // 2
if aheight > w.lines:
print(
f"The height of the graph ({aheight}) is greater then the height of the terminal ({w.lines}).", file=sys.stderr)
if height > w.lines:
print(f"The height of the graph ({height}) is greater then the height of the terminal ({w.lines}).", file=sys.stderr)
return 1
if awidth > w.columns:
print(
f"The width of the graph ({awidth}) is greater then the width of the terminal ({w.columns}).", file=sys.stderr)
if height > w.columns:
print(f"The width of the graph ({height}) is greater then the width of the terminal ({w.columns}).", file=sys.stderr)
return 1
if atype == type_types.block:
height //= 2
ai, aj = densities[atype]
height *= ai
width *= aj
if xmin >= xmax:
print("xmin must be less than xmax.", file=sys.stderr)
@ -730,8 +938,7 @@ def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
array = [[0 for j in range(height)] for i in range(width)]
for j, function in enumerate(afunctions):
acolor = color + \
1 if len(afunctions) == 1 else j % (len(colors) - 2) + 3
acolor = color + 1 if len(afunctions) == 1 else j % (len(colors) - 2) + 3
for i in (x / xres for x in range(rows * xres)):
x = i * xstep + xmin
@ -747,9 +954,70 @@ def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
else:
array[ax][ay] = acolor
return graph(height, width, xmin, xmax, ymin, ymax, array, border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, atype, style, title, file)
return graph(
height,
width,
xmin,
xmax,
ymin,
ymax,
array,
border,
axis,
axislabel,
axistick,
axisunitslabel,
xunits,
yunits,
atype,
style,
title,
file,
)
def function(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: float, afunction: Callable[[float], float], border: bool = False, axis: bool = True, axislabel: bool = True, axistick: bool = True, axisunitslabel: bool = True, xunits: units_types = units_types.fracts, yunits: units_types = units_types.fracts, atype: type_types = type_types.braille, style: style_types = style_types.light, color: color_types = color_types.red, title: Optional[str] = None, file: TextIO = sys.stdout, check: bool = True) -> int:
def function(
height: int,
width: int,
xmin: float,
xmax: float,
ymin: float,
ymax: float,
afunction: Callable[[float], float],
border: bool = False,
axis: bool = True,
axislabel: bool = True,
axistick: bool = True,
axisunitslabel: bool = True,
xunits: units_types = units_types.fracts,
yunits: units_types = units_types.fracts,
atype: type_types = type_types.braille,
style: style_types = style_types.light,
color: color_types = color_types.red,
title: Optional[str] = None,
file: TextIO = sys.stdout,
check: bool = True,
) -> int:
"""Convert single function to function array and output."""
return functions(height, width, xmin, xmax, ymin, ymax, (afunction,), border, axis, axislabel, axistick, axisunitslabel, xunits, yunits, atype, style, color, title, file, check)
return functions(
height,
width,
xmin,
xmax,
ymin,
ymax,
(afunction,),
border,
axis,
axislabel,
axistick,
axisunitslabel,
xunits,
yunits,
atype,
style,
color,
title,
file,
check,
)

View File

@ -22,6 +22,7 @@ if sys.platform != "win32":
def wcswidth(astr: str) -> int:
return libc.wcswidth(astr, len(astr))
else:
from wcwidth import wcswidth
@ -47,7 +48,7 @@ styles = (
("", "", "", "", "", "", "", "", "", "", ""), # Double
("", "", "", "", "", "", "", "", "", "", ""), # Light Arc
("", "", "", "", "", "", "", "", "", "", ""), # Light Dashed
("", "", "", "", "", "", "", "", "", "", "") # Heavy Dashed
("", "", "", "", "", "", "", "", "", "", ""), # Heavy Dashed
# (" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ")) #No border
)
@ -65,8 +66,19 @@ def strcol(astr: str) -> int:
# 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: str = "", title: Optional[str] = None, style: style_types = style_types.light, file: TextIO = sys.stdout, check: bool = True) -> int:
def table(
array: List[List[str]],
headerrow: bool = False,
headercolumn: bool = False,
tableborder: bool = True,
cellborder: bool = False,
padding: int = 1,
alignment: str = "",
title: Optional[str] = None,
style: style_types = style_types.light,
file: TextIO = sys.stdout,
check: bool = True,
) -> int:
"""Output char array as table."""
if not array:
return 1
@ -86,8 +98,7 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
width += 2 * padding * columns
if check and width > w.columns:
print(
f"The width of the table ({width}) is greater then the width of the terminal ({w.columns}).", file=sys.stderr)
print(f"The width of the table ({width}) is greater then the width of the terminal ({w.columns}).", file=sys.stderr)
return 1
if title:
@ -182,7 +193,21 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
return 0
def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[str]] = None, aheadercolumn: Optional[Sequence[str]] = None, headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: str = "", title: Optional[str] = None, style: style_types = style_types.light, file: TextIO = sys.stdout, check: bool = True) -> int:
def array(
aarray: Sequence[Sequence[Any]],
aheaderrow: Optional[Sequence[str]] = None,
aheadercolumn: Optional[Sequence[str]] = None,
headerrow: bool = False,
headercolumn: bool = False,
tableborder: bool = True,
cellborder: bool = False,
padding: int = 1,
alignment: str = "",
title: Optional[str] = None,
style: style_types = style_types.light,
file: TextIO = sys.stdout,
check: bool = True,
) -> int:
"""Convert array to char array and output as table."""
if not aarray:
return 1
@ -191,9 +216,7 @@ def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[str]] =
columns = len(aarray[0])
if not all(len(x) == columns for x in aarray):
print(
"Error: The rows of the array must have the same number of columns.",
file=sys.stderr)
print("Error: The rows of the array must have the same number of columns.", file=sys.stderr)
return 1
if aheaderrow:
@ -203,15 +226,11 @@ def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[str]] =
columns += 1
if aheaderrow and len(aheaderrow) != columns:
print(
"Error: The header row must have the same number of columns as the array.",
file=sys.stderr)
print("Error: The header row must have the same number of columns as the array.", file=sys.stderr)
return 1
if aheadercolumn and len(aheadercolumn) != (rows - 1 if aheaderrow else rows):
print(
"Error: The header column must have the same number of rows as the array.",
file=sys.stderr)
print("Error: The header column must have the same number of rows as the array.", file=sys.stderr)
return 1
aaarray = [["" for j in range(columns)] for i in range(rows)]
@ -226,12 +245,27 @@ def array(aarray: Sequence[Sequence[Any]], aheaderrow: Optional[Sequence[str]] =
aaarray[i][0] = aheadercolumn[ii]
j = 1 if aheadercolumn else 0
aaarray[i][j:] = map(str, aarray[ii][:columns - j])
aaarray[i][j:] = map(str, aarray[ii][: columns - j])
return table(aaarray, headerrow, headercolumn, tableborder, cellborder, padding, alignment, title, style, file, check)
def functions(xmin: float, xmax: float, xstep: float, afunctions: Sequence[Callable[[float], float]], headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: str = "", title: Optional[str] = None, style: style_types = style_types.light, file: TextIO = sys.stdout, check: bool = True) -> int:
def functions(
xmin: float,
xmax: float,
xstep: float,
afunctions: Sequence[Callable[[float], float]],
headerrow: bool = False,
headercolumn: bool = False,
tableborder: bool = True,
cellborder: bool = False,
padding: int = 1,
alignment: str = "",
title: Optional[str] = None,
style: style_types = style_types.light,
file: TextIO = sys.stdout,
check: bool = True,
) -> int:
"""Convert one or more functions to array and output as table."""
if not afunctions:
return 1
@ -252,7 +286,11 @@ def functions(xmin: float, xmax: float, xstep: float, afunctions: Sequence[Calla
aheaderrow = [""] * columns
aheaderrow = aaheaderrow if len(afunctions) == 1 else aaheaderrow[:-1] + [aaheaderrow[-1] + str(j - length + 2) for j in range(1, columns)]
aheaderrow = (
aaheaderrow
if len(afunctions) == 1
else aaheaderrow[:-1] + [aaheaderrow[-1] + str(j - length + 2) for j in range(1, columns)]
)
aarray = [[0 for j in range(columns)] for i in range(rows)]
@ -261,9 +299,41 @@ def functions(xmin: float, xmax: float, xstep: float, afunctions: Sequence[Calla
aarray[i][1:] = [function(temp) for function in afunctions]
return array(aarray, aheaderrow, None, headerrow, headercolumn, tableborder, cellborder, padding, alignment, title, style, file, check)
return array(
aarray, aheaderrow, None, headerrow, headercolumn, tableborder, cellborder, padding, alignment, title, style, file, check
)
def function(xmin: float, xmax: float, xstep: float, afunction: Callable[[float], float], headerrow: bool = False, headercolumn: bool = False, tableborder: bool = True, cellborder: bool = False, padding: int = 1, alignment: str = "", title: Optional[str] = None, style: style_types = style_types.light, file: TextIO = sys.stdout, check: bool = True) -> int:
def function(
xmin: float,
xmax: float,
xstep: float,
afunction: Callable[[float], float],
headerrow: bool = False,
headercolumn: bool = False,
tableborder: bool = True,
cellborder: bool = False,
padding: int = 1,
alignment: str = "",
title: Optional[str] = None,
style: style_types = style_types.light,
file: TextIO = sys.stdout,
check: bool = True,
) -> int:
"""Convert single function to array and output as table."""
return functions(xmin, xmax, xstep, (afunction,), headerrow, headercolumn, tableborder, cellborder, padding, alignment, title, style, file, check)
return functions(
xmin,
xmax,
xstep,
(afunction,),
headerrow,
headercolumn,
tableborder,
cellborder,
padding,
alignment,
title,
style,
file,
check,
)

View File

@ -1,149 +0,0 @@
#!/usr/bin/env python3
# Teal Dulcet, CS546
# Run: python3 -OO test.py
import math
import operator
import random
import sys
import graphs
import tables
def afunction(x: float) -> float:
return x + 1
def function1(x: float) -> float:
return 2 * x
def function2(x: float) -> float:
return x ** 2
rows = 5
columns = 5
xmin = -10
xmax = 10
xstep = 0.5
print("\nOutput array as table\n")
array = [[random.randint(0, sys.maxsize)
for j in range(columns)] for i in range(rows)]
for style in tables.style_types:
tables.array(array, None, None, style=style)
array = [[random.random() for j in range(columns)] for i in range(rows)]
for style in tables.style_types:
tables.array(array, None, None, style=style)
print("\nOutput char array as table\n")
array = [["Header row/column 1", "Header row 2", "Header row 3", "Header row 4", "Header row 5"],
["Header column 2", "Data 1", "Data 2", "Data 3", "Data 4"],
["Header column 3", "Data 5", "Data 6", "Data 7", "Data 8"],
["Header column 4", "Data 9", "Data 10", "Data 11", "Data 12"],
["Header column 5", "Data 13", "Data 14", "Data 15", "Data 16"]]
for style in tables.style_types:
tables.array(array, None, None, headerrow=True,
headercolumn=True, style=style)
print("\nOutput array as table with separate header row and column\n")
array = [[f"Data {i + j:n}" for j in range(4)]
for i in range(1, 4 * 4 + 1, 4)]
headerrow = ["Header row/column 1", "Header row 2",
"Header row 3", "Header row 4", "Header row 5"]
headercolumn = ["Header column 2", "Header column 3",
"Header column 4", "Header column 5"]
for style in tables.style_types:
tables.array(array, headerrow, headercolumn, headerrow=True,
headercolumn=True, cellborder=True, style=style)
tables.array(array, headerrow, headercolumn,
headerrow=True, headercolumn=True, style=style)
tables.array(array, headerrow[:-1], None, headerrow=True, style=style)
tables.array(array, None, [headerrow[0]] +
headercolumn[:-1], headercolumn=True, style=style)
tables.array(array, None, None, cellborder=True, style=style)
tables.array(array, None, None, tableborder=False, style=style)
tables.array(array, headerrow, headercolumn, tableborder=False,
headerrow=True, headercolumn=True, style=style)
tables.array(array, headerrow[:-1], None,
tableborder=False, headerrow=True, style=style)
tables.array(array, None, [headerrow[0]] + headercolumn[:-1],
tableborder=False, headercolumn=True, style=style)
tables.array(array, None, None, tableborder=False,
cellborder=True, style=style)
array = [[bool(random.getrandbits(1)) for j in range(columns)]
for i in range(rows)]
for style in tables.style_types:
tables.array(array, None, None, style=style)
print("\nOutput sorted array as table\n")
array = ([random.randint(0, sys.maxsize)
for j in range(columns)] for i in range(rows))
sortdimension = 0
array = sorted(array, key=operator.itemgetter(sortdimension))
for style in tables.style_types:
tables.array(array, None, None, style=style)
print("\nOutput single function as table\n")
for style in tables.style_types:
tables.function(xmin, xmax, xstep, afunction, headerrow=True, style=style)
for style in tables.style_types:
tables.function(xmin, xmax, xstep, lambda x: x +
1, headerrow=True, style=style)
print("\nOutput multiple functions as table\n")
for style in tables.style_types:
tables.functions(xmin, xmax, xstep, [
function1, function2], headerrow=True, style=style)
for style in tables.style_types:
tables.functions(xmin, xmax, xstep, [
lambda x: 2 * x, lambda x: x ** 2], headerrow=True, style=style)
height = 160
width = 160
xmin = -20
xmax = 20
ymin = -20
ymax = 20
print("\nOutput array as histogram\n")
array = [random.gauss(0, 1) for i in range(100)]
for style in graphs.style_types:
graphs.histogram(height, width, xmin, xmax, ymin, ymax, array, style=style)
print("\nOutput single array as plot\n")
array = [range(i, i + 2) for i in range(10)]
for atype in graphs.atype_types:
for mark in graphs.mark_types:
for style in graphs.style_types:
graphs.plot(height, width, xmin, xmax, ymin, ymax,
array, atype=atype, mark=mark, style=style)
print("\nOutput single function as graph\n")
for style in graphs.style_types:
graphs.function(height, width, xmin, xmax, ymin,
ymax, afunction, style=style)
for style in graphs.style_types:
graphs.function(height, width, xmin, xmax, ymin,
ymax, lambda x: x + 1, style=style)
print("\nOutput multiple functions as graph\n")
for style in graphs.style_types:
graphs.functions(height, width, xmin, xmax, ymin, ymax,
[function1, function2], style=style)
for style in graphs.style_types:
graphs.functions(height, width, xmin, xmax, ymin, ymax, [
lambda x: 2 * x, lambda x: x ** 2], style=style)
for style in graphs.style_types:
graphs.functions(height, width, -(2 * math.pi), 2 * math.pi, -4, 4,
[math.sin, math.cos, math.tan], axisunitslabel=False, style=style)