Command line tools (gammapy.scripts
)¶
Warning
The Gammapy command line interface (CLI) described here is experimental and only supports a small sub-set of the functionality available via the Gammapy Python package. We have added a few sections at the bottom of this page to explain the current Implementation, Limitations and Plan. And since we don’t offer much here yet, at least we describe how you can Write your own CLI.
Introduction¶
Currently, Gammapy is first and foremost a Python package. This means that to use it you have to write a Python script or Jupyter notebook, where you import the functions and classes needed for a given analysis, and then call them, passing parameters to configure the analysis.
That said, for some very commonly used and easy to configure analysis tasks we have implemented a command line interface (CLI). It is automatically installed together with the Gammapy python package.
Execute¶
To execute the Gammapy CLI, type the command gammapy
at your terminal shell (not in Python):
$ gammapy --help
or equivalently, just type this:
$ gammapy
Either way, the command should print some help text to the console and then exit:
$ gammapy
Gammapy command line interface.
Gammapy is a Python package for gamma-ray astronomy.
For further information, see http://gammapy.org/
Options:
--log-level [debug|info|warning|error]
Logging verbosity level
--ignore-warnings Ignore warnings?
--version Print version and exit
-h, --help Show this message and exit.
Commands:
check Run checks for Gammapy
image Analysis - 2D images
info Display information about Gammapy
All CLI functionality for Gammapy is implemented as sub-commands of the
main gammapy
command. If a command has sub-commands, they are listed
in the help output. E.g. the help output from gammapy
above shows
that there is a sub-command called gammapy image
. Actually, gammapy image
itself isn’t a command that does something, but another command group
that is used to group sub-commands:
$ gammapy image
Usage: gammapy image [OPTIONS] COMMAND [ARGS]...
Analysis - 2D images
Options:
-h, --help Show this message and exit.
Commands:
bin Bin events into an image.
fit Fit morphology model to image using Sherpa.
ts Compute TS image.
Finally, gammapy image bin
is a proper sub-sub-command that does something,
it doesn’t have any sub-commands itself, just arguments and options. If you call
it without passing the required arguments, you will get an error:
$ gammapy image bin
Usage: gammapy image bin [OPTIONS] EVENT_FILE REFERENCE_FILE OUT_FILE
Error: Missing argument "event_file".
Use --help
to see the help text and available options:
$ gammapy image bin --help
Usage: gammapy image bin [OPTIONS] EVENT_FILE REFERENCE_FILE OUT_FILE
Bin events into an image.
You have to give the event, reference and out FITS filename.
Options:
--overwrite Overwrite existing files?
-h, --help Show this message and exit.
So now you know how the Gammapy CLI is structured and how to discover all available sub-commands, arguments and options.
Command not found¶
Usually tools that install Gammapy (e.g. setuptools via python setup.py install
or pip
or package managers like conda
) will put the gammapy
command
line tool in a directory that is on your PATH
, and if you type gammapy
the command is found and executed.
However, due to the large number of supported systems (Linux, Mac OS, Windows)
and different ways to install Python packages like Gammapy (e.g. system install, user install,
virtual environments, conda environments) and environments to launch command line tools
like gammapy
(e.g. bash, csh, Windows command prompt, Jupyter, …) it is not unheard of
that users have trouble running gammapy
after installing it.
This usually looks like this:
$ gammapy
-bash: gammapy: command not found
If you just installed Gammapy, search the install log for the message
“Installing gammapy script” to see where gammapy
was installed, and
check that this location is on your PATH:
echo $PATH
If you don’t manage to figure out where the gammapy
command line tool is installed,
you can try calling it like this instead:
$ python -m gammapy
This also has the advantage that it avoids issues where users have multiple versions
of Python and Gammapy installed and accidentally launch one they don’t want because
it comes first on their PATH
. For the same reason these days the recommended way
to use e.g. pip
is via python -m pip
.
If this still doesn’t work, check if you are using the right Python and have Gammapy installed:
$ which python
$ python -c 'import gammapy'
To see more information about your shell environment, these commands might be helpful:
$ python -m site
$ python -m gammapy info
$ echo $PATH
$ conda info -a # if you're using conda
If you’re still stuck or have any question, feel free to ask for help with installation issues on the Gammapy mailing list of Slack any time!
Example¶
Here’s one example what you can do with the Gammapy CLI: use the gammapy image bin
command to create a counts image from a Fermi-LAT event list as well as a FITS image
that serves as a reference geometry (projection, center, binning) for the counts image
we’re creating.
$ gammapy image bin --help
Usage: gammapy image bin [OPTIONS] EVENT_FILE REFERENCE_FILE OUT_FILE
Bin events into an image.
You have to give the event, reference and out FITS filename.
Options:
--overwrite Overwrite existing files?
-h, --help Show this message and exit.
$ gammapy image bin \
$GAMMAPY_EXTRA/datasets/fermi_2fhl/2fhl_events.fits.gz \
$GAMMAPY_EXTRA/datasets/fermi_survey/all.fits.gz \
out.fits
INFO:gammapy.scripts.image_bin:Executing cli_image_bin
INFO:gammapy.scripts.image_bin:Reading /Users/deil/code/gammapy-extra/datasets/fermi_2fhl/2fhl_events.fits.gz
INFO:gammapy.scripts.image_bin:Reading /Users/deil/code/gammapy-extra/datasets/fermi_survey/all.fits.gz
INFO:gammapy.scripts.image_bin:Writing out.fits
If you have the FTOOLS installed or other tools that can work with the files that Gammapy supports, you can of course use them together:
$ ftlist $GAMMAPY_EXTRA/datasets/fermi_2fhl/2fhl_events.fits.gz H
Name Type Dimensions
---- ---- ----------
HDU 1 Primary Array Null Array
HDU 2 EVENTS BinTable 23 cols x 60978 rows
HDU 3 GTI BinTable 2 cols x 36589 rows
$ ftlist out.fits H
Name Type Dimensions
---- ---- ----------
HDU 1 COUNTS Image Real8(2001x101)
$ ds9 out.fits
Reference¶
Here is auto-generated documentation for all available sub-commands, arguments
and options of the gammapy
command line interface (CLI).
It’s not very readable at the moment. With the current formatting it’s a bit hard to tell where documentation for a new sub-command starts and what level of subcommand one is looking at for a given heading. Maybe change to one page per sub-command?
gammapy¶
Gammapy command line interface (CLI).
Gammapy is a Python package for gamma-ray astronomy.
Use --help
to see available sub-commands, as well as the available
arguments and options for each sub-command.
For further information, see http://gammapy.org/ and http://docs.gammapy.org/
Examples ——–
$ gammapy –help $ gammapy –version $ gammapy info –help $ gammapy info
gammapy [OPTIONS] COMMAND [ARGS]...
Options
-
--log-level
<log_level>
¶ Logging verbosity level
-
--ignore-warnings
¶
Ignore warnings?
-
--version
¶
Print version and exit
image¶
Analysis - 2D images
gammapy image [OPTIONS] COMMAND [ARGS]...
bin¶
Bin events into an image.
You have to give the event, reference and out FITS filename.
gammapy image bin [OPTIONS] EVENT_FILE REFERENCE_FILE OUT_FILE
Options
-
--overwrite
¶
Overwrite existing files?
Arguments
-
EVENT_FILE
¶
Required argument
-
REFERENCE_FILE
¶
Required argument
-
OUT_FILE
¶
Required argument
fit¶
Fit morphology model to image using Sherpa.
Uses initial parameters from a JSON file (for now only Gaussians).
gammapy image fit [OPTIONS]
Options
-
--counts
<counts>
¶ Counts FITS file name
-
--exposure
<exposure>
¶ Exposure FITS file name
-
--background
<background>
¶ Background FITS file name
-
--psf
<psf>
¶ PSF JSON file name
-
--sources
<sources>
¶ Sources JSON file name (contains start values for fit of Gaussians)
-
--roi
<roi>
¶ Region of interest (ROI) file name (ds9 reg format)
-
--outfile
<outfile>
¶ Output JSON file with fit results
ts¶
Compute TS image.
The INPUT_FILE and OUTPUT_FILE arguments are FITS filenames.
The INPUT_FILE FITS file must contain the following HDU extensions: * ‘counts’ – Counts image * ‘background’ – Background image * ‘exposure’ – Exposure image
gammapy image ts [OPTIONS] INPUT_FILE OUTPUT_FILE
Options
-
--psf
<psf>
¶ JSON file containing PSF information.
-
--morphology
<morphology>
¶ Which source morphology to use for TS calculation.
-
--width
<width>
¶ Width of the shell, measured as fraction of the inner radius.
-
--scales
<scales>
¶ Angular kernel scales in deg (comma-separated list).
-
--downsample
<downsample>
¶ Downsample factor of the data to obtain optimal performance. Must be power of 2. Can be “auto” to choose the downsample factor automatically depending on the scale.
-
--residual
¶
Whether to compute a residual TS image. If a residual TS image is computed an excess model has to be provided using the “–model” parameter.
-
--model
<model>
¶ Input excess model FITS file name
-
--threshold
<threshold>
¶ Minimal required initial (before fitting) TS value, that the fit is done at all.
-
--overwrite
¶
Overwrite output files.
Arguments
-
INPUT_FILE
¶
Required argument
-
OUTPUT_FILE
¶
Required argument
Implementation¶
Currently, the command line interface (CLI) of Gammapy is implemented using click to define sub-commands, arguments and options, as well as calling the right function that implements a given sub-command.
We have chosen to implement all functionality via a single command line tool called
gammapy
, with each task as a subcommand. The gammapy
command line tool uses
the setuptools console_scripts entry point method to automatically create command
line tools when Gammapy is installed.
This means that to be able to use the tools you have to install Gammapy. Although, from the source folder you can still execute it without installing via
$ python -m gammapy
which executes gammapy/__main__.py
as a script as explained
here.
Another way to install the gammapy
command line tool once, but to have
it point at the Gammapy git source folder while you’re hacking on Gammapy is to use
$ python -m pip install --editable .
Either gammapy
or python -m gammapy
call the gammapy.scripts.main.cli
function,
which is a click.Group
object. If you want you can also import and execute it yourself:
>>> from gammapy.scripts.main import cli
>>> type(cli)
click.core.Group
>>> cli()
>>> cli(['--version'])
>>> cli(['image', 'bin', '--help'])
This is what we do to test the CLI, we import gammapy.scripts.main.cli
and run it via
gammapy.utils.testing.run_cli
and check the return code and sometimes console output
or generated files. Note that this means that all tests run in a single Python process,
we don’t “shell out” and create a subprocess that calls gammapy
from a sub-shell.
This is also how the auto-generated CLI documentation in the Reference
section above was generated: we use the sphinx-click Sphinx extension that imports and
inspects gammapy.scripts.main.cli
to find out about all the available sub-commands
and help text / arguments / options. The click.Group
object exposes all information
as attributes and methods. To just give one example:
>>> from gammapy.scripts.main import cli
>>> cli.commands
{'check': <click.core.Group at 0x112107048>,
'image': <click.core.Group at 0x112102e10>,
'info': <click.core.Command at 0x1120bb278>}
If you’re new to Python command line tools or Click, probably setuptools entry points
and click groups seem very complex. And they are, compared to the rest of Gammapy which
is just def
and class
statements to make functions and classes, i.e. “normal” Python code.
Just know that to use and even work on the Gammapy CLI you don’t have to understand how
it works under the hood, but if you want to, it’s actually not that complex.
A good path to learn is to start by reading gammapy/__main__.py and gammapy/scripts/main.py and then to look at an example of how a sub-command in Gammapy is implemented and tested, e.g. gammapy/scripts/image_bin.py and gammapy/scripts/tests/test_image_bin.py.
Note how sub-commands are click.Command
objects:
>>> from gammapy.scripts.image_bin import cli_image_bin
>>> type(cli_image_bin)
click.core.Command
that are independent and how the main cli
is created via cli.add_command
calls in
gammapy/scripts/main.py
.
Now you have a basic understanding how things work and should be able to work on Gammapy CLI
(e.g. add more functionality to the CLI interface). If you’re curious to learn how it
works in detail, we suggest you read the click docs and play with the Gammapy cli
object in IPython like we did above when looking at cli.commands
, or read and play with
the standalone example in the Write your own CLI section below.
Limitations¶
The current click-based Gammapy CLI is pretty nice, it is very simple to add commands and also documenting and testing them is pretty nice.
However, the current implementation has some issues and limitations. We describe them in this section, and then in the next one discuss more generally the plan and options for the Gammapy high-level (CLI or non-CLI) interface.
- There is no support for in-memory tool chain analysis pipelines.
I mean something lik e.g.
gammapy bin
followed bygammapy fit
without writing intermediate files and starting the two commands as separate processes. - There is no support for configuring or writing provenance information for commands or command pipelines (i.e. store which commands were executed with which arguments in input config or “workflow” files as well as output result files).
- More generally, we have to see if the separation of Gammapy as a library of “normal” Python functions and classes that can’t be driven by config files or the command line, and then separate functions that represent the CLI is what we want. It means that we have two different ways to use Gammapy in very different ways, and there is duplication and not a nice transition and re-use between the two ways.
More technical issues that can certainly be fixed if we want to stick with the current click-based CLI:
gammapy
always imports all code from all sub-commands, which drags in large fraction ofastropy
andgammapy
whether it is used or not. This means thatgammapy --help
takes a few seconds, whereas other commands likegit --help
just take a very small fraction of a second. This can be improved either by optimising import times throughout Astropy and Gammapy in general, or by lazy-loading the subcommands or by delaying imports into the callbacks from the subcommands.- The CLI documentation isn’t nice yet (see the Reference section above). The sphinx-click package that we use isn’t very well-developed or configurable. However, it’s a single Python file that we could just copy into Gammapy and modify and extend to generate documentation in exactly the way we like. E.g. we probably would want to have help text including examples and links to other parts for the Gammapy API and CLI docs that appear nicely on the console as well on in the HTML docs.
Plan¶
There is no concrete plan yet concerning the high-level user interface for Gammapy. Feedback from users and developers on the mailing list is highly welcome! What do you want?
Some options we are considering to build the high-level end-user interface for Gammapy:
- Collection of command line tools. Examples: FTOOLs, Fermi ScienceTools, ctools
- Config-file driven analysis. Examples: FermiPy, or the H.E.S.S.-internal HAP
- No special config- or CLI interface, just normal Python functions and classes. Examples: Sherpa and most Python package like e.g. Astropy or scikit-learn.
- Something more fancy that supports tool configuration and running from Python, config files or a CLI using a single implementation. Examples: ctapipe, fact-tools, python-fire
Options 1 and 2 are nice and simple, and they are user-friendly interfaces, and they would allow us to have a stable high-level interface while being able to continue to improve the Gammapy package without breaking user scripts over the coming years.
Their drawback is that they create a second way to use Gammapy, with some users learning and using the more flexible and powerful Python package, and some the simpler to use, but less flexible high-level interface. And note that eventually this second interface will grow into a config file with 100 options (that’s what we have in HAP) or into 10s of CLI tools with in total again 100s of options (see the ctools). However, the Fermi Science tools CLI and Fermipy config interface are examples where the interface size remains at a reasonable level (for users to learn and for developers to implement and maintain) while still exposing everything that most users need.
Options 3 and 4 are similar, in either case the analysis functionality that is available in Gammapy would be written once. Option 3 is what we have now in the Gammapy Python package. Changing to option 4 would mean adding some boilerplate code everywhere (e.g. Python decorators or sub-classing from “tool” base classes like what ctapipe is developing) or relying on the dynamic and inspection features of the Python language offers (see e.g. python-fire), to make it possible to configure and drive analyses not just via Python code, but via some configuration coming either from configuration files (YAML or XML) or command line options.
So what should we do for Gammapy?
I would suggest we continue with the prototyping of the CLI interface as well
as of a config-file based interface (gammapy.scripts.SpectrumAnalysisIACT
is a starting point).
Pull requests that improve and extend what we have are welcome any time!
In parallel, we continue to learn and evaluate solutions others have developed. In python-cli-examples I have started an exploration and evaluation of Python CLI packages, namely click, but also cliff and traitlets, and I might take a closer look also at cement and python-fire there. We should also look in detail at what other projects like LSST, JWST, Fermi, ctapipe, and others do concerning configuration and interface of their science tools. Later in 2018 we will need a comprehensive proposal for code organisation and high-level interface for Gammapy. Suggestions or even contributions are welcome any time!
Write your own CLI¶
This section explains how to write your own command line interface (CLI).
We will focus on the command line aspect, and use a very simple example
where we just call gammapy.stats.significance
.
From the interactive Python or IPython prompt or from a Jupyter notebook you just import the functionality you need and call it, like this:
>>> from gammapy.stats import significance
>>> significance(n_observed=10, mu_background=4.2, method='lima')
2.3979181291475453
If you imagine that the actual computation involves many lines of code (and not just a one-line function call), and that you need to do this computation frequently, you will probably write a Python script that looks something like this:
# Compute significance for a Poisson count observation
from gammapy.stats import significance
n_observed = 10
mu_background = 4.2
method = 'lima'
s = significance(n_observed, mu_background, method)
print(s)
We have introduced variables that hold the parameters for the analysis and put
them before the computation. Let’s say this script is in a file called significance.py
,
then to use it you put the parameters you like and then execute it via:
$ python significance.py
If you want, you can also put the line #!/usr/bin/env python
at the top of the
script, make it executable via chmod +x significance.py
and then you’ll be able
to execute it via ./significance.py
if you prefer to execute it like this.
This works on Linux and Mac OS, but not on Windows.
It is also possible to omit the .py
extension from the filename, i.e. to simply
call the file significance
. Either way has some advantages and disadvantages,
it’s a matter of taste. Omitting the .py
is nice because users calling the tool
usually don’t care that it’s a Python script, and it’s shorter. But omitting the .py
also
means that some advanced users that open up the file in an editor have a harder time
(because the editor might not recognise it as a Python file and syntax highlight appropriately),
or more importantly that importing functions of classes from that script from other Python
files or Jupyter notebooks is not easily possible, leading some people to rename it or
copy & paste from it. We’re explaining these details, because if you work with colleagues
and share scripts, you’ll encounter the #!/usr/bin/env python
and scripts with and without
.py
and will need to know how to work with them.
Writing and using such scripts is perfectly fine and a common way to run science analyses.
However, if you use it very frequently it might become annoying to have to open up and
edit the significance.py
file every time to use it. In that case, you can change your
script into a command line interface that allows you to set analysis parameters without
having to edit the file, like this:
$ python significance.py --help
Usage: significance.py [OPTIONS] N_OBSERVED MU_BACKGROUND
Compute significance for a Poisson count observation.
The significance is the tail probability to observe N_OBSERVED counts or
more, given a known background level MU_BACKGROUND.
Options:
--method [lima|simple] Significance computation method
--help Show this message and exit.
$ python significance.py 10 4.2
2.39791813
$ python significance.py 10 4.2 --method simple
2.83011021
In Python, there are several ways to do command line argument parsing and to create
command line interfaces. Of course you’re free to do whatever you like, but if
you’re not sure what to use to build your own CLIs, we suggest you give click
a try. Here is how you’d rewrite your significance.py
as a click CLI:
import click
from gammapy.stats import significance
# You can call the callback function for the click command anything you like.
# `cli` is just a commonly used generic term for "command line interface".
@click.command()
@click.argument('n_observed')
@click.argument('mu_background')
@click.option('--method', type=click.Choice(['lima', 'simple']),
default='lima', help='Significance computation method')
def cli(n_observed, mu_background, method):
"""Compute significance for a Poisson count observation.
The significance is the tail probability to observe N_OBSERVED counts
or more, given a known background level MU_BACKGROUND."""
s = significance(n_observed, mu_background, method)
print(s)
if __name__ == '__main__':
cli()
As mentioned above in the Implementation, we use click in
Gammapy itself. We also use click frequently for our own projects if we choose to add
a CLI (no matter if Gammapy is used or not). Putting the CLI in a file called make.py
makes it easy to go back to a project after a while and to remember or quickly figure out
again how it works (as opposed to just having a bunch of Python scripts or Jupyter notebooks
where it’s harder to remember where to edit parameters and which ones to run in which order).
One example is the gamma-cat make.py.
If you find that you don’t like click, another popular alternative to create CLIs is
argparse from the Python standard library. To learn argparse, either read the official
documentation, or the PYMOTW argparse tutorial. For basic use cases argparse
is
similar to click
, the main difference being that click
uses decorators
(@command
, @argument
, @option
) attached to a callback function to execute,
whereas argparse
uses classes and method calls to create a parser object, and then
you have to call parse_args
yourself and also pass the args
to the code or function
to execute yourself. So for basic use cases, but also for more advanced use cases where
you define a CLI with sub-commands, argparse
can be used just as well, it’s just
a little harder to learn and use than click
(of course that’s a matter of opinion).
Another advantage of choosing Click is that once you’ve learned it, you’ll be able to
quickly read and understand, or even contribute to the Gammapy CLI.
Reference/API¶
Besides the CLI interface, the gammapy.scripts
package currently contains a bunch of things
that will probably all be removed or rewritten and integrated in other sub-packages of Gammapy,
leaving scripts
just as the high-level command line script interface for Gammapy.
gammapy.scripts Package¶
Gammapy command line interface (scripts).
Functions¶
create_bg_observation_list (indir, outdir, …) |
Make total observation list and filter the observations. |
group_observations (outdir, overwrite, test) |
Group list of observations runs according to observation properties. |
make_bg_cube_models (indir, outdir[, …]) |
Create background cube models from the complete dataset of an experiment. |
stack_observations (indir, outdir, overwrite) |
Stack events for each observation group (bin) and make background model. |
Classes¶
BgRateTable (energy_lo, energy_hi, data) |
Background rate table. |
CTAIrf ([aeff, edisp, psf, bkg, ref_sensi]) |
CTA instrument response function container. |
CTAObservationSimulation |
Simulate observation for one IRF and target. |
CTAPerf ([aeff, edisp, psf, bkg, sens, rmf]) |
CTA instrument response function container. |
ObservationParameters ([alpha, livetime, …]) |
Container for observation parameters. |
Psf68Table (energy_lo, energy_hi, data) |
Background rate table. |
SensitivityEstimator (irf, livetime[, slope, …]) |
Estimate differential sensitivity for the ON/OFF method, ie 1D analysis |
SensitivityTable (energy_lo, energy_hi, data) |
Sensitivity table. |
SingleObsImageMaker (obs, empty_image, …[, …]) |
Compute images for one observation. |
SpectrumAnalysisIACT (observations, config) |
High-level analysis class to perform a full 1D IACT spectral analysis. |
StackedObsImageMaker ([empty_image, …]) |
Compute stacked images for many observations. |
Target ([name, model]) |
Observation target information. |