"""File: histo.py Purpose: Construct a histogram of a user-input collection of values Run: python histo.py Input: n: number of user-input values vals: the values from which a histogram will be constructed (floats) b: number of bars in the user-input collection min_v: the smallest possible value considered in the histogram. Note that it's possible that min_v > min(vals). max_v: the largest possible value considered in the histogram. Note that it's possible that max_v < max(vals). Output: A histogram of X's with b bars covering the values in vals that are >= min_v and < max_v """ verbose = True #---------------------------------------------------------------------- def get_vals(vals, n): """Read the n user-input values into the vals list""" print "Enter the values, one per line" for i in range(n): x = float(raw_input("")) vals.append(x) if verbose: print "vals =", vals #---------------------------------------------------------------------- def bar_bounds(bounds, b, min_v, max_v): """Find the upper bound for each bar""" bar_width = (max_v - min_v)/b for i in range(1, b+1): bounds.append(min_v + i*bar_width) if verbose: print "bounds =", bounds #---------------------------------------------------------------------- def find_subint(x, min_v, bounds): """Determine which bin the value x belongs to""" if x < min_v or x >= bounds[len(bounds)-1]: return None for i in range(len(bounds)): if x < bounds[i]: return i return None # Never executed #---------------------------------------------------------------------- def bar_heights(vals, min_v, bounds, bar_counts): """Determine the number of values in each subinterval""" for x in vals: subint = find_subint(x, min_v, bounds) if subint != None: bar_counts[subint] = bar_counts[subint] + 1 if verbose: print "bar_counts =", bar_counts #---------------------------------------------------------------------- def find_int_len(x): """Determine the number of characters to the left of the decimal point in the float x""" count = 0 y = abs(int(x)) while y > 0: y = y/10 count = count+1 if x < 0: count = count+1 return count #---------------------------------------------------------------------- def create_format(min_val, max_val): """Create a format string that can be used to print the upper and lower bounds of the bars""" len_min = find_int_len(min_val) len_max = find_int_len(max_val) if len_min > len_max: field_width = len_min+2 # For decimal and one place to right of decimal else: field_width = len_max+2 # For decimal and one place to right of decimal format_s = '%' + str(field_width) + '.1f' return format_s #---------------------------------------------------------------------- def print_histo(min_v, bounds, bar_counts): """Print each subinterval and a bar indicating the number of values that fall in the subinterval""" s = create_format(min_v, bounds[len(bounds)-1]) for i in range(len(bounds)): upper_bound = bounds[i] if i == 0: lower_bound = min_v else: lower_bound = bounds[i-1] bar = bar_counts[i]*'X' print s % lower_bound, "--", s % upper_bound, bar #---------------------------------------------------------------------- # Main program # Get data n = int(raw_input("How many values will you input?\n ")) vals = [] get_vals(vals, n) # Get histogram information b = int(raw_input("How many bars should there be in the histogram?\n ")) min_v = float(raw_input("What's the smallest value in the histogram?\n ")) max_v = float(raw_input("What's the largest value in the histogram?\n ")) bounds = [] bar_bounds(bounds, b, min_v, max_v) bar_counts = [0]*b # Count number of values in each subinterval bar_heights(vals, min_v, bounds, bar_counts) print_histo(min_v, bounds, bar_counts)