Notcurses 3.0.13
a blingful library for TUIs and character graphics
Loading...
Searching...
No Matches
plot.c File Reference
#include <math.h>
#include <float.h>
#include <limits.h>
#include <string.h>
#include <inttypes.h>
#include "internal.h"
Include dependency graph for plot.c:

Go to the source code of this file.

Data Structures

struct  ncplot
 

Macros

#define MAXWIDTH   2
 
#define CREATE(T, X)
 

Typedefs

typedef struct ncplot ncplot
 

Functions

int update_domain_uint64_t (ncuplot *ncp, uint64_t x)
 
int update_domain_double (ncdplot *ncp, uint64_t x)
 
ncuplot * ncuplot_create (ncplane *n, const ncplot_options *opts, uint64_t miny, uint64_t maxy)
 
ncplanencuplot_plane (ncuplot *n)
 
int ncuplot_add_sample (ncuplot *n, uint64_t x, uint64_t y)
 
int ncuplot_set_sample (ncuplot *n, uint64_t x, uint64_t y)
 
void ncuplot_destroy (ncuplot *n)
 
ncdplot * ncdplot_create (ncplane *n, const ncplot_options *opts, double miny, double maxy)
 
ncplanencdplot_plane (ncdplot *n)
 
int ncdplot_add_sample (ncdplot *n, uint64_t x, double y)
 
int ncdplot_set_sample (ncdplot *n, uint64_t x, double y)
 
int ncuplot_sample (const ncuplot *n, uint64_t x, uint64_t *y)
 
int ncdplot_sample (const ncdplot *n, uint64_t x, double *y)
 
void ncdplot_destroy (ncdplot *n)
 

Macro Definition Documentation

◆ CREATE

#define CREATE (   T,
 
)

Definition at line 85 of file plot.c.

86 { \
87 T* slots; \
88 T miny, maxy; \
89 ncplot plot; \
90} nc##X##plot; \
91\
92static int redraw_pixelplot_##T(nc##X##plot* ncp){ \
93 if(calculate_gradient_vector(&ncp->plot, 1)){ \
94 return -1; \
95 } \
96 const int scale = ncplane_pile_const(ncp->plot.ncp)->cellpxx; \
97 ncplane_erase(ncp->plot.ncp); \
98 unsigned dimy, dimx; \
99 ncplane_dim_yx(ncp->plot.ncp, &dimy, &dimx); \
100 const unsigned scaleddim = dimx * scale; \
101 /* each transition is worth this much change in value */ \
102 const size_t states = ncplane_pile_const(ncp->plot.ncp)->cellpxy; \
103 /* FIXME can we not rid ourselves of this meddlesome double? either way, the \
104 interval is one row's range (for linear plots), or the base \
105 (base^slots == maxy-miny) of the range (for exponential plots). */ \
106 double interval; \
107 if(ncp->plot.exponentiali){ \
108 if(ncp->maxy > ncp->miny){ \
109 interval = pow(ncp->maxy - ncp->miny, (double)1 / (dimy * states)); \
110/* fprintf(stderr, "miny: %ju maxy: %ju dimy: %d states: %zu\n", miny, maxy, dimy, states); */ \
111 }else{ \
112 interval = 0; \
113 } \
114 }else{ \
115 interval = ncp->maxy < ncp->miny ? 0 : (ncp->maxy - ncp->miny) / ((double)dimy * states); \
116 } \
117 const int startx = ncp->plot.labelaxisd ? NCPREFIXCOLUMNS : 0; /* plot cols begin here */ \
118 /* if we want fewer slots than there are available columns, our final column \
119 will be other than the plane's final column. most recent x goes here. */ \
120 const unsigned finalx = (ncp->plot.slotcount < scaleddim - 1 - (startx * scale) ? \
121 startx + (ncp->plot.slotcount / scale) - 1 : dimx - 1); \
122 ncplane_set_styles(ncp->plot.ncp, ncp->plot.legendstyle); \
123 if(ncp->plot.labelaxisd){ \
124 /* show the *top* of each interval range */ \
125 for(unsigned y = 0 ; y < dimy ; ++y){ \
126 ncplane_set_channels(ncp->plot.ncp, ncp->plot.channels[y * states]); \
127 char buf[NCPREFIXSTRLEN + 1]; \
128 if(ncp->plot.exponentiali){ \
129 if(y == dimy - 1){ /* we cheat on the top row to exactly match maxy */ \
130 ncqprefix(ncp->maxy * 100, 100, buf, 0); \
131 }else{ \
132 ncqprefix(pow(interval, (y + 1) * states) * 100, 100, buf, 0); \
133 } \
134 }else{ \
135 ncqprefix((ncp->maxy - interval * states * (dimy - y - 1)) * 100, 100, buf, 0); \
136 } \
137 if(y == dimy - 1 && strlen(ncp->plot.title)){ \
138 ncplane_printf_yx(ncp->plot.ncp, dimy - y - 1, 0, "%*.*s %s", \
139 NCPREFIXSTRLEN, NCPREFIXSTRLEN, buf, ncp->plot.title); \
140 }else{ \
141 ncplane_printf_yx(ncp->plot.ncp, dimy - y - 1, 0, "%*.*s", \
143 } \
144 } \
145 }else if(strlen(ncp->plot.title)){ \
146 ncplane_set_channels(ncp->plot.ncp, ncp->plot.channels[(dimy - 1) * states]); \
147 ncplane_printf_yx(ncp->plot.ncp, 0, NCPREFIXCOLUMNS - strlen(ncp->plot.title), "%s", ncp->plot.title); \
148 } \
149 ncplane_set_styles(ncp->plot.ncp, NCSTYLE_NONE); \
150 if((int)finalx < startx){ /* exit on pathologically narrow planes */ \
151 return 0; \
152 } \
153 if(!interval){ \
154 interval = 1; \
155 } \
156 uint32_t* pixels = malloc(dimy * dimx * states * scale * sizeof(*pixels)); \
157 if(pixels == NULL){ \
158 return -1; \
159 } \
160 /* FIXME just zero out as we copy to each */ \
161 memset(pixels, 0, dimy * dimx * states * scale * sizeof(*pixels)); \
162 /* a column corresponds to |scale| slots' worth of samples. prepare the working gval set. */ \
163 T* gvals = malloc(sizeof(*gvals) * scale); \
164 if(gvals == NULL){ \
165 free(pixels); \
166 return -1; \
167 } \
168 int idx = ncp->plot.slotstart; /* idx holds the real slot index; we move backwards */ \
169 /* iterate backwards across the plot from the final (rightmost) x being \
170 plotted (finalx) to the first (leftmost) x being plotted (startx). */ \
171 for(int x = finalx ; x >= startx ; --x){ \
172 /* load gvals retaining the same ordering we have in the actual array */ \
173 for(int i = scale - 1 ; i >= 0 ; --i){ \
174 gvals[i] = ncp->slots[idx]; /* clip the value at the limits of the graph */ \
175 if(gvals[i] < ncp->miny){ \
176 gvals[i] = ncp->miny; \
177 } \
178 if(gvals[i] > ncp->maxy){ \
179 gvals[i] = ncp->maxy; \
180 } \
181 /* FIXME if there are an odd number, only go up through the valid ones... */ \
182 if(--idx < 0){ \
183 idx = ncp->plot.slotcount - 1; \
184 } \
185 } \
186 /* starting from the least-significant row, progress in the more significant \
187 direction, prepping pixels, aborting early if we can't draw anything in a \
188 given cell. */ \
189 T intervalbase = ncp->miny; \
190 bool done = !ncp->plot.bset->fill; \
191 for(unsigned y = 0 ; y < dimy ; ++y){ \
192 /* if we've got at least one interval's worth on the number of positions \
193 times the number of intervals per position plus the starting offset, \
194 we're going to print *something* */ \
195 for(int i = 0 ; i < scale ; ++i){ \
196 size_t egcidx; \
197 if(intervalbase < gvals[i]){ \
198 if(ncp->plot.exponentiali){ \
199 /* we want the log-base-interval of gvals[i] */ \
200 double scaled = log(gvals[i] - ncp->miny) / log(interval); \
201 double sival = intervalbase ? log(intervalbase) / log(interval) : 0; \
202 egcidx = scaled - sival; \
203 }else{ \
204 egcidx = (gvals[i] - intervalbase) / interval; \
205 } \
206 if(egcidx >= states){ \
207 egcidx = states; \
208 done = false; \
209 } \
210 }else{ \
211 egcidx = 0; \
212 } \
213/*fprintf(stderr, "WRITING TO y/x %d/%d (%zu)\n", y, x, dimx * dimy * scale * states); */\
214 for(size_t yy = 0 ; yy < egcidx ; ++yy){ \
215 int poff = x * scale + i + (((dimy - 1 - y) * states + (states - 1 - yy)) * dimx * scale); \
216 uint32_t color = ncchannels_fg_rgb(ncp->plot.channels[y * states + yy]); \
217 ncpixel_set_a(&color, 0xff); \
218 pixels[poff] = color; \
219 } \
220 } \
221 if(done){ \
222 break; \
223 } \
224 if(ncp->plot.exponentiali){ \
225 intervalbase = ncp->miny + pow(interval, (y + 1) * states - 1); \
226 }else{ \
227 intervalbase += (states * interval); \
228 } \
229 } \
230 } \
231 if(ncp->plot.printsample){ \
232 ncplane_set_styles(ncp->plot.ncp, ncp->plot.legendstyle); \
233 ncplane_set_channels(ncp->plot.ncp, ncp->plot.maxchannels); \
234 /* FIXME is this correct for double? */ \
235 /* we use idx, and thus get an immediate count, changing as we load it.
236 * if you want a stable summary, print the previous slot */ \
237 ncplane_printf_aligned(ncp->plot.ncp, 0, NCALIGN_RIGHT, "%" PRIu64, (uint64_t)ncp->slots[idx]); \
238 } \
239 ncplane_home(ncp->plot.ncp); \
240 struct ncvisual* ncv = ncvisual_from_rgba(pixels, dimy * states, dimx * scale * 4, dimx * scale); \
241 free(pixels); \
242 free(gvals); \
243 if(ncv == NULL){ \
244 return -1; \
245 } \
246 struct ncvisual_options vopts = { \
247 .n = ncp->plot.pixelp, \
248 .blitter = NCBLIT_PIXEL, \
250 }; \
251 if(ncvisual_blit(ncplane_notcurses(ncp->plot.ncp), ncv, &vopts) == NULL){ \
252 ncvisual_destroy(ncv); \
253 return -1; \
254 } \
255 ncvisual_destroy(ncv); \
256 return 0; \
257} \
258\
259static int redraw_plot_##T(nc##X##plot* ncp){ \
260 if(ncp->plot.bset->geom == NCBLIT_PIXEL){ \
261 return redraw_pixelplot_##T(ncp); \
262 } \
263 if(calculate_gradient_vector(&ncp->plot, 0)){ \
264 return -1; \
265 } \
266 ncplane_erase(ncp->plot.ncp); \
267 const unsigned scale = ncp->plot.bset->width; \
268 unsigned dimy, dimx; \
269 ncplane_dim_yx(ncp->plot.ncp, &dimy, &dimx); \
270 const unsigned scaleddim = dimx * scale; \
271 /* each transition is worth this much change in value */ \
272 const size_t states = ncp->plot.bset->height + 1; \
273 /* FIXME can we not rid ourselves of this meddlesome double? either way, the \
274 interval is one row's range (for linear plots), or the base \
275 (base^slots == maxy-miny) of the range (for exponential plots). */ \
276 double interval; \
277 if(ncp->plot.exponentiali){ \
278 if(ncp->maxy > ncp->miny){ \
279 interval = pow(ncp->maxy - ncp->miny, (double)1 / (dimy * states)); \
280/* fprintf(stderr, "miny: %ju maxy: %ju dimy: %d states: %zu\n", miny, maxy, dimy, states); */ \
281 }else{ \
282 interval = 0; \
283 } \
284 }else{ \
285 interval = ncp->maxy < ncp->miny ? 0 : (ncp->maxy - ncp->miny) / ((double)dimy * states); \
286 } \
287 const int startx = ncp->plot.labelaxisd ? NCPREFIXCOLUMNS : 0; /* plot cols begin here */ \
288 /* if we want fewer slots than there are available columns, our final column \
289 will be other than the plane's final column. most recent x goes here. */ \
290 const unsigned finalx = (ncp->plot.slotcount < scaleddim - 1 - (startx * scale) ? \
291 startx + (ncp->plot.slotcount / scale) - 1 : dimx - 1); \
292 ncplane_set_styles(ncp->plot.ncp, ncp->plot.legendstyle); \
293 if(ncp->plot.labelaxisd){ \
294 /* show the *top* of each interval range */ \
295 for(unsigned y = 0 ; y < dimy ; ++y){ \
296 ncplane_set_channels(ncp->plot.ncp, ncp->plot.channels[y]); \
297 char buf[NCPREFIXSTRLEN + 1]; \
298 if(ncp->plot.exponentiali){ \
299 if(y == dimy - 1){ /* we cheat on the top row to exactly match maxy */ \
300 ncqprefix(ncp->maxy * 100, 100, buf, 0); \
301 }else{ \
302 ncqprefix(pow(interval, (y + 1) * states) * 100, 100, buf, 0); \
303 } \
304 }else{ \
305 ncqprefix((ncp->maxy - interval * states * (dimy - y - 1)) * 100, 100, buf, 0); \
306 } \
307 if(y == dimy - 1 && strlen(ncp->plot.title)){ \
308 ncplane_printf_yx(ncp->plot.ncp, dimy - y - 1, NCPREFIXCOLUMNS - strlen(buf), "%s %s", buf, ncp->plot.title); \
309 }else{ \
310 ncplane_printf_yx(ncp->plot.ncp, dimy - y - 1, NCPREFIXCOLUMNS - strlen(buf), "%s", buf); \
311 } \
312 } \
313 }else if(strlen(ncp->plot.title)){ \
314 ncplane_set_channels(ncp->plot.ncp, ncp->plot.channels[dimy - 1]); \
315 ncplane_printf_yx(ncp->plot.ncp, 0, NCPREFIXCOLUMNS - strlen(ncp->plot.title), "%s", ncp->plot.title); \
316 } \
317 ncplane_set_styles(ncp->plot.ncp, NCSTYLE_NONE); \
318 if((int)finalx < startx){ /* exit on pathologically narrow planes */ \
319 return 0; \
320 } \
321 if(!interval){ \
322 interval = 1; \
323 } \
324 int idx = ncp->plot.slotstart; /* idx holds the real slot index; we move backwards */ \
325 for(int x = finalx ; x >= startx ; --x){ \
326 /* a single column might correspond to more than 1 ('scale', up to \
327 MAXWIDTH) slots' worth of samples. prepare the working gval set. */ \
328 T gvals[MAXWIDTH]; \
329 /* load it retaining the same ordering we have in the actual array */ \
330 for(int i = scale - 1 ; i >= 0 ; --i){ \
331 gvals[i] = ncp->slots[idx]; /* clip the value at the limits of the graph */ \
332 if(gvals[i] < ncp->miny){ \
333 gvals[i] = ncp->miny; \
334 } \
335 if(gvals[i] > ncp->maxy){ \
336 gvals[i] = ncp->maxy; \
337 } \
338 /* FIXME if there are an odd number, only go up through the valid ones... */ \
339 if(--idx < 0){ \
340 idx = ncp->plot.slotcount - 1; \
341 } \
342 } \
343 /* starting from the least-significant row, progress in the more significant \
344 direction, drawing egcs from the grid specification, aborting early if \
345 we can't draw anything in a given cell. */ \
346 T intervalbase = ncp->miny; \
347 const wchar_t* egc = ncp->plot.bset->plotegcs; \
348 bool done = !ncp->plot.bset->fill; \
349 for(unsigned y = 0 ; y < dimy ; ++y){ \
350 ncplane_set_channels(ncp->plot.ncp, ncp->plot.channels[y]); \
351 size_t egcidx = 0, sumidx = 0; \
352 /* if we've got at least one interval's worth on the number of positions \
353 times the number of intervals per position plus the starting offset, \
354 we're going to print *something* */ \
355 for(unsigned i = 0 ; i < scale ; ++i){ \
356 sumidx *= states; \
357 if(intervalbase < gvals[i]){ \
358 if(ncp->plot.exponentiali){ \
359 /* we want the log-base-interval of gvals[i] */ \
360 double scaled = log(gvals[i] - ncp->miny) / log(interval); \
361 double sival = intervalbase ? log(intervalbase) / log(interval) : 0; \
362 egcidx = scaled - sival; \
363 }else{ \
364 egcidx = (gvals[i] - intervalbase) / interval; \
365 } \
366 if(egcidx >= states){ \
367 egcidx = states - 1; \
368 done = false; \
369 } \
370 sumidx += egcidx; \
371 }else{ \
372 egcidx = 0; \
373 } \
374/* printf(stderr, "y: %d i(scale): %d gvals[%d]: %ju egcidx: %zu sumidx: %zu interval: %f intervalbase: %ju\n", y, i, i, gvals[i], egcidx, sumidx, interval, intervalbase); */ \
375 } \
376 /* if we're not UTF8, we can only arrive here via NCBLIT_1x1 (otherwise \
377 we would have errored out during construction). even then, however, \
378 we need handle ASCII differently, since it can't print full block. \
379 in ASCII mode, sumidx != 0 means swap colors and use space. in all \
380 modes, sumidx == 0 means don't do shit, since we erased earlier. */ \
381/* if(sumidx)fprintf(stderr, "dimy: %d y: %d x: %d sumidx: %zu egc[%zu]: %lc\n", dimy, y, x, sumidx, sumidx, egc[sumidx]); */ \
382 if(sumidx){ \
383 uint64_t chan = ncp->plot.channels[y]; \
384 if(notcurses_canutf8(ncplane_notcurses(ncp->plot.ncp))){ \
385 char utf8[MB_LEN_MAX + 1]; \
386 int bytes = wctomb(utf8, egc[sumidx]); \
387 if(bytes < 0){ \
388 return -1; \
389 } \
390 utf8[bytes] = '\0'; \
391 nccell* c = ncplane_cell_ref_yx(ncp->plot.ncp, dimy - y - 1, x); \
392 cell_set_bchannel(c, ncchannels_bchannel(chan)); \
393 cell_set_fchannel(c, ncchannels_fchannel(chan)); \
394 nccell_set_styles(c, NCSTYLE_NONE); \
395 if(pool_blit_direct(&ncp->plot.ncp->pool, c, utf8, bytes, 1) <= 0){ \
396 return -1; \
397 } \
398 }else{ \
399 const uint64_t swapbg = ncchannels_bchannel(chan); \
400 const uint64_t swapfg = ncchannels_fchannel(chan); \
401 ncchannels_set_bchannel(&chan, swapfg); \
402 ncchannels_set_fchannel(&chan, swapbg); \
403 ncplane_set_channels(ncp->plot.ncp, chan); \
404 if(ncplane_putchar_yx(ncp->plot.ncp, dimy - y - 1, x, ' ') <= 0){ \
405 return -1; \
406 } \
407 ncchannels_set_bchannel(&chan, swapbg); \
408 ncchannels_set_fchannel(&chan, swapfg); \
409 ncplane_set_channels(ncp->plot.ncp, chan); \
410 } \
411 } \
412 if(done){ \
413 break; \
414 } \
415 if(ncp->plot.exponentiali){ \
416 intervalbase = ncp->miny + pow(interval, (y + 1) * states - 1); \
417 }else{ \
418 intervalbase += (states * interval); \
419 } \
420 } \
421 } \
422 if(ncp->plot.printsample){ \
423 ncplane_set_styles(ncp->plot.ncp, ncp->plot.legendstyle); \
424 ncplane_set_channels(ncp->plot.ncp, ncp->plot.maxchannels); \
425 ncplane_printf_aligned(ncp->plot.ncp, 0, NCALIGN_RIGHT, "%" PRIu64, (uint64_t)ncp->slots[idx]); \
426 } \
427 ncplane_home(ncp->plot.ncp); \
428 return 0; \
429} \
430\
431static const struct blitset* \
432create_##T(nc##X##plot* ncpp, ncplane* n, const ncplot_options* opts, \
433 const T miny, const T maxy, const T trueminy, const T truemaxy){ \
434 /* set up ->plot.ncp first so it gets destroyed on error */ \
435 ncpp->plot.ncp = n; \
436 if(ncplane_set_widget(ncpp->plot.ncp, ncpp, (void(*)(void*))nc##X##plot_destroy)){ \
437 return NULL; \
438 } \
439 ncplot_options zeroed = {0}; \
440 if(!opts){ \
441 opts = &zeroed; \
442 } \
443 if(opts->flags >= (NCPLOT_OPTION_PRINTSAMPLE << 1u)){ \
444 logwarn("provided unsupported flags %016" PRIx64, opts->flags); \
445 } \
446 /* if miny == maxy (enabling domain detection), they both must be equal to 0 */ \
447 if(miny == maxy && miny){ \
448 return NULL; \
449 } \
450 if(opts->rangex < 0){ \
451 logerror("error: supplied negative independent range %d", opts->rangex); \
452 return NULL; \
453 } \
454 if(maxy < miny){ \
455 logerror("error: supplied maxy < miny"); \
456 return NULL; \
457 } \
458 /* DETECTMAXONLY can't be used without domain detection */ \
459 if(opts->flags & NCPLOT_OPTION_DETECTMAXONLY && (miny != maxy)){ \
460 logerror("supplied DETECTMAXONLY without domain detection"); \
461 return NULL; \
462 } \
463 const notcurses* notc = ncplane_notcurses(n); \
464 ncblitter_e blitfxn = opts ? opts->gridtype : NCBLIT_DEFAULT; \
465 if(blitfxn == NCBLIT_DEFAULT){ \
466 blitfxn = ncplot_defblitter(notc); \
467 } \
468 bool degrade_blitter = !(opts && (opts->flags & NCPLOT_OPTION_NODEGRADE)); \
469 const struct blitset* bset = lookup_blitset(&notc->tcache, blitfxn, degrade_blitter); \
470 if(bset == NULL){ \
471 return NULL; \
472 } \
473 unsigned sdimy, sdimx; \
474 ncplane_dim_yx(n, &sdimy, &sdimx); \
475 if(sdimx <= 0){ \
476 return NULL; \
477 } \
478 unsigned dimx = sdimx; \
479 ncpp->plot.title = strdup(opts->title ? opts->title : ""); \
480 ncpp->plot.rangex = opts->rangex; \
481 /* if we're sizing the plot based off the plane dimensions, scale it by the \
482 plot geometry's width for all calculations */ \
483 const unsigned scaleddim = dimx * (bset->geom == NCBLIT_PIXEL ? ncplane_pile_const(n)->cellpxx : bset->width); \
484 const unsigned scaledprefixlen = NCPREFIXCOLUMNS * (bset->geom == NCBLIT_PIXEL ? ncplane_pile_const(n)->cellpxx : bset->width); \
485 if((ncpp->plot.slotcount = ncpp->plot.rangex) == 0){ \
486 ncpp->plot.slotcount = scaleddim; \
487 } \
488 if(dimx < ncpp->plot.rangex){ \
489 ncpp->plot.slotcount = scaleddim; \
490 } \
491 ncpp->plot.legendstyle = opts->legendstyle; \
492 if( (ncpp->plot.labelaxisd = opts->flags & NCPLOT_OPTION_LABELTICKSD) ){ \
493 if(ncpp->plot.slotcount + scaledprefixlen > scaleddim){ \
494 if(scaleddim > scaledprefixlen){ \
495 ncpp->plot.slotcount = scaleddim - scaledprefixlen; \
496 } \
497 } \
498 } \
499 size_t slotsize = sizeof(*ncpp->slots) * ncpp->plot.slotcount; \
500 ncpp->slots = malloc(slotsize); \
501 if(ncpp->slots == NULL){ \
502 return NULL; \
503 } \
504 memset(ncpp->slots, 0, slotsize); \
505 ncpp->plot.maxchannels = opts->maxchannels; \
506 ncpp->plot.minchannels = opts->minchannels; \
507 ncpp->plot.bset = bset; \
508 ncpp->miny = miny; \
509 ncpp->maxy = maxy; \
510 ncpp->plot.vertical_indep = opts->flags & NCPLOT_OPTION_VERTICALI; \
511 ncpp->plot.exponentiali = opts->flags & NCPLOT_OPTION_EXPONENTIALD; \
512 ncpp->plot.detectonlymax = opts->flags & NCPLOT_OPTION_DETECTMAXONLY; \
513 ncpp->plot.printsample = opts->flags & NCPLOT_OPTION_PRINTSAMPLE; \
514 if( (ncpp->plot.detectdomain = (miny == maxy)) ){ \
515 ncpp->maxy = trueminy; \
516 if(!ncpp->plot.detectonlymax){ \
517 ncpp->miny = truemaxy; \
518 } \
519 } \
520 ncpp->plot.slotstart = 0; \
521 ncpp->plot.slotx = 0; \
522 ncpp->plot.chancount = 0; \
523 ncpp->plot.channels = NULL; \
524 if(bset->geom == NCBLIT_PIXEL){ \
525 if(create_pixelp(&ncpp->plot, n)){ \
526 return NULL; \
527 } \
528 } \
529 redraw_plot_##T(ncpp); \
530 return bset; \
531} \
532/* if x is less than the window, return -1, as the sample will be thrown away. \
533 if the x is within the current window, find the proper slot and update it. \
534 otherwise, the x is the newest sample. if it is obsoletes all existing slots, \
535 reset them, and write the new sample anywhere. otherwise, write it to the \
536 proper slot based on the current newest slot. */ \
537int window_slide_##T(nc##X##plot* ncp, int64_t x){ \
538 if(x <= ncp->plot.slotx){ /* x is within window, do nothing */ \
539 return 0; \
540 } /* x is newest; we might be keeping some, might not */ \
541 int64_t xdiff = x - ncp->plot.slotx; /* the raw amount we're advancing */ \
542 ncp->plot.slotx = x; \
543 if(xdiff >= ncp->plot.slotcount){ /* we're throwing away all old samples, write to 0 */ \
544 memset(ncp->slots, 0, sizeof(*ncp->slots) * ncp->plot.slotcount); \
545 ncp->plot.slotstart = 0; \
546 return 0; \
547 } \
548 /* we're throwing away only xdiff slots, which is less than slotcount. \
549 first, we'll try to clear to the right...number to reset on the right of \
550 the circular buffer. min of (available at current or to right, xdiff) */ \
551 int slotsreset = ncp->plot.slotcount - ncp->plot.slotstart - 1; \
552 if(slotsreset > xdiff){ \
553 slotsreset = xdiff; \
554 } \
555 if(slotsreset){ \
556 memset(ncp->slots + ncp->plot.slotstart + 1, 0, slotsreset * sizeof(*ncp->slots)); \
557 } \
558 ncp->plot.slotstart = (ncp->plot.slotstart + xdiff) % ncp->plot.slotcount; \
559 xdiff -= slotsreset; \
560 if(xdiff){ /* throw away some at the beginning */ \
561 memset(ncp->slots, 0, xdiff * sizeof(*ncp->slots)); \
562 } \
563 return 0; \
564} \
565\
566static int update_domain_##T(nc##X##plot* ncp, uint64_t x); \
const struct blitset * lookup_blitset(const tinfo *tcache, ncblitter_e setid, bool may_degrade)
Definition blit.c:1297
const char * egc
Definition egcpool.h:173
const nccell * c
Definition egcpool.h:296
uint32_t idx
Definition egcpool.h:298
notcurses * ncplane_notcurses(const ncplane *n)
Definition notcurses.c:2626
#define NCPREFIXCOLUMNS
Definition notcurses.h:3825
int y
Definition notcurses.h:1905
const struct ncplane_options struct ncvisual * ncv
Definition notcurses.h:3484
const struct ncplane_options struct ncvisual struct ncvisual_options * vopts
Definition notcurses.h:3484
const struct ncplane_options * opts
Definition notcurses.h:3483
@ NCALIGN_RIGHT
Definition notcurses.h:84
#define NCPLOT_OPTION_EXPONENTIALD
Definition notcurses.h:4481
ncblitter_e
Definition notcurses.h:65
@ NCBLIT_PIXEL
Definition notcurses.h:73
@ NCBLIT_DEFAULT
Definition notcurses.h:66
#define NCPLOT_OPTION_NODEGRADE
Definition notcurses.h:4483
#define NCPLOT_OPTION_VERTICALI
Definition notcurses.h:4482
#define NCSTYLE_NONE
Definition notcurses.h:775
vopts n
Definition notcurses.h:3502
#define NCPREFIXSTRLEN
Definition notcurses.h:3828
#define NCPLOT_OPTION_PRINTSAMPLE
Definition notcurses.h:4485
int int x
Definition notcurses.h:1905
#define NCPLOT_OPTION_LABELTICKSD
Definition notcurses.h:4480
#define NCVISUAL_OPTION_NODEGRADE
Definition notcurses.h:3337
#define NCPLOT_OPTION_DETECTMAXONLY
Definition notcurses.h:4484
#define MAXWIDTH
Definition plot.c:84
ncblitter_e geom
Definition internal.h:399
unsigned width
Definition internal.h:400
Definition plot.c:9
tinfo tcache
Definition internal.h:360
return NULL
Definition termdesc.h:229
ncvisual * ncvisual_from_rgba(const void *rgba, int rows, int rowstride, int cols)
Definition visual.c:776
ncplane * ncvisual_blit(notcurses *nc, ncvisual *ncv, const struct ncvisual_options *vopts)
Definition visual.c:1136

◆ MAXWIDTH

#define MAXWIDTH   2

Definition at line 84 of file plot.c.

Typedef Documentation

◆ ncplot

typedef struct ncplot ncplot

Function Documentation

◆ ncdplot_add_sample()

int ncdplot_add_sample ( ncdplot *  n,
uint64_t  x,
double  y 
)

Definition at line 709 of file plot.c.

Here is the caller graph for this function:

◆ ncdplot_create()

ncdplot * ncdplot_create ( ncplane n,
const ncplot_options opts,
double  miny,
double  maxy 
)

Definition at line 690 of file plot.c.

693 {
694 return n->plot.ncp;
695}
696
697int ncuplot_add_sample(ncuplot* n, uint64_t x, uint64_t y){
698 return add_sample_uint64_t(n, x, y);
699}
700
701int ncuplot_set_sample(ncuplot* n, uint64_t x, uint64_t y){
702 if(window_slide_uint64_t(n, x)){
703 return -1;
int ncuplot_set_sample(ncuplot *n, uint64_t x, uint64_t y)
Definition plot.c:670
int ncuplot_add_sample(ncuplot *n, uint64_t x, uint64_t y)
Definition plot.c:666
Here is the caller graph for this function:

◆ ncdplot_destroy()

void ncdplot_destroy ( ncdplot *  n)

Definition at line 732 of file plot.c.

736 {
737 return n->plot.ncp;
738}
Here is the caller graph for this function:

◆ ncdplot_plane()

ncplane * ncdplot_plane ( ncdplot *  n)

Definition at line 705 of file plot.c.

706 {
707 return -1;

◆ ncdplot_sample()

int ncdplot_sample ( const ncdplot *  n,
uint64_t  x,
double *  y 
)

Definition at line 728 of file plot.c.

729 { // create_double() destroys n on error
730 ncdplot_destroy(ret);
void ncdplot_destroy(ncdplot *n)
Definition plot.c:732
Here is the caller graph for this function:

◆ ncdplot_set_sample()

int ncdplot_set_sample ( ncdplot *  n,
uint64_t  x,
double  y 
)

Definition at line 713 of file plot.c.

713 {
714 ncplot_destroy(&n->plot);
715 free(n->slots);
716 free(n);
717 }
718}
719
720// takes ownership of n on all paths
721ncdplot* ncdplot_create(ncplane* n, const ncplot_options* opts, double miny, double maxy){
722 ncdplot* ret = malloc(sizeof(*ret));
free(duplicated)
ncdplot * ncdplot_create(ncplane *n, const ncplot_options *opts, double miny, double maxy)
Definition plot.c:690
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ncuplot_add_sample()

int ncuplot_add_sample ( ncuplot *  n,
uint64_t  x,
uint64_t  y 
)

Definition at line 666 of file plot.c.

667 {
668 const int64_t diff = ncp->plot.slotx - x; /* amount behind */

◆ ncuplot_create()

ncuplot * ncuplot_create ( ncplane n,
const ncplot_options opts,
uint64_t  miny,
uint64_t  maxy 
)

Definition at line 647 of file plot.c.

647 {
648 return -1;
649 }
650 return 0;
651}
652
653/* x must be within n's window at this point */
654static void
655update_sample_uint64_t(ncuplot* ncp, int64_t x, uint64_t y, bool reset){
656 const int64_t diff = ncp->plot.slotx - x; /* amount behind */
657 const int idx = (ncp->plot.slotstart + ncp->plot.slotcount - diff) % ncp->plot.slotcount;
658 if(reset){
659 ncp->slots[idx] = y;
660 }else{
Here is the caller graph for this function:

◆ ncuplot_destroy()

void ncuplot_destroy ( ncuplot *  n)

Definition at line 681 of file plot.c.

686 { // create_uint64_t() destroys n on error
687 ncuplot_destroy(ret);
void ncuplot_destroy(ncuplot *n)
Definition plot.c:681
Here is the caller graph for this function:

◆ ncuplot_plane()

ncplane * ncuplot_plane ( ncuplot *  n)

Definition at line 662 of file plot.c.

◆ ncuplot_sample()

int ncuplot_sample ( const ncuplot *  n,
uint64_t  x,
uint64_t *  y 
)

Definition at line 724 of file plot.c.

Here is the caller graph for this function:

◆ ncuplot_set_sample()

int ncuplot_set_sample ( ncuplot *  n,
uint64_t  x,
uint64_t  y 
)

Definition at line 670 of file plot.c.

670 {
671 ncp->slots[idx] = y;
672 }else{
673 ncp->slots[idx] += y;
674 }
675}
676
677// takes ownership of n on all paths
678ncuplot* ncuplot_create(ncplane* n, const ncplot_options* opts, uint64_t miny, uint64_t maxy){
679 ncuplot* ret = malloc(sizeof(*ret));
ncuplot * ncuplot_create(ncplane *n, const ncplot_options *opts, uint64_t miny, uint64_t maxy)
Definition plot.c:647

◆ update_domain_double()

int update_domain_double ( ncdplot *  ncp,
uint64_t  x 
)

Definition at line 603 of file plot.c.

603 {
604 free(n->title);
605 if(ncplane_set_widget(n->ncp, NULL, NULL) == 0){
606 ncplane_destroy(n->ncp);
607 }
608 ncplane_destroy(n->pixelp);
609 free(n->channels);
610}
611
612/* if we're doing domain detection, update the domain to reflect the value we
613 just set. if we're not, check the result against the known ranges, and
614 return -1 if the value is outside of that range. */
615int update_domain_uint64_t(ncuplot* ncp, uint64_t x){
616 const uint64_t val = ncp->slots[x % ncp->plot.slotcount];
617 if(ncp->plot.detectdomain){
618 if(val > ncp->maxy){
619 ncp->maxy = val;
620 }
int ncplane_destroy(ncplane *ncp)
Definition notcurses.c:1018
int update_domain_uint64_t(ncuplot *ncp, uint64_t x)
Definition plot.c:584
Here is the call graph for this function:

◆ update_domain_uint64_t()

int update_domain_uint64_t ( ncuplot *  ncp,
uint64_t  x 
)

Definition at line 584 of file plot.c.

584 { \
585 return -1; \
586 } \
587 return redraw_plot_##T(ncpp); \
588} \
589int sample_##T(const nc##X##plot* ncp, int64_t x, T* y){ \
590 if(x < ncp->plot.slotx - (ncp->plot.slotcount - 1)){ /* x is behind window */ \
591 return -1; \
592 }else if(x > ncp->plot.slotx){ /* x is ahead of window */ \
593 return -1; \
594 } \
595 *y = ncp->slots[x % ncp->plot.slotcount]; \
596 return 0; \
597}
598
599CREATE(uint64_t, u)
600CREATE(double, d)
601
#define CREATE(T, X)
Definition plot.c:85