Exemple #1
0
    def plot(self):

        if self._ratio_plot:
            gs = gridspec.GridSpec(nrows=2, ncols=1, height_ratios=[3, 1], wspace=1.08, hspace=0., bottom=0.12, left=0.18) 
            # gs.update(wspace=0.1, hspace=0.1, left=0.1, right=0.4, bottom=0.1, top=0.9) 
            # gs.update(hspace=0.05) # set the spacing between axes. 
            # gs.update(left=0.05, right=0.48, wspace=0.05)
            # self._plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9)

            
            ax0 = self._plt.subplot(gs[0])
            ax1 = self._plt.subplot(gs[1])
        else:
            ax0 = self._plt.gca()

        # Set the logo.lin
        ax0.add_artist(self.logo_box())

        # Set basic plot element formattings. lin
        self.set_formatting()

        # Normalize all the histograms.
        self.normalize_hists()


        z_indices = range(len(self._hists), 0, -1)
        
        if "error" in self._plot_types:
            z_indices[self._plot_types.index("error")] *= 10

        if "theory" in self._plot_types:
            z_indices[self._plot_types.index("theory")] *= 5

        # First, draw the regular "non-ratio" plot.


        legend_handles = []
        for i in range(len(self._hists)):

            plot_type = self._plot_types[i]

            if plot_type == 'hist':

                #print("this is hist")
            
                #self._hists[i].hist().SetLineStyle(self._line_styles[i])

                plot = self._rplt.hist(self._hists[i].hist(), axes=ax0, zorder=z_indices[i], emptybins=False)
                plot[1].set_dashes(self._line_styles[i])
                legend_handles.append( plot )

                # print legend_handles[i][1].get_dashes()
            
            elif plot_type == 'error':
            
                plot = self._rplt.errorbar(self._hists[i].hist(), axes=ax0, zorder=z_indices[i], emptybins=False, xerr=1, yerr=1, ls='None', marker='o', markersize=10, pickradius=8, capthick=5, capsize=8, elinewidth=5, alpha=1.0)
                legend_handles.append( plot )
            
            elif plot_type == "theory":

                if self._x_scale == "log":
                    x_s = np.exp( self._hists[i][0] )
                else:
                    
                    x_s = self._hists[i][0]

                # There are two portions of x. 
                # Find the index where we need to switch.
                np_correction_index = 0
                for ab in range(len(x_s)):
                    if x_s[ab] > self.get_np_correction_boundary():
                        np_correction_index = ab
                        break


                # print np_correction_index, self.get_np_correction_boundary()
                # print x_s
                
                y_line_s = self._hists[i][2]
                y_min_s = self._hists[i][1]
                y_max_s = self._hists[i][3]

                # print x_s[ : np_correction_index]
                # Distribution.
                ax0.plot(x_s[ : np_correction_index + 1], y_line_s[ : np_correction_index + 1], lw=12, zorder=z_indices[i], color=self._plot_colors[i], ls="dotted")


                

                if "Track" not in self._x_label: 
                    ax0.plot(x_s[np_correction_index : ], y_line_s[np_correction_index : ], lw=8, zorder=z_indices[i], color=self._plot_colors[i])
                    ax0.fill_between(x_s[np_correction_index : ], y_max_s[np_correction_index : ], y_min_s[np_correction_index : ], zorder=z_indices[i], where=np.less_equal(y_min_s[np_correction_index : ], y_max_s[np_correction_index : ]), facecolor=self._plot_colors[i], color=self._plot_colors[i], interpolate=True, alpha=0.2, linewidth=0.)
                else:
                    ax0.plot(x_s[np_correction_index : ], y_line_s[np_correction_index : ], ls="dotted", lw=12, zorder=z_indices[i], color=self._plot_colors[i])


                theory_min_interpolate_function = self.extrap1d(interpolate.interp1d(x_s, y_min_s))
                theory_line_interpolate_function = self.extrap1d(interpolate.interp1d(x_s, y_line_s))
                theory_max_interpolate_function = self.extrap1d(interpolate.interp1d(x_s, y_max_s))

                if self._hists[0].x_range() != (0, -1):
                    
                    # This is important for log plots because we don't want to consider the bins that's not visibile while figuring out how many bins to use for theory.



                    # x_s_to_use = filter( lambda x: x >= self._hists[0].x_range()[0], self._plot_points_x_s[self._plot_types.index("error")] )
                    x_s_to_use = self._plot_points_x_s[self._plot_types.index("error")]
                
                else:
                    x_s_to_use = self._plot_points_x_s[self._plot_types.index("error")]


                theory_extrapolated_min = theory_min_interpolate_function(x_s_to_use)
                theory_extrapolated_line = theory_line_interpolate_function(x_s_to_use)
                theory_extrapolated_max = theory_max_interpolate_function(x_s_to_use)

                # print "the data x points were", (x_s_to_use)
                
            if plot_type == "theory":
                self._plot_points_x_s.append( x_s )
                self._plot_points_y_s.append( [] )
            elif plot_type == "error":
                data_points_x = plot[0].get_xdata()
                data_points_y = plot[0].get_ydata()


                data_plot_points_x = []
                data_plot_points_y = []

                for i in range(0, len(data_points_x)):
                    if float(data_points_x[i]) > 0.0:   # This is just to ignore the points at the 0th bin.
                        data_plot_points_x.append(data_points_x[i])
                        data_plot_points_y.append(data_points_y[i])

                data_x_errors, data_y_errors = [], []
                for x_segment in plot[2][0].get_segments():
                    data_x_errors.append((x_segment[1][0] - x_segment[0][0]) / 2.)
                for y_segment in plot[2][1].get_segments():
                    data_y_errors.append((y_segment[1][1] - y_segment[0][1]) / 2.)

                self._plot_points_x_s.append( data_plot_points_x )
                self._plot_points_y_s.append( data_plot_points_y )

            elif plot_type == "hist":

                
                bin_width = (self._hists[i].hist().upperbound() - self._hists[i].hist().lowerbound()) / self._hists[i].hist().nbins()

                if self._x_scale != "log":
                    data_points_x = [x + bin_width / 2 for x in plot[1].get_xdata()][:-1]
                else:
                    data_points_x = plot[1].get_xdata()[:-1]
                
                data_points_y = plot[1].get_ydata()

                data_plot_points_x = []
                data_plot_points_y = []

                for i in range(0, len(data_points_x)):
                    if float(data_points_x[i]) > 0.0:   # This is just to ignore the points at the 0th bin.
                        data_plot_points_x.append(data_points_x[i])
                        data_plot_points_y.append(data_points_y[i])

                self._plot_points_x_s.append( data_plot_points_x )
                self._plot_points_y_s.append( data_plot_points_y )
                


        if self._y_scale == 'log':
            ax0.set_yscale('log')
            pass


        # Ratio plot.

        if self._ratio_plot:

            if (type(self._ratio_to_index) == dict) or (type(self._ratio_to_index) == int and self._plot_types[self._ratio_to_index] == "hist" or self._plot_types[self._ratio_to_index] == "error"):
                # print "ratio to something else"

                
                for i in range(len(self._hists)):
                    
                    if type(self._ratio_to_index) == int:
                        denominator_hist = self._hists[self._ratio_to_index].hist()
                    elif type(self._ratio_to_index) == dict:
                        denominator_hist = self._hists[self._ratio_to_index[i]].hist()

                    plot_type = self._plot_types[i]

                    ratio_hist = copy.deepcopy( self._hists[i].hist() )

                    #print(ratio_hist.lowerbound())
                    divided_hist = Hist(len(ratio_hist), ratio_hist.lowerbound(), ratio_hist.upperbound())
                    for k in range(len(ratio_hist)):
                        num_val = ratio_hist.GetBinContent(k)
                        denom_val = denominator_hist.GetBinContent(k)
                        #print(i, num_val, denom_val)
                        num_err = ratio_hist.GetBinError(k)
                        denom_err = denominator_hist.GetBinError(k)
                        if denom_val != 0.0:
                            divided_hist.SetBinContent(k+1, num_val*1.0/denom_val)
                            print(i, num_val*1.0/denom_val)
                        if denom_err != 0.0:
                            divided_hist.SetBinError(k+1, num_err*1.0/denom_val)
                            print(i, num_err*1.0/denom_val)


                    divided_hist.SetColor(self._plot_colors[i])
                    #ratio_hist.Divide(denominator_hist)
                    
                    if plot_type == 'hist':
                        plot = self._rplt.hist(divided_hist, axes=ax1, zorder=z_indices[i], emptybins=False, lw=8)
                        print("i", i)
                        plot[1].set_dashes(self._line_styles[i])


                    elif plot_type == 'error':
                        self._rplt.errorbar(divided_hist, axes=ax1, zorder=z_indices[i], emptybins=False, ls='None', marker='o', markersize=10, pickradius=8, capthick=5, capsize=8, elinewidth=5, alpha=1.0)
                        
                        
        # Ratio plot ends.


        handles, labels = legend_handles, self._plot_labels

        handler_map = {}
        if "theory" in self._plot_types:
            
            

            if "Track" not in self._x_label: 
                th_line, = ax0.plot(range(1), linewidth=8, color='red')
                th_patch = mpatches.Patch(facecolor='red', alpha=0.2, linewidth=0., edgecolor='red')

                handles.insert( self._plot_types.index("theory"), (th_patch, th_line))
            else:
                th_line, = ax0.plot(range(1), linewidth=12, ls="dotted", color='red')
                handles.insert( self._plot_types.index("theory"), (th_line, ))
            
            # labels.insert( self._plot_types.index("theory"), self._plot_labels[self._plot_types.index("theory")])

            handler_map[th_line ] = HandlerLine2D(marker_pad=0)

        for i in range(len(handles)):
            if self._plot_types[i] == "hist":
                line, = ax0.plot(range(1), linewidth=8, color=self._plot_colors[i], dashes=self._line_styles[i])
                handles[i] = line

                handler_map[line] = HandlerLine2D(marker_pad=0)
        



        legend = ax0.legend(handles, labels, frameon=0, fontsize=50, handler_map=handler_map, bbox_to_anchor=self._legend_location[1], loc=self._legend_location[0] )
        # legend = ax0.legend(handles, labels, frameon=0, fontsize=60, handler_map=handler_map, bbox_to_anchor=self._legend_location, loc="upper left" )
        ax0.add_artist(legend)

        # Any additional texts.
        extra = Rectangle((0, 0), 1, 1, fc="w", fill=False, edgecolor='none', linewidth=0)
        # ax0.legend([extra]*len(labels), labels, loc=7, frameon=0, borderpad=0.1, fontsize=60, bbox_to_anchor=[1.00, 0.53])


        # get the width of your widest label, since every label will need 
        #to shift by this amount after we align to the right
        shift = max([t.get_window_extent(plt.gcf().canvas.get_renderer()).width for t in legend.get_texts()])


        if self._text_outside_the_frame:
            outside_text = ax0.legend( [extra], ["CMS 2011 Open Data"], frameon=0, borderpad=0, fontsize=50, bbox_to_anchor=(1.0, 1.005), loc='lower right')
            ax0.add_artist(outside_text)

        
        if "Soft Drop" in self._plot_labels[0]:
            additional_text =  self._hists[1].additional_text()
        else:
            additional_text = self._hists[0].additional_text()

        for position, anchor_location, text in additional_text:
            texts = text.split("\n")
            additional_info = ax0.legend( [extra] * len(texts), texts, frameon=0, borderpad=0, fontsize=50, bbox_to_anchor=position, loc=anchor_location)

            if position[0] > 0.30:
                for t in additional_info.get_texts():
                    t.set_ha('right') # ha is alias for horizontalalignment
                    t.set_position((shift,0))
                
            
        # if len()

        

        # Axes labels.

        # ax0.set_xlabel(self._x_label, fontsize=60)

        # if "$" in self._y_label:
        if self._y_label[0] == "$":
            ax0.set_ylabel(self._y_label, fontsize=105, y=0.5, rotation=0, labelpad=120)
        else:
            ax0.set_ylabel(self._y_label, fontsize=65, y=0.5, labelpad=50)

        if self._ratio_plot:
            ax1.set_xlabel(self._x_label, fontsize=70, labelpad=35)
            ax1.set_ylabel(self._ratio_label, fontsize=55, labelpad=25)
        else:
            ax0.set_xlabel(self._x_label, fontsize=70, labelpad=35)

        # Axes labels end.


        self._plt.sca(ax0)

        self._plt.tick_params(which='major', width=5, length=25, labelsize=70)
        self._plt.tick_params(which='minor', width=3, length=15)

        if self._ratio_plot:
            self._plt.sca(ax1)
            
            self._plt.tick_params(which='major', axis='x', width=5, length=25, labelsize=70)
            self._plt.tick_params(which='major', axis='y', width=5, length=25, labelsize=45)

            self._plt.tick_params(which='minor', width=3, length=15)



        if self._ratio_plot:
            self._plt.gcf().set_size_inches(30, 24, forward=1)
        else:
            self._plt.gcf().set_size_inches(30, 24, forward=1)

        
        
        
        self._plt.sca(ax0)
        self._plt.autoscale()
        self._plt.xscale(self._x_scale)
        self._plt.gca().xaxis.set_major_formatter(mpl.ticker.ScalarFormatter())


        if self._ratio_plot:
            self._plt.sca(ax1)
            self._plt.autoscale()
            self._plt.xscale(self._x_scale)
            self._plt.gca().xaxis.set_major_formatter(mpl.ticker.ScalarFormatter())

            self._plt.sca(ax0)
            self._plt.gca().get_xaxis().set_ticklabels([])

            

        if self._x_lims[1] == -1:
            ax0.set_xlim( self._x_lims[0], ax0.get_xlim()[1] )
        else:
            ax0.set_xlim( self._x_lims[0], self._x_lims[1] )

        if self._y_lims[1] == -1:
            ax0.set_ylim( self._y_lims[0], ax0.get_ylim()[1] * 1.125 )
        else:
            # print self._y_lims[0], self._y_lims[1]
            ax0.set_ylim( self._y_lims[0], self._y_lims[1] )

        if self._ratio_plot:
            ax1.set_xlim( ax0.get_xlim()[0], ax0.get_xlim()[1] )
            ax1.set_ylim(0., 2.5)

        if self._hists[0].axes_label_pi():
            plt.sca(ax0)
            plt.gca().set_xticks( [0, round(0.5*np.pi, 3), round(np.pi, 3), round(1.5*np.pi, 3), round(2*np.pi, 3)] )
            plt.gca().set_xticklabels( ["0", "$\pi / 2$", "$\pi$", "$3 \pi / 2$", "$2 \pi$"] )

            if self._ratio_plot:
                plt.sca(ax1)
                plt.gca().set_xticks( [0, round(0.5*np.pi, 3), round(np.pi, 3), round(1.5*np.pi, 3), round(2*np.pi, 3)] )
                plt.gca().set_xticklabels( ["0", "$\pi / 2$", "$\pi$", "$3 \pi / 2$", "$2 \pi$"] )          

                plt.sca(ax0)
                plt.gca().set_xticklabels( [] )


        if self._x_scale == "log":
            if self._ratio_plot:
                self._plt.sca(ax1)
                # ax1.xaxis.set_major_formatter(mtick.FormatStrFormatter('%.0e'))
                ax1.xaxis.set_major_formatter(mpl.ticker.ScalarFormatter(useMathText=False))

            self._plt.sca(ax0)

            # print self._plt.gca().get_xlim()

            

            upper_lim = self._plt.gca().get_xlim()[1]
            lower_lim = self._plt.gca().get_xlim()[0]

            # print lower_lim

            if lower_lim < 0.01:
                denominations = [9] # 1 + 9 = 10.
            else:
                denominations = [1, 3, 5] # 1 + 1 = 2; 2 + 3 = 5; 5 + 5 = 10. 

            multiplier = lower_lim

            count = 0
            x_ticks = [lower_lim]
            
            # print abs(x_ticks[-1] - upper_lim) > 1e-6
    

            if float(upper_lim) <= 5.:

                while abs(x_ticks[-1] - upper_lim) > 1e-6:
                    
            
                    x_ticks.append( x_ticks[-1] + denominations[count] * multiplier )

                    # print x_ticks[-1] + denominations[count] * multiplier
                    
                    if count == (len(denominations) - 1):
                        count = 0
                        multiplier = x_ticks[-1]
                    else:
                        count += 1

                    # print x_ticks[-1]
            else:
                # print abs(x_ticks[-1] - upper_lim)
                # while abs(x_ticks[-1] - upper_lim) > 20:
                    
                #   x_ticks.append( x_ticks[-1] + denominations[count] * multiplier )

                #   # print x_ticks[-1] + denominations[count] * multiplier
                    
                #   if count == 2:
                #       count = 0
                #       multiplier = x_ticks[-1]
                #   else:
                #       count += 1
                pass

                x_ticks = [100, 200, 500, 1000, 2000]



            # print x_ticks
            self._plt.xticks(x_ticks)

            if self._ratio_plot:
                self._plt.sca(ax1)
                self._plt.xticks(x_ticks)


        if self._ratio_plot:
            self._plt.sca(ax1)
            self._plt.gca().get_yaxis().set_ticks( [ x for x in self._plt.gca().get_yaxis().get_majorticklocs() if x < 2.5 and x > 0.] )
        
        # Minor ticks.
        if not self._x_scale == "log":
            if len(ax0.get_xaxis().get_majorticklocs()) >= 2:
                factor = abs(ax0.get_xaxis().get_majorticklocs()[1] - ax0.get_xaxis().get_majorticklocs()[0]) / 10
                
                ax0.xaxis.set_minor_locator(MultipleLocator(factor))

                if self._ratio_plot:
                    ax1.xaxis.set_minor_locator(MultipleLocator(factor))

        if not self._y_scale == "log":
            if len(ax0.get_yaxis().get_majorticklocs()) >= 2:
                factor = abs(ax0.get_yaxis().get_majorticklocs()[1] - ax0.get_yaxis().get_majorticklocs()[0]) / 5

                ax0.yaxis.set_minor_locator(MultipleLocator(factor))
        
        if self._ratio_plot:
            ax1.yaxis.set_minor_locator(MultipleLocator(0.1))


        def convert_to_axes_coordinates(x, y):
            x_bounds, y_bounds = ax0.get_xlim(), ax0.get_ylim()
            return (x - x_bounds[0]) / (x_bounds[1] - x_bounds[0]), (y - y_bounds[0]) / (y_bounds[1] - y_bounds[0])




        # Any possible markers.
        for marker in self._mark_regions:

            #print marker

            if "Area" in self._x_label:
                ax0.plot([marker[0], marker[0]], [2, marker[1] ], zorder=9999, color='red', linewidth=8, linestyle="dashed")
            else:
                #print([marker[0], marker[0]])
                #print( [ax0.get_ylim()[0], marker[1] ])
                ax0.plot([marker[0], marker[0]], [ax0.get_ylim()[0], marker[1]], zorder=9999, color='red', linewidth=8, linestyle="dashed")

            unit_x_minor_tick_length = abs(ax0.get_xaxis().get_majorticklocs()[1] - ax0.get_xaxis().get_majorticklocs()[0]) /  10
            unit_y_minor_tick_length = abs(ax0.get_yaxis().get_majorticklocs()[1] - ax0.get_yaxis().get_majorticklocs()[0]) /  5

            # print ax0.get_yaxis().get_majorticklocs()[1], ax0.get_yaxis().get_majorticklocs()[0]

            if marker[2] != None:
                # Arrows.
                if marker[2] == "right":


                    if self._y_scale == 'log':
                        #ax0.arrow(marker[0], fy(marker[3]), marker[4], 0., head_width=unit_y_minor_tick_length, head_length=unit_x_minor_tick_length, fc='red', ec='red', transform=ax0.transAxes)
                        #ax0.arrow(marker[0], fy(marker[3]), marker[4], 0., fc='red', ec='red', transform=ax0.transAxes)
                        #ax0.arrow(marker[0], marker[3], marker[4], 0., head_width=unit_y_minor_tick_length, head_length=unit_x_minor_tick_length, fc='red', ec='red')
                        
                        x_o, y_o = convert_to_axes_coordinates(marker[0], marker[3])
                        delta_x, delta_y = convert_to_axes_coordinates(marker[4], 0)

                        print(x_o, y_o, delta_x, delta_y)

                        ax0.arrow(x_o, y_o, delta_x, delta_y, fc='red', ec='red', head_length=0.02, head_width=0.03, transform=ax0.transAxes)
                    
                    else:
                        ax0.arrow(marker[0], marker[3], marker[4], 0., head_width=unit_y_minor_tick_length, head_length=unit_x_minor_tick_length, fc='red', ec='red')
                elif marker[2] == "left":
                    
                    if self._y_scale == 'log':
                        x_o, y_o = convert_to_axes_coordinates(marker[0], marker[3])
                        delta_x, delta_y = convert_to_axes_coordinates(marker[4], 0)
                        
                        ax0.arrow(marker[0], marker[3], marker[4], 0., head_width=unit_y_minor_tick_length, head_length=unit_x_minor_tick_length, fc='red', ec='red', transform=ax0.transAxes)
                    else:
                        ax0.arrow(marker[0], marker[3], marker[4], 0., head_width=unit_y_minor_tick_length, head_length=unit_x_minor_tick_length, fc='red', ec='red')
            

            if "Area" in self._x_label:
                ax0.text(marker[0], 1., "$\pi \mathrm{R}^2$", color='red', fontsize=75, horizontalalignment='center')
          

        self._plt.gcf().set_snap(True)