home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------
- * The GMT-system: @(#)pshistogram.c 2.22 3/13/95
- *
- * Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith
- * See README file for copying and redistribution conditions.
- *--------------------------------------------------------------------*/
- /*
- * pshistogram.c -- a program for plotting histograms
- *
- *
- * Author: Walter H. F. Smith
- * Date: 15 February, 1988
- *
- * Updated to v2.0 5-May-1991 Paul Wessel
- * Updated to v3.0 1-Jan-1995 Paul Wessel
- *
- */
-
- #include "gmt.h"
-
- #define COUNTS 0
- #define FREQ_PCT 1
- #define LOG_COUNTS 2
- #define LOG_FREQ_PCT 3
-
- double yy0, yy1, xmin, xmax;
-
- float *x;
- int *boxh;
-
- int n = 0;
- int n_boxes = 0;
- int n_counted = 0;
- double box_width = 0.0;
- double west = 0.0, east = 0.0, south = 0.0, north = 0.0;
- float stats[6];
-
- FILE *fp_in = NULL;
-
- char buffer[512];
-
- int center_box = FALSE, cumulative = FALSE, draw_outline = FALSE;
- int second = FALSE, hist_type = COUNTS;
-
- struct PEN pen;
- struct FILL fill;
-
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- int i;
- int inquire = FALSE, error = FALSE, automatic = FALSE, stairs = FALSE;
- double tmp;
-
- argc = gmt_begin (argc, argv);
-
- gmt_init_pen (&pen, 1);
- gmt_init_fill (&fill, 0, 0, 0);
-
- for (i = 1; i < argc; i++) {
- if (argv[i][0] == '-') {
- switch (argv[i][1]) {
-
- /* Common parameters */
-
- case 'B':
- case 'H':
- case 'J':
- case 'K':
- case 'O':
- case 'P':
- case 'R':
- case 'U':
- case 'V':
- case 'X':
- case 'x':
- case 'Y':
- case 'y':
- case 'c':
- case '\0':
- error += get_common_args (argv[i], &west, &east, &south, &north);
- break;
-
- /* Supplemental parameters */
-
- case '2':
- second = TRUE;
- break;
- case 'C':
- center_box = TRUE;
- break;
- case 'E':
- sscanf (&argv[i][2], "%lf/%lf", &z_project.view_azimuth, &z_project.view_elevation);
- break;
- case 'G':
- if (gmt_getfill (&argv[i][2], &fill)) {
- gmt_fill_syntax ('G');
- error++;
- }
- break;
- case 'L': /* Set line attributes */
- if (gmt_getpen (&argv[i][2], &pen)) {
- gmt_pen_syntax ('L');
- error++;
- }
- draw_outline = TRUE;
- break;
- case 'I':
- inquire = TRUE;
- break;
- case 'Q':
- cumulative = TRUE;
- break;
- case 'S':
- stairs = TRUE;
- break;
- case 'W':
- box_width = atof (&argv[i][2]);
- break;
- case 'Z':
- hist_type = atoi (&argv[i][2]);
- break;
- default:
- error = TRUE;
- gmt_default_error (argv[i][1]);
- break;
- }
- }
- else {
- if ((fp_in = fopen(argv[i], "r")) == NULL) {
- fprintf (stderr, "pshistogram: Cannot open file %s\n", argv[i]);
- exit(-1);
- }
- }
- }
-
- if (argc == 1 || gmt_quick) {
- fprintf (stderr,"pshistogram %s - Calculate and plot histograms\n\n", GMT_VERSION);
- fprintf (stderr, "usage: pshistogram [file] -Jx<scale> -W [-2] [-B<tickinfo>] [-C] [-Eaz/el] [-G<fill>]\n");
- fprintf (stderr, " [-H] [-I] [-K] [-L<pen>] [-O] [-P] [-Q] [-Rw/e/s/n] [-S] [-U[text]] [-V]\n");
- fprintf (stderr, " [-X<x_shift>] [-Y<y_shift>] [-Z[type]] [-c<ncopies>]\n\n");
-
- if (gmt_quick) exit(-1);
- fprintf (stderr, " -Jx for linear projection. Scale in %s/units\n", gmt_unit_names[gmtdefs.measure_unit]);
- fprintf (stderr, " Use / to specify separate x/y scaling.\n");
- fprintf (stderr, " If -JX is used then give axes lengths rather than scales\n");
-
- fprintf (stderr, " -W sets the bin width\n");
- fprintf (stderr, "\n\tOPTIONS:\n");
- fprintf (stderr, " -2 read second rather than first column\n");
- explain_option ('b');
- fprintf (stderr, " -C will center the bins\n");
- fprintf (stderr, " -E set azimuth and elevation of viewpoint for 3-D perspective [180/90]\n");
- fprintf (stderr, " -G specify Grayshade for columns.\n");
- fprintf (stderr, " Grayshade range is black (0) through white (255). For color fill, use\n");
- fprintf (stderr, " -Gr/g/b, where r, g, and b each range from 0 to 255\n");
- explain_option ('H');
- fprintf (stderr, " -I will inquire about min/max x and y. No plotting is done\n");
- explain_option ('K');
- fprintf (stderr, " -L <pen> is penwidth. Specify r/g/b for colored line.\n");
- fprintf (stderr, " Append O for dOtted line, A for dAshed [Default = 1, black, solid]\n");
- explain_option ('O');
- explain_option ('P');
- fprintf (stderr, " -Q plot a cumulative histogram\n");
- explain_option ('r');
- fprintf (stderr, " If neither -R nor -I are set, w/e/s/n will be based on input data\n");
- fprintf (stderr, " -S Draws a stairs-step diagram instead of histogram.\n");
- explain_option ('U');
- explain_option ('V');
- explain_option ('X');
- fprintf (stderr, " -Z to choose type of vertical axis. Select from\n");
- fprintf (stderr, " 0 - Counts [Default]\n");
- fprintf (stderr, " 1 - Frequency percent\n");
- fprintf (stderr, " 2 - Log10 (counts)\n");
- fprintf (stderr, " 3 - Log10 (frequency percent)\n");
- explain_option ('c');
- explain_option ('.');
-
- exit(-1);
- }
-
- if (project_info.projection < 0 || project_info.projection > 9) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -J option: Only linear projection supported.\n", gmt_program);
- error++;
- }
- if (z_project.view_azimuth > 360.0 || z_project.view_elevation <= 0.0 || z_project.view_elevation > 90.0) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -E option: Enter azimuth in 0-360 range, elevation in 0-90 range\n", gmt_program);
- error++;
- }
- if (hist_type < COUNTS || hist_type > LOG_FREQ_PCT) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -Z option: histogram type must be 0, 1, 2, or 3\n", gmt_program);
- error++;
- }
- if (box_width <= 0.0) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -W option: bin width must be nonzero\n", gmt_program);
- error++;
- }
-
- if (error) exit (-1);
-
- if (inquire) gmtdefs.verbose = TRUE;
- if (!inquire && (west == east || south == north)) automatic = TRUE;
-
- if (fp_in == NULL) fp_in = stdin;
-
- if ( read_data() ) {
- fprintf (stderr, "pshistogram: Fatal error, read only 0 points.\n");
- exit (-1);
- }
-
- if (gmtdefs.verbose) {
- fprintf (stderr, "pshistogram: Extreme values of the data :\t%lg\t%lg\n", x[0], x[n-1]);
- fprintf (stderr, "pshistogram: Locations: L2, L1, LMS; Scales: L2, L1, LMS\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
- stats[0], stats[1], stats[2], stats[3], stats[4], stats[5]);
- }
-
- if (west == east) { /* Set automatic x range [ and tickmarks] */
- if (frame_info.anot_int[0] == 0.0) {
- tmp = pow (10.0, floor (d_log10 (xmax-xmin)));
- if (((xmax-xmin) / tmp) < 3.0) tmp *= 0.5;
- }
- else
- tmp = frame_info.anot_int[0];
- west = floor (xmin / tmp) * tmp;
- east = ceil (xmax / tmp) * tmp;
- if (frame_info.anot_int[0] == 0.0) {
- frame_info.anot_int[0] = frame_info.frame_int[0] = tmp;
- frame_info.plot = TRUE;
- }
- }
-
- if ( fill_boxes () ) {
- fprintf (stderr, "pshistogram: Fatal error during box fill.\n");
- exit (-1);
- }
-
- if (gmtdefs.verbose) fprintf (stderr, "\npshistogram: min/max values are :\t%lg\t%lg\t%lg\t%lg\n", xmin, xmax, yy0, yy1);
-
- if (inquire) { /* Only info requested, quit before plotting */
- free((char *) x);
- free((char *) boxh);
- exit (0);
- }
-
- if (automatic) { /* Set up s/n based on 'clever' rounding up of the minmax values */
- project_info.region = TRUE;
- south = 0.0;
- if (frame_info.anot_int[1] == 0.0) {
- tmp = pow (10.0, floor (d_log10 (yy1)));
- if ((yy1 / tmp) < 3.0) tmp *= 0.5;
- }
- else
- tmp = frame_info.anot_int[1];
- north = ceil (yy1 / tmp) * tmp;
- if (frame_info.anot_int[1] == 0.0) { /* Tickmarks not set */
- frame_info.anot_int[1] = frame_info.frame_int[1] = tmp;
- frame_info.plot = TRUE;
- }
- if (project_info.pars[0] == 0.0) { /* Must give default xscale */
- project_info.pars[0] = gmtdefs.x_axis_length / (east - west);
- project_info.projection = LINEAR;
- }
- if (project_info.pars[1] == 0.0) { /* Must give default yscale */
- project_info.pars[1] = gmtdefs.y_axis_length / north;
- project_info.projection = LINEAR;
- }
- }
-
- if (automatic && gmtdefs.verbose) fprintf (stderr, "pshistogram: Use w/e/s/n = %lg/%lg/%lg/%lg and x-tic/y-tick = %lg/%lg\n",
- west, east, south, north, frame_info.anot_int[0], frame_info.anot_int[1]);
-
- map_setup (west, east, south, north);
-
- ps_plotinit (CNULL, gmtdefs.overlay, gmtdefs.page_orientation, gmtdefs.x_origin, gmtdefs.y_origin,
- gmtdefs.global_x_scale, gmtdefs.global_y_scale, gmtdefs.n_copies,
- gmtdefs.dpi, gmtdefs.measure_unit, gmtdefs.paper_width, gmtdefs.page_rgb, gmt_epsinfo (argv[0]));
- echo_command (argc, argv);
- if (gmtdefs.unix_time) timestamp (argc, argv);
-
- if (project_info.three_D) ps_transrotate (-z_project.xmin, -z_project.ymin, 0.0);
-
- map_clip_on (-1, -1, -1, 3);
- if ( plot_boxes (stairs) ) {
- fprintf (stderr, "pshistogram: Fatal error during box plotting.\n");
- exit (-1);
- }
-
- map_clip_off();
-
- if (frame_info.plot) {
- ps_setpaint (gmtdefs.basemap_frame_rgb[0], gmtdefs.basemap_frame_rgb[1], gmtdefs.basemap_frame_rgb[2]);
- map_basemap ();
- }
- ps_setpaint (0, 0, 0);
-
- if (project_info.three_D) ps_rotatetrans (z_project.xmin, z_project.ymin, 0.0);
- ps_plotend (gmtdefs.last_page);
-
- free((char *) x);
- free((char *) boxh);
-
- gmt_end (argc, argv);
- }
-
- int read_data () {
- int i, n_alloc = GMT_CHUNK;
- float tmp;
-
- x = (float *) memory (CNULL, n_alloc , sizeof (float), "pshistogram");
-
- n = 0;
- xmin = MAXDOUBLE; xmax = -MAXDOUBLE;
-
- if (gmtdefs.io_header) for (i = 0; i < gmtdefs.n_header_recs; i++) fgets (buffer, 512, fp_in);
-
- while (fgets (buffer, 512, fp_in)) {
-
- /* Check for a blank line */
-
- if (buffer[0] == '\0') continue;
-
- if (sscanf(buffer, "%f %f", &x[n], &tmp) ) {
- if (second) x[n] = tmp;
- n++;
- }
- if (n == n_alloc) {
- n_alloc += GMT_CHUNK;
- x = (float *) memory ((char *)x, n_alloc , sizeof (float), "pshistogram");
- }
- xmin = MIN (xmin, x[n-1]);
- xmax = MAX (xmax, x[n-1]);
- }
-
- if (gmtdefs.verbose) fprintf (stderr,"N points read:\t%d\n", n);
-
- x = (float *) memory ((char *)x, n , sizeof (float), "pshistogram");
- if (fp_in != stdin) fclose (fp_in);
-
- get_loc_scl (x, n, stats);
-
- return( !(n) );
- }
-
- int fill_boxes () {
-
- double add_half = 0.0;
-
- int b0, b1, i, ibox, count_sum;
-
- n_boxes = ceil( (east - west) / box_width);
-
- if (center_box) {
- n_boxes++;
- add_half = 0.5;
- }
-
- if (n_boxes <= 0) return (-1);
-
- boxh = (int *) memory (CNULL, n_boxes , sizeof (int), "pshistogram");
-
- n_counted = 0;
-
- /* First fill boxes with counts */
-
- for (i = 0; i < n; i++) {
- ibox = floor( ( (x[i] - west) / box_width) + add_half);
- if (ibox < 0 || ibox >= n_boxes) continue;
- boxh[ibox] ++;
- n_counted++;
- }
-
- if (cumulative) {
- count_sum = 0;
- for (ibox = 0; ibox < n_boxes; ibox++) {
- count_sum += boxh[ibox];
- boxh[ibox] = count_sum;
- }
- b0 = 0;
- b1 = count_sum;
- }
- else {
- b0 = n_counted;
- b1 = 0;
- for (ibox = 0; ibox < n_boxes; ibox++) {
- if (b0 > boxh[ibox]) b0 = boxh[ibox];
- if (b1 < boxh[ibox]) b1 = boxh[ibox];
- }
- }
-
- /* Now find out what the min max y will be */
-
- if (b0) {
- if (hist_type == LOG_COUNTS)
- yy0 = d_log1p( (double)b0);
- else if (hist_type == FREQ_PCT)
- yy0 = (100.0 * b0) / n_counted;
- else if (hist_type == LOG_FREQ_PCT)
- yy0 = d_log1p( 100.0 * b0 / n_counted );
- else
- yy0 = b0;
- }
- else {
- yy0 = 0;
- }
- if (b1) {
- if (hist_type == LOG_COUNTS)
- yy1 = d_log1p( (double)b1);
- else if (hist_type == FREQ_PCT)
- yy1 = (100.0 * b1) / n_counted;
- else if (hist_type == LOG_FREQ_PCT)
- yy1 = d_log1p( 100.0 * b1 / n_counted );
- else
- yy1 = b1;
- }
- else {
- yy1 = 0;
- }
- return (0);
- }
-
- int plot_boxes (stairs)
- BOOLEAN stairs;
- {
-
- int i, ibox, first = FALSE;
-
- double x[4], y[4], xx, yy;
-
- if (draw_outline) {
- ps_setline (pen.width);
- ps_setpaint (pen.r, pen.g, pen.b);
- if (pen.texture) ps_setdash (pen.texture, pen.offset);
- }
-
- for (ibox = 0; ibox < n_boxes; ibox++) {
- if (stairs || boxh[ibox]) {
- x[0] = west + ibox * box_width;
- if (center_box) x[0] -= (0.5 * box_width);
- x[1] = x[0] + box_width;
- if (x[0] < west) x[0] = west;
- if (x[1] > east) x[1] = east;
- x[2] = x[1];
- x[3] = x[0];
- y[0] = y[1] = south;
- if (hist_type == LOG_COUNTS)
- y[2] = d_log1p( (double)boxh[ibox]);
- else if (hist_type == FREQ_PCT)
- y[2] = (100.0 * boxh[ibox]) / n_counted;
- else if (hist_type == LOG_FREQ_PCT)
- y[2] = d_log1p( 100.0 * boxh[ibox] / n_counted );
- else
- y[2] = boxh[ibox];
- y[3] = y[2];
-
- for (i = 0; i < 4; i++) {
- geo_to_xy (x[i], y[i], &xx, &yy);
- if (project_info.three_D) xyz_to_xy (xx, yy, project_info.z_level, &xx, &yy);
- x[i] = xx; y[i] = yy;
- }
-
- if (stairs) {
- if (first) {
- first = FALSE;
- ps_plot (x[0], y[0], 2);
- }
- ps_plot (x[3], y[3], 3);
- ps_plot (x[2], y[2], 3);
- }
- else if (fill.use_pattern)
- ps_imagefill (x, y, 4, fill.pattern_no, fill.pattern, fill.inverse, fill.icon_size, draw_outline);
- else
- ps_polygon (x, y, 4, fill.r, fill.g, fill.b, draw_outline);
- }
- }
-
- if (stairs) ps_plot (x[1], y[1], 3);
-
- if (draw_outline && pen.texture) ps_setdash (CNULL, 0);
-
- return(0);
- }
-
- int get_loc_scl (x, n, stats)
- float x[], stats[]; /* L2, L1, LMS location, L2, L1, LMS scale */
- int n;
- {
-
- int i, j, istop, multiplicity = 1, compx();
- double xsum = 0.0, x2sum = 0.0, mid_point_sum = 0.0, length, short_length = 1.0e+30;
-
- if (n < 3) return(-1);
-
- qsort((char *) x, n, sizeof(float), compx);
-
- j = n/2;
-
- if (n%2)
- stats[1] = x[j];
- else
- stats[1] = 0.5 * (x[j] + x[j-1]);
-
- istop = n - j;
- for (i = 0; i < istop; i++) {
- length = x[i + j] - x[i];
- if (length == short_length) {
- multiplicity++;
- mid_point_sum += (0.5 * (x[i + j] + x[i]) );
- }
- else if (length < short_length) {
- multiplicity = 1;
- mid_point_sum = (0.5 * (x[i + j] + x[i]) );
- short_length = length;
- }
- }
- if (multiplicity > 1) mid_point_sum /= multiplicity;
- stats[2] = mid_point_sum;
-
- getmad (x, n, &stats[1], &stats[4]);
- getmad (x, n, &stats[2], &stats[5]);
-
- for (i = 0; i < n; i++) {
- xsum += x[i];
- x2sum += (x[i] * x[i]);
- }
- stats[0] = xsum / n;
- stats[3] = sqrt( (n * x2sum - xsum * xsum) / (n * (n - 1) ) );
-
- return(0);
- }
-
- int getmad (x, n, location, scale)
- float x[], *location, *scale;
- int n;
- {
- double e_low, e_high, error, last_error;
- int i_low, i_high, n_dev, n_dev_stop;
-
- i_low = 0;
- while (i_low < n && x[i_low] <= *location) i_low++;
- i_low--;
-
- i_high = n - 1;
- while (i_high >= 0 && x[i_high] >= *location) i_high--;
- i_high++;
-
- n_dev_stop = n / 2;
- error = 0.0;
- n_dev = 0;
-
-
- while (n_dev < n_dev_stop) {
-
- last_error = error;
-
- if (i_low < 0) {
- error = x[i_high] - *location;
- i_high++;
- n_dev++;
- }
-
- else if (i_high == n) {
- error = *location - x[i_low];
- i_low--;
- n_dev++;
- }
- else {
- e_low = *location - x[i_low];
- e_high = x[i_high] - *location;
-
- if (e_low < e_high) {
- error = e_low;
- i_low--;
- n_dev++;
- }
- else if (e_high < e_low) {
- error = e_high;
- i_high++;
- n_dev++;
- }
- else {
- error = e_high;
- i_low--;
- i_high++;
- if ( !(n_dev)) n_dev--; /* First time count only once */
- n_dev += 2;
- }
- }
- }
-
- if (n%2)
- *scale = 1.4826 * error;
- else
- *scale = 0.7413 * (error + last_error);
-
- return (0);
- }
-
- int compx (p1, p2)
- float *p1, *p2;
- {
- if ( (*p1) < (*p2) )
- return(-1);
- else if ( (*p1) > (*p2) )
- return(1);
- else
- return(0);
- }
-
-