Files
nvtop/src/plot.c
Maxime Schmitt 2a0666388d Fix plot rounding
2018-12-26 21:23:52 +01:00

137 lines
4.8 KiB
C

#include <tgmath.h>
#include <string.h>
#include "nvtop/plot.h"
static inline int data_level(double rows, double data, double increment) {
return (int)(rows - round(data / increment));
}
void nvtop_line_plot(WINDOW *win, size_t num_data, const double *data,
double min, double max, unsigned num_plots,
const char *legend[]) {
if (num_data == 0)
return;
int rows, cols;
getmaxyx(win, rows, cols);
rows -= 1; // Maximum drawable character
double increment = (max - min) / (double)(rows);
int low_data_level = data_level(0, min, increment);
for (size_t k = 0; k < num_plots; ++k) {
int level_previous = data_level(rows, data[k], increment) - low_data_level;
int level_next, level_current;
wattron(win, COLOR_PAIR(1 + k % 5));
for (size_t i = k; i < num_data || i < (size_t)cols; i += num_plots) {
level_next = i + num_plots >= num_data
? level_next
: data_level(rows, data[i + num_plots], increment) -
low_data_level;
level_current = data_level(rows, data[i], increment) - low_data_level;
int top, bottom;
if (level_current == level_previous) {
mvwaddch(win, level_current, i, ACS_HLINE);
top = bottom = level_current;
} else {
if (level_current < level_previous) {
top = level_previous;
bottom = level_current;
} else {
top = level_current;
bottom = level_previous;
}
for (int j = bottom + 1; j < top; j++) {
mvwaddch(win, j, i, ACS_VLINE);
}
if (level_current > level_previous) {
mvwaddch(win, level_current, i, ACS_LLCORNER);
mvwaddch(win, level_previous, i, ACS_URCORNER);
} else {
mvwaddch(win, level_current, i, ACS_ULCORNER);
mvwaddch(win, level_previous, i, ACS_LRCORNER);
}
}
for (unsigned j = 0; j < num_plots; ++j) {
if (j == k)
continue;
int cross_level = -low_data_level;
if (j < k || i + j < num_plots + k)
cross_level += data_level(rows, data[i - k + j], increment);
else
cross_level +=
data_level(rows, data[i - k + j - num_plots], increment);
if (cross_level == top && top == bottom)
continue;
if (cross_level > bottom && cross_level < top) {
mvwaddch(win, cross_level, i, ACS_PLUS);
} else {
if (cross_level == top) {
mvwaddch(win, cross_level, i, ACS_BTEE);
} else {
if (cross_level == bottom) {
mvwaddch(win, cross_level, i, ACS_TTEE);
} else {
wattroff(win, COLOR_PAIR(1 + k % 5));
wattron(win, COLOR_PAIR(1 + j % 5));
mvwaddch(win, cross_level, i, ACS_HLINE);
wattroff(win, COLOR_PAIR(1 + j % 5));
wattron(win, COLOR_PAIR(1 + k % 5));
}
}
}
}
level_previous = level_current;
}
wattroff(win, COLOR_PAIR(1 + k % 5));
}
int plot_y_position = 0;
for (unsigned i = 0; i < num_plots && plot_y_position < rows; ++i) {
if (legend[i]) {
size_t length = strlen(legend[i]);
wattron(win, COLOR_PAIR(1 + i % 5));
if (length < (size_t)cols) {
mvwprintw(win, plot_y_position, cols-length, "%s", legend[i]);
} else {
wmove(win, plot_y_position, 0);
for (int j = 0; j < cols; ++j) {
waddch(win, legend[i][j]);
}
}
wattroff(win, COLOR_PAIR(1 + i % 5));
plot_y_position++;
}
}
}
void nvtop_bar_plot(WINDOW *win, size_t num_data, const double *data,
double min, double max) {
if (num_data == 0)
return;
int rows, cols;
getmaxyx(win, rows, cols);
rows -= 1;
double increment = (max - min) / (double)(rows);
int low_data_level = data_level(0, min, increment);
for (size_t i = 0; i < num_data || i < (size_t)cols; ++i) {
for (int j = data_level(rows, data[i], increment) - low_data_level;
j <= rows; j++) {
mvwaddch(win, j, i, ACS_CKBOARD);
}
}
}
void draw_rectangle(WINDOW *win, unsigned startX, unsigned startY, unsigned sizeX, unsigned sizeY) {
for (unsigned i = 0; i < sizeX - 2; ++i) {
mvwaddch(win, startY, startX + 1 + i, ACS_HLINE);
mvwaddch(win, startY + sizeY - 1, startX + 1 + i, ACS_HLINE);
}
for (unsigned i = 0; i < sizeY - 2; ++i) {
mvwaddch(win, startY + 1 + i, startX, ACS_VLINE);
mvwaddch(win, startY + 1 + i, startX + sizeX - 1, ACS_VLINE);
}
mvwaddch(win, startY, startX, ACS_ULCORNER);
mvwaddch(win, startY, startX + sizeX - 1, ACS_URCORNER);
mvwaddch(win, startY + sizeY - 1, startX, ACS_LLCORNER);
mvwaddch(win, startY + sizeY - 1, startX + sizeX - 1, ACS_LRCORNER);
}