plots: always start from the right #457

pull/469/head
nick black 5 years ago
parent cfdd8c4c5c
commit b04a37c433
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -27,7 +27,7 @@ typedef struct ncplot_options {
// number of "pixels" per row x column
ncgridgeom_e gridtype;
// independent variable is a contiguous range
uint64_t rangex;
int rangex;
// dependent min and max. set both equal to 0 to
// use domain autodiscovery.
uint64_t miny, maxy;

@ -2557,7 +2557,7 @@ typedef struct ncplot_options {
// of keys. for a time range, say the previous hour sampled with second
// resolution, the independent variable would be the range [0..3600): 3600.
// if rangex is 0, it is dynamically set to the number of columns.
uint64_t rangex;
int rangex;
uint64_t miny, maxy; // y axis min and max. for autodiscovery, set them equal.
bool labelaxisd; // generate labels for the dependent axis
bool exponentialy; // is y-axis exponential? (not yet implemented)

@ -193,7 +193,6 @@ void Tick(ncpp::NotCurses* nc, uint64_t sec) {
if(!nc->render()){
throw std::runtime_error("error rendering");
}
mtx.unlock();
}
void Ticker(ncpp::NotCurses* nc) {

@ -154,24 +154,27 @@ typedef struct ncplot {
ncplane* ncp;
uint64_t maxchannel;
uint64_t minchannel;
bool vertical_indep;
bool vertical_indep; // not yet implemented FIXME
ncgridgeom_e gridtype;
// requested number of slots. 0 for automatically setting the number of slots
// to span the horizontal area.
uint64_t rangex;
// to span the horizontal area. if there are more slots than there are
// columns, we prefer showing more recent slots to less recent. if there are
// fewer slots than there are columns, they prefer the left side.
int rangex;
// domain minimum and maximum. if detectdomain is true, these are
// progressively enlarged/shrunk to fit the sample set. if not, samples
// outside these bounds are counted, but the displayed range covers only this.
uint64_t miny, maxy;
// circular buffer, with the oldest element at slotstart, and slotcount
// elements. slotcount is max(columns, rangex).
int64_t* slots;
unsigned slotstart; // slot index corresponding to slotx
uint64_t slotx; // x value corresponding to slots[slotstart]
unsigned slotcount;
bool labelaxisd; // label dependent axis
bool exponentialy;
bool detectdomain;
// sloutcount-element circular buffer of samples. the newest one (rightmost)
// is at slots[slotstart]; they get older as you go back (and around).
// elements. slotcount is max(columns, rangex), less label room.
uint64_t* slots;
int slotcount;
int slotstart; // index of most recently-written slot
int64_t slotx; // x value corresponding to slots[slotstart] (newest x)
bool labelaxisd; // label dependent axis (consumes PREFIXSTRLEN columns)
bool exponentialy; // not yet implemented FIXME
bool detectdomain; // is domain detection in effect (stretch the domain)?
} ncplot;
typedef struct ncmenu {

@ -20,8 +20,10 @@ redraw_plot(ncplot* n){
const size_t states = wcslen(geomdata[n->gridtype].egcs);
// FIXME can we not rid ourselves of this meddlesome double?
double interval = n->maxy < n->miny ? 0 : (n->maxy - n->miny) / ((double)dimy * states);
int idx = n->slotstart;
const int startx = n->labelaxisd ? PREFIXSTRLEN : 0;
const int startx = n->labelaxisd ? PREFIXSTRLEN : 0; // plot cols begin here
// if we want fewer slots than there are available columns, our final column
// will be other than the plane's final column. most recent x goes here.
const int finalx = (n->slotcount < dimx - 1 - startx ? startx + n->slotcount - 1 : dimx - 1);
if(n->labelaxisd){
// show the *top* of each interval range
for(int y = 0 ; y < dimy ; ++y){
@ -30,39 +32,41 @@ redraw_plot(ncplot* n){
ncplane_putstr_yx(ncplot_plane(n), dimy - y - 1, PREFIXSTRLEN - strlen(buf), buf);
}
}
if(interval){
for(uint64_t x = startx ; x < n->slotcount + startx ; ++x){
if(x >= (unsigned)dimx){
// exit on pathologically narrow planes, or sampleless draws
if(finalx < startx || !interval){
return 0;
}
int idx = n->slotstart; // idx holds the real slot index; we move backwards
for(int x = finalx ; x >= startx ; --x){
uint64_t gval = n->slots[idx]; // clip the value at the limits of the graph
if(gval < n->miny){
gval = n->miny;
}
if(gval > n->maxy){
gval = n->maxy;
}
// starting from the least-significant row, progress in the more significant
// direction, drawing egcs from the grid specification, aborting early if
// we can't draw anything in a given cell.
double intervalbase = n->miny;
for(int y = 0 ; y < dimy ; ++y){
// if we've got at least one interval's worth on the number of positions
// times the number of intervals per position plus the starting offset,
// we're going to print *something*
if(intervalbase >= gval){
break;
}
uint64_t gval = n->slots[idx]; // clip the value at the limits of the graph
if(gval < n->miny){
gval = n->miny;
}
if(gval > n->maxy){
gval = n->maxy;
size_t egcidx = (gval - intervalbase) / interval;
if(egcidx >= states){
egcidx = states - 1;
}
// starting from the least-significant row, progress in the more significant
// direction, drawing egcs from the grid specification, aborting early if
// we can't draw anything in a given cell.
double intervalbase = n->miny;
for(int y = 0 ; y < dimy ; ++y){
// if we've got at least one interval's worth on the number of positions
// times the number of intervals per position plus the starting offset,
// we're going to print *something*
if(intervalbase >= gval){
break;
}
size_t egcidx = (gval - intervalbase) / interval;
if(egcidx >= states){
egcidx = states - 1;
}
if(ncplane_putwc_yx(ncplot_plane(n), dimy - y - 1, x, geomdata[n->gridtype].egcs[egcidx]) <= 0){
return -1;
}
intervalbase += (states * interval);
if(ncplane_putwc_yx(ncplot_plane(n), dimy - y - 1, x, geomdata[n->gridtype].egcs[egcidx]) <= 0){
return -1;
}
idx = (idx + 1) % n->slotcount;
intervalbase += (states * interval);
}
if(--idx < 0){
idx = n->slotcount - 1;
}
}
if(ncplane_cursor_move_yx(ncplot_plane(n), 0, 0)){
@ -80,6 +84,9 @@ ncplot* ncplot_create(ncplane* n, const ncplot_options* opts){
if(opts->miny == opts->maxy && opts->miny){
return NULL;
}
if(opts->rangex < 0){
return NULL;
}
if(opts->maxy < opts->miny){
return NULL;
}
@ -91,7 +98,7 @@ ncplot* ncplot_create(ncplane* n, const ncplot_options* opts){
if(sdimx <= 0){
return NULL;
}
uint64_t dimx = sdimx;
int dimx = sdimx;
ncplot* ret = malloc(sizeof(*ret));
if(ret){
ret->rangex = opts->rangex;
@ -159,43 +166,48 @@ update_domain(ncplot* n, uint64_t x){
return 0;
}
// if x is less than the window, return -1
// if x is less than the window, return -1, as the sample will be thrown away.
// if the x is within the current window, find the proper slot and update it.
// otherwise, the x is the newest sample. if it is obsoletes all existing slots,
// reset them, and write the new sample anywhere. otherwise, write it to the
// proper slot based on the current newest slot.
static inline int
window_slide(ncplot* n, uint64_t x){
if(x < n->slotx){ // x is behind window, won't be counted
window_slide(ncplot* n, int64_t x){
if(x < n->slotx - (n->slotcount - 1)){ // x is behind window, won't be counted
return -1;
}else if(x < n->slotx + n->slotcount){ // x is within window, do nothing
}else if(x <= n->slotx){ // x is within window, do nothing
return 0;
} // x is newest; we might be keeping some, might not
int64_t xdiff = x - n->slotx; // the raw amount we're advancing
n->slotx = x;
if(xdiff >= n->slotcount){ // we're throwing away all old samples, write to 0
memset(n->slots, 0, sizeof(*n->slots) * n->slotcount);
n->slotstart = 0;
return 0;
} // x is beyond window; we might be keeping some, might not
uint64_t newslotx = x - n->slotcount + 1; // the new value of slotx
uint64_t slotdiff = newslotx - n->slotx; // the raw amount we're advancing
if(slotdiff > n->slotcount){
slotdiff = n->slotcount;
} // slotdiff is the number of slots to reset, and amount to advance slotstart
n->slotx = newslotx;
// number to reset on the right of the circular buffer. min of (available at
// current or to right, slotdiff)
uint64_t slotsreset = n->slotcount - n->slotstart;
if(slotsreset > slotdiff){
slotsreset = slotdiff;
}
// we're throwing away only xdiff slots, which is less than n->slotcount.
// first, we'll try to clear to the right...number to reset on the right of
// the circular buffer. min of (available at current or to right, xdiff)
int slotsreset = n->slotcount - n->slotstart - 1;
if(slotsreset > xdiff){
slotsreset = xdiff;
}
if(slotsreset){
memset(n->slots + n->slotstart, 0, slotsreset * sizeof(*n->slots));
n->slotstart += slotsreset;
n->slotstart %= n->slotcount;
slotdiff -= slotsreset;
memset(n->slots + n->slotstart + 1, 0, slotsreset * sizeof(*n->slots));
}
if(slotdiff){
memset(n->slots, 0, slotdiff * sizeof(*n->slots));
n->slotstart = slotdiff - 1;
n->slotstart = (n->slotstart + xdiff) % n->slotcount;
xdiff -= slotsreset;
if(xdiff){ // throw away some at the beginning
memset(n->slots, 0, xdiff * sizeof(*n->slots));
}
return 0;
}
// x must be within n's window
// x must be within n's window at this point
static inline void
update_sample(ncplot* n, uint64_t x, uint64_t y, bool reset){
uint64_t idx = x % n->slotcount;
update_sample(ncplot* n, int64_t x, uint64_t y, bool reset){
const int64_t diff = n->slotx - x; // amount behind
const int idx = (n->slotstart + n->slotcount - diff) % n->slotcount;
if(reset){
n->slots[idx] = y;
}else{

Loading…
Cancel
Save