Ejemplo n.º 1
0
    def draw_to_canvas(self):
        """
        Draw this figure to a canvas, which is then returned.
        """
        if len(self._plottables) == 0:
            raise IndexError("No plottables defined")
        c = Canvas(width=self.style.canvasWidth,
                   height=self.style.canvasHeight,
                   size_includes_decorations=True)
        if self.legend.position == 'seperate':
            legend_width = .2
            pad_legend = Pad(1 - legend_width, 0, 1., 1., name="legend")
            pad_legend.SetLeftMargin(0.0)
            pad_legend.SetFillStyle(0)  # make this pad transparent
            pad_legend.Draw()
        else:
            legend_width = 0
        pad_plot = Pad(
            0.,
            0.,
            1 - legend_width,
            1.,
            name="plot",
        )
        pad_plot.SetMargin(*self.style.plot_margins)
        pad_plot.Draw()
        pad_plot.cd()

        # awkward hack around a bug in get limits where everything fails if one plottable is shitty...
        xmin, xmax, ymin, ymax = None, None, None, None
        for pdic in self._plottables:
            try:
                limits = get_limits(pdic['p'],
                                    logx=self.plot.logx,
                                    logy=self.plot.logy)
                # Beware: Python 2 evaluates min/max of None in an undefined way with no error! Wow...
                xmin = min([xmin, limits[0]
                            ]) if xmin is not None else limits[0]
                xmax = max([xmax, limits[1]
                            ]) if xmax is not None else limits[1]
                ymin = min([ymin, limits[2]
                            ]) if ymin is not None else limits[2]
                ymax = max([ymax, limits[3]
                            ]) if ymax is not None else limits[3]
            except (TypeError, ValueError):
                # some plottables do not work with this rootpy function (eg. graph without points, tf1)
                # TODO: should be fixed upstream
                pass
        # overwrite these ranges if defaults are given
        if self.plot.xmin is not None:
            xmin = self.plot.xmin
        if self.plot.xmax is not None:
            xmax = self.plot.xmax
        if self.plot.ymax is not None:
            ymax = self.plot.ymax
        if self.plot.ymin is not None:
            ymin = self.plot.ymin

        if not all([val is not None for val in [xmin, xmax, ymin, ymax]]):
            raise TypeError(
                "unable to determine plot axes ranges from the given plottables"
            )

        colors = get_color_generator(self.plot.palette,
                                     self.plot.palette_ncolors)

        # draw an empty frame within the given ranges;
        frame_from_plottable = [
            p for p in self._plottables if p.get('use_as_frame')
        ]
        if len(frame_from_plottable) > 0:
            frame = frame_from_plottable[0]['p'].Clone('__frame')
            frame.Reset()
            frame.SetStats(0)
            frame.xaxis.SetRangeUser(xmin, xmax)
            frame.yaxis.SetRangeUser(ymin, ymax)
            frame.GetXaxis().SetTitle(self.xtitle)
            frame.GetYaxis().SetTitle(self.ytitle)
            self._theme_plottable(frame)
            frame.Draw()
        else:
            frame = Graph()
            frame.SetName("__frame")
            # add a silly point in order to have root draw this frame...
            frame.SetPoint(0, 0, 0)
            frame.GetXaxis().SetLimits(xmin, xmax)
            frame.GetYaxis().SetLimits(ymin, ymax)
            frame.SetMinimum(ymin)
            frame.SetMaximum(ymax)
            frame.GetXaxis().SetTitle(self.xtitle)
            frame.GetYaxis().SetTitle(self.ytitle)
            self._theme_plottable(frame)
            # Draw this frame: 'A' should draw the axis, but does not work if nothing else is drawn.
            # L would draw a line between the points but is seems to do nothing if only one point is present
            # P would also draw that silly point but we don't want that!
            frame.Draw("AL")

        xtick_length = frame.GetXaxis().GetTickLength()
        ytick_length = frame.GetYaxis().GetTickLength()

        for i, pdic in enumerate(self._plottables):
            obj = pdic['p']
            if isinstance(obj, ROOT.TLegendEntry):
                _root_color = Color(pdic['color'])
                _root_markerstyle = MarkerStyle(pdic['markerstyle'])
                obj.SetMarkerStyle(_root_markerstyle('root'))
                obj.SetMarkerColor(_root_color('root'))

            elif isinstance(obj, (ROOT.TH1, ROOT.TGraph, ROOT.TF1)):
                self._theme_plottable(obj)
                obj.SetMarkerStyle(pdic.get('markerstyle', 'circle'))
                if pdic.get('color', None):
                    obj.color = pdic['color']
                else:
                    try:
                        color = next(colors)
                    except StopIteration:
                        log.warning("Ran out of colors; defaulting to black")
                        color = 1
                    obj.color = color
                xaxis = obj.GetXaxis()
                yaxis = obj.GetYaxis()

                # Set the title to the given title:
                obj.title = self.title

                # the xaxis depends on the type of the plottable :P
                if isinstance(obj, ROOT.TGraph):
                    # SetLimit on a TH1 is simply messing up the
                    # lables of the axis to screw over the user, presumably...
                    xaxis.SetLimits(xmin, xmax)
                    yaxis.SetLimits(ymin, ymax)  # for unbinned data
                    # 'P' plots the current marker, 'L' would connect the dots with a simple line
                    # see: https://root.cern.ch/doc/master/classTGraphPainter.html for more draw options
                    drawoption = 'Psame'
                elif isinstance(obj, ROOT.TH1):
                    obj.SetStats(0)
                    xaxis.SetRangeUser(xmin, xmax)
                    yaxis.SetRangeUser(ymin, ymax)
                    drawoption = 'same'
                elif isinstance(obj, ROOT.TF1):
                    # xaxis.SetLimits(xmin, xmax)
                    # yaxis.SetLimits(ymin, ymax)  # for unbinned data
                    drawoption = 'same'
                obj.Draw(drawoption)
            # Its ok if obj is non; then we just add it to the legend.
            else:
                raise TypeError("Un-plottable type given.")
        pad_plot.SetTicks()
        pad_plot.SetLogx(self.plot.logx)
        pad_plot.SetLogy(self.plot.logy)
        pad_plot.SetGridx(self.plot.gridx)
        pad_plot.SetGridy(self.plot.gridy)

        # do we have legend titles?
        if any([pdic.get('legend_title') for pdic in self._plottables]):
            leg = self._create_legend()
            longest_label = 0
            for pdic in self._plottables:
                if not pdic.get('legend_title', False):
                    continue
                leg.AddEntry(pdic['p'], pdic['legend_title'])
                if len(pdic['legend_title']) > longest_label:
                    longest_label = len(pdic['legend_title'])

            # Set the legend position
            # vertical:
            if self.legend.position.startswith('t'):
                leg_hight = leg.y2 - leg.y1
                leg.y2 = 1 - pad_plot.GetTopMargin() - ytick_length
                leg.y1 = leg.y2 - leg_hight
            elif self.legend.position.startswith('b'):
                leg_hight = leg.y2 - leg.y1
                leg.y1 = pad_plot.GetBottomMargin() + ytick_length
                leg.y2 = leg.y1 + leg_hight
            # horizontal:
            if self.legend.position[1:].startswith('l'):
                leg_width = 0.3
                leg.x1 = pad_plot.GetLeftMargin() + xtick_length
                leg.x2 = leg.x1 + leg_width
            elif self.legend.position[1:].startswith('r'):
                leg_width = 0.3
                leg.x2 = 1 - pad_plot.GetRightMargin() - xtick_length
                leg.x1 = leg.x2 - leg_width
            if self.legend.position == 'seperate':
                with pad_legend:
                    leg.Draw()
            else:
                leg.Draw()
        if self.plot.logx:
            pad_plot.SetLogx(True)
        if self.plot.logy:
            pad_plot.SetLogy(True)
        pad_plot.Update(
        )  # needed sometimes with import of canvas. maybe because other "plot" pads exist...
        return c
Ejemplo n.º 2
0
def tau_from_scan(unfoldingObject, regularisation_settings):
    variable = regularisation_settings.variable

    # Plots that get outputted by the scan
    lCurve = TGraph()
    scanResult = TSpline3()
    d = 'signal'
    a = ''

    # Parameters of scan
    # Number of points to scan, and min/max tau
    nScan = 200
    minTau = 1.E-6
    maxTau = 1.E-0

    if variable == 'abs_lepton_eta':
        minTau = 1.E-8
        maxTau = 1.E-3
    elif variable == 'lepton_pt':
        minTau = 1.E-6
        maxTau = 1.E-2
    elif variable == 'NJets':
        minTau = 1.E-6
        maxTau = 1.E-2

    # Scan is performed here
    iBest = unfoldingObject.ScanTau(nScan, minTau, maxTau, scanResult,
                                    TUnfoldDensity.kEScanTauRhoSquareAvg)

    # Plot the scan result
    # Correlation as function of log tau
    canvas = TCanvas()

    # Add point corresponding to optimum tau
    t = Double(0)
    x = Double(0)
    scanResult.GetKnot(iBest, t, x)

    bestTau = Graph(1)
    bestTau.SetPoint(1, t, x)
    bestTau.markercolor = 'red'
    bestTau.SetMarkerSize(1.5)
    bestTau.SetMarkerStyle(34)
    bestTau.GetXaxis().SetTitle('log(#tau)')
    bestTau.GetYaxis().SetTitle(
        'Average global correlation coefficient squared')
    bestTau.SetTitle('{0} {1}'.format(variable,
                                      regularisation_settings.channel))
    bestTau.GetYaxis().SetRangeUser(x * 0.8, 0.95)
    bestTau.GetXaxis().SetLimits(log(minTau, 10), log(maxTau, 10))

    bestTau.Draw('AP')

    scanResult.SetMarkerColor(600)
    scanResult.SetMarkerSize(0.5)
    scanResult.SetMarkerStyle(20)
    scanResult.Draw('LPSAME')
    # Redraw to get it to appear on top of TSpline3...
    bestTau.Draw('PSAME')

    # Write to file
    output_dir = regularisation_settings.output_folder
    make_folder_if_not_exists(output_dir)
    canvas.SaveAs(
        output_dir +
        '/{0}_{1}.png'.format(variable, regularisation_settings.channel))

    return unfoldingObject.GetTau()