From 29b2297b89268587cb6e10bd2020e55325fe5982 Mon Sep 17 00:00:00 2001 From: Oscar Gonzalez Lopez Date: Tue, 3 Dec 2024 19:38:10 +0100 Subject: [PATCH] Saving tests and the last version for the pyroot and the C++ code for ROOT --- .github/workflows/softwarecheck.yml | 40 +++++ scripts/setup_cmstyle | 25 +-- src/TCmsCanvas.H | 100 +++++++++++ src/cmsstyle.C | 249 ++++++++++++++++++++++++++-- src/cmsstyle.H | 165 +++++++++++++++--- src/cmsstyle/cmsstyle.py | 19 ++- src/colorsets.H | 11 +- tests/test_cmsCanvas.C | 35 +++- tests/test_cmsCanvas.py | 71 ++++++++ 9 files changed, 645 insertions(+), 70 deletions(-) create mode 100644 .github/workflows/softwarecheck.yml create mode 100644 src/TCmsCanvas.H create mode 100644 tests/test_cmsCanvas.py diff --git a/.github/workflows/softwarecheck.yml b/.github/workflows/softwarecheck.yml new file mode 100644 index 0000000..cbcf026 --- /dev/null +++ b/.github/workflows/softwarecheck.yml @@ -0,0 +1,40 @@ +name: Software_check +on: + push: + pull_request: + types: [opened] +jobs: + py3-job: + runs-on: ubuntu-latest + container: cmscloud/al9-cms:latest + steps: + - name: Checking_python_3.9 + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - run: | + python3 -V + ls + pwd + python3 -m py_compile src/cmsstyle/cmsstyle.py + python3 -m py_compil src/cmsstyle/cmsstyle.py + - run: | + cd src + echo '{gROOT->LoadMacro("cmsstyle.C++");}' > hola.C + root -q hola.C + ls cmsstyle_C.sod +# + py2-job: + runs-on: ubuntu-latest + container: cmscloud/cc7-cms:latest + steps: + - name: Checking_python_2.7 + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - run: | + python -V + ls + pwd + python -m py_compile src/cmsstyle/cmsstyle.py +# diff --git a/scripts/setup_cmstyle b/scripts/setup_cmstyle index 26bb368..2f7367c 100644 --- a/scripts/setup_cmstyle +++ b/scripts/setup_cmstyle @@ -6,6 +6,7 @@ # using the directory of the actual implementation we want to use of CMSStyle. # # Written by O. Gonzalez (2024_11_12) +# 2024_12_01 Changing the used directory for a real one. # fich_=${BASH_SOURCE[0]} @@ -13,26 +14,26 @@ if [ ".${fich_::1}" != "./" ] ; then # Relative directory fich_="$PWD/${fich_}" fi -# Setting up the variables: +# Getting the simplest name of the directory +if [[ ${fich_:(-22):1} == "/" ]] ; then + cd ${fich_::-21} >& /dev/null +else # We are in scripts! + cd .. >& /dev/null +fi +export CMSSTYLE_DIR=`pwd -P` +cd - >& /dev/null -export CMSSTYLE_DIR=${fich_::-22} echo "Using CMSStyle located in $CMSSTYLE_DIR" +# Setting up the related variables: + if [[ ! $ROOT_INCLUDE_PATH == *"${CMSSTYLE_DIR}/src"* ]]; then - if [[ -z "$ROOT_INCLUDE_PATH" ]] ; then - export ROOT_INCLUDE_PATH=${CMSSTYLE_DIR}/src - else - export ROOT_INCLUDE_PATH=${CMSSTYLE_DIR}/src:$ROOT_INCLUDE_PATH - fi + export ROOT_INCLUDE_PATH=${CMSSTYLE_DIR}/src${ROOT_INCLUDE_PATH:+":$ROOT_INCLUDE_PATH"} fi # We also put the same version for python, in case... if [[ ".${PYTHONPATH}" != *"${CMSSTYLE_DIR}/src"* ]] ; then - if [[ -z ${PYTHONPATH} ]] ; then - export PYTHONPATH=${CMSSTYLE_DIR}/src - else - export PYTHONPATH=${CMSSTYLE_DIR}/src:${PYTHONPATH} - fi + export PYTHONPATH=${CMSSTYLE_DIR}/src${PYTHONPATH:+":$PYTHONPATH"} fi # # Note: diff --git a/src/TCmsCanvas.H b/src/TCmsCanvas.H new file mode 100644 index 0000000..1460ca8 --- /dev/null +++ b/src/TCmsCanvas.H @@ -0,0 +1,100 @@ +///@file +/// +/// This code contains the declaration and definition of the class TCmsCanvas +/// that inherits from a normal TCanvas en ROOT but keep track of created +/// objects that are not visible to the user, for its proper deletion as the +/// TCanvas is destroyed. +/// +///
+/// Written by O. Gonzalez (2024_11_12)
+/// 
+/// + +#ifndef CMSSTYLE_TCMSCANVAS__H_ +#define CMSSTYLE_TCMSCANVAS__H_ + +#include +#include + +#include + +namespace cmsstyle { + + +/// This is the class that CMSStyle (in the C++ version) uses to handle the +/// TCanvases that are defined to be plotted, but one has to keep in mind that +/// externally + +class TCmsCanvas : public TCanvas { + + // Internal variables (pointers to keep track) + + TASImage *CMS_logo; ///< CMS Logo when used in the TCanvas. + TPad *pad_logo; ///< TPad containing the CMS logo, when used. + + // Internal methods + + /// Initialization of the internal variables... + void Initialize (void) { + CMS_logo=nullptr; + pad_logo=nullptr; + } + +public: + + /// Normal constructor: It just creates the Canvas using the arguments and + /// the corresponding constructor method ot eh TCanvas. It also initializes + /// the values to keep track of when needed. + /// + /// Arguments: + /// name: Name of the created object + /// title: Title for the TCanvas + /// wtopx: X position of the top left corner of the canvas in pixels. + /// wtopy: Y position of the top left corner of the canvas in pixels + /// ww: the window size in pixels along X. + /// wh: the window size in pixels along Y. + /// + TCmsCanvas (const char *name, + const char *title, + Int_t wtopx, + Int_t wtopy, + Int_t ww, + Int_t wh) : TCanvas(name,title,wtopx,wtopy,ww,wh) { + Initialize(); + } + + /// Destructor of the class, as the most important object since it handles + /// the deletion of objects defined + ~TCmsCanvas () { + if (CMS_logo!=nullptr) delete CMS_logo; + if (pad_logo!=nullptr) delete pad_logo; + } + + + /// Method to draw the CMS Logo in the defined TCanvas in a TPad set at the indicated location + /// of the currently used TPad. + void AddCmsLogo (Float_t x0, Float_t y0, Float_t x1, Float_t y1, const char *logofile) + { + if (CMS_logo!=nullptr) delete CMS_logo; + CMS_logo = new TASImage(logofile); + + auto oldpad = gPad; + + if (pad_logo!=nullptr) delete pad_logo; + pad_logo = new TPad("logo", "logo", x0, y0, x1, y1); + pad_logo->Draw(); + pad_logo->cd(); + CMS_logo->Draw("X"); + pad_logo->Modified(); + + oldpad->cd(); + } + + + + +}; + +} // Namespace cmsstyle +#endif +///---------------------------------------------------------------------- diff --git a/src/cmsstyle.C b/src/cmsstyle.C index a323ef5..5a5128f 100644 --- a/src/cmsstyle.C +++ b/src/cmsstyle.C @@ -5,6 +5,9 @@ /// /// root[] .L cmsstyle.C++ (or equivalently with CompileMacro() or LoadMacro()) /// +/// or simply from the command line (example to just compile) +/// echo '{gROOT->LoadMacro("cmsstyle.C++");}' > /tmp/hola.C ; root -q /tmp/hola.C +/// /// but it can also be loaded from an interactive session of ROOT as /// /// root[] .L cmsstyle.C @@ -19,9 +22,13 @@ #include #include #include +#include +#include +#include #include #include +#include // Globals from ROOT @@ -143,14 +150,27 @@ void setCMSStyle (bool force) // Some additional parameters we need to set as "style" - if (ROOT_VERSION_MAJOR>6 || (ROOT_VERSION_MINOR>=32 && ROOT_VERSION_MAJOR==6)) { // Not available before 6.32! - TColor::DefinedColors(1); - } +#if (ROOT_VERSION_MAJOR>6 || (ROOT_VERSION_MINOR>=32 && ROOT_VERSION_MAJOR==6)) // Not available before 6.32! + TColor::DefinedColors(1); +#endif // Using the Style. cmsStyle->cd(); } +// ---------------------------------------------------------------------- +void ResetCmsDescriptors (void) + // This method allows to reset all the values for the CMS-related dataset // descriptors to the default. +{ + cms_lumi = "Run 2, 138 fb^{#minus1}"; + cms_energy = "13 TeV"; + + cmsText = "CMS"; + extraText = "Preliminary"; + + additionalInfo.clear(); +} + // ---------------------------------------------------------------------- void SetEnergy (float energy, const std::string &unit) // This methos sets the centre-of-mass energy value and unit to be displayed. @@ -168,7 +188,61 @@ void SetEnergy (float energy, const std::string &unit) } // ---------------------------------------------------------------------- +void SetCmsLogoFilename (const std::string &filename) + // This allows to set the location of the file with the CMS Logo in case we + // want to use that instead of the "CMS" text. + // When not set (default), the text version is written. +{ + if (filename.length()==0) useCmsLogo =""; + + // We just check for it! + else if (FILE *file = fopen(filename.c_str(),"r")) { + useCmsLogo = filename; + fclose(file); + } + + else { // We may look inside the CMSStyle directory if the variable is defined. + char *x = std::getenv("CMSSTYLE_DIR"); + useCmsLogo =""; + + if (x!=nullptr) { + useCmsLogo = std::string(x) + std::string("/") + filename; + + if (FILE *file = fopen(useCmsLogo.c_str(),"r")) { + fclose(file); + } + else useCmsLogo =""; + } + if (useCmsLogo.length()==0) { + std::cerr<<"ERROR: Indicated file for CMS Logo: "< objs) // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- -TCanvas *cmsCanvas (const char *canvName, - Float_t x_min, - Float_t x_max, - Float_t y_min, - Float_t y_max, - const char *nameXaxis, - const char *nameYaxis, - Bool_t square, - Int_t iPos, - Float_t extraSpace, - Bool_t with_z_axis, - Float_t scaleLumi, - Float_t yTitOffset) - // his method defines and returns the TCanvas for a normal/basic plot. +TCmsCanvas *cmsCanvas (const char *canvName, + Float_t x_min, + Float_t x_max, + Float_t y_min, + Float_t y_max, + const char *nameXaxis, + const char *nameYaxis, + Bool_t square, + Int_t iPos, + Float_t extraSpace, + Bool_t with_z_axis, + Float_t scaleLumi, + Float_t yTitOffset) + // This method defines and returns the TCmsCanvas (a wrapper for TCanvas) for + // a normal/basic plot. { // Set CMS style if not set already if (cmsStyle==nullptr) setCMSStyle(); @@ -241,7 +316,7 @@ TCanvas *cmsCanvas (const char *canvName, Float_t R = 0.03 * H; // Setting up the TCanvas - TCanvas *canv = new TCanvas(canvName, canvName, 50, 50, W, H); + TCmsCanvas *canv = new TCmsCanvas(canvName, canvName, 50, 50, W, H); canv->SetFillColor(0); canv->SetBorderMode(0); canv->SetFrameFillStyle(0); @@ -288,8 +363,86 @@ void CMS_lumi (TPad *ppad, Int_t iPosX, Float_t scaleLumi) /// implementation was complicated and obscure, so rewritten here with a /// cleaner coding. + Float_t relPosX = 0.035; + Float_t relPosY = 0.035; + Float_t relExtraDY = 1.2; + + Bool_t outOfFrame = (int(iPosX / 10) == 0); + Int_t alignX_ = max(int(iPosX / 10), 1); + Int_t alignY_ = (iPosX==0)?1:3; + Int_t align_ = 10 * alignX_ + alignY_; + + Float_t H = ppad->GetWh() * ppad->GetHNDC(); + Float_t W = ppad->GetWw() * ppad->GetWNDC(); + Float_t l = ppad->GetLeftMargin(); + Float_t t = ppad->GetTopMargin(); + Float_t r = ppad->GetRightMargin(); + Float_t b = ppad->GetBottomMargin(); + Float_t outOfFrame_posY = 1 - t + lumiTextOffset * t; + + ppad->cd(); + + std::string lumiText(cms_lumi); + if (cms_energy != "") lumiText += " (" + cms_energy + ")"; + + //OLD if (scaleLumi) lumiText = ScaleText(lumiText, scaleLumi); + + drawText(lumiText.c_str(),1-r,outOfFrame_posY,42,31,lumiTextSize * t * scaleLumi); + + + // Now we go to the CMS message: + + Float_t posX_ = 0; + if (iPosX % 10 <= 1) posX_ = l + relPosX * (1 - l - r); + else if (iPosX % 10 == 2) posX_ = l + 0.5 * (1 - l - r); + else if (iPosX % 10 == 3) posX_ = 1 - r - relPosX * (1 - l - r); + Float_t posY_ = 1 - t - relPosY * (1 - t - b); + if (outOfFrame) { // CMS logo and extra text out of the frame + if (useCmsLogo.length()>0) { // Using CMS Logo instead of the text label (uncommon!) + + } + else { + if (cmsText.length()!=0) { + drawText(cmsText.c_str(),l,outOfFrame_posY,cmsTextFont,11,cmsTextSize * t); + // Checking position of the extraText after the CMS logo text. + Float_t scale=1; + if (W > H) scale = H/ float(W); // For a rectangle; + l += 0.043 * (extraTextFont * t * cmsTextSize) * scale; + } + + if (extraText.length()!=0) { // Only if something to write + drawText(extraText.c_str(),l,outOfFrame_posY,extraTextFont,align_,extraOverCmsTextSize * cmsTextSize * t); + } + } + } + else { // In the frame! + if (useCmsLogo.length()>0) { // Using CMS Logo instead of the text label + posX_ = l + 0.045 * (1 - l - r) * W / H; + posY_ = 1 - t - 0.045 * (1 - t - b); + // This is only for TCanvas! + addCmsLogo((TCmsCanvas*) ppad, posX_,posY_ - 0.15,posX_ + 0.15 * H / W,posY_); + } + else { + if (cmsText.length()!=0) { + drawText(cmsText.c_str(),posX_,posY_,cmsTextFont,align_,cmsTextSize * t); + // Checking position of the extraText after the CMS logo text. + posY_ -= relExtraDY * cmsTextSize * t; + } + if (extraText.length()!=0) { // Only if something to write + drawText(extraText.c_str(),posX_,posY_,extraTextFont,align_,extraOverCmsTextSize * cmsTextSize * t); + } + else posY_ += relExtraDY * cmsTextSize * t; // Preparing for additional text! + } + + for (UInt_t i=0; iSetTextSize(textSize); + leg->SetTextFont(textFont); + leg->SetTextColor(textColor); + leg->SetBorderSize(0); + leg->SetFillStyle(0); + leg->SetFillColor(0); + + if (columns!=0) leg->SetNColumns(columns); + leg->Draw(); + + return leg; +} + +// ---------------------------------------------------------------------- +void drawText(const char *text, Float_t posX, Float_t posY, + Font_t font, Short_t align, Float_t size) + // This is a method to write a Text in a simplified and straightforward // (i.e. user-friendly) way. +{ + TLatex latex; + latex.SetNDC(); + latex.SetTextAngle(0); + latex.SetTextColor(kBlack); + + latex.SetTextFont(font); + latex.SetTextAlign(align); + latex.SetTextSize(size); + + latex.DrawLatex(posX, posY, text); +} + +// ---------------------------------------------------------------------- +void addCmsLogo (TCmsCanvas *canv,Float_t x0, Float_t y0, Float_t x1, Float_t y1, const char *logofile) + // This is a method to draw the CMS logo (that should be set using the + // corresponding method or on the fly) in a TPad set at the indicated location + // of the currently used TPad. +{ + if (logofile!=nullptr) { + SetCmsLogoFilename(logofile); // Trying to load the file) + } + + if (useCmsLogo.length()==0) { + std::cerr<<"ERROR: Not possible to add the CMS Logo as the file is not properly defined (not found?)"<AddCmsLogo(x0,y0,x1,y1,useCmsLogo.c_str()); + UpdatePad(); // For gPad +} + // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- diff --git a/src/cmsstyle.H b/src/cmsstyle.H index 02eb9ec..58914b6 100644 --- a/src/cmsstyle.H +++ b/src/cmsstyle.H @@ -10,10 +10,10 @@ #ifndef CMSSTYLE_CMSSTYLE__H_ #define CMSSTYLE_CMSSTYLE__H_ +#include "TCmsCanvas.H" #include -#include -#include +//OLD #include #include #include @@ -23,24 +23,55 @@ namespace cmsstyle { -// Some global variables: +// Some global variables (do not access directly, use the corresponding methods +// to access them or change them! std::string cms_lumi = "Run 2, 138 fb^{#minus1}"; std::string cms_energy = "13 TeV"; +std::string cmsText = "CMS"; +std::string extraText = "Preliminary"; + TStyle *cmsStyle = nullptr; +std::vector usingPalette2D; // To define a color palette for 2-D histograms + +Float_t lumiTextSize = 0.6; // text sizes and text offsets with respect to the top frame in unit of the top margin size +Float_t lumiTextOffset = 0.2; +Float_t cmsTextSize = 0.75; +Float_t cmsTextOffset = 0.1; + +std::string useCmsLogo = ""; // To draw the CMS Logo (filename with path must be provided, may be relative to $CMSSTYLE_DIR) + +//OLD Bool_t writeExtraText = kTRUE; // For the extra and addtional text + +Font_t cmsTextFont = 61; // default is helvetic-bold +Font_t extraTextFont = 52; // default is helvetica-italics +Font_t additionalInfoFont = 42; + +std::vector additionalInfo; ///< For extra info, text set under the extra text, for in-frame descriptor. + +Float_t extraOverCmsTextSize = 0.76; // ratio of 'CMS' and extra text size + /// Method to setup the style for the ROOT session! /// Arguments: /// force; allows to force the style within the ROOT seassion. void setCMSStyle (bool force=kTRUE); +/// Method to access the CMSStyle variable. It should be easier to access the +/// gROOT->gStyle pointer after setting the CMSStyle, but in case. +TStyle *getCMSStyle (void) {return cmsStyle;} // /////////////////////////////////////////////// // Configuration methods // /////////////////////////////////////////////// +/// This method allows to reset all the values for the CMS-related dataset +/// descriptors to the default. +/// +void ResetCmsDescriptors (void); + /// This method sets the centre-of-mass energy value and unit to be displayed. /// Arguments: /// energy: The centre-of-mass energy value. If 0 the "unit part if the used string) @@ -54,7 +85,45 @@ void setCMSStyle (bool force=kTRUE); void SetEnergy (float energy, const std::string &unit="TeV"); +/// This allows to set the location of the file with the CMS Logo in case we +/// want to use that instead of the "CMS" text. +/// When not set (default), the text version is written. +/// +/// Arguments: +/// filename: path and filename of the file to be drawn. It can be relative to +/// the CMSSTYLE_DIR path (when set). +void SetCmsLogoFilename (const std::string &filename); + +/// This allows to set the extra text. If set to an empty string, nothing +/// extra is written. +/// +/// Arguments: +/// text: string to be used as extra text. Empty string means "no extra text", +/// "p" is shortcut for Preliminary (default), +/// "s" is shortcut for Simulation +/// "su" is shortcut for Supplementary +/// "wip" is shortcut for "Work in progress" +/// "pw" is shortcut for "Private work (CMS data)" +/// +/// The shortcuts are provided to the recommended values explained in +/// https://cms-analysis.docs.cern.ch/guidelines/plotting/general/#cms-label-requirements +/// +/// Note that combinations are possibles, but not with the shortcuts! i.e. to +/// write "Simulation Preliminary" the only text value is the full expression. +/// +/// Furthermore, when "Private" is included in the text, the CMS logo is not DRAWN/WRITTEN! +/// +void SetExtraText (const std::string &text); +/// This methods allows to append additional information to be displayed, +/// e.g. a string identifying a region, or selection cuts in an automatic way +/// below the CMS-logo-related information (ExtraText, if any) when that is +/// drawn/written inside the frame. +/// +/// Arguments: +/// text: string to be appended as a new line of information. +/// +void AppendAdditionalInfo(const std::string &text) {additionalInfo.push_back(text);} /// Returns the maximum value associated to the objects that are going to be /// plotted. @@ -70,7 +139,9 @@ Float_t cmsReturnMaxY (const std::vector objs); // Plotting and related methods // /////////////////////////////////////////////// -/// This method defines and returns the TCanvas for a normal/basic plot. +/// This method defines and returns the TCmsCanvas (a wrapper for TCanvas) for +/// a normal/basic plot. +/// /// Arguments: /// canvName: Name of the canvas /// x_max: The minimum value of the x-axis. @@ -82,26 +153,26 @@ Float_t cmsReturnMaxY (const std::vector objs); /// iPos (optional): The position of the CMS logo. Defaults to 11 (see CMS_lumi method for further details). /// extraSpace (optional): Additional space to add to the left margin to fit labels. Defaults to 0. /// with_z_axis (optional): Whether to include a z-axis for 2D histograms. Defaults to False. -/// scaleLumi (optional): Scaling factor for the luminosity text size. Defaults to 0.75 (see CMS_lumi method for further details). +/// scaleLumi (optional): Scaling factor for the luminosity text size. Defaults to 1 (see CMS_lumi method for further details). /// yTitOffset (optional): Set the value for the Y-axis title offset in case default is not good. Defaults to -999 (ignored) /// /// Returns: -/// The produced TCanvas. It is created with a new command... calling +/// The produced TCmsCanvas. It is created with a new command... calling /// method takes responsability of its deletion. /// -TCanvas *cmsCanvas (const char *canvName, - Float_t x_min, - Float_t x_max, - Float_t y_min, - Float_t y_max, - const char *nameXaxis, - const char *nameYaxis, - Bool_t square = kTRUE, - Int_t iPos = 11, - Float_t extraSpace = 0, - Bool_t with_z_axis = kFALSE, - Float_t scaleLumi = 0.75, - Float_t yTitOffset = -999); +TCmsCanvas *cmsCanvas (const char *canvName, + Float_t x_min, + Float_t x_max, + Float_t y_min, + Float_t y_max, + const char *nameXaxis, + const char *nameYaxis, + Bool_t square = kTRUE, + Int_t iPos = 11, + Float_t extraSpace = 0, + Bool_t with_z_axis = kFALSE, + Float_t scaleLumi = 1.0, + Float_t yTitOffset = -999); /// This is the method to draw the "CMS" seal (logo and text) and put the /// luminosity value. @@ -110,11 +181,11 @@ TCanvas *cmsCanvas (const char *canvName, /// ppad: The pad where to draw the "CMS" seal /// iPos (optional): Position of the "CMS" seal. Defaults to 11 (top-left, left-aligned). /// Alternatives are 33 (top-right, right-aligned), 22 (center, centered) -/// and 0 (out of frame, in exceptional cases). +/// and 0x (out of frame, in exceptional cases). /// Position is calculated as 10*(alignment 1/2/3) + position (1/2/3 = l/c/r). -/// scaleLumi (optional): Scaling factor for the luminosity text size. Defaults to 0.75. +/// scaleLumi (optional): Scaling factor for the luminosity text size. Defaults to 1.0 /// -void CMS_lumi (TPad *ppad, Int_t iPosX=11, Float_t scaleLumi=0.75); +void CMS_lumi (TPad *ppad, Int_t iPosX=11, Float_t scaleLumi=1.0); /// This is a (mostly internal) method to setup the parameters of the provided /// object in a "serialized" way. @@ -139,6 +210,56 @@ void cmsObjectDraw (TObject *obj, Option_t *option = "", std::map confs = std::map()); +/// This is the method to setup a legend according to the style! +/// +/// Arguments: +/// x1: The left position of the legend in NDC (0-1). +/// y1: The bottom position of the legend in NDC (0-1). +/// x2: The right position of the legend in NDC (0-1). +/// y2: The top position of the legend in NDC (0-1). +/// textSize (optional): The text size of the legend entries. Defaults to 0.04. +/// textFont (optional): The font of the legend entries. Defaults to 42 (helvetica). +/// textColor (optional): The color of the legend entries. Defaults to kBlack. +/// columns (optional): The number of columns in the legend. +/// +/// Note that parameters may be override later on. +/// +/// Returns: +/// A pointer to the defined TLegend. It is created with a new command, so +/// the calling routine must take care of the deletion. +TLegend *cmsLeg(Float_t x1, Float_t y1, Float_t x2, Float_t y2, + Float_t textSize=0.04, + Style_t textFont=42, + Color_t textColor=kBlack, + Int_t columns=0); + +/// This is a method to write a Text in a simplified and straightforward +/// (i.e. user-friendly) way. +/// +/// Arguments: +/// text: Text to be written on the plot. +/// posX: Position in X dimension of the text (in NDC coordinates [0,1] +/// posY: Position in Y dimension of the text (in NDC coordinates [0,1] +/// font: Font to be used for the text +/// align: Code for the alignment of the text with respect to the position +/// size: Size of the font +/// +void drawText(const char *text, Float_t posX, Float_t posY, Font_t font, Short_t align, Float_t size); + +/// This is a method to draw the CMS logo (that should be set using the +/// corresponding method or on the fly) in a TPad set at the indicated location +/// of the currently used TPad. +/// +/// Arguments: +/// canv: CMSCanvas that needs to be used to plot the CMSLogo. +/// x0: X position (in relative dimensions) of the lower-left corner of the logo +/// y0: Y position (in relative dimensions) of the lower-left corner of the logo. +/// x1: X position (in relative dimensions) of the upper-left corner of the logo. +/// y1: Y position (in relative dimensions) of the upper-left corner of the logo. +/// logofile (optional): filename (with path) for the logo picture (see SetCmsLogoFilename for details) +/// +void addCmsLogo (TCmsCanvas *canv,Float_t x0, Float_t y0, Float_t x1, Float_t y1, const char *logofile=nullptr); + // /////////////////////////////////////////////// // Modifiers and accesors for the Style or Canvas // /////////////////////////////////////////////// diff --git a/src/cmsstyle/cmsstyle.py b/src/cmsstyle/cmsstyle.py index e8d8817..c269fc1 100644 --- a/src/cmsstyle/cmsstyle.py +++ b/src/cmsstyle/cmsstyle.py @@ -18,6 +18,9 @@ cms_lumi = "Run 2, 138 fb^{#minus1}" cms_energy = "13 TeV" +cmsText = "CMS" +extraText = "Preliminary" + cmsStyle = None usingPalette2D = None # To define a color palette for 2-D histograms @@ -85,10 +88,6 @@ def SetLumi (lumi, unit="fb", round_lumi=False): else: cms_lumi = lumi - -cmsText = "CMS" -extraText = "Preliminary" - def SetCmsText(text): """ Function that allows to edit the default @@ -184,6 +183,7 @@ class p6: kGrape = rt.kP6Grape kGray = rt.kP6Gray if (rt.GetColor(rt.kP6Violet).GetTitle=='#7a21dd'): # There was a bug in the first implementation in ROOT + # (I think no "released" version is affected. 6.34.00 is already OK) kViolet = rt.kP6Violet else: kViolet = rt.TColor.GetColor("#7a21dd") @@ -324,6 +324,7 @@ def SetCMSPalette(): cmsStyle.SetPalette(rt.kViridis) #cmsStyle.SetPalette(rt.kCividis) +# # # # def GetPalette(hist): """ Get the colour palette object associated with a histogram. @@ -532,6 +533,13 @@ def setCMSStyle(force=rt.kTRUE): # Using the Style. cmsStyle.cd() +# # # # +def getCMSStyle (): + """This returns the CMSStyle variable, in case it is required externally, + although usually it should be accessed via ROOT.gStyle after setting it. + """ + return cmsStyle + # ###### ## ## ###### ## ## ## ## ## #### # ## ## ### ### ## ## ## ## ## ### ### ## # ## #### #### ## ## ## ## #### #### ## @@ -542,6 +550,7 @@ def setCMSStyle(force=rt.kTRUE): def CMS_lumi(pad, iPosX=11, scaleLumi=None): + """ Draw the CMS text and luminosity information on the specified pad. @@ -1183,7 +1192,7 @@ def setRootObjectProperties (obj,**kwargs): elif hasattr(obj,xkey): method = xkey else: - print(f"Indicated argument for configuration is invalid: {xkey} {xval} {type(obj)}") + print("Indicated argument for configuration is invalid: {} {} {}".format(xkey, xval, type(obj))) raise AttributeError("Invalid argument") if xval is None: diff --git a/src/colorsets.H b/src/colorsets.H index c105e16..2fc3c76 100644 --- a/src/colorsets.H +++ b/src/colorsets.H @@ -13,7 +13,7 @@ #ifndef CMSSTYLE_COLORSETS__H_ #define CMSSTYLE_COLORSETS__H_ -#include "TColor.h" +#include namespace cmsstyle { @@ -36,21 +36,14 @@ struct p6 { const int p6::kRed = kP6Red; const int p6::kGrape = kP6Grape; const int p6::kGray = kP6Gray; -//SEE BELOW const int p6::kViolet = kP6Violet; + const int p6::kViolet = kP6Violet; // It should be fine! #else const int p6::kBlue = TColor::GetColor("#5790fc"); const int p6::kYellow = TColor::GetColor("#f89c20"); const int p6::kRed = TColor::GetColor("#e42536"); const int p6::kGrape = TColor::GetColor("#964a8b"); const int p6::kGray = TColor::GetColor("#9c9ca1"); -// SEE BELOW const int p6::kViolet = TColor::GetColor("#7a21dd"); -#endif - -// kP6Violet is wrong in some versions... -#if ROOT_VERSION_CODE < ROOT_VERSION(6,35,0) const int p6::kViolet = TColor::GetColor("#7a21dd"); -#else - const int p6::kViolet = kP6Violet; #endif /// /////////////////// diff --git a/tests/test_cmsCanvas.C b/tests/test_cmsCanvas.C index 768a08d..38aa38d 100644 --- a/tests/test_cmsCanvas.C +++ b/tests/test_cmsCanvas.C @@ -30,12 +30,26 @@ void test_cmsCanvas () } h1.Add(&h2); + auto *hdata = (TH1F*) h1.Clone("data"); + for (int i=1;i<=60;++i) { + hdata->SetBinError(i,0.12*hdata->GetBinContent(i)); + hdata->SetBinContent(i, hdata->GetBinContent(i)*(1+0.1*cos(6.28*i/20.))); + } + // Plotting the histogram! cmsstyle::setCMSStyle(); // Setting the style - TCanvas *c = cmsstyle::cmsCanvas("Testing",0.0,10.0,0.08,cmsstyle::cmsReturnMaxY({&h1,&h2}), - "X var [test]","Y var"); +// cmsstyle::SetCmsLogoFilename("CMS-BW-Label.png"); // e.g. +// cmsstyle::SetExtraText("Private work (CMS data)"); // e.g. +// cmsstyle::AppendAdditionalInfo("Doing our job"); // e.g. + + + TCanvas *c = cmsstyle::cmsCanvas("Testing",0.0,10.0,0.08,3*cmsstyle::cmsReturnMaxY({&h1,&h2,hdata}), + "X var [test]","Y var" + ,kTRUE // Square? + //,0 // position of the Logo: 0 is out-of-frame, default is 11. + ); gPad->SetLogy(); @@ -44,12 +58,25 @@ void test_cmsCanvas () {"FillStyle", 1001}, } ); - cmsstyle::cmsObjectDraw(&h2,"",{ {"LineColor", cmsstyle::p6::kGrape}, - {"FillColor", cmsstyle::p6::kGrape}, + cmsstyle::cmsObjectDraw(&h2,"",{ {"LineColor", cmsstyle::p6::kYellow}, + {"FillColor", cmsstyle::p6::kYellow}, {"FillStyle", 1001}, } ); + cmsstyle::cmsObjectDraw(hdata,"E",{ {"MarkerStyle", kFullCircle} + } ); + + + // The legend! + + auto *plotlegend = cmsstyle::cmsLeg (0.55,0.65,0.9,0.9); + + plotlegend->AddEntry(hdata,"Data","p"); + plotlegend->AddEntry(&h1,"Sample Number 1","f"); + plotlegend->AddEntry(&h2,"Sample Number 2","f"); +// cmsstyle::cmsObjectDraw(plotlegend); + // Saving the result! cmsstyle::UpdatePad(c); diff --git a/tests/test_cmsCanvas.py b/tests/test_cmsCanvas.py new file mode 100644 index 0000000..de69be2 --- /dev/null +++ b/tests/test_cmsCanvas.py @@ -0,0 +1,71 @@ +# +# This python macro +# +# Written by O. Gonzalez (2024_12_02) +# + +import math + +import ROOT + +import cmsstyle + +# # # # +def test_cmsCanvas (): + """Make the plot with the histograms on the fly. + + """ + + # Producing the histograms to plot + h1 = ROOT.TH1F("test1","test1",60,0.0,10.0) + h2 = ROOT.TH1F("test2","test2",60,0.0,10.0) + + for i in range(1,61): + h1.SetBinContent(i,10*math.exp(-i/5.0)) + h2.SetBinContent(i,8*math.exp(-i/15.0)) + + h1.Add(h2) + + hdata = h1.Clone("data") + for i in range(1,61): + hdata.SetBinError(i,0.12*hdata.GetBinContent(i)) + hdata.SetBinContent(i, hdata.GetBinContent(i)*(1+0.1*math.cos(6.28*i/20.))) + + # Plotting the histogram! + + cmsstyle.setCMSStyle() # Setting the style + + c = cmsstyle.cmsCanvas("Testing",0.0,10.0,0.08,3*cmsstyle.cmsReturnMaxY(h1,h2,hdata), + "X var [test]","Y var"); + + ROOT.gPad.SetLogy() + + cmsstyle.cmsObjectDraw(h1,"",LineColor=cmsstyle.p6.kGray, + FillColor=cmsstyle.p6.kGray, + FillStyle=1001) + + cmsstyle.cmsObjectDraw(h2,"",LineColor=cmsstyle.p6.kYellow, + FillColor=cmsstyle.p6.kYellow, + FillStyle=1001) + + cmsstyle.cmsObjectDraw(hdata,"E",MarkerStyle=ROOT.kFullCircle) + + # The legend! + + plotlegend = cmsstyle.cmsLeg(0.5,0.8,0.5,0.8) + + plotlegend.AddEntry(hdata,"Data","p") + plotlegend.AddEntry(h1,"Sample Number 1","f") + plotlegend.AddEntry(h2,"Sample Number 2","f") + + # Saving the result! + cmsstyle.UpdatePad(c) + + c.SaveAs("test_cmsCanvas.png") + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# For running as a shell command to get the list of files (comma-separated) +if __name__ == '__main__': + test_cmsCanvas() + +# #######################################################################