def plot_histograms()

in src/lookoutequipment/evaluation.py [0:0]


    def plot_histograms(self, nb_cols=3, max_plots=12):
        """
        Once the histograms are computed, we can plot the top N by decreasing 
        ranking distance. By default, this will plot the histograms for the top
        12 signals, with 3 plots per line.
        
        Parameters:
            nb_cols (integer):
                Number of plots to assemble on a given row (default: 3)
            max_plots (integer):
                Number of signal to consider (default: 12)
                
        Returns:
            tuple: tuple containing:
                * A ``matplotlib.pyplot.figure`` where the plots are drawn
                * A ``list of matplotlib.pyplot.Axis`` with each plot drawn here
        """
        # Prepare the figure:
        nb_rows = len(self.df_list.keys()) // nb_cols + 1
        plt.style.use('Solarize_Light2')
        prop_cycle = plt.rcParams['axes.prop_cycle']
        colors = prop_cycle.by_key()['color']
        fig = plt.figure(figsize=(16, int(nb_rows * 3)))
        gs = gridspec.GridSpec(nb_rows, nb_cols, hspace=0.5, wspace=0.25)
        axes = []
        for i in range(max_plots):
            axes.append(fig.add_subplot(gs[i]))

        # Loops through each signal by decreasing distance order:
        i = 0
        for tag, current_rank in tqdm(
            self.rank.items(), 
            total=max_plots, 
            desc='Preparing histograms'
        ):
            # We stop after reaching the number of plots we are interested in:
            if i > max_plots - 1:
                break

            try:
                # Get the anomaly and the normal values from the current signal:
                current_signal_values = self.df_list[tag][tag]
                current_signal_evaluation = self.df_list[tag].loc[self.ts_label_evaluation, tag]
                current_signal_training = self.df_list[tag].loc[self.ts_normal_training, tag]

                # Compute the bin width and bin edges to match the 
                # number of bins we want to have on each histogram:
                bin_width =(np.max(current_signal_values) - np.min(current_signal_values))/self.num_bins
                bins = np.arange(
                    np.min(current_signal_values), 
                    np.max(current_signal_values) + bin_width, 
                    bin_width
                )

                # Add both histograms in the same plot:
                axes[i].hist(current_signal_training, 
                         density=True, 
                         alpha=0.5, 
                         color=colors[1], 
                         bins=bins, 
                         edgecolor='#FFFFFF')
                axes[i].hist(current_signal_evaluation, 
                         alpha=0.5, 
                         density=True, 
                         color=colors[5], 
                         bins=bins, 
                         edgecolor='#FFFFFF')

            except Exception as e:
                print(e)
                axes[i] = plt.subplot(gs[i])

            # Removes all the decoration to leave only the histograms:
            axes[i].grid(False)
            axes[i].get_yaxis().set_visible(False)
            axes[i].get_xaxis().set_visible(False)

            # Title will be the tag name followed by the score:
            title = tag
            title += f' (score: {current_rank:.02f})'
            axes[i].set_title(title, fontsize=10)

            i+= 1
            
        return fig, axes