<jupyter_start><jupyter_text>This is a very brief demo to show how one could go from an environment with just a Python 3 runtime to pyhf installed and being useful.  Installation To take advantage of the great tools that `uproot` provides us let's install `pyhf` with the [`xmlio` options](https://diana-hep.org/pyhf/examples/notebooks/XML_ImportExport.html)```$ python3 -m pip install pyhf[xmlio]```but this is Binder! so I've already done that for you. :)<jupyter_code>! pyhf --version<jupyter_output>pyhf, version 0.2.2<jupyter_text>Running with CLI Now that we have `pyhf` installed let's ask what the CLI can do for us<jupyter_code>! pyhf --help<jupyter_output>Usage: pyhf [OPTIONS] COMMAND [ARGS]...

Options:
  --version   Show the version and exit.
  -h, --help  Show this message and exit.

Commands:
  cls
  inspect
  json2xml
  xml2json  Entrypoint XML: The top-level XML file for the PDF definition.<jupyter_text>and then let's use `pyhf inspect` to check to see if our `example.json` is in a correct form for the schema<jupyter_code>! pyhf inspect example.json<jupyter_output>Summary       
    ------------------  
       channels  1
        samples  2
     parameters  2
      modifiers  2

       channels  nbins
     ----------  -----
  singlechannel    2  

        samples
     ----------
     background
         signal

     parameters  constraint              modifiers
     ----------  ----------              ----------
             mu  unconstrained           normfactor
uncorr_bkguncrt  constrained_by_poisson  shapesys

    measurement           poi            parameters
     ----------        ----------        ----------
(*) Measurement            mu            (none)<jupyter_text>finally use `pyhf cls` to get the observed CL_s and the expected CL_s band values (the "[Brazil Band](https://arxiv.org/pdf/1306.3117.pdfpage=102)")<jupyter_code>! pyhf cls example.json<jupyter_output>{
    "CLs_exp": [
        0.0004090387453250841,
        0.0032606968023913925,
        0.02255257597653917,
        0.11898700005707148,
        0.39844667251932997
    ],
    "CLs_obs": 0.053994246621274014
}<jupyter_text>Expanding the CLI with other toolsAdditionally, you can also use [JSON Patch](https://tools.ietf.org/html/rfc6902) to patch a new signal in and update the likelihood (think reinterpretation).<jupyter_code>! pyhf cls example.json --patch new_signal.json<jupyter_output>{
    "CLs_exp": [
        0.031409129113842485,
        0.09019050672644717,
        0.2345563523518709,
        0.5053369568952392,
        0.8098259293224213
    ],
    "CLs_obs": 0.3536906623262466
}<jupyter_text>and as the return format from `pyhf cls` is JSON you can also use [`jq`](https://stedolan.github.io/jq/) to filter results<jupyter_code>! pyhf cls example.json --patch new_signal.json | jq .CLs_obs<jupyter_output>[0;39m0.3536906623262466[0m<jupyter_text>and of course given the way the CLI is setup you can pipe in the JSON which means that you can grab remotely hosted files (think HEPData). Here we `curl` down the Background only and signal patch JSON from HEPData ```$ curl -sL https://doi.org/10.17182/hepdata.89408.v1/r2 | \  tar -O -xzv RegionA/BkgOnly.json | \  pyhf cls --patch <(curl -sL https://doi.org/10.17182/hepdata.89408.v1/r2 | \    tar -O -xzv RegionA/patch.sbottom_1300_205_60.json) | \  jq .CLs_obs```<jupyter_code>! curl -sL https://doi.org/10.17182/hepdata.89408.v1/r2 | tar -O -xzv RegionA/BkgOnly.json > RegionA_BkgOnly.json
! curl -sL https://doi.org/10.17182/hepdata.89408.v1/r2 | tar -O -xzv RegionA/patch.sbottom_1300_205_60.json > RegionA_patch.sbottom_1300_205_60.json
! pyhf cls RegionA_BkgOnly.json --patch RegionA_patch.sbottom_1300_205_60.json | jq .CLs_obs<jupyter_output>RegionA/BkgOnly.json
RegionA/patch.sbottom_1300_205_60.json
/srv/conda/envs/notebook/lib/python3.7/site-packages/pyhf/tensor/numpy_backend.py:252: RuntimeWarning: invalid value encountered in log
  return n * np.log(lam) - lam - gammaln(n + 1.0)
[0;39m0.24443635754482018[0m<jupyter_text>and compare to another signal point```$ curl -sL https://doi.org/10.17182/hepdata.89408.v1/r2 | \  tar -O -xzv RegionA/BkgOnly.json | \  pyhf cls --patch <(curl -sL https://doi.org/10.17182/hepdata.89408.v1/r2 | \    tar -O -xzv RegionA/patch.sbottom_1300_230_100.json) | \  jq .CLs_obs```<jupyter_code>! curl -sL https://doi.org/10.17182/hepdata.89408.v1/r2 | tar -O -xzv RegionA/patch.sbottom_1300_230_100.json > RegionA_patch.sbottom_1300_230_100.json
! pyhf cls RegionA_BkgOnly.json --patch RegionA_patch.sbottom_1300_230_100.json | jq .CLs_obs<jupyter_output>RegionA/patch.sbottom_1300_230_100.json
/srv/conda/envs/notebook/lib/python3.7/site-packages/pyhf/tensor/numpy_backend.py:252: RuntimeWarning: invalid value encountered in log
  return n * np.log(lam) - lam - gammaln(n + 1.0)
[0;39m0.040766025813435774[0m
{'fraction_non_alphanumeric': 0.12492256865579186, 'fraction_numerical': 0.10695849679950444, 'mean_word_length': 3.0981387478849407, 'pattern_counts': {'":': 4, '<': 27, '<?xml version=': 0, '>': 28, 'https://': 11, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '50616', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 2085, 'n_tokens_neox': 1753, 'n_words': 410, 'path': 'notebooks/cli.ipynb', 'repo_name': 'matthewfeickert/talk-LHCb-Stats-Forum', 'size': '4843'}