ASCIIGraph draws graphs to serial console using the "Terminal" lib. The graph scales automatically, shows minimum and maximum. Custom designs can be applied through setting several characters.

Committer:
tknapp
Date:
Fri Jul 12 08:57:45 2013 +0000
Revision:
1:0f0b1ad6f3ac
Parent:
0:6885118d9d3f
Initial commit.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tknapp 1:0f0b1ad6f3ac 1 /*
tknapp 1:0f0b1ad6f3ac 2 * mbed library to draw graphs to serial console
tknapp 1:0f0b1ad6f3ac 3 * Copyright (c) 2013 Tobias Knapp
tknapp 1:0f0b1ad6f3ac 4 * Released under the MIT License: http://mbed.org/license/mit
tknapp 1:0f0b1ad6f3ac 5 */
tknapp 1:0f0b1ad6f3ac 6
tknapp 0:6885118d9d3f 7 #include "ASCIIGraph.h"
tknapp 0:6885118d9d3f 8
tknapp 0:6885118d9d3f 9 ASCIIGraph::ASCIIGraph(Terminal * terminal, int startX, int startY, int width, int height, int labelXoffset){
tknapp 0:6885118d9d3f 10 term = terminal;
tknapp 0:6885118d9d3f 11 START_X = startX >= 0 ? startX : 0;
tknapp 0:6885118d9d3f 12 START_Y = startY >= 0 ? startY : 0;
tknapp 0:6885118d9d3f 13 HEIGHT = height > 2 ? height : 8;
tknapp 0:6885118d9d3f 14 WIDTH = width > 2 ? width : 20;
tknapp 0:6885118d9d3f 15 LABEL_X_OFFSET = labelXoffset >= 7 ? labelXoffset : 7;
tknapp 0:6885118d9d3f 16
tknapp 0:6885118d9d3f 17 //Set default drawing chars
tknapp 0:6885118d9d3f 18 xAxisChar = '-';
tknapp 0:6885118d9d3f 19 zeroChar = '+';
tknapp 0:6885118d9d3f 20 yAxisChar = '|';
tknapp 0:6885118d9d3f 21 filledChar = '#';
tknapp 0:6885118d9d3f 22 plainChar = ' ';
tknapp 0:6885118d9d3f 23
tknapp 0:6885118d9d3f 24 //Init data and fill with 0
tknapp 0:6885118d9d3f 25 pData = new float[WIDTH];
tknapp 0:6885118d9d3f 26 for(int i = 0; i < WIDTH; ++i){
tknapp 0:6885118d9d3f 27 pData[i] = 0.0;
tknapp 0:6885118d9d3f 28 }
tknapp 0:6885118d9d3f 29
tknapp 0:6885118d9d3f 30 //Init line
tknapp 0:6885118d9d3f 31 pLine = new char[WIDTH+1];
tknapp 0:6885118d9d3f 32 pLine[WIDTH] = '\0'; // end-char
tknapp 0:6885118d9d3f 33
tknapp 0:6885118d9d3f 34 //Set first true
tknapp 0:6885118d9d3f 35 first = true;
tknapp 0:6885118d9d3f 36
tknapp 0:6885118d9d3f 37 //Clear screen
tknapp 0:6885118d9d3f 38 //term->cls();
tknapp 0:6885118d9d3f 39
tknapp 0:6885118d9d3f 40 //Set coord sys bases
tknapp 0:6885118d9d3f 41 BASE_X = START_X + LABEL_X_OFFSET + 1;
tknapp 0:6885118d9d3f 42 BASE_Y = START_Y + HEIGHT - 1;
tknapp 0:6885118d9d3f 43
tknapp 0:6885118d9d3f 44 }
tknapp 0:6885118d9d3f 45
tknapp 0:6885118d9d3f 46 void ASCIIGraph::initGraph(){
tknapp 0:6885118d9d3f 47
tknapp 0:6885118d9d3f 48 //Clear Screen
tknapp 0:6885118d9d3f 49 term->cls();
tknapp 0:6885118d9d3f 50
tknapp 0:6885118d9d3f 51 //Draw y-axis
tknapp 0:6885118d9d3f 52 for(int i = 0; i < HEIGHT; ++i){
tknapp 0:6885118d9d3f 53 term->locate(START_X + LABEL_X_OFFSET ,START_Y+i);
tknapp 0:6885118d9d3f 54 term->putc(yAxisChar); //166 //179 //186
tknapp 0:6885118d9d3f 55 }
tknapp 0:6885118d9d3f 56
tknapp 0:6885118d9d3f 57 //Draw (0|0)
tknapp 0:6885118d9d3f 58 term->locate(START_X + LABEL_X_OFFSET, START_Y + HEIGHT);
tknapp 0:6885118d9d3f 59 term->putc(zeroChar); //43 //192 //200
tknapp 0:6885118d9d3f 60
tknapp 0:6885118d9d3f 61 //Draw x-axis
tknapp 0:6885118d9d3f 62 for(int i = 0; i < WIDTH; ++i){
tknapp 0:6885118d9d3f 63 term->locate(START_X+LABEL_X_OFFSET+1+i, START_Y + HEIGHT);
tknapp 0:6885118d9d3f 64 term->putc(xAxisChar); //45 //196 //205
tknapp 0:6885118d9d3f 65 }
tknapp 0:6885118d9d3f 66
tknapp 0:6885118d9d3f 67 //Gimmic: Print Hello if large enough
tknapp 0:6885118d9d3f 68 if(WIDTH > 48 && HEIGHT > 6){
tknapp 0:6885118d9d3f 69 int x = (WIDTH - 47)/2;
tknapp 0:6885118d9d3f 70 int y = (HEIGHT - 7)/2;
tknapp 0:6885118d9d3f 71
tknapp 0:6885118d9d3f 72 int boxX = START_X + LABEL_X_OFFSET + 1 + x;
tknapp 0:6885118d9d3f 73 int boxY = START_Y + 1 + y;
tknapp 0:6885118d9d3f 74 term->locate(boxX, boxY++);
tknapp 0:6885118d9d3f 75 term->printf(" ## ### ### ### ### ### # ");
tknapp 0:6885118d9d3f 76 term->locate(boxX, boxY++);
tknapp 0:6885118d9d3f 77 term->printf("# # # # # # # # ");
tknapp 0:6885118d9d3f 78 term->locate(boxX, boxY++);
tknapp 0:6885118d9d3f 79 term->printf("#### ### # # # # ## ### ## ### ### ");
tknapp 0:6885118d9d3f 80 term->locate(boxX, boxY++);
tknapp 0:6885118d9d3f 81 term->printf("# # # # # # # # # # # # # # #");
tknapp 0:6885118d9d3f 82 term->locate(boxX, boxY++);
tknapp 0:6885118d9d3f 83 term->printf("# # #### ### ### ### ### # ### ### # # ");
tknapp 0:6885118d9d3f 84 term->locate(boxX, boxY++);
tknapp 0:6885118d9d3f 85 term->printf(" # ");
tknapp 0:6885118d9d3f 86 term->locate(boxX, boxY++);
tknapp 0:6885118d9d3f 87 term->printf(" # ");
tknapp 0:6885118d9d3f 88 wait(3);
tknapp 0:6885118d9d3f 89 }
tknapp 0:6885118d9d3f 90
tknapp 0:6885118d9d3f 91 }
tknapp 0:6885118d9d3f 92
tknapp 0:6885118d9d3f 93 ASCIIGraph::~ASCIIGraph(){
tknapp 0:6885118d9d3f 94 delete[] pData;
tknapp 0:6885118d9d3f 95 delete[] pLine;
tknapp 0:6885118d9d3f 96 }
tknapp 0:6885118d9d3f 97
tknapp 0:6885118d9d3f 98 void ASCIIGraph::pushDataPoint(float dataPoint){
tknapp 0:6885118d9d3f 99
tknapp 0:6885118d9d3f 100 if(!first){
tknapp 0:6885118d9d3f 101 //Shift data to left
tknapp 0:6885118d9d3f 102 for(int i = 1; i < WIDTH; ++i)
tknapp 0:6885118d9d3f 103 pData[i-1] = pData[i];
tknapp 0:6885118d9d3f 104
tknapp 0:6885118d9d3f 105 //Set new dataPoint at the end
tknapp 0:6885118d9d3f 106 pData[WIDTH-1] = dataPoint;
tknapp 0:6885118d9d3f 107
tknapp 0:6885118d9d3f 108 } else {
tknapp 0:6885118d9d3f 109 //Fill entire array with first dataPoint if array is empty
tknapp 0:6885118d9d3f 110 for(int i = 0; i < WIDTH; ++i){
tknapp 0:6885118d9d3f 111 pData[i] = dataPoint;
tknapp 0:6885118d9d3f 112 }
tknapp 0:6885118d9d3f 113 first = false;
tknapp 0:6885118d9d3f 114 }
tknapp 0:6885118d9d3f 115 }
tknapp 0:6885118d9d3f 116
tknapp 0:6885118d9d3f 117 //Draws Graph
tknapp 0:6885118d9d3f 118 void ASCIIGraph::drawGraph(){
tknapp 0:6885118d9d3f 119
tknapp 0:6885118d9d3f 120 float min;
tknapp 0:6885118d9d3f 121 float max;
tknapp 0:6885118d9d3f 122 float diff;
tknapp 0:6885118d9d3f 123 float valOfChar;
tknapp 0:6885118d9d3f 124
tknapp 0:6885118d9d3f 125 //Find min and max
tknapp 0:6885118d9d3f 126 min = pData[0];
tknapp 0:6885118d9d3f 127 max = pData[0];
tknapp 0:6885118d9d3f 128 for(int i = 1; i < WIDTH; ++i){
tknapp 0:6885118d9d3f 129 if(pData[i] < min)
tknapp 0:6885118d9d3f 130 min = pData[i];
tknapp 0:6885118d9d3f 131 if(pData[i] > max)
tknapp 0:6885118d9d3f 132 max = pData[i];
tknapp 0:6885118d9d3f 133 }
tknapp 0:6885118d9d3f 134
tknapp 0:6885118d9d3f 135 //Calculate diff
tknapp 0:6885118d9d3f 136 diff = max - min;
tknapp 0:6885118d9d3f 137
tknapp 0:6885118d9d3f 138 /* Calculate y-value of one cell in terminal
tknapp 0:6885118d9d3f 139 * e.g. diff = 5, HEIGHT in terminal is 10
tknapp 0:6885118d9d3f 140 * => valOfChar = 5 / 10 = 0.5
tknapp 0:6885118d9d3f 141 * => The y-value of each vertical cell is 0.5
tknapp 0:6885118d9d3f 142 * => Two set (filled) cells represent the value 1.0
tknapp 0:6885118d9d3f 143 */
tknapp 0:6885118d9d3f 144 valOfChar = (diff / (float)HEIGHT);
tknapp 0:6885118d9d3f 145 term->locate(BASE_X - 1, BASE_Y + 3);
tknapp 0:6885118d9d3f 146 term->printf("Min: %f Max: %f Diff: %f Val: %f", min, max, diff, valOfChar);
tknapp 0:6885118d9d3f 147
tknapp 0:6885118d9d3f 148 //Update scale
tknapp 0:6885118d9d3f 149 term->locate(START_X, START_Y);
tknapp 0:6885118d9d3f 150 term->printf("%4.1f", max);
tknapp 0:6885118d9d3f 151
tknapp 0:6885118d9d3f 152 term->locate(START_X, BASE_Y + 1);
tknapp 0:6885118d9d3f 153 term->printf("%4.1f", min);
tknapp 0:6885118d9d3f 154
tknapp 0:6885118d9d3f 155 /*
tknapp 0:6885118d9d3f 156 //Draw cell-by-cell (slow)
tknapp 0:6885118d9d3f 157 for(int i = 0; i < WIDTH; ++i){
tknapp 0:6885118d9d3f 158 for(int j = 0; j < HEIGHT; ++j){
tknapp 0:6885118d9d3f 159 term->locate(BASE_X + i, BASE_Y - j);
tknapp 0:6885118d9d3f 160 if( (j*valOfChar) < (pData[i]-min) )
tknapp 0:6885118d9d3f 161 term->putc((int)'#');
tknapp 0:6885118d9d3f 162 else
tknapp 0:6885118d9d3f 163 term->putc((int)' ');
tknapp 0:6885118d9d3f 164 }
tknapp 0:6885118d9d3f 165 }
tknapp 0:6885118d9d3f 166 */
tknapp 0:6885118d9d3f 167
tknapp 0:6885118d9d3f 168 //Draw line-by-line (fast)
tknapp 0:6885118d9d3f 169
tknapp 0:6885118d9d3f 170 for(int i = 0; i < HEIGHT; ++i){
tknapp 0:6885118d9d3f 171 for(int j = 0; j < WIDTH; ++j){
tknapp 0:6885118d9d3f 172 pLine[j] = ((i*valOfChar) < (pData[j]-min)) ? filledChar : plainChar;
tknapp 0:6885118d9d3f 173 }
tknapp 0:6885118d9d3f 174 term->locate(BASE_X, BASE_Y - i);
tknapp 0:6885118d9d3f 175 term->printf(pLine);
tknapp 0:6885118d9d3f 176 }
tknapp 0:6885118d9d3f 177
tknapp 0:6885118d9d3f 178 //TODO: Create one array holding ALL cells and print them at once!
tknapp 0:6885118d9d3f 179 }
tknapp 0:6885118d9d3f 180
tknapp 0:6885118d9d3f 181 void ASCIIGraph::reset(){
tknapp 0:6885118d9d3f 182 first = true;
tknapp 0:6885118d9d3f 183 term->locate(START_X, START_Y);
tknapp 0:6885118d9d3f 184 term->printf(" ");
tknapp 0:6885118d9d3f 185 term->locate(START_X, BASE_Y + 1);
tknapp 0:6885118d9d3f 186 term->printf(" ");
tknapp 0:6885118d9d3f 187 }