/*****************************************************************************
* Project: RooFit *
* Package: RooFitCore *
* File: $Id: RooPlot.cc,v 1.45 2005/06/21 16:42:31 wverkerke Exp $
* Authors: *
* WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
* DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
* *
* Copyright (c) 2000-2005, Regents of the University of California *
* and Stanford University. All rights reserved. *
* *
* Redistribution and use in source and binary forms, *
* with or without modification, are permitted according to the terms *
* listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
*****************************************************************************/
// -- CLASS DESCRIPTION [PLOT] --
// A RooPlot is a plot frame and a container for graphics objects
// within that frame. As a frame, it provides the TH1 public interface
// for settting plot ranges, configuring axes, etc. As a container, it
// holds an arbitrary set of objects that might be histograms of data,
// curves representing a fit model, or text labels. Use the Draw()
// method to draw a frame and the objects it contains. Use the various
// add...() methods to add objects to be drawn. In general, the
// add...() methods create a private copy of the object you pass them
// and return a pointer to this copy. The caller owns the input object
// and this class owns the returned object.
#include "RooFit.h"
#include "RooPlot.h"
#include "RooPlot.h"
#include "RooAbsReal.h"
#include "RooAbsRealLValue.h"
#include "RooPlotable.h"
#include "RooArgSet.h"
#include "RooCurve.h"
#include "RooHist.h"
#include "TAttLine.h"
#include "TAttFill.h"
#include "TAttMarker.h"
#include "TAttText.h"
#include "Riostream.h"
#include <string.h>
#include <assert.h>
ClassImp(RooPlot)
;
RooPlot::RooPlot(Double_t xmin, Double_t xmax) :
TH1(histName(),"A RooPlot",100,xmin,xmax),
_items(), _plotVarClone(0), _plotVarSet(0), _normObj(0),
_defYmin(1e-5), _defYmax(1)
{
// Create an empty frame with the specified x-axis limits.
initialize();
}
RooPlot::RooPlot(Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax) :
TH1(histName(),"A RooPlot",100,xmin,xmax), _items(), _plotVarClone(0),
_plotVarSet(0), _normObj(0), _defYmin(1e-5), _defYmax(0)
{
// Create an empty frame with the specified x- and y-axis limits.
SetMinimum(ymin);
SetMaximum(ymax);
initialize();
}
RooPlot::RooPlot(const RooAbsRealLValue &var1, const RooAbsRealLValue &var2) :
TH1(histName(),"A RooPlot",100,var1.getMin(),var1.getMax()), _items(),
_plotVarClone(0), _plotVarSet(0), _normObj(0), _defYmin(1e-5), _defYmax(0)
{
// Create an empty frame with the specified x- and y-axis limits
// and with labels determined by the specified variables.
if(!var1.hasMin() || !var1.hasMax()) {
cout << "RooPlot::RooPlot: cannot create plot for variable without finite limits: "
<< var1.GetName() << endl;
return;
}
if(!var2.hasMin() || !var2.hasMax()) {
cout << "RooPlot::RooPlot: cannot create plot for variable without finite limits: "
<< var1.GetName() << endl;
return;
}
SetMinimum(var2.getMin());
SetMaximum(var2.getMax());
SetXTitle(var1.getTitle(kTRUE));
SetYTitle(var2.getTitle(kTRUE));
initialize();
}
RooPlot::RooPlot(const RooAbsRealLValue &var1, const RooAbsRealLValue &var2,
Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax) :
TH1(histName(),"A RooPlot",100,xmin,xmax), _items(), _plotVarClone(0),
_plotVarSet(0), _normObj(0), _defYmin(1e-5), _defYmax(0)
{
// Create an empty frame with the specified x- and y-axis limits
// and with labels determined by the specified variables.
SetMinimum(ymin);
SetMaximum(ymax);
SetXTitle(var1.getTitle(kTRUE));
SetYTitle(var2.getTitle(kTRUE));
initialize();
}
RooPlot::RooPlot(const char* name, const char* title, const RooAbsRealLValue &var, Double_t xmin, Double_t xmax, Int_t nbins) :
TH1(name,title,nbins,xmin,xmax), _items(),
_plotVarClone(0), _plotVarSet(0), _normObj(0), _defYmin(1e-5), _defYmax(1)
{
// Create an empty frame with its title and x-axis range and label taken
// from the specified real variable. We keep a clone of the variable
// so that we do not depend on its lifetime and are decoupled from
// any later changes to its state.
// plotVar can be a composite in case of a RooDataSet::plot, need deepClone
_plotVarSet = (RooArgSet*) RooArgSet(var).snapshot() ;
_plotVarClone= (RooAbsRealLValue*)_plotVarSet->find(var.GetName()) ;
TString xtitle= var.getTitle(kTRUE);
SetXTitle(xtitle.Data());
initialize();
_normBinWidth = (xmax-xmin)/nbins ;
}
RooPlot::RooPlot(const RooAbsRealLValue &var, Double_t xmin, Double_t xmax, Int_t nbins) :
TH1(histName(),"RooPlot",nbins,xmin,xmax), _items(),
_plotVarClone(0), _plotVarSet(0), _normObj(0), _defYmin(1e-5), _defYmax(1)
{
// Create an empty frame with its title and x-axis range and label taken
// from the specified real variable. We keep a clone of the variable
// so that we do not depend on its lifetime and are decoupled from
// any later changes to its state.
// plotVar can be a composite in case of a RooDataSet::plot, need deepClone
_plotVarSet = (RooArgSet*) RooArgSet(var).snapshot() ;
_plotVarClone= (RooAbsRealLValue*)_plotVarSet->find(var.GetName()) ;
TString xtitle= var.getTitle(kTRUE);
SetXTitle(xtitle.Data());
TString title("A RooPlot of \"");
title.Append(var.getTitle());
title.Append("\"");
SetTitle(title.Data());
initialize();
_normBinWidth = (xmax-xmin)/nbins ;
}
void RooPlot::initialize() {
// Perform initialization that is common to all constructors.
// We hold 1D plot objects
fDimension=1 ;
// We do not have useful stats of our own
SetStats(kFALSE);
// Default vertical padding of our enclosed objects
setPadFactor(0.05);
// We don't know our normalization yet
_normNumEvts= 0;
_normBinWidth = 0;
_normVars= 0;
// Create an iterator over our enclosed objects
_iterator= _items.MakeIterator();
assert(0 != _iterator);
}
TString RooPlot::histName() const
{
return TString(Form("frame_%08x",this)) ;
}
RooPlot::~RooPlot() {
// Delete the items in our container and our iterator.
_items.Delete();
delete _iterator;
if(_plotVarSet) delete _plotVarSet;
if(_normVars) delete _normVars;
}
void RooPlot::updateNormVars(const RooArgSet &vars) {
if(0 == _normVars) _normVars= (RooArgSet*) vars.snapshot(kTRUE);
}
Stat_t RooPlot::GetBinContent(Int_t /*i*/) const {
// A plot object is a frame without any bin contents of its own so this
// method always returns zero.
return 0;
}
Stat_t RooPlot::GetBinContent(Int_t, Int_t) const
{
// A plot object is a frame without any bin contents of its own so this
// method always returns zero.
return 0;
}
Stat_t RooPlot::GetBinContent(Int_t, Int_t, Int_t) const
{
// A plot object is a frame without any bin contents of its own so this
// method always returns zero.
return 0;
}
void RooPlot::addObject(TObject *obj, Option_t *drawOptions, Bool_t invisible) {
// Add a generic object to this plot. The specified options will be
// used to Draw() this object later. The caller transfers ownership
// of the object with this call, and the object will be deleted
// when its containing plot object is destroyed.
if(0 == obj) {
cout << fName << "::addObject: called with a null pointer" << endl;
return;
}
DrawOpt opt(drawOptions) ;
opt.invisible = invisible ;
_items.Add(obj,opt.rawOpt());
}
void RooPlot::addTH1(TH1 *hist, Option_t *drawOptions, Bool_t invisible) {
// Add a TH1 histogram object to this plot. The specified options
// will be used to Draw() this object later. "SAME" will be added to
// the options if they are not already present. Note that histograms
// should probably not be drawn with error bars since they will not
// be calculated correctly for bins with low statistics, and will
// not be accounted for in the automatic y-axis range adjustment. To
// histogram data in a RooDataSet without these problems, use
// RooDataSet::plotOn(). The caller transfers ownership of the
// object with this call, and the object will be deleted when its
// containing plot object is destroyed.
if(0 == hist) {
cout << fName << "::addTH1: called with a null pointer" << endl;
return;
}
// check that this histogram is really 1D
if(1 != hist->GetDimension()) {
cout << fName << "::addTH1: cannot plot histogram with "
<< hist->GetDimension() << " dimensions" << endl;
return;
}
// add option "SAME" if necessary
TString options(drawOptions);
options.ToUpper();
if(!options.Contains("SAME")) options.Append("SAME");
// update our y-axis label and limits
updateYAxis(hist->GetMinimum(),hist->GetMaximum(),hist->GetYaxis()->GetTitle());
// use this histogram's normalization if necessary
updateFitRangeNorm(hist);
// add the histogram to our list
addObject(hist,options.Data(),invisible);
}
void RooPlot::addPlotable(RooPlotable *plotable, Option_t *drawOptions, Bool_t invisible, Bool_t refreshNorm) {
// Add the specified plotable object to our plot. Increase our y-axis
// limits to fit this object if necessary. The default lower-limit
// is zero unless we are plotting an object that takes on negative values.
// This call transfers ownership of the plotable object to this class.
// The plotable object will be deleted when this plot object is deleted.
// update our y-axis label and limits
updateYAxis(plotable->getYAxisMin(),plotable->getYAxisMax(),plotable->getYAxisLabel());
// use this object's normalization if necessary
updateFitRangeNorm(plotable,refreshNorm) ;
// add this element to our list and remember its drawing option
TObject *obj= plotable->crossCast();
if(0 == obj) {
cout << fName << "::add: cross-cast to TObject failed (nothing added)" << endl;
}
else {
DrawOpt opt(drawOptions) ;
opt.invisible = invisible ;
_items.Add(obj,opt.rawOpt());
}
}
void RooPlot::updateFitRangeNorm(const TH1* hist) {
// Update our plot normalization over our plot variable's fit range,
// which will be determined by the first suitable object added to our plot.
const TAxis* xa = ((TH1*)hist)->GetXaxis() ;
_normBinWidth = (xa->GetXmax()-xa->GetXmin())/hist->GetNbinsX() ;
_normNumEvts = hist->GetEntries()/_normBinWidth ;
}
void RooPlot::updateFitRangeNorm(const RooPlotable* rp, Bool_t refreshNorm) {
// Update our plot normalization over our plot variable's fit range,
// which will be determined by the first suitable object added to our plot.
if (_normNumEvts != 0) {
// If refresh feature is disabled stop here
if (!refreshNorm) return ;
Double_t corFac(1.0) ;
if (dynamic_cast<const RooHist*>(rp)) corFac = _normBinWidth/rp->getFitRangeBinW() ;
cout << "RooPlot::updateFitRangeNorm: New event count of " << rp->getFitRangeNEvt()/corFac
<< " will supercede previous event count of " << _normNumEvts << " for normalization of PDF projections" << endl ;
// Nominal bin width (i.e event density) is already locked in by previously drawn histogram
// scale this histogram to match that density
_normNumEvts = rp->getFitRangeNEvt()/corFac ;
_normObj = rp ;
//cout << "correction factor = " << _normBinWidth << "/" << rp->getFitRangeBinW() << endl ;
//cout << "updating numevts to " << _normNumEvts << endl ;
} else {
_normObj = rp ;
_normNumEvts = rp->getFitRangeNEvt() ;
_normBinWidth = rp->getFitRangeBinW() ;
//cout << "updating numevts to " << _normNumEvts << endl ;
}
}
void RooPlot::updateYAxis(Double_t ymin, Double_t ymax, const char *label) {
// Update our y-axis limits to accomodate an object whose spread
// in y is (ymin,ymax). Use the specified y-axis label if we don't
// have one assigned already.
// force an implicit lower limit of zero if appropriate
if(GetMinimum() == 0 && ymin > 0) ymin= 0;
// calculate padded values
Double_t ypad= getPadFactor()*(ymax-ymin);
ymax+= ypad;
if(ymin < 0) ymin-= ypad;
// update our limits if necessary
if(GetMaximum() < ymax) {
_defYmax = ymax ;
SetMaximum(ymax);
}
if(GetMinimum() > ymin) {
_defYmin = ymin ;
SetMinimum(ymin);
}
// use the specified y-axis label if we don't have one already
if(0 == strlen(GetYaxis()->GetTitle())) SetYTitle(label);
}
void RooPlot::Draw(Option_t *options) {
// Draw this plot and all of the elements it contains. The specified options
// only apply to the drawing of our frame. The options specified in our add...()
// methods will be used to draw each object we contain.
TH1::Draw(options);
_iterator->Reset();
TObject *obj = 0;
while((obj= _iterator->Next())) {
DrawOpt opt(_iterator->GetOption()) ;
if (!opt.invisible) {
obj->Draw(opt.drawOptions);
}
}
TH1::Draw("AXISSAME");
}
void RooPlot::printToStream(ostream& os, PrintOption opt, TString indent) const {
// Print info about this plot object to the specified stream.
//
// Standard: plot variable and number of contained objects
// Shape: list of our contained objects
oneLinePrint(os,*this);
if(opt >= Standard) {
TString deeper(indent);
deeper.Append(" ");
if(0 != _plotVarClone) {
os << indent << " Plotting ";
_plotVarClone->printToStream(os,OneLine,deeper);
}
else {
os << indent << " No plot variable specified" << endl;
}
os << indent << " Plot contains " << _items.GetSize() << " object(s)" << endl;
if(opt >= Shape) {
_iterator->Reset();
TObject *obj = 0;
while((obj= _iterator->Next())) {
os << deeper << "(Options=\"" << _iterator->GetOption() << "\") ";
// Is this a printable object?
if(obj->IsA()->InheritsFrom(RooPrintable::Class())) {
ostream& oldDefault= RooPrintable::defaultStream(&os);
obj->Print("1");
RooPrintable::defaultStream(&oldDefault);
}
// is it a TNamed subclass?
else if(obj->IsA()->InheritsFrom(TNamed::Class())) {
oneLinePrint(os,(const TNamed&)(*obj));
}
// at least it is a TObject
else {
os << obj->ClassName() << "::" << obj->GetName() << endl;
}
}
}
}
}
const char* RooPlot::nameOf(Int_t idx) const
{
// Return the name of the object at slot 'idx' in this RooPlot.
// If the given index is out of range, return a null pointer
TObject* obj = _items.At(idx) ;
if (!obj) {
cout << "RooPlot::nameOf(" << GetName() << ") index " << idx << " out of range" << endl ;
return 0 ;
}
return obj->GetName() ;
}
TObject* RooPlot::getObject(Int_t idx) const
{
// Return the name of the object at slot 'idx' in this RooPlot.
// If the given index is out of range, return a null pointer
TObject* obj = _items.At(idx) ;
if (!obj) {
cout << "RooPlot::getObject(" << GetName() << ") index " << idx << " out of range" << endl ;
return 0 ;
}
return obj ;
}
TAttLine *RooPlot::getAttLine(const char *name) const {
// Return a pointer to the line attributes of the named object in this plot,
// or zero if the named object does not exist or does not have line attributes.
return dynamic_cast<TAttLine*>(findObject(name));
}
TAttFill *RooPlot::getAttFill(const char *name) const {
// Return a pointer to the fill attributes of the named object in this plot,
// or zero if the named object does not exist or does not have fill attributes.
return dynamic_cast<TAttFill*>(findObject(name));
}
TAttMarker *RooPlot::getAttMarker(const char *name) const {
// Return a pointer to the marker attributes of the named object in this plot,
// or zero if the named object does not exist or does not have marker attributes.
return dynamic_cast<TAttMarker*>(findObject(name));
}
TAttText *RooPlot::getAttText(const char *name) const {
// Return a pointer to the text attributes of the named object in this plot,
// or zero if the named object does not exist or does not have text attributes.
return dynamic_cast<TAttText*>(findObject(name));
}
RooCurve* RooPlot::getCurve(const char* name) const {
// Return a RooCurve pointer of the named object in this plot,
// or zero if the named object does not exist or is not a RooCurve
return dynamic_cast<RooCurve*>(findObject(name)) ;
}
RooHist* RooPlot::getHist(const char* name) const {
// Return a RooCurve pointer of the named object in this plot,
// or zero if the named object does not exist or is not a RooCurve
return dynamic_cast<RooHist*>(findObject(name)) ;
}
Bool_t RooPlot::drawBefore(const char *before, const char *target) {
// Change the order in which our contained objects are drawn so that
// the target object is drawn just before the specified object.
// Returns kFALSE if either object does not exist.
return _items.moveBefore(before, target, caller("drawBefore"));
}
Bool_t RooPlot::drawAfter(const char *after, const char *target) {
// Change the order in which our contained objects are drawn so that
// the target object is drawn just after the specified object.
// Returns kFALSE if either object does not exist.
return _items.moveAfter(after, target, caller("drawAfter"));
}
TObject *RooPlot::findObject(const char *name, const TClass* clas) const {
// Find the named object in our list of items and return a pointer
// to it. Return zero and print a warning message if the named
// object cannot be found. If no name is supplied the last object
// added is returned.
//
// Note that the returned pointer is to a
// TObject and so will generally need casting. Use the getAtt...()
// methods to change the drawing style attributes of a contained
// object directly.
TObject *obj = 0;
TObject *ret = 0;
TIterator* iter = _items.MakeIterator() ;
while((obj=iter->Next())) {
if ((!name || !TString(name).CompareTo(obj->GetName())) &&
(!clas || (obj->IsA()==clas))) {
ret = obj ;
}
}
delete iter ;
if (ret==0) {
cout << "RooPlot::findObject(" << GetName() << ") cannot find object " << (name?name:"<last>") << endl ;
}
return ret ;
}
TString RooPlot::getDrawOptions(const char *name) const {
// Return the Draw() options registered for the named object. Return
// an empty string if the named object cannot be found.
TObjOptLink *link= _items.findLink(name,caller("getDrawOptions"));
DrawOpt opt(0 == link ? "" : link->GetOption()) ;
return TString(opt.drawOptions) ;
}
Bool_t RooPlot::setDrawOptions(const char *name, TString options) {
// Register the specified drawing options for the named object.
// Return kFALSE if the named object cannot be found.
TObjOptLink *link= _items.findLink(name,caller("setDrawOptions"));
if(0 == link) return kFALSE;
DrawOpt opt(link->GetOption()) ;
strcpy(opt.drawOptions,options) ;
link->SetOption(opt.rawOpt());
return kTRUE;
}
Bool_t RooPlot::getInvisible(const char* name) const
{
TObjOptLink *link= _items.findLink(name,caller("getInvisible"));
if(0 == link) return kFALSE;
return DrawOpt(link->GetOption()).invisible ;
}
void RooPlot::setInvisible(const char* name, Bool_t flag)
{
TObjOptLink *link= _items.findLink(name,caller("getInvisible"));
DrawOpt opt ;
if(link) {
opt.initialize(link->GetOption()) ;
}
opt.invisible = flag ;
link->SetOption(opt.rawOpt()) ;
}
TString RooPlot::caller(const char *method) const {
TString name(fName);
if(strlen(method)) {
name.Append("::");
name.Append(method);
}
return name;
}
void RooPlot::SetMaximum(Double_t maximum)
{
TH1::SetMaximum(maximum==-1111?_defYmax:maximum) ;
}
void RooPlot::SetMinimum(Double_t minimum)
{
TH1::SetMinimum(minimum==-1111?_defYmin:minimum) ;
}
Double_t RooPlot::chiSquare(const char* curvename, const char* histname, Int_t nFitParam) const
{
// Find curve object
RooCurve* curve = (RooCurve*) findObject(curvename,RooCurve::Class()) ;
if (!curve) {
cout << "RooPlot::chiSquare(" << GetName() << ") cannot find curve" << endl ;
return -1. ;
}
// Find histogram object
RooHist* hist = (RooHist*) findObject(histname,RooHist::Class()) ;
if (!hist) {
cout << "RooPlot::chiSquare(" << GetName() << ") cannot find histogram" << endl ;
return -1. ;
}
return curve->chiSquare(*hist,nFitParam) ;
}
RooHist* RooPlot::pullHist(const char* histname, const char* curvename) const
{
// Find curve object
RooCurve* curve = (RooCurve*) findObject(curvename,RooCurve::Class()) ;
if (!curve) {
cout << "RooPlot::pullHist(" << GetName() << ") cannot find curve" << endl ;
return 0 ;
}
// Find histogram object
RooHist* hist = (RooHist*) findObject(histname,RooHist::Class()) ;
if (!hist) {
cout << "RooPlot::pullHist(" << GetName() << ") cannot find histogram" << endl ;
return 0 ;
}
return hist->makePullHist(*curve) ;
}
void RooPlot::DrawOpt::initialize(const char* rawOpt)
{
if (!rawOpt) {
drawOptions[0] = 0 ;
invisible=kFALSE ;
return ;
}
strcpy(drawOptions,rawOpt) ;
strtok(drawOptions,":") ;
const char* extraOpt = strtok(0,":") ;
if (extraOpt) {
invisible = (extraOpt[0]=='I') ;
}
}
const char* RooPlot::DrawOpt::rawOpt() const
{
static char buf[128] ;
strcpy(buf,drawOptions) ;
if (invisible) {
strcat(buf,":I") ;
}
return buf ;
}
Double_t RooPlot::getFitRangeNEvt(Double_t xlo, Double_t xhi) const
{
Double_t scaleFactor = 1.0 ;
if (_normObj) {
scaleFactor = _normObj->getFitRangeNEvt(xlo,xhi)/_normObj->getFitRangeNEvt() ;
}
cout << "RooPlot::getFitRangeNEvt(" << GetName() << ") WARNING: Unable to obtain event count in range "
<< xlo << " to " << xhi << ", substituting full event count" << endl ;
return getFitRangeNEvt()*scaleFactor ;
}
ROOT page - Class index - Class Hierarchy - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.