Alien-libhisto
view release on metacpan or search on metacpan
bundled/tools/src/cmd_top.c view on Meta::CPAN
if (max_col > bar_max) max_col = bar_max;
bool in_bar_color = false;
for (int k = 0; k < max_col && pos + 32 < (int)sizeof(row_buf); ++k) {
if (k == kde_col && k == fit_col) {
if (in_bar_color) { pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "\033[0m"); in_bar_color = false; }
pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "\033[1;33mâ¦\033[0m");
} else if (k == kde_col) {
if (in_bar_color) { pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "\033[0m"); in_bar_color = false; }
pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "\033[1;36mâ\033[0m");
} else if (k == fit_col) {
if (in_bar_color) { pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "\033[0m"); in_bar_color = false; }
pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "\033[1;35mâ\033[0m");
} else if (k < full_chars) {
if (!in_bar_color) { pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "%s", color_ansi); in_bar_color = true; }
pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "â");
} else if (k == full_chars && rem_eighths > 0) {
if (!in_bar_color) { pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "%s", color_ansi); in_bar_color = true; }
pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "%s", BLOCKS_UTF8[rem_eighths]);
} else {
if (in_bar_color) { pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "\033[0m"); in_bar_color = false; }
pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, " ");
}
}
if (in_bar_color) {
pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "\033[0m");
}
/* Error whiskers if enabled */
if (st->show_errors && total_w > 0.0) {
double err = 0.0;
histo_bin_error(h, i, &err);
if (err > 0.0 && pos + 32 < (int)sizeof(row_buf)) {
pos += snprintf(row_buf + pos, sizeof(row_buf) - pos, "\033[90m â±%.2gâ\033[0m", err);
}
}
tui_render_row(f, row_buf, width, true);
rows_drawn++;
}
if (kde) histo_kde_destroy(kde);
if (fit_res) histo_fit_result_destroy(fit_res);
while (rows_drawn < max_rows) {
tui_render_row(f, "", width, true);
rows_drawn++;
}
}
static void render_help_viewport(tui_frame_t *f, const tui_state_t *st, int width, int max_rows) {
if (st && st->view_mode == VIEW_2D_HEATMAP) {
const char *help_lines_2d[] = {
"ââ Interactive Help Cheatsheet (2D Heatmap Mode) âââââââââââââââââââââââââââ",
"",
"DISPLAY & INTENSITY SCALING",
" l Toggle Log-Z intensity color scale (LIN <-> LOG-Z)",
" p / P Cycle color palettes (viridis, plasma, inferno, magma, turbo, cividis, gray, rainbow)",
" C Toggle TrueColor / Monochrome ASCII density",
" g Toggle Color Range Legend reference bar",
" [Space] Freeze / Unfreeze live streaming display",
" c Clear all accumulators and reset live count",
"",
"COMMANDS & PROMPT (:)",
" :palette <NAME> Set color palette (or shorthand :p <NAME>)",
" :clear Clear accumulators",
" :quit / :q Quit application cleanly",
" :help Open this help modal",
"",
"Press [?], [Esc], or [Space] to dismiss this help window."
};
size_t n_lines = sizeof(help_lines_2d) / sizeof(help_lines_2d[0]);
int rows_drawn = 0;
for (size_t i = 0; i < n_lines && rows_drawn < max_rows; ++i) {
tui_render_row(f, help_lines_2d[i], width, true);
rows_drawn++;
}
while (rows_drawn < max_rows) {
tui_render_row(f, "", width, true);
rows_drawn++;
}
return;
}
const char *help_lines[] = {
"ââ Interactive Help Cheatsheet âââââââââââââââââââââââââââââââââââââââââââ",
"",
"NAVIGATION & VIEWPORT DISPLAY & SCALING",
" + / - , Wheel Zoom in / out l Cycle Log scales (Y, X, Log-Log)",
" â/â, h/l Pan viewport left/right p Cycle color palettes",
" 0 Reset to full range a Toggle Dynamic Auto-Range",
" r / R Rebin coarser / finer C Toggle TrueColor / Monochrome",
" k Toggle KDE curve f Toggle Curve Fit overlay",
" Tab / 1..9 Switch active column s Save snapshot to disk",
" w Cycle rolling window H Toggle Compact header mode",
" B Auto-fit bins to rows Click Inspect bin details",
"COMMANDS & PROMPT (:)",
" :bins <N|auto> Set bin count / auto-fit :save [path] Save binary / JSON snapshot",
" :col <N> Select metric column (1..16) :window <N> Set rolling window size",
" :decay <lambda> Set exponential decay rate :compact [on] Toggle compact header",
" :range A B Set range (e.g. :r 0 100) [Space] Freeze / Unfreeze display",
" :autorange Toggle dynamic autorange c Clear all accumulators",
" :help Open full help modal q Quit cleanly",
"",
"Press [?], [Esc], or [Space] to dismiss this help window."
};
size_t n_lines = sizeof(help_lines) / sizeof(help_lines[0]);
int rows_drawn = 0;
for (size_t i = 0; i < n_lines && rows_drawn < max_rows; ++i) {
tui_render_row(f, help_lines[i], width, true);
rows_drawn++;
}
while (rows_drawn < max_rows) {
tui_render_row(f, "", width, true);
rows_drawn++;
}
}
bundled/tools/src/cmd_top.c view on Meta::CPAN
st->scale_mode = SCALE_LOG_LOG;
tui_engine_rebuild_1d_log(eng, 50, NULL);
} else {
st->scale_mode = SCALE_LINEAR;
tui_engine_rebuild_1d(eng, 50, 0, 0, NULL);
}
}
} else if (strncasecmp(cmd, "autorange", 9) == 0 || (strncasecmp(cmd, "a", 1) == 0 && (cmd[1] == ' ' || cmd[1] == '\0'))) {
const char *arg = strchr(cmd, ' ');
if (arg) {
while (*arg == ' ') arg++;
if (strcasecmp(arg, "on") == 0 || strcasecmp(arg, "1") == 0 || strcasecmp(arg, "true") == 0) {
tui_engine_set_autorange(eng, true, eng->auto_range_threshold);
} else if (strcasecmp(arg, "off") == 0 || strcasecmp(arg, "0") == 0 || strcasecmp(arg, "false") == 0) {
tui_engine_set_autorange(eng, false, eng->auto_range_threshold);
} else {
double thresh = atof(arg);
if (thresh > 0.0 && thresh < 1.0) {
tui_engine_set_autorange(eng, true, thresh);
}
}
} else {
tui_engine_set_autorange(eng, !eng->auto_range, eng->auto_range_threshold);
}
} else if (strncasecmp(cmd, "zoom ", 5) == 0 || strncasecmp(cmd, "z ", 2) == 0) {
double factor = atof(cmd + (*cmd == 'z' ? 2 : 5));
if (factor > 0.0) {
if (eng->is_2d) {
tui_engine_zoom_2d(eng, 1.0 / factor, st->paused ? &st->frozen_snapshot_2d : NULL);
} else {
tui_engine_zoom_1d(eng, 1.0 / factor, st->paused ? &st->frozen_snapshot : NULL);
}
snprintf(st->status_msg, sizeof(st->status_msg), "Zoomed %.2fx", factor);
st->status_msg_time = cli_get_time_sec();
}
} else if (strncasecmp(cmd, "pan ", 4) == 0) {
double frac_x = 0.0, frac_y = 0.0;
int n_parsed = sscanf(cmd + 4, "%lf %lf", &frac_x, &frac_y);
if (n_parsed >= 1) {
if (eng->is_2d) {
tui_engine_pan_2d(eng, frac_x, (n_parsed >= 2 ? frac_y : 0.0), st->paused ? &st->frozen_snapshot_2d : NULL);
} else {
tui_engine_pan_1d(eng, frac_x, st->paused ? &st->frozen_snapshot : NULL);
}
snprintf(st->status_msg, sizeof(st->status_msg), "Panned %.0f%%", frac_x * 100.0);
st->status_msg_time = cli_get_time_sec();
}
} else if (strcasecmp(cmd, "clear") == 0 || strcasecmp(cmd, "reset") == 0) {
tui_engine_clear(eng);
} else if (strcasecmp(cmd, "help") == 0 || strcasecmp(cmd, "h") == 0) {
st->modal = MODAL_HELP;
} else if (strcasecmp(cmd, "quit") == 0 || strcasecmp(cmd, "q") == 0) {
eng->running = false;
}
}
static void print_top_usage(FILE *out) {
if (!out) out = stdout;
fprintf(out, "Usage: histo-top [OPTIONS] [FILE]\n");
fprintf(out, " histo top [OPTIONS] [FILE]\n\n");
fprintf(out, "Real-time interactive terminal monitor for streaming 1D/2D distributions.\n\n");
fprintf(out, "1D Geometry Options:\n");
fprintf(out, " -n, --bins=<N> Initial number of bins (default: 50)\n");
fprintf(out, " --min=<X> Initial lower boundary (default: 0.0)\n");
fprintf(out, " --max=<X> Initial upper boundary (default: 100.0)\n");
fprintf(out, " -a, --auto-range Enable dynamic quantile auto-ranging (default: ON)\n");
fprintf(out, " --no-auto-range Disable dynamic auto-ranging\n\n");
fprintf(out, "2D Geometry Options:\n");
fprintf(out, " --2d Enable 2D bivariate heatmap mode\n");
fprintf(out, " --xbins=<N> Number of bins along X axis (default: 50)\n");
fprintf(out, " --xmin=<X>, --xmax=<X> Initial X axis bounds (default: [0, 100])\n");
fprintf(out, " --ybins=<N> Number of bins along Y axis (default: 50)\n");
fprintf(out, " --ymin=<Y>, --ymax=<Y> Initial Y axis bounds (default: [0, 100])\n\n");
fprintf(out, "Input Parsing & Columns:\n");
fprintf(out, " -w, --weights Input stream contains weights: 'x weight' or 'x y weight'\n");
fprintf(out, " --value-col=<COL> 1-based column for sample coordinate in 1D mode (default: 1)\n");
fprintf(out, " --xcol=<COL> 1-based column for X coordinate in 2D mode (default: 1)\n");
fprintf(out, " --ycol=<COL> 1-based column for Y coordinate in 2D mode (default: 2)\n");
fprintf(out, " --weights-col=<COL> 1-based column for sample weight (default: 2 for 1D, 3 for 2D)\n");
fprintf(out, " -d, --delimiter=<CHAR> Field delimiter character (default: whitespace/auto)\n\n");
fprintf(out, "Display & Styling:\n");
fprintf(out, " -p, --palette=<NAME> Color palette: viridis (default), plasma, inferno, magma,\n");
fprintf(out, " turbo, cividis, grayscale, rainbow (alias: --colormap)\n");
fprintf(out, " -M, --mono Monochrome mode (disable ANSI colors)\n");
fprintf(out, " -h, --help Show this help message\n\n");
fprintf(out, "Interactive Keyboard Controls:\n");
fprintf(out, " [Space] Freeze / resume live ingestion snapshot\n");
fprintf(out, " [a] Toggle dynamic auto-ranging\n");
fprintf(out, " [l] Cycle count scale (Linear -> Log-Y -> Log-X -> Log-Log in 1D; Log-Z in 2D)\n");
fprintf(out, " [p] Cycle color palette preset\n");
fprintf(out, " [k] Toggle real-time Gaussian Kernel Density Estimation (KDE) overlay (1D)\n");
fprintf(out, " [f] Toggle online Gaussian parametric curve fit overlay (1D)\n");
fprintf(out, " [e] Toggle error bars (1D)\n");
fprintf(out, " [y] Toggle vertical count axis scale ruler (1D)\n");
fprintf(out, " [g] Toggle color reference legend bar (2D)\n");
fprintf(out, " [r / R] Increase / decrease bin resolution\n");
fprintf(out, " [c] Clear / reset accumulated histogram data\n");
fprintf(out, " [:] Open interactive command prompt (:help, :autorange, :rebin, :save, :quit)\n");
fprintf(out, " [?] Show full in-app help modal\n");
fprintf(out, " [q] Quit monitor\n");
}
int cmd_top_main(int argc, char **argv) {
bool is_2d = false;
uint32_t nbins = 50;
uint32_t xbins = 50, ybins = 50;
double rmin = 0.0, rmax = 100.0;
double xmin = 0.0, xmax = 100.0;
double ymin = 0.0, ymax = 100.0;
bool auto_range = true;
bool monochrome = false;
bool has_weights = false;
char delim = ' ';
int val_col = 1, x_col = 1, y_col = 2, w_col = 2;
histo_palette_t palette = HISTO_PALETTE_VIRIDIS;
uint32_t flags = HISTO_FLAG_TRACK_SUMW2 | HISTO_FLAG_EXACT_MOMENTS;
const char *file_arg = NULL;
for (int i = 1; i < argc; ++i) {
const char *arg = argv[i];
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
bundled/tools/src/cmd_top.c view on Meta::CPAN
} else {
snprintf(badge, sizeof(badge), "[EOF | N=%lu]", (unsigned long)n_entries);
}
} else {
double rate = eng.current_rate_ops;
char rate_str[32];
if (rate >= 1e6) snprintf(rate_str, sizeof(rate_str), "%.1fM/s", rate / 1e6);
else if (rate >= 1e3) snprintf(rate_str, sizeof(rate_str), "%.1fk/s", rate / 1e3);
else snprintf(rate_str, sizeof(rate_str), "%.0f/s", rate);
if (eng.has_weights) {
snprintf(badge, sizeof(badge), "[LIVE: %s | N=%lu | W=%.2f]", rate_str, (unsigned long)n_entries, tot_w);
} else {
snprintf(badge, sizeof(badge), "[LIVE: %s | N=%lu]", rate_str, (unsigned long)n_entries);
}
}
render_top_border(&frame, eng.is_2d ? "libhisto top (2D)" : "libhisto top", badge, cols);
if (st.compact_header) {
char stats_buf[256];
if (eng.is_2d) {
if (snap_2d && n_entries > 0) {
histo2d_axis_t ax, ay;
histo2d_axis_x(snap_2d, &ax);
histo2d_axis_y(snap_2d, &ay);
snprintf(stats_buf, sizeof(stats_buf), "[2D] X:[%.1f,%.1f] Y:[%.1f,%.1f] â N=%lu â %s â Pal:%s",
ax.min, ax.max, ay.min, ay.max, (unsigned long)n_entries,
st.log_z ? "LOG-Z" : "LIN", histo_palette_name(st.palette));
} else {
snprintf(stats_buf, sizeof(stats_buf), "Waiting for 2D stream...");
}
} else {
if (snap && n_entries > 0) {
double mean = 0, sdev = 0, med = 0, p95 = 0;
histo_mean(snap, &mean);
histo_std_dev(snap, &sdev);
histo_median(snap, &med);
histo_quantile(snap, 0.95, &p95);
snprintf(stats_buf, sizeof(stats_buf), "[Col %d] Mean: %.2f ± %.2f â Med: %.2f â P95: %.2f â N=%lu â Pal:%s",
eng.val_col, mean, sdev, med, p95, (unsigned long)n_entries, histo_palette_name(st.palette));
} else {
snprintf(stats_buf, sizeof(stats_buf), "Waiting for stream...");
}
}
tui_render_row(&frame, stats_buf, cols, true);
render_divider(&frame, cols);
} else {
// Row 2: Stats summary
char stats_buf[256];
if (eng.is_2d) {
if (snap_2d && n_entries > 0) {
histo2d_axis_t ax, ay;
histo2d_axis_x(snap_2d, &ax);
histo2d_axis_y(snap_2d, &ay);
snprintf(stats_buf, sizeof(stats_buf),
"X: [%.2f, %.2f] %ux â Y: [%.2f, %.2f] %uy â Entries: %lu â Weight: %.2f",
ax.min, ax.max, histo2d_nbins_x(snap_2d),
ay.min, ay.max, histo2d_nbins_y(snap_2d),
(unsigned long)n_entries, tot_w);
} else {
snprintf(stats_buf, sizeof(stats_buf), "Waiting for streaming 'x y' samples...");
}
} else {
if (snap && n_entries > 0) {
double mean = 0, sdev = 0, med = 0, iqr = 0, p95 = 0, p99 = 0;
histo_mean(snap, &mean);
histo_std_dev(snap, &sdev);
histo_median(snap, &med);
histo_iqr(snap, &iqr);
histo_quantile(snap, 0.95, &p95);
histo_quantile(snap, 0.99, &p99);
snprintf(stats_buf, sizeof(stats_buf), "Mean: %.2f ± %.2f â Med: %.2f â IQR: %.2f â P95: %.2f â P99: %.2f",
mean, sdev, med, iqr, p95, p99);
} else {
snprintf(stats_buf, sizeof(stats_buf), "Waiting for streaming samples...");
}
}
tui_render_row(&frame, stats_buf, cols, true);
// Row 3: Divider
render_divider(&frame, cols);
// Row 4: Subheader
char subhdr[384];
if (eng.is_2d) {
if (snap_2d) {
histo2d_axis_t ax, ay;
histo2d_axis_x(snap_2d, &ax);
histo2d_axis_y(snap_2d, &ay);
snprintf(subhdr, sizeof(subhdr), "2D Heatmap â X: %u bins [%.1f, %.1f] â Y: %u bins [%.1f, %.1f] â Pal: %s â %s %s",
histo2d_nbins_x(snap_2d), ax.min, ax.max,
histo2d_nbins_y(snap_2d), ay.min, ay.max,
histo_palette_name(st.palette),
st.log_z ? "LOG-Z" : "LIN",
st.show_legend ? "â Legend: ON" : "");
} else {
snprintf(subhdr, sizeof(subhdr), "Initializing 2D...");
}
} else if (snap) {
double r_min = 0, r_max = 0;
histo_range(snap, &r_min, &r_max);
uint32_t nb = histo_nbins(snap);
const char *sc = (st.scale_mode == SCALE_LOG_Y) ? "LOG-Y" :
(st.scale_mode == SCALE_LOG_X) ? "LOG-X" :
(st.scale_mode == SCALE_LOG_LOG) ? "LOG-LOG" : "LIN";
char kde_tag[64] = "";
char fit_tag[64] = "";
if (st.show_kde && n_entries >= 5) {
histo_kde_t *sub_kde = histo_kde_create_from_histo(snap, NULL);
if (sub_kde) {
double bw = histo_kde_get_bandwidth(sub_kde);
snprintf(kde_tag, sizeof(kde_tag), "â KDE: Gauss(h=%.2g) ", bw);
histo_kde_destroy(sub_kde);
} else {
snprintf(kde_tag, sizeof(kde_tag), "â KDE ");
}
}
if (st.show_fit && n_entries >= 5) {
histo_fit_result_t *sub_fit = NULL;
histo_fit_model(snap, HISTO_FIT_MODEL_GAUSSIAN, NULL, NULL, &sub_fit);
if (sub_fit && sub_fit->converged) {
snprintf(fit_tag, sizeof(fit_tag), "â Fit: μ=%.2f Ï=%.2f ", sub_fit->params[1], sub_fit->params[2]);
histo_fit_result_destroy(sub_fit);
} else {
if (sub_fit) histo_fit_result_destroy(sub_fit);
snprintf(fit_tag, sizeof(fit_tag), "â Fit: Gauss ");
}
}
char err_tag[32] = "";
if (st.show_errors) snprintf(err_tag, sizeof(err_tag), "â Err: ON ");
char yaxis_tag[32] = "";
if (st.show_y_axis) snprintf(yaxis_tag, sizeof(yaxis_tag), "â Axis: ON ");
char col_tag[32] = "";
if (eng.val_col > 1) snprintf(col_tag, sizeof(col_tag), "Col:%d â ", eng.val_col);
char win_tag[32] = "";
( run in 0.945 second using v1.01-cache-2.11-cpan-9789f410c06 )