{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# PyROOT Basics" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Let's import ROOT first and initialise interactive environment." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Welcome to JupyROOT 6.28/00\n" ] } ], "source": [ "import ROOT\n", "%jsroot on" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For non-interactive use, the following lines should be at the very top of the python file:\n", "```\n", "import ROOT\n", "ROOT.gROOT.SetBatch(True)\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Root Trees" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "A ROOT file with simulated Z->μμ events is prepared for you. Let's open it and get a `TTree` with the physics content out of it." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from ROOT import TFile\n", "file = TFile(\"Zmumu.root\")\n", "tree = file.Get(\"physics\")" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "To get familiarised with the contents of a file we can get number of entries and the content of one event." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Entries: 2500000\n", "======> EVENT:123\n", " lep1_pt = 36.6134\n", " lep1_eta = 1.72734\n", " lep1_phi = 2.45882\n", " lep1_E = 106.242\n", " lep1_m = 0.102701\n", " lep2_pt = 24.3234\n", " lep2_eta = 0.999867\n", " lep2_phi = -0.616201\n", " lep2_E = 37.5293\n", " lep2_m = 0.105446\n", " Z_pt = 12.4495\n", " Z_eta = 3.02829\n", " Z_phi = 2.32848\n", " Z_E = 143.771\n", " Z_m = 63.6461\n" ] } ], "source": [ "print(f\"Entries: {tree.GetEntries()}\")\n", "tree.Show(123)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "We can also scan through the tree and get a matrix of the quantities. We can pass the following arguments:\n", "- variables to list (e.g. `lep1_pt:lep2_pt:Z_pt`)\n", "- selection to apply (e.g. `Z_m > 200`)\n", "- options (let's skip this for now)\n", "- important for python: number of entries and first entry (otherwise the whole tree will get printed)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" }, { "name": "stdout", "output_type": "stream", "text": [ "************************************************\n", "* Row * lep1_pt * lep2_pt * Z_pt *\n", "************************************************\n", "* 1000 * 28.552259 * 24.640493 * 29.956617 *\n", "* 1001 * 46.691467 * 32.588851 * 20.080736 *\n", "* 1002 * 51.384120 * 23.717432 * 30.551261 *\n", "* 1003 * 51.648632 * 42.388435 * 93.866516 *\n", "* 1004 * 43.037010 * 40.113140 * 3.7478344 *\n", "* 1005 * 46.186592 * 43.645080 * 9.5110168 *\n", "* 1006 * 51.771820 * 35.814361 * 16.38661 *\n", "* 1007 * 30.069040 * 20.602933 * 9.9353952 *\n", "* 1008 * 42.196514 * 37.382263 * 5.1595315 *\n", "* 1009 * 51.599880 * 11.514470 * 46.104538 *\n", "************************************************\n" ] } ], "source": [ "tree.Scan(\"lep1_pt:lep2_pt:Z_pt\", \"\", \"\", 10, 1000)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" }, { "name": "stdout", "output_type": "stream", "text": [ "************************************************\n", "* Row * lep1_pt * lep2_pt * Z_pt *\n", "************************************************\n", "* 1213 * 139.37292 * 87.473121 * 66.915741 *\n", "* 1341 * 116.42005 * 39.788391 * 81.070587 *\n", "* 1844 * 85.993904 * 64.176918 * 28.775011 *\n", "************************************************\n", "==> 3 selected entries\n" ] } ], "source": [ "tree.Scan(\"lep1_pt:lep2_pt:Z_pt\", \"Z_m > 200\", \"\", 1000, 1000)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Useful `TTree` functions\n", "\n", "| Command | Action |\n", "| :------------ | :------- |\n", "| `tree.Print()` | prints the content of the tree |\n", "| `tree.Scan()` | scans the rows and columns |\n", "| `tree.Draw(\"x\")` | draw a branch of tree `x` |\n", "| `tree.Draw(\"x\", \"x > 0\")` | draw `x` when `x > 0` |\n", "| `tree.Draw(\"x\", \"x > 0 && y > 0\")` | draw `x` when both `x > 0` and `y > 0` |\n", "| `tree.Draw(\"y\", \"\", \"same\")` | uperimpose `y` on `x` |\n", "| `tree.Draw(\"y:x\")` | make `y` vs `x` 2D scatter plot |\n", "| `tree.Draw(\"z:y:x\")` | make `z:y:x` 3D plot |\n", "| `tree.Draw(\"sqrt(x*x + y*y)\")` | plot calculated quantity |\n", "| `tree.Draw(\"x>>h1\")` | dump a root branch to a histogram |\n", "| more... | [TTree documentation](https://root.cern.ch/doc/master/classTTree.html) |" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Drawing/Plotting Tree Content" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's plot a few variables directly. Note that when using Jupyter I have to create a canvas to plot on first. This is not needed when running interactively." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "from ROOT import TCanvas\n", "canvas = TCanvas(\"canvas\", \"\", 800, 450)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "One can draw directly from a `TTree`. The available options are:\n", "- the quantity to draw (e.g. `lep1_pt`)\n", "- selection to apply (e.g. `lep1_pt < 1000`)\n", "- drawing/plotting options" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "tree.Draw(\"lep1_pt\")\n", "canvas.Draw()" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "tree.Draw(\"lep1_pt\", \"lep1_pt < 250\", \"logy\")\n", "canvas.Draw()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "tree.Draw(\"lep1_pt:lep2_pt\", \"lep1_pt < 500 && lep2_pt < 500\", \"colz\")\n", "canvas.Draw()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "# we want to hide statistics box from now on\n", "from ROOT import gStyle\n", "gStyle.SetOptStat(0)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "As we have seen ROOT makes assumptions how to make a histogram, mainly binning and axis ranges.\n", "\n", "Let's create a histogram manually. Usually one uses `TH1D` which has double precision. Even if our quantities are not very precise, the precision matters if we have a lot of events (which is usually the case in HEP).\n", "\n", "The options for `TH1D` are:\n", "- name/identifier\n", "- title (used for display, limited LaTeX support present)\n", "- number of bins\n", "- minimum bin edge\n", "- maximum bin edge" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from ROOT import TH1D\n", "hist = TH1D(\"hist_lep1_pt\", \"Leading lepton p_{T}\", 50, 0, 500)\n", "tree.Draw(\"lep1_pt >> hist_lep1_pt\", \"\", \"logy\")\n", "canvas.Draw()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Often we want to do more complex data manipulations. In such case we loop the tree and fill the histogram(s) manually.\n", "\n", "Notes:\n", "- This loads the whole file by default, even the variables we are not iterested in.\n", "- In this example we will reuse the lepton pT histogram so we call `hist.Clear()` first." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "hist.Clear()\n", "hist_sum = TH1D(\"hist_lep_pt_sum\", \"Scalar sum of lepton p_{T}\", 50, 0, 500)\n", "hist_sum.Sumw2() # for proper error handling\n", "\n", "for entry in tree:\n", " hist.Fill(entry.lep1_pt)\n", " hist_sum.Fill(entry.lep1_pt + entry.lep2_pt, 0.95)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "hist.Draw(\"hist logy PLC\") # PLC automatically chooses colors\n", "hist_sum.Draw(\"hist same PLC\") # to draw on same canvas\n", "canvas.Draw()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we want to save to a file, we can make a new file and write the histogram to it." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "with TFile(\"output.root\", \"recreate\") as f: # or \"update\" if you want to write to an existing file\n", " hist_sum.Write() # write histogram to file\n", " f.WriteObject(hist, \"hist_custom\") # write histogram to file with custom name" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Useful `TH1` functions\n", "\n", "| Command | Action |\n", "| :------------ | :------- |\n", "| `hist.GetMean()` | mean of a histogram |\n", "| `hist.GetRMS()` | RMS of a histogram |\n", "| `hist.GetBinContent(i)` | content of a bin with index `i` |\n", "| `hist.GetBinError(i)` | uncertainty of a bin with index `i` |\n", "| `hist.GetMaximum()` | maximum value of the histogram |\n", "| `hist.GetMaximumBin()` | the bin with the maximum value |\n", "| `hist.Integral()` | integral of the histogram |\n", "| `hist.GetXaxis()` | x-axis |\n", "| `hist.GetYaxis()` | y-axis |\n", "| more... | [TH1 documentation](https://root.cern.ch/doc/master/classTH1.html) |" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise 1: Histogram Drawing\n", "\n", "Write a python macro `ExerciseHist.py`.\n", "\n", "1. Open the `Zmumu.root` file and load the tree called `physics`.\n", "2. Create two histograms with 40 bins ranging from 0 to 0.2 GeV to plot the muon masses.\n", "3. Fill the histograms with leading and subleading muon mass from branches `lep1_m` and `lep2_m`.\n", "4. Calculate the mean values and RMSs.\n", "5. Calculate the integrals.\n", "\n", "Bonus questions:\n", "1. Are the integrals the same and why?\n", "2. Write the histogram to a file." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Graphs" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Graphs are used to display value pairs, errors can be defined to be either symmetric or antisymmetric." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from ROOT import TGraphAsymmErrors\n", "# create graph with asymmetric errors with 3 points\n", "graph = TGraphAsymmErrors(3)\n", "# set the points and their errors\n", "graph.SetPoint(0, 3.0, 2.1)\n", "graph.SetPointError(0, 0.1, 0.2, 0.3, 0.4)\n", "graph.SetPoint(1, 5.0, 2.9)\n", "graph.SetPointError(1, 0.4, 0.3, 0.2, 0.1)\n", "graph.SetPoint(2, 7.2, 3.5)\n", "graph.SetPointError(2, 0.1, 0.1, 0.1, 0.1)\n", "# set style\n", "graph.SetMarkerStyle(21)\n", "graph.SetMarkerSize(1)\n", "# draw axis (A), points (L), and line (P)\n", "graph.Draw(\"APL\")\n", "canvas.Draw()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Useful `TGraph` functions\n", "\n", "| Command | Action |\n", "| :------------ | :------- |\n", "| [`TGraph(n)`](https://root.cern.ch/doc/master/classTGraph.html) | 1D graph without errors with `n` points |\n", "| [`TGraphErrors(n)`](https://root.cern.ch/doc/master/classTGraphErrors.html) | 1D graph with symmetrical errors with `n` points |\n", "| [`TGraphAsymmErrors(n)`](https://root.cern.ch/doc/master/classTGraphAsymmErrors.html) | 1D graph with asymmetrical errors with `n` points |\n", "| `graph.SetPoint(i, x, y)` | set a point with index `i` with coordinates `x` and `y` |\n", "| `graph.SetPointError(i, ex, ey)` | set symmetrical errors of a point with index `i` and values `ex` and `ey` |\n", "| `graph.SetPointError(i, exl, exh, eyl, exh)` | set asymmetrical errors of a point with index `i` and values `exl`, `exh`, `eyl` and `eyh` |\n", "| `graph.Fit(\"function\")` | fit a function with name `function` |\n", "| more... | click class constructor above |" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Functions\n", "\n", "Classes for 1 to 3 dimensional functions: `TF1`, `TF2` and `TF3`.\n", "\n", "One can use:\n", "- predefined functions\n", "- custom functions where `[n]` defines a `n`-th parameter\n", "- full C++ functions (will not look at today)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from ROOT import TF1, kBlue\n", "# use of predefined cuntions, e.g. \"gaus\", \"pol1\", \"pol3\"\n", "f_gaus = TF1(\"f_gaus\", \"gaus\", -2, 2)\n", "f_gaus.SetParameter(0, 10)\n", "f_gaus.SetParameter(1, 1)\n", "f_gaus.SetParameter(2, 0.5)\n", "# use of custom functions\n", "f_custom = TF1(\"f_custom\", \"[0]*exp(-0.5*pow((x-[1])/[2], 2))\", -2, 2)\n", "f_custom.SetParameter(0, 5)\n", "f_custom.SetParameter(1, 0)\n", "f_custom.SetParameter(2, 1)\n", "# make sure colors are different\n", "f_custom.SetLineColor(kBlue)\n", "# draw\n", "f_gaus.Draw()\n", "f_custom.Draw(\"same\")\n", "canvas.Draw()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Functions can be used to fit a `TGraph` or a `TH1`." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " FCN=244801 FROM MIGRAD STATUS=CONVERGED 87 CALLS 88 TOTAL\n", " EDM=1.09943e-09 STRATEGY= 1 ERROR MATRIX UNCERTAINTY 1.6 per cent\n", " EXT PARAMETER STEP FIRST \n", " NO. NAME VALUE ERROR SIZE DERIVATIVE \n", " 1 Constant 1.31588e+05 1.38812e+02 -1.20496e-01 -9.64144e-08\n", " 2 Mean 9.06721e+01 2.25958e-03 4.18742e-07 2.07789e-02\n", " 3 Sigma 3.23897e+00 2.59313e-03 -2.80403e-07 -2.12173e-01\n" ] }, { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from ROOT import TF1, TH1D\n", "\n", "f_fit = TF1(\"f_fit\", \"gaus\", 70, 110)\n", "\n", "hist_Z = TH1D(\"hist_Zmass\", \"Z boson mass\", 80, 70, 110)\n", "tree.Draw(\"Z_m >> hist_Zmass\")\n", "\n", "hist_Z.Fit(\"f_fit\") # note that this associates the function with the histogram\n", "\n", "canvas.Draw()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Useful `TF1` functions\n", "\n", "| Command | Action |\n", "| :------------ | :------- |\n", "| `graph.SetParameter(i, value)` | set parameter with index `i` and value `value` |\n", "| `graph.GetParameter(i)` | get parameter with index `i` |\n", "| `graph.GetParError(i)` | get parameter error with index `i` |\n", "| `graph.SetLineColor(kRed)` | set line color (e.g. `kRed`) |\n", "| more... | [TF1 documentation](https://root.cern.ch/doc/master/classTF1.html) |" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise 2: Graphs and Fits\n", "\n", "Write a python macro `ExerciseGraph.py`.\n", "\n", "1. Create a graph with symmetric errors and 5 points.\n", "2. Set the following points:\n", " `(1.0, 2.1), (2.0, 2.9), (3.0, 4.05), (4.0, 5.2), (5.0, 5.95)`\n", "3. Set the errors on `x` to 0.0 and the errors on `y` to 0.1 (all at once).\n", "4. Draw the graph including the axes and error bars.\n", "5. Create a one dimensional function `f(x) = ax + b` and fit it to the graph.\n", "\n", "Bonus questions:\n", "1. Programatically obtain the two parameters `a` and `b` and their estimated uncertainties." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Other Canvas Elements\n", "\n", "One canvas can be reused to plot many items besides histograms, graphs and functions:\n", "- legends\n", "- labels\n", "- lines\n", "- arrows\n", "\n", "Simple objects listed above do not require the `same` argument." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from ROOT import TLegend\n", "legend = TLegend(0.7, 0.75, 0.90, 0.87)\n", "legend.AddEntry(hist_Z, \"simulation\", \"l\")\n", "legend.AddEntry(f_fit, \"fit\", \"l\")\n", "legend.SetBorderSize(0)\n", "legend.Draw()\n", "canvas.Draw()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise 3: Canvas and Legends\n", "\n", "Write a python macro `ExerciseCanvas.py`.\n", "\n", "1. Create two histograms with 50 bins ranging from -3 to 3 with two different names.\n", "2. Fill first histogram with Gaussian distribution with 10000 entries.\n", "3. Fill second histogram with a second order polynomial and 5000 entries (hint: `hist2.FillRandom(\"pol2\", 500)`).\n", "4. Set the line color of the first histogram to `kRed` and second to `kBlue`.\n", "5. Draw both histograms on a canvas.\n", "6. Clone both histograms and normalise them (scale with inverse of the integral).\n", "7. Draw both histograms on a different canvas.\n", "8. Draw a legend on both canvases at position `(0.16, 0.63, 0.45, 0.91)`; bonus: do it after you created both canvases.\n", "9. Save both canvases in a PDF; bonus: save them in the same file." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ratio plots" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Often we want to plot ratio between two distributions (e.g. data and Monte Carlo or how well fit matches the distribution)." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " FCN=22.1778 FROM MIGRAD STATUS=CONVERGED 54 CALLS 55 TOTAL\n", " EDM=1.30715e-07 STRATEGY= 1 ERROR MATRIX ACCURATE \n", " EXT PARAMETER STEP FIRST \n", " NO. NAME VALUE ERROR SIZE DERIVATIVE \n", " 1 Constant 1.58988e+02 4.47298e+00 8.40573e-03 1.35230e-04\n", " 2 Mean 6.62197e-03 2.25355e-02 5.27819e-05 -8.76854e-04\n", " 3 Sigma 9.93481e-01 1.69678e-02 1.05689e-05 9.41157e-02\n" ] }, { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from ROOT import TH1D\n", "hist_for_ratio = TH1D(\"hist_ratio\", \"hist\", 50, -5, 5)\n", "hist_for_ratio.FillRandom(\"gaus\", 2000)\n", "hist_for_ratio.Fit(\"gaus\")\n", "hist_for_ratio.GetXaxis().SetTitle(\"x\")\n", "canvas.Clear() # Fit does not draw into correct pad\n", "\n", "from ROOT import TRatioPlot\n", "ratio_plot = TRatioPlot(hist_for_ratio)\n", "ratio_plot.Draw()\n", "ratio_plot.GetLowerRefYaxis().SetTitle(\"ratio\")\n", "ratio_plot.GetUpperRefYaxis().SetTitle(\"entries\")\n", "canvas.Draw()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But sometimes one ratio pad is not enough or we want to do it manually." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "# it seems JSROOT is buggy with multiple pads, so we disable it for this example\n", "%jsroot off" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from ROOT import TGraphAsymmErrors\n", "\n", "graph = TGraphAsymmErrors()\n", "for i in range(1, hist_Z.GetNbinsX() + 1):\n", " y = hist_Z.GetBinContent(i)\n", " x = hist_Z.GetBinCenter(i)\n", " exh = exl = hist_Z.GetBinWidth(i) / 2\n", "\n", " graph.SetPoint(i - 1, x, y / f_fit.Eval(x))\n", " graph.SetPointError(i - 1, exl, exh, hist_Z.GetBinErrorLow(i) / f_fit.Eval(x), hist_Z.GetBinErrorUp(i) / f_fit.Eval(x))\n", "\n", "from ROOT import TCanvas, TLine, TPad\n", "canvas_pads = TCanvas(\"canvas_pads\", \"Double ratio\")\n", "pad_top = TPad(\"top_pad\", \"Top pad\", 0, 0.4, 1, 1)\n", "pad_top.Draw()\n", "pad_bottom = TPad(\"bottom_pad\", \"Bottom pad\", 0, 0, 1, 0.4)\n", "pad_bottom.Draw()\n", "\n", "pad_top.cd()\n", "hist_Z.Draw()\n", "\n", "pad_bottom.cd()\n", "frame_bottom = pad_bottom.DrawFrame(hist_Z.GetBinLowEdge(1), 0, hist_Z.GetBinLowEdge(hist_Z.GetNbinsX() + 1), 2, \"Middle pad frame\");\n", "line = TLine(hist_Z.GetBinLowEdge(1), 1, hist_Z.GetBinLowEdge(hist_Z.GetNbinsX() + 1), 1)\n", "line.Draw(\"same\")\n", "graph.Draw(\"P same\")\n", "pad_bottom.Update()\n", "pad_bottom.RedrawAxis()\n", "\n", "canvas_pads.Draw()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unfortunately \"ROOT plotting math\" is quite complex. We will use a simple example to demonstrate the idea. Label sizes are relative to the height (and width) of the pad so we need to rescale the values to the size of the pad. As width is constant in our example we only take the fractions of the height and divide by it." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "pad_top.SetBottomMargin(0.01)\n", "pad_bottom.SetTopMargin(0.01)\n", "hist_Z.SetTitle(\"\")\n", "hist_Z.GetXaxis().SetLabelSize(0)\n", "hist_Z.GetYaxis().SetLabelSize(0.04/0.6)\n", "frame_bottom.SetTitle(\"\")\n", "frame_bottom.GetXaxis().SetLabelSize(0.04/0.4)\n", "frame_bottom.GetYaxis().SetLabelSize(0.04/0.4)\n", "canvas_pads.Draw()" ] } ], "metadata": { "kernelspec": { "display_name": "LCG_103 + venv", "language": "python-custom", "name": "lcg_103" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.12" }, "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" } } }, "nbformat": 4, "nbformat_minor": 2 }