Alien-libhisto

 view release on metacpan or  search on metacpan

bundled/tools/src/cmd_plot.c  view on Meta::CPAN

    double max_scaled = (log_scale && max_content > 0.0) ? log10(max_content + 1.0) : max_content;
    bool is_ascii = (strcmp(style, "ascii") == 0);

    for (uint32_t i = 0; i < nbins; ++i) {
        double content = 0.0;
        histo_bin_content(h, i, &content);

        if (content <= 0.0 || max_scaled <= 0.0) {
            fputc(' ', out);
            continue;
        }

        double val_scaled = log_scale ? log10(content + 1.0) : content;
        double frac = val_scaled / max_scaled;
        int level = (int)(frac * 8.0 + 0.5);
        if (level < 1) level = 1;
        if (level > 8) level = 8;

        if (use_color) {
            char color_ansi[32] = "";
            histo_palette_sample_ansi_fg(palette, frac, color_ansi, sizeof(color_ansi));
            fprintf(out, "%s", color_ansi);
        }

        if (is_ascii) {
            fprintf(out, "%s", SPARKLINE_ASCII[level]);
        } else {
            fprintf(out, "%s", SPARKLINE_UNICODE[level]);
        }

        if (use_color) {
            fprintf(out, "\033[0m");
        }
    }

    if (show_stats) {
        double mean = 0.0, sdev = 0.0, rmin = 0.0, rmax = 0.0;
        histo_mean(h, &mean);
        histo_std_dev(h, &sdev);
        histo_range(h, &rmin, &rmax);
        uint64_t entries = histo_num_entries(h);

        fprintf(out, "  [N=%llu, range=[%.2g, %.2g), μ=%.2g, σ=%.2g]",
               (unsigned long long)entries, rmin, rmax, mean, sdev);
    }
    fprintf(out, "\n");
}

static void render_histogram_dispatch(const histo_t *h, int term_width, const char *style, bool use_color, histo_palette_t palette, bool log_scale, bool show_errors, bool show_stats, const char *title, bool sparkline, FILE *out) {
    if (sparkline) {
        render_histogram_sparkline(h, style, use_color, palette, log_scale, show_stats, out);
    } else {
        render_histogram_console(h, term_width, style, use_color, palette, log_scale, show_errors, show_stats, title, out);
    }
}

#include "cli_opt.h"

int histo_cli_plot(int argc, char **argv, FILE *out, FILE *err) {
    if (!out) out = stdout;
    if (!err) err = stderr;

    int term_width = cli_get_terminal_width(80);
    const char *style = "blocks";
    const char *color_mode = "auto";
    const char *palette_name = NULL;
    histo_palette_t palette = HISTO_PALETTE_VIRIDIS;
    bool log_scale = false;
    bool show_errors = false;
    bool show_stats = true;
    bool sparkline = false;
    bool watch_mode = false;
    bool clear_screen = false;
    bool mode_2d = false;
    double scale_input = 1.0;
    const char *title = NULL;

    const cli_opt_spec_t specs[] = {
        {'W', "width", NULL, CLI_OPT_TYPE_INT, &term_width, NULL, 0, "COLS",
         "Plot width in characters (default: auto terminal width)", NULL},
        {'s', "style", NULL, CLI_OPT_TYPE_STRING, &style, NULL, 0, "STYLE",
         "Glyph style: blocks (default), ascii, shaded, sparkline", "blocks"},
        {'S', "sparkline", NULL, CLI_OPT_TYPE_BOOL, &sparkline, NULL, 0, NULL,
         "Render compact single-line sparkline", NULL},
        {0, "scale-input", NULL, CLI_OPT_TYPE_DOUBLE, &scale_input, NULL, 0, "FACTOR",
         "Multiply incoming measurements by scale factor (e.g. 1e-3 for ns->us)", "1.0"},
        {'c', "color", NULL, CLI_OPT_TYPE_STRING, &color_mode, NULL, 0, "MODE",
         "Color mode: auto (default), always, never", "auto"},
        {'p', "palette", "colormap", CLI_OPT_TYPE_STRING, &palette_name, NULL, 0, "NAME",
         "Color palette: viridis (default), plasma, inferno, magma, turbo, cividis, grayscale, rainbow", "viridis"},
        {'l', "log", NULL, CLI_OPT_TYPE_BOOL, &log_scale, NULL, 0, NULL,
         "Use logarithmic scale for bar lengths / 2D intensity", NULL},
        {'e', "errors", NULL, CLI_OPT_TYPE_BOOL, &show_errors, NULL, 0, NULL,
         "Display error bars (1D mode when sum_w2 is tracked)", NULL},
        {0, "2d", NULL, CLI_OPT_TYPE_BOOL, &mode_2d, NULL, 0, NULL,
         "Render in 2D bivariate heatmap mode", NULL},
        {0, "stats", NULL, CLI_OPT_TYPE_BOOL, &show_stats, NULL, CLI_OPT_FLAG_SET_TRUE, NULL,
         "Show full statistical summary header/footer (default: ON)", NULL},
        {0, "no-stats", NULL, CLI_OPT_TYPE_BOOL, &show_stats, NULL, CLI_OPT_FLAG_SET_FALSE, NULL,
         "Suppress statistical summary header", NULL},
        {0, "title", NULL, CLI_OPT_TYPE_STRING, &title, NULL, 0, "TITLE",
         "Set custom plot title", NULL},
        {'w', "watch", NULL, CLI_OPT_TYPE_BOOL, &watch_mode, NULL, 0, NULL,
         "Continuously render incoming snapshots from stream", NULL},
        {0, "clear", NULL, CLI_OPT_TYPE_BOOL, &clear_screen, NULL, 0, NULL,
         "Clear entire screen between updates", NULL}
    };

    cli_opt_parser_t parser;
    cli_opt_init(&parser, specs, sizeof(specs) / sizeof(specs[0]),
                 "histo-plot", "[OPTIONS] [HISTOGRAM_FILE...]",
                 "Renders 1D distributions and 2D bivariate heatmaps as ASCII / Unicode terminal charts.");

    int rc = cli_opt_parse(&parser, argc, argv, 1);
    if (rc < 0) {
        cli_opt_print_help(&parser, out);
        cli_opt_free(&parser);
        return 0;
    }
    if (rc > 0) {
        fprintf(err, "%s\n", cli_opt_error(&parser));



( run in 1.121 second using v1.01-cache-2.11-cpan-5c0b1e786e0 )