{ "cells": [ { "cell_type": "markdown", "id": "ab948fc7", "metadata": {}, "source": [ "# TwoSidedFrequentistUpperLimitWithBands\n", "TwoSidedFrequentistUpperLimitWithBands\n", "\n", "\n", "This is a standard demo that can be used with any ROOT file\n", "prepared in the standard way. You specify:\n", " - name for input ROOT file\n", " - name of workspace inside ROOT file that holds model and data\n", " - name of ModelConfig that specifies details for calculator tools\n", " - name of dataset\n", "\n", "With default parameters the macro will attempt to run the\n", "standard hist2workspace example and read the ROOT file\n", "that it produces.\n", "\n", "You may want to control:\n", "```cpp\n", " double confidenceLevel=0.95;\n", " double additionalToysFac = 1.;\n", " int nPointsToScan = 12;\n", " int nToyMC = 200;\n", "```\n", "\n", "This uses a modified version of the profile likelihood ratio as\n", "a test statistic for upper limits (eg. test stat = 0 if muhat>mu).\n", "\n", "Based on the observed data, one defines a set of parameter points\n", "to be tested based on the value of the parameter of interest\n", "and the conditional MLE (eg. profiled) values of the nuisance parameters.\n", "\n", "At each parameter point, pseudo-experiments are generated using this\n", "fixed reference model and then the test statistic is evaluated.\n", "The auxiliary measurements (global observables) associated with the\n", "constraint terms in nuisance parameters are also fluctuated in the\n", "process of generating the pseudo-experiments in a frequentist manner\n", "forming an 'unconditional ensemble'. One could form a 'conditional'\n", "ensemble in which these auxiliary measurements are fixed. Note that the\n", "nuisance parameters are not randomized, which is a Bayesian procedure.\n", "Note, the nuisance parameters are floating in the fits. For each point,\n", "the threshold that defines the 95% acceptance region is found. This\n", "forms a \"Confidence Belt\".\n", "\n", "After constructing the confidence belt, one can find the confidence\n", "interval for any particular dataset by finding the intersection\n", "of the observed test statistic and the confidence belt. First\n", "this is done on the observed data to get an observed 1-sided upper limt.\n", "\n", "Finally, there expected limit and bands (from background-only) are\n", "formed by generating background-only data and finding the upper limit.\n", "The background-only is defined as such that the nuisance parameters are\n", "fixed to their best fit value based on the data with the signal rate fixed to 0.\n", "The bands are done by hand for now, will later be part of the RooStats tools.\n", "\n", "On a technical note, this technique IS the generalization of Feldman-Cousins\n", "with nuisance parameters.\n", "\n", "Building the confidence belt can be computationally expensive.\n", "Once it is built, one could save it to a file and use it in a separate step.\n", "\n", "Note, if you have a boundary on the parameter of interest (eg. cross-section)\n", "the threshold on the two-sided test statistic starts off at moderate values and plateaus.\n", "\n", "[#0] PROGRESS:Generation -- generated toys: 500 / 999\n", "NeymanConstruction: Prog: 12/50 total MC = 39 this test stat = 0\n", " SigXsecOverSM=0.69 alpha_syst1=0.136515 alpha_syst3=0.425415 beta_syst2=1.08496 [-1e+30, 0.011215] in interval = 1\n", "\n", "this tells you the values of the parameters being used to generate the pseudo-experiments\n", "and the threshold in this case is 0.011215. One would expect for 95% that the threshold\n", "would be ~1.35 once the cross-section is far enough away from 0 that it is essentially\n", "unaffected by the boundary. As one reaches the last points in the scan, the\n", "threshold starts to get artificially high. This is because the range of the parameter in\n", "the fit is the same as the range in the scan. In the future, these should be independently\n", "controlled, but they are not now. As a result the ~50% of pseudo-experiments that have an\n", "upward fluctuation end up with muhat = muMax. Because of this, the upper range of the\n", "parameter should be well above the expected upper limit... but not too high or one will\n", "need a very large value of nPointsToScan to resolve the relevant region. This can be\n", "improved, but this is the first version of this script.\n", "\n", "Important note: when the model includes external constraint terms, like a Gaussian\n", "constraint to a nuisance parameter centered around some nominal value there is\n", "a subtlety. The asymptotic results are all based on the assumption that all the\n", "measurements fluctuate... including the nominal values from auxiliary measurements.\n", "If these do not fluctuate, this corresponds to an \"conditional ensemble\". The\n", "result is that the distribution of the test statistic can become very non-chi^2.\n", "This results in thresholds that become very large.\n", "\n", "\n", "\n", "\n", "**Author:** Kyle Cranmer,Contributions from Aaron Armbruster, Haoshuang Ji, Haichen Wang and Daniel Whiteson \n", "This notebook tutorial was automatically generated with ROOTBOOK-izer from the macro found in the ROOT repository on Tuesday, May 19, 2026 at 08:36 PM." ] }, { "cell_type": "code", "execution_count": null, "id": "605eaea9", "metadata": { "collapsed": false }, "outputs": [], "source": [ "%%cpp -d\n", "#include \"TFile.h\"\n", "#include \"TROOT.h\"\n", "#include \"TH1F.h\"\n", "#include \"TCanvas.h\"\n", "#include \"TSystem.h\"\n", "#include \n", "\n", "#include \"RooWorkspace.h\"\n", "#include \"RooSimultaneous.h\"\n", "#include \"RooAbsData.h\"\n", "\n", "#include \"RooStats/ModelConfig.h\"\n", "#include \"RooStats/FeldmanCousins.h\"\n", "#include \"RooStats/ToyMCSampler.h\"\n", "#include \"RooStats/PointSetInterval.h\"\n", "#include \"RooStats/ConfidenceBelt.h\"\n", "\n", "#include \"RooStats/RooStatsUtils.h\"\n", "#include \"RooStats/ProfileLikelihoodTestStat.h\"\n", "\n", "using namespace RooFit;\n", "using namespace RooStats;\n", "using std::cout, std::endl;" ] }, { "cell_type": "markdown", "id": "df2ae959", "metadata": {}, "source": [ " Arguments are defined. " ] }, { "cell_type": "code", "execution_count": null, "id": "b8801847", "metadata": { "collapsed": false }, "outputs": [], "source": [ "const char *infile = \"\";\n", "const char *workspaceName = \"combined\";\n", "const char *modelConfigName = \"ModelConfig\";\n", "const char *dataName = \"obsData\";" ] }, { "cell_type": "code", "execution_count": null, "id": "1f1be0a5", "metadata": { "collapsed": false }, "outputs": [], "source": [ "double confidenceLevel = 0.95;" ] }, { "cell_type": "markdown", "id": "f2fe825c", "metadata": {}, "source": [ "degrade/improve number of pseudo-experiments used to define the confidence belt.\n", "value of 1 corresponds to default number of toys in the tail, which is 50/(1-confidenceLevel)" ] }, { "cell_type": "code", "execution_count": null, "id": "fdce8ae9", "metadata": { "collapsed": false }, "outputs": [], "source": [ "double additionalToysFac = 0.5;\n", "int nPointsToScan = 20; // number of steps in the parameter of interest\n", "int nToyMC = 200; // number of toys used to define the expected limit and band" ] }, { "cell_type": "markdown", "id": "35620cce", "metadata": {}, "source": [ "-------------------------------------------------------\n", "First part is just to access a user-defined file\n", "or create the standard example file if it doesn't exist" ] }, { "cell_type": "code", "execution_count": null, "id": "1e0e0ce1", "metadata": { "collapsed": false }, "outputs": [], "source": [ "const char *filename = \"\";\n", "if (!strcmp(infile, \"\")) {\n", " filename = \"results/example_combined_GaussExample_model.root\";\n", " bool fileExist = !gSystem->AccessPathName(filename); // note opposite return code\n", " // if file does not exists generate with histfactory\n", " if (!fileExist) {\n", " // Normally this would be run on the command line\n", " cout << \"will run standard hist2workspace example\" << endl;\n", " gROOT->ProcessLine(\".! prepareHistFactory .\");\n", " gROOT->ProcessLine(\".! hist2workspace config/example.xml\");\n", " cout << \"\\n\\n---------------------\" << endl;\n", " cout << \"Done creating example input\" << endl;\n", " cout << \"---------------------\\n\\n\" << endl;\n", " }\n", "\n", "} else\n", " filename = infile;" ] }, { "cell_type": "markdown", "id": "3308ade1", "metadata": {}, "source": [ "Try to open the file" ] }, { "cell_type": "code", "execution_count": null, "id": "8ae35b51", "metadata": { "collapsed": false }, "outputs": [], "source": [ "TFile *inputFile = TFile::Open(filename);" ] }, { "cell_type": "markdown", "id": "b77d5100", "metadata": {}, "source": [ "-------------------------------------------------------\n", "Now get the data and workspace" ] }, { "cell_type": "markdown", "id": "d8111b46", "metadata": {}, "source": [ "get the workspace out of the file" ] }, { "cell_type": "code", "execution_count": null, "id": "d539eb2e", "metadata": { "collapsed": false }, "outputs": [], "source": [ "RooWorkspace *w = (RooWorkspace *)inputFile->Get(workspaceName);" ] }, { "cell_type": "markdown", "id": "f5eeec17", "metadata": {}, "source": [ "get the modelConfig out of the file" ] }, { "cell_type": "code", "execution_count": null, "id": "2a762dc3", "metadata": { "collapsed": false }, "outputs": [], "source": [ "ModelConfig *mc = (ModelConfig *)w->obj(modelConfigName);" ] }, { "cell_type": "markdown", "id": "907a08c1", "metadata": {}, "source": [ "get the modelConfig out of the file" ] }, { "cell_type": "code", "execution_count": null, "id": "2f423082", "metadata": { "collapsed": false }, "outputs": [], "source": [ "RooAbsData *data = w->data(dataName);\n", "\n", "cout << \"Found data and ModelConfig:\" << endl;\n", "mc->Print();" ] }, { "cell_type": "markdown", "id": "02e9dd00", "metadata": {}, "source": [ "-------------------------------------------------------\n", "Now get the POI for convenience\n", "you may want to adjust the range of your POI" ] }, { "cell_type": "code", "execution_count": null, "id": "a6f23c5b", "metadata": { "collapsed": false }, "outputs": [], "source": [ "RooRealVar *firstPOI = (RooRealVar *)mc->GetParametersOfInterest()->first();\n", "/* firstPOI->setMin(0);*/\n", "/* firstPOI->setMax(10);*/" ] }, { "cell_type": "markdown", "id": "ee098ebb", "metadata": {}, "source": [ "-------------------------------------------------------\n", "create and use the FeldmanCousins tool\n", "to find and plot the 95% confidence interval\n", "on the parameter of interest as specified\n", "in the model config\n", "REMEMBER, we will change the test statistic\n", "so this is NOT a Feldman-Cousins interval" ] }, { "cell_type": "code", "execution_count": null, "id": "5a0627aa", "metadata": { "collapsed": false }, "outputs": [], "source": [ "FeldmanCousins fc(*data, *mc);\n", "fc.SetConfidenceLevel(confidenceLevel);\n", "fc.AdditionalNToysFactor(additionalToysFac); // improve sampling that defines confidence belt" ] }, { "cell_type": "markdown", "id": "a2a0b7ca", "metadata": {}, "source": [ "fc.UseAdaptiveSampling(true); // speed it up a bit, but don't use for expected limits" ] }, { "cell_type": "code", "execution_count": null, "id": "3515a36a", "metadata": { "collapsed": false }, "outputs": [], "source": [ "fc.SetNBins(nPointsToScan); // set how many points per parameter of interest to scan\n", "fc.CreateConfBelt(true); // save the information in the belt for plotting" ] }, { "cell_type": "markdown", "id": "67c7dc22", "metadata": {}, "source": [ "-------------------------------------------------------\n", "Feldman-Cousins is a unified limit by definition\n", "but the tool takes care of a few things for us like which values\n", "of the nuisance parameters should be used to generate toys.\n", "so let's just change the test statistic and realize this is\n", "no longer \"Feldman-Cousins\" but is a fully frequentist Neyman-Construction.\n", "fc.GetTestStatSampler()->SetTestStatistic(&onesided);\n", "((ToyMCSampler*) fc.GetTestStatSampler())->SetGenerateBinned(true);" ] }, { "cell_type": "code", "execution_count": null, "id": "5ca494f9", "metadata": { "collapsed": false }, "outputs": [], "source": [ "ToyMCSampler *toymcsampler = (ToyMCSampler *)fc.GetTestStatSampler();\n", "ProfileLikelihoodTestStat *testStat = dynamic_cast(toymcsampler->GetTestStatistic());" ] }, { "cell_type": "markdown", "id": "c62b22f0", "metadata": {}, "source": [ "Since this tool needs to throw toy MC the PDF needs to be\n", "extended or the tool needs to know how many entries in a dataset\n", "per pseudo experiment.\n", "In the 'number counting form' where the entries in the dataset\n", "are counts, and not values of discriminating variables, the\n", "datasets typically only have one entry and the PDF is not\n", "extended." ] }, { "cell_type": "code", "execution_count": null, "id": "74a273d7", "metadata": { "collapsed": false }, "outputs": [], "source": [ "if (!mc->GetPdf()->canBeExtended()) {\n", " if (data->numEntries() == 1)\n", " fc.FluctuateNumDataEntries(false);\n", " else\n", " cout << \"Not sure what to do about this model\" << endl;\n", "}\n", "\n", "if (mc->GetGlobalObservables()) {\n", " cout << \"will use global observables for unconditional ensemble\" << endl;\n", " mc->GetGlobalObservables()->Print();\n", " toymcsampler->SetGlobalObservables(*mc->GetGlobalObservables());\n", "}" ] }, { "cell_type": "markdown", "id": "9b73f1ff", "metadata": {}, "source": [ "Now get the interval" ] }, { "cell_type": "code", "execution_count": null, "id": "bf2174ce", "metadata": { "collapsed": false }, "outputs": [], "source": [ "PointSetInterval *interval = fc.GetInterval();\n", "ConfidenceBelt *belt = fc.GetConfidenceBelt();" ] }, { "cell_type": "markdown", "id": "a16c7a36", "metadata": {}, "source": [ "print out the interval on the first Parameter of Interest" ] }, { "cell_type": "code", "execution_count": null, "id": "194c7d89", "metadata": { "collapsed": false }, "outputs": [], "source": [ "cout << \"\\n95% interval on \" << firstPOI->GetName() << \" is : [\" << interval->LowerLimit(*firstPOI) << \", \"\n", " << interval->UpperLimit(*firstPOI) << \"] \" << endl;" ] }, { "cell_type": "markdown", "id": "2d8cb8e3", "metadata": {}, "source": [ "get observed UL and value of test statistic evaluated there" ] }, { "cell_type": "code", "execution_count": null, "id": "de093ed8", "metadata": { "collapsed": false }, "outputs": [], "source": [ "RooArgSet tmpPOI(*firstPOI);\n", "double observedUL = interval->UpperLimit(*firstPOI);\n", "firstPOI->setVal(observedUL);\n", "double obsTSatObsUL = fc.GetTestStatSampler()->EvaluateTestStatistic(*data, tmpPOI);" ] }, { "cell_type": "markdown", "id": "3f9fb373", "metadata": {}, "source": [ "Ask the calculator which points were scanned" ] }, { "cell_type": "code", "execution_count": null, "id": "dd1e4db6", "metadata": { "collapsed": false }, "outputs": [], "source": [ "RooDataSet *parameterScan = (RooDataSet *)fc.GetPointsToScan();\n", "RooArgSet *tmpPoint;" ] }, { "cell_type": "markdown", "id": "9e9b050d", "metadata": {}, "source": [ "make a histogram of parameter vs. threshold" ] }, { "cell_type": "code", "execution_count": null, "id": "5a2e7695", "metadata": { "collapsed": false }, "outputs": [], "source": [ "TH1F *histOfThresholds =\n", " new TH1F(\"histOfThresholds\", \"\", parameterScan->numEntries(), firstPOI->getMin(), firstPOI->getMax());\n", "histOfThresholds->GetXaxis()->SetTitle(firstPOI->GetName());\n", "histOfThresholds->GetYaxis()->SetTitle(\"Threshold\");" ] }, { "cell_type": "markdown", "id": "b03e9429", "metadata": {}, "source": [ "loop through the points that were tested and ask confidence belt\n", "what the upper/lower thresholds were.\n", "For FeldmanCousins, the lower cut off is always 0" ] }, { "cell_type": "code", "execution_count": null, "id": "729d705f", "metadata": { "collapsed": false }, "outputs": [], "source": [ "for (Int_t i = 0; i < parameterScan->numEntries(); ++i) {\n", " tmpPoint = (RooArgSet *)parameterScan->get(i)->clone(\"temp\");\n", " // cout <<\"get threshold\"<GetAcceptanceRegionMax(*tmpPoint);\n", " double poiVal = tmpPoint->getRealValue(firstPOI->GetName());\n", " histOfThresholds->Fill(poiVal, arMax);\n", "}\n", "TCanvas *c1 = new TCanvas();\n", "c1->Divide(2);\n", "c1->cd(1);\n", "histOfThresholds->SetMinimum(0);\n", "histOfThresholds->Draw();\n", "c1->cd(2);" ] }, { "cell_type": "markdown", "id": "b9779ac9", "metadata": {}, "source": [ "-------------------------------------------------------\n", "Now we generate the expected bands and power-constraint" ] }, { "cell_type": "markdown", "id": "16821314", "metadata": {}, "source": [ "First: find parameter point for mu=0, with conditional MLEs for nuisance parameters" ] }, { "cell_type": "code", "execution_count": null, "id": "1cc35b12", "metadata": { "collapsed": false }, "outputs": [], "source": [ "std::unique_ptr nll{mc->GetPdf()->createNLL(*data)};\n", "std::unique_ptr profile{nll->createProfile(*mc->GetParametersOfInterest())};\n", "firstPOI->setVal(0.);\n", "profile->getVal(); // this will do fit and set nuisance parameters to profiled values\n", "RooArgSet *poiAndNuisance = new RooArgSet();\n", "if (mc->GetNuisanceParameters())\n", " poiAndNuisance->add(*mc->GetNuisanceParameters());\n", "poiAndNuisance->add(*mc->GetParametersOfInterest());\n", "w->saveSnapshot(\"paramsToGenerateData\", *poiAndNuisance);\n", "RooArgSet *paramsToGenerateData = (RooArgSet *)poiAndNuisance->snapshot();\n", "cout << \"\\nWill use these parameter points to generate pseudo data for bkg only\" << endl;\n", "paramsToGenerateData->Print(\"v\");\n", "\n", "RooArgSet unconditionalObs;\n", "unconditionalObs.add(*mc->GetObservables());\n", "unconditionalObs.add(*mc->GetGlobalObservables()); // comment this out for the original conditional ensemble\n", "\n", "double CLb = 0;\n", "double CLbinclusive = 0;" ] }, { "cell_type": "markdown", "id": "57b1ab8e", "metadata": {}, "source": [ "Now we generate background only and find distribution of upper limits" ] }, { "cell_type": "code", "execution_count": null, "id": "167bee97", "metadata": { "collapsed": false }, "outputs": [], "source": [ "TH1F *histOfUL = new TH1F(\"histOfUL\", \"\", 100, 0, firstPOI->getMax());\n", "histOfUL->GetXaxis()->SetTitle(\"Upper Limit (background only)\");\n", "histOfUL->GetYaxis()->SetTitle(\"Entries\");\n", "for (int imc = 0; imc < nToyMC; ++imc) {\n", "\n", " // set parameters back to values for generating pseudo data\n", " // cout << \"\\n get current nuis, set vals, print again\" << endl;\n", " w->loadSnapshot(\"paramsToGenerateData\");\n", " // poiAndNuisance->Print(\"v\");\n", "\n", " std::unique_ptr toyData;\n", " // now generate a toy dataset for the main measurement\n", " if (!mc->GetPdf()->canBeExtended()) {\n", " if (data->numEntries() == 1)\n", " toyData = std::unique_ptr{mc->GetPdf()->generate(*mc->GetObservables(), 1)};\n", " else\n", " cout << \"Not sure what to do about this model\" << endl;\n", " } else {\n", " // cout << \"generating extended dataset\"<{mc->GetPdf()->generate(*mc->GetObservables(), Extended())};\n", " }\n", "\n", " // generate global observables\n", " std::unique_ptr one{mc->GetPdf()->generateSimGlobal(*mc->GetGlobalObservables(), 1)};\n", " const RooArgSet *values = one->get();\n", " std::unique_ptr allVars{mc->GetPdf()->getVariables()};\n", " allVars->assign(*values);\n", "\n", " // get test stat at observed UL in observed data\n", " firstPOI->setVal(observedUL);\n", " double toyTSatObsUL = fc.GetTestStatSampler()->EvaluateTestStatistic(*toyData, tmpPOI);\n", " // toyData->get()->Print(\"v\");\n", " // cout <<\"obsTSatObsUL \" <numEntries(); ++i) {\n", " tmpPoint = (RooArgSet *)parameterScan->get(i)->clone(\"temp\");\n", " double arMax = belt->GetAcceptanceRegionMax(*tmpPoint);\n", " firstPOI->setVal(tmpPoint->getRealValue(firstPOI->GetName()));\n", " // double thisTS = profile->getVal();\n", " double thisTS = fc.GetTestStatSampler()->EvaluateTestStatistic(*toyData, tmpPOI);\n", "\n", " // cout << \"poi = \" << firstPOI->getVal()\n", " // << \" max is \" << arMax << \" this profile = \" << thisTS << endl;\n", " // cout << \"thisTS = \" << thisTS<getVal();\n", " } else {\n", " break;\n", " }\n", " }\n", "\n", " histOfUL->Fill(thisUL);\n", "\n", " // for few events, data is often the same, and UL is often the same\n", " // cout << \"thisUL = \" << thisUL<Draw();\n", "c1->SaveAs(\"two-sided_upper_limit_output.pdf\");" ] }, { "cell_type": "markdown", "id": "021a8e75", "metadata": {}, "source": [ "if you want to see a plot of the sampling distribution for a particular scan point:" ] }, { "cell_type": "code", "execution_count": null, "id": "ab9417af", "metadata": { "collapsed": false }, "outputs": [], "source": [ "/*\n", "SamplingDistPlot sampPlot;\n", "int indexInScan = 0;\n", "tmpPoint = (RooArgSet*) parameterScan->get(indexInScan)->clone(\"temp\");\n", "firstPOI->setVal( tmpPoint->getRealValue(firstPOI->GetName()) );\n", "toymcsampler->SetParametersForTestStat(tmpPOI);\n", "SamplingDistribution* samp = toymcsampler->GetSamplingDistribution(*tmpPoint);\n", "sampPlot.AddSamplingDistribution(samp);\n", "sampPlot.Draw();\n", " */" ] }, { "cell_type": "markdown", "id": "db627371", "metadata": {}, "source": [ "Now find bands and power constraint" ] }, { "cell_type": "code", "execution_count": null, "id": "1731b11d", "metadata": { "collapsed": false }, "outputs": [], "source": [ "Double_t *bins = histOfUL->GetIntegral();\n", "TH1F *cumulative = (TH1F *)histOfUL->Clone(\"cumulative\");\n", "cumulative->SetContent(bins);\n", "double band2sigDown = 0, band1sigDown = 0, bandMedian = 0, band1sigUp = 0, band2sigUp = 0;\n", "for (int i = 1; i <= cumulative->GetNbinsX(); ++i) {\n", " if (bins[i] < RooStats::SignificanceToPValue(2))\n", " band2sigDown = cumulative->GetBinCenter(i);\n", " if (bins[i] < RooStats::SignificanceToPValue(1))\n", " band1sigDown = cumulative->GetBinCenter(i);\n", " if (bins[i] < 0.5)\n", " bandMedian = cumulative->GetBinCenter(i);\n", " if (bins[i] < RooStats::SignificanceToPValue(-1))\n", " band1sigUp = cumulative->GetBinCenter(i);\n", " if (bins[i] < RooStats::SignificanceToPValue(-2))\n", " band2sigUp = cumulative->GetBinCenter(i);\n", "}\n", "cout << \"-2 sigma band \" << band2sigDown << endl;\n", "cout << \"-1 sigma band \" << band1sigDown << \" [Power Constraint)]\" << endl;\n", "cout << \"median of band \" << bandMedian << endl;\n", "cout << \"+1 sigma band \" << band1sigUp << endl;\n", "cout << \"+2 sigma band \" << band2sigUp << endl;\n", "\n", "// print out the interval on the first Parameter of Interest\n", "cout << \"\\nobserved 95% upper-limit \" << interval->UpperLimit(*firstPOI) << endl;\n", "cout << \"CLb strict [P(toy>obs|0)] for observed 95% upper-limit \" << CLb << endl;\n", "cout << \"CLb inclusive [P(toy>=obs|0)] for observed 95% upper-limit \" << CLbinclusive << endl;" ] }, { "cell_type": "markdown", "id": "d4f2bbcb", "metadata": {}, "source": [ "Draw all canvases " ] }, { "cell_type": "code", "execution_count": null, "id": "dabcb007", "metadata": { "collapsed": false }, "outputs": [], "source": [ "%jsroot on\n", "gROOT->GetListOfCanvases()->Draw()" ] } ], "metadata": { "kernelspec": { "display_name": "ROOT C++", "language": "c++", "name": "root" }, "language_info": { "codemirror_mode": "text/x-c++src", "file_extension": ".C", "mimetype": " text/x-c++src", "name": "c++" } }, "nbformat": 4, "nbformat_minor": 5 }