Skip to content
Extraits de code Groupes Projets
histogram.py 5,21 ko
Newer Older
  • Learn to ignore specific revisions
  • import numpy as np
    import matplotlib.pyplot as plt
    import random, csv
    
    class Histogram:
        def __init__(self, n_bins = 0, a = 0, b = 0):
            """Crée un histograme de n_bins réparties uniformément entre a et b"""
            self._data = [0 for i in range(n_bins)]
            self._n_bins = n_bins
            self._a = a
            self._b = b
            self._cached_integral = None
    
        def fill(self, x):
            """Remplis la bin correspondant à la valeur 'x'"""
            self._cached_integral = None
            bin_number = int((x-self._a)*self._n_bins/(self._b-self._a))
            if bin_number >= 0 and bin_number < self._n_bins:
                self._data[bin_number] += 1
                return bin_number
            else:
                print("Warning, {} out of bounds.".format(x))
                return -1
    
        def get_maximum(self):
            """Retourne le maximum de l'histogramme"""
            maximum = self._data[0]
            for x in self._data[1:]:
                if x > maximum:
                    maximum = x
            return maximum
        
        def get_bin_center(self,bin_id):
            """Returns center of bin 'bin_id'"""
            return self._a+(bin_id+0.5)*(self._b-self._a)/self._n_bins
    
        def draw(self):
            """Affiche l'histogramme en console"""
            y_max = self.get_maximum()
            scale = 1.
            if y_max > 50:
                scale = 50*1./y_max
                y_max = 50
            # vertical axis : 50 pxl
            y = y_max + 1
            while y > 0:
                to_print = ""
                if (y == y_max+1):
                    to_print = "y ^"
                else:
                    to_print = "  |"
    
                for x in range(self._n_bins):
                    if self._data[x] >= y/scale:
                        to_print += "#"
                    else:
                        to_print += " "
                print (to_print)
                y-=1
    
            print (" -"+"+"+(self._n_bins-1)*"-"+">")
            print ("  |"+(self._n_bins-1)*" "+"x")
            if scale != 1:
                print ("y-axis scale : 1 # = {}".format(1./scale))
                
        def save(self, file_name):
            """Save histogram as CSV file"""
            with open(file_name,'w') as file:
                writer = csv.writer(file)
                writer.writerow(["bin id","bin center", "n entries"])
                bin_size = (self._b - self._a)*1./self._n_bins
                for bin_id, bin_content in enumerate(self._data):
                    writer.writerow([bin_id, self._a+(bin_id+0.5)*bin_size, bin_content])
                    
                    
        def load(self, file_name):
            """Read histogram from CSV file"""
            self._data = []
            line_id           = 0
            first_bin_center  = 0
            second_bin_center = 0
            with open(file_name,'r') as file:
                reader = csv.reader(file)
                for row in reader:
                    line_id += 1
                    if line_id == 1:
                        #Skipping line containing column titles
                        continue
                    else:
                        if line_id == 2:
                            first_bin_center = float(row[1])
                        elif line_id == 3:
                            second_bin_center = float(row[1])
                            
                        self._data.append(float(row[2]))
            bin_width = second_bin_center - first_bin_center
            self._a = first_bin_center-0.5*bin_width
            self._b = self._a + len(self._data) * bin_width
            self._n_bins = len(self._data)
            
        def print(self):
            print(len(self._data))
            print(self._data)
            
            bin_size = (self._b - self._a)*1./self._n_bins
            bins = [self._a + i*bin_size for i in range(len(self._data))]
            print(bins)
            plt.hist(bins[:],bins,weights = self._data)
            plt.show()
    
        
        def _compute_integral(self):
            """Computes the integral of the histogram"""
            self._cached_integral = [ 0 for i in self._data]
            for index, value in enumerate(self._data):
                if index == 0:
                    self._cached_integral[0] = value
                else:
                    self._cached_integral[index] = self._cached_integral[index-1]+value
            
        def get_integral(self, a = -1, b = -1):
            """Returns integral between bin ]a and b]"""
            if self._cached_integral == None:
                self._compute_integral()
            if b < 0:
                b = len(self._data)-1
            if a < 0:
                return self._cached_integral[b]
            else:
                return self._cached_integral[b]-self._cached_integral[a]
        
        def get_random(self):
            if self._cached_integral == None:
                self._compute_integral()
            
            yy = random.random()*self._cached_integral[-1]
            
            for xx_bin, integ in enumerate(self._cached_integral):
                
                if integ >= yy:
                    return self.get_bin_center(xx_bin)
            
            TypeError("This state should never be reached.")
            
        
        def fill_random(self, histo, n_entries):
            """Fills this histogram n times following 'histo' distribution"""
            for i in range(n_entries):
                self.fill(histo.get_random())
            
        def get_average(self):
            """Returns average of histogram"""
            av = 0
            for index, value in enumerate(self._data):
                av += self.get_bin_center(index)*value
            return av*1./self.get_integral()