X-Git-Url: https://git.xandkar.net/?a=blobdiff_plain;ds=sidebyside;f=bin%2Fplotsi;fp=bin%2Fplotsi;h=0000000000000000000000000000000000000000;hb=a68d5744f8758fc77c34c612edac06dbc0bea129;hp=7a8812e3bc59979499a38ff077ce976a42e72e90;hpb=e184ff59e5cc01f9f62d0be272b77e59e149a6f1;p=khome.git diff --git a/bin/plotsi b/bin/plotsi deleted file mode 100755 index 7a8812e..0000000 --- a/bin/plotsi +++ /dev/null @@ -1,310 +0,0 @@ -#! /usr/bin/awk -f -# -# Plot Simply -# -# TODO: Incremental plotting (new canvas for each data line) -# TODO: Support manual set of max y - -function orange(str) {return "\033[33m" str "\033[0m";} -function orange_bright(str) {return "\033[1;33m" str "\033[0m";} -function green(str) {return "\033[32m" str "\033[0m";} -function grey_dark(str) {return "\033[30m" str "\033[0m";} -function grey_light(str) {return "\033[37m" str "\033[0m";} - -function abs(n) {return n >= 0 ? n : -n} -function round(n_float) {return int(n_float + 0.5)} -function log_10(n) {return log(n) / log(10)} - -function width(n, w) { - # - # log(0) == -inf - # - w = 1 + round(n > 0 ? log_10(n) : (n == 0 ? 1 : log_10(-n) + 1)); # +1 for neg sign - #printf("n: %d, w: %d\n", n, w); - return w; -} - -function bins_append_item_to_bin(bin, val, bin_i) { - bin_i = bin_item_count[bin]++; - bins[bin, bin_i] = val; -} - -BEGIN { - # CLI options: w, h, p, a, b - limits["canvas_width"] = (w ? w : 70); - limits["canvas_height"] = (h ? h : 20); - char_point = orange_bright(p ? p : "."); - char_pad = grey_dark(a ? a : ""); # FIXME: non-blank pad is broken after adding the y labels - char_blank = grey_dark(b ? b : "|"); - aggregation = g ? g : "mean"; - data_field = df ? df : 1; - - y_orig_min = 0; - y_orig_max = 0; -} - -{ - y_orig = $data_field; - if (y_orig > y_orig_max) y_orig_max = y_orig; - if (y_orig < y_orig_min) y_orig_min = y_orig; - data_0[NR] = y_orig; -} - -function aggregate_mean() { -} - -function aggregate(array) { - if (aggregation == "mean") { - return aggregate_mean(array); - } else { - printf("Unknown aggregation: %s\n", aggregation) > "/dev/stderr"; - exit(2); - } -} - -function data_scaled_x_to_width(\ - data_in, data_out, limits, - - x_orig, - datum, - x_bin, - bins, - bin_item_counts, - bin_sum, - bin_item_count, - i, - bin_item, - bin_mean \ -) { - # Find limit points - x_orig_min = 0; - x_orig_max = 0; - for (x_orig in data_in) { - if (x_orig > x_orig_max) x_orig_max = x_orig; - if (x_orig < x_orig_min) x_orig_min = x_orig; - } - #x_orig_range = x_orig_max - x_orig_min; - # Place items in bins - x_bin_min = 0; - x_bin_max = 0; - for (x_orig in data_in) { - datum = data_in[x_orig]; - x_bin = round(x_orig * limits["canvas_width_x"] / length(data_in)); - if (x_bin > x_bin_max) x_bin_max = x_bin; - if (x_bin < x_bin_min) x_bin_min = x_bin; - bin_item_count = ++bin_item_counts[x_bin]; - bins[x_bin, bin_item_count] = datum; - #printf("x_orig: %f, x_bin: %f, bin_item_count: %f, datum: %f\n", x_orig, x_bin, bin_item_count, datum); - } - # Aggregate bins - for (x_bin in bin_item_counts) { - bin_sum = 0; - bin_item_count = bin_item_counts[x_bin]; - for (i = 1; i <= bin_item_count; i++) { - bin_item = bins[x_bin, i]; - bin_sum += bin_item; - #printf("x_bin: %f, bin_item_count: %f, bin_item: %f, bin_sum: %f\n", x_bin, bin_item_count, bin_item, bin_sum); - } - bin_mean = bin_sum / bin_item_count; - data_out[x_bin] = bin_mean; - #printf("x_bin: %f, bin_mean: %f, bin_sum: %f, bin_item_count: %f\n", - #x_bin, bin_mean, bin_sum, bin_item_count); - } - limits["x_min"] = x_bin_min; - limits["x_max"] = x_bin_max; -} - -function data_scaled_y_to_height(\ - data_in, data_out, limits, - - data_scaled, x, y, y_orig, y_scaled \ -) { - # Offset orig - # TODO: Is there a better, closed-form way to get the offset? - # TODO: Is there better way to map canvas to value ranges altogether? - if (y_orig_min < 0) { - offset_orig = -1 * y_orig_min; - } else { - offset_orig = 0; - } - for (x in data_in) { - y = data_in[x]; - #printf("x: %f, y: %f, y_min: %f, y_max: %f\n", x, y, y_min, y_max); - data_in_offsetted[x] = y + offset_orig; - } - y_orig_offseted_min = y_orig_min + offset_orig; - y_orig_offseted_max = y_orig_max + offset_orig; - - # Scale to height - y_scaled_min = 0; - y_scaled_max = 0; - for (x in data_in_offsetted) { - y_orig_offsetted = data_in_offsetted[x]; - y_scaled = \ - y_orig_offseted_max > 0 \ - ? round((y_orig_offsetted * limits["canvas_height"]) / y_orig_offseted_max) \ - : 0; - #printf(\ - #"x: %6.2f, y_orig_offsetted: %6.2f, y_orig_max: %6.2f, y_scaled: %6.2f\n", - #x, y_orig_offsetted, y_orig_max, y_scaled); - if (y_scaled > y_scaled_max) y_scaled_max = y_scaled; - if (y_scaled < y_scaled_min) y_scaled_min = y_scaled; - data_out[x] = y_scaled - } - - # Save limits - limits["y_min"] = y_scaled_min; - limits["y_max"] = y_scaled_max; - range_orig = y_orig_max - y_orig_min; - offset_scaled = \ - range_orig > 0 \ - ? round(offset_orig * limits["canvas_height"] / range_orig) \ - : 0; - limits["offset_scaled"] = offset_scaled; - #printf("offset_orig: %f, offset_scaled: %f\n", offset_orig, offset_scaled); -} - -function canvas_init(canvas, width, height, row, col) { - for (row=0; row <= height; row++) { - for (col=0; col <= width; col++) { - canvas[row, col] = char_pad char_blank char_pad; - } - } -} - -function canvas_overlay_highlight_ticks_x(canvas, limits, row, col) { - for (col=limits["canvas_width_y"] - 1; col <= limits["canvas_width"]; col++) { - offset = limits["offset_scaled"]; - #printf("offset: %f\n", offset); - row = 0 + offset; - #row = 0; - canvas[row, col] = char_pad green("-") char_pad; - } -} - -function canvas_overlay_highlight_zero_row(canvas, limits, row, col) { - #print "canvas_overlay_highlight_zero_row"; - for (col=limits["canvas_width_y"] - 1; col <= limits["canvas_width"]; col++) { - offset = limits["offset_scaled"]; - row = 0 + offset; - #printf("col: %6.2f, row: %6.2f, offset: %f\n", col, row, offset); - #row = 0; - canvas[row, col] = char_pad green("-") char_pad; - } -} - -function canvas_overlay_highlight_zero_col(canvas, limits, row, col) { - #print "canvas_overlay_highlight_zero_col"; - for (row=0; row <= limits["canvas_height"]; row++) { - col = limits["canvas_width_y"]; # was also -1. Why? - # TODO: Refactor color/character configs to ease composition - canvas[row, col] = green("|"); - } - canvas[limits["canvas_height"], limits["canvas_width_y"]] = green("+"); - canvas[0 , limits["canvas_width_y"]] = green("+"); -} -function canvas_overlay_highlight_zero(canvas, limits) { - #print "canvas_overlay_highlight_zero"; - canvas[0 + limits["offset_scaled"], 0 + limits["canvas_width_y"]] = green("+"); -} - -function canvas_overlay_data(canvas, data, limits, x_data, x_canvas, y, yi, yj) { - #print "canvas_overlay_data"; - for (x_data in data) { - x_canvas = x_data + limits["canvas_width_y"] + 1; - y = data[x_data]; - # TODO: Would be nice to scale width of all cells to the widest - #point = y; - #printf("canvas_width_y: %6.2f, x0: %6.2f, x1: %6.2f, x: %6.2f, y: %6.2f\n", - #limits["canvas_width_y"], x0, x1, x, y); - # TODO: This special case for 0 is kind of a kludge - can we do better? - canvas[y, x_canvas] = x_data == 0 ? char_point : char_pad char_point char_pad; - - if (y > limits["offset_scaled"]) { - for (yi = y - 1; yi >= limits["offset_scaled"]; yi--) { - #printf("yi: %6.2f\n", yi); - canvas[yi, x_canvas] = x_data == 0 ? orange("|") : char_pad orange("|") char_pad; - } - } else if (y < limits["offset_scaled"]) { - for (yj = limits["offset_scaled"]; yj > y; yj--) { - #printf("yj: %6.2f\n", yj); - canvas[yj, x_canvas] = x_data == 0 ? orange("|") : char_pad orange("|") char_pad; - } - } - } -} - -function canvas_overlay_y_lab(canvas, limits, y_lab_fmt, y_max_str, i) { - y_lab_fmt = "%" limits["canvas_width_y"] - 1 "d "; - y_max_str = sprintf(y_lab_fmt, y_orig_max); - y_min_str = sprintf(y_lab_fmt, y_orig_min); - #printf("y_width: %f, y_max_str: \"%s\", y_min_str: \"%s\"\n", limits["canvas_width_y"], y_max_str, y_min_str); - for (i=1; i<=length(y_max_str); i++) { - canvas[limits["canvas_height"], i - 1] = substr(y_max_str, i, 1); - } - canvas[0 + limits["offset_scaled"], 0 + limits["canvas_width_y"] - 1] = 0; - for (i=1; i<=length(y_min_str); i++) { - canvas[0, i - 1] = substr(y_min_str, i, 1); - } -} - -function canvas_print(canvas, limits, row, col) { - for (row = limits["canvas_height"]; row >= 0; row--) { - for (col = 0; col <= limits["canvas_width"]; col++) { - printf("%s", canvas[row, col]); - } - printf("\n"); - } -} - -END { - # Find maximum y number width - y_orig_min_width = width(y_orig_min); - y_orig_max_width = width(y_orig_max); - if (y_orig_max_width >= y_orig_min_width) { - y_width = y_orig_max_width; - } else { - y_width = y_orig_min_width; - } - limits["canvas_width_y"] = y_width + 1; - limits["canvas_width_x"] = limits["canvas_width"] - limits["canvas_width_y"]; - - data_scaled_x_to_width(data_0, data_1, limits); - data_scaled_y_to_height(data_1, data_2, limits); - - canvas_init(canvas, limits["canvas_width"], limits["canvas_height"]); - canvas_overlay_highlight_zero_row(canvas, limits); - canvas_overlay_highlight_zero_col(canvas, limits); - canvas_overlay_highlight_zero(canvas, limits); - canvas_overlay_y_lab(canvas, limits); - canvas_overlay_data(canvas, data_2, limits); - #for (l in limits) { - #printf("limits[%s] -> %s\n", l, limits[l]); - #} - canvas_print(canvas, limits); -} - -# An even better way to think about scaling: ratios!!! Duh! :-D -# -# val_max / val_current = width / val_scaled -# -# val_max width -# ----------- = ------------ -# val_current val_scaled -# -# val_max * val_scaled = val_current * width -# val_scaled = (val_current * width) / val_max -# -# -# num_data_points width -# ---------------- = ----- -# x 1 -# -# width * x = num_data_points -# x = num_data_points / width -# -# But that is what I already tried, and it is awkward to scale up when -# thinking thsese terms, so it is much better to first route each data -# point to an appropriate bin and then aggregate each bin: -# 1. Route: bins[scale(datum)] -# 2. Aggregate: for bin in bins: for val in bin: aggregate(val)