/* * histogram.c * * Quick histogram functions * * Copyright © 2013-2020 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. * * Authors: * 2013-2014 Thomas White * * This file is part of CrystFEL. * * CrystFEL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * CrystFEL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CrystFEL. If not, see . * */ #include #include #include #include #include #include "histogram.h" /** \file histogram.h */ struct _histogram { int n_vals; int max_vals; double *vals; double min; double max; int full; int n_bins; double bin_width; int *bins; int plot_height; int peak; double mean; double stddev; }; Histogram *histogram_init() { Histogram *hi; hi = malloc(sizeof(struct _histogram)); if ( hi == NULL ) return NULL; hi->n_vals = 0; hi->max_vals = 0; hi->vals = NULL; hi->full = 0; hi->max = -INFINITY; hi->min = INFINITY; hi->bins = NULL; hi->n_bins = 50; hi->plot_height = 10; return hi; } void histogram_free(Histogram *hi) { free(hi); } void histogram_add_value(Histogram *hi, double val) { if ( hi->n_vals == hi->max_vals ) { double *new_vals; new_vals = realloc(hi->vals, (hi->max_vals+512)*sizeof(double)); if ( new_vals == NULL ) { hi->full = 1; fprintf(stderr, "Histogram %p full.\n", hi); return; } hi->max_vals += 512; hi->vals = new_vals; } hi->vals[hi->n_vals++] = val; if ( val > hi->max ) hi->max = val; if ( val < hi->min ) hi->min = val; } static void calc_bins(Histogram *hi) { int i; if ( hi->bins != NULL ) { free(hi->bins); } hi->bins = calloc(hi->n_bins, sizeof(int)); if ( hi->bins == NULL ) { fprintf(stderr, "Failed to allocate bins.\n"); return; } hi->bin_width = (hi->max - hi->min)/hi->n_bins; for ( i=0; in_vals; i++ ) { int j; j = (hi->vals[i] - hi->min) / hi->bin_width; /* Tidy up rounding errors */ if ( j < 0 ) j = 0; if ( j >= hi->n_bins ) j = hi->n_bins - 1; hi->bins[j]++; } hi->peak = 0; for ( i=0; in_bins; i++ ) { if ( hi->bins[i] > hi->peak ) hi->peak = hi->bins[i]; } } static void calc_stddev(Histogram *hi) { double sum = 0.0; int i; for ( i=0; in_vals; i++ ) { sum += hi->vals[i]; } hi->mean = sum / hi->n_vals; sum = 0.0; for ( i=0; in_vals; i++ ) { sum += pow(hi->vals[i] - hi->mean, 2.0); } hi->stddev = sqrt(sum / hi->n_vals); } int *histogram_get_data(Histogram *hi, int *n) { calc_bins(hi); *n = hi->n_bins; return hi->bins; } void histogram_show(Histogram *hi) { int i; int *bins; double lines_per_count; char tmp[32]; size_t n_left, n_mid, n_right; calc_bins(hi); calc_stddev(hi); bins = malloc(hi->n_bins*sizeof(int)); if ( bins == NULL ) { fprintf(stderr, "Couldn't scale bins\n"); return; } lines_per_count = (double)hi->plot_height / hi->peak; for ( i=0; in_bins; i++ ) { bins[i] = hi->bins[i] * lines_per_count; } for ( i=hi->plot_height-1; i>=0; i-- ) { int j; for ( j=0; jn_bins; j++ ) { if ( bins[j] > i ) { printf("*"); } else { printf(" "); } } printf("\n"); } printf("|"); for ( i=1; in_bins-1; i++ ) { double bin_low, bin_high; bin_low = hi->min + i*hi->bin_width; bin_high = hi->min + (i+1)*hi->bin_width; if ( (bin_low < 0.0) && (bin_high > 0.0) ) { printf("+"); } else { printf("-"); } } printf("|\n"); snprintf(tmp, 31, "%.2f", hi->min); n_left = strlen(tmp); snprintf(tmp, 31, "%.2f", hi->max); n_right = strlen(tmp); n_mid = hi->n_bins - (n_left + n_right); printf("%.2f", hi->min); for ( i=0; imax); printf("Mean = %.2f, Std dev = %.2f\n", hi->mean, hi->stddev); free(bins); } double histogram_get_min(Histogram *hi) { return hi->min; } double histogram_get_max(Histogram *hi) { return hi->max; } int histogram_get_num_bins(Histogram *hi) { return hi->n_bins; } void histogram_set_min(Histogram *hi, double min) { hi->min = min; } void histogram_set_max(Histogram *hi, double max) { hi->max = max; } void histogram_set_num_bins(Histogram *hi, int n) { hi->n_bins = n; }