This is a fixed-text formatted version of a Jupyter notebook.

Getting started with Gammapy

Introduction

This is a getting started tutorial for Gammapy.

In this tutorial we will use the Second Fermi-LAT Catalog of High-Energy Sources (2FHL) catalog, corresponding event list and images to learn how to work with some of the central Gammapy data structures.

We will cover the following topics:

If you’re not yet familiar with the listed Astropy classes, maybe check out the Astropy introduction for Gammapy users first.

Setup

Important: to run this tutorial the environment variable GAMMAPY_EXTRA must be defined and point to the directory, where the gammapy-extra is respository located on your machine. To check whether your setup is correct you can execute the following cell:

In [1]:
import os

path = os.path.expandvars("$GAMMAPY_DATA")

if not os.path.exists(path):
    raise Exception("gammapy-data repository not found!")
else:
    print("Great your setup is correct!")
Great your setup is correct!

In case you encounter an error, you can un-comment and execute the following cell to continue. But we recommend to set up your enviroment correctly as decribed here after you are done with this notebook.

In [2]:
# os.environ['GAMMAPY_DATA'] = os.path.join(os.getcwd(), '..')

Now we can continue with the usual IPython notebooks and Python imports:

In [3]:
%matplotlib inline
import matplotlib.pyplot as plt
In [4]:
import numpy as np
import astropy.units as u
from astropy.coordinates import SkyCoord
from astropy.visualization import simple_norm

Maps

The gammapy.maps package contains classes to work with sky images and cubes.

In this section, we will use a simple 2D sky image and will learn how to:

  • Read sky images from FITS files
  • Smooth images
  • Plot images
  • Cutout parts from images
  • Reproject images to different WCS
In [5]:
from gammapy.maps import Map

vela_2fhl = Map.read(
    "$GAMMAPY_DATA/fermi_2fhl/fermi_2fhl_vela.fits.gz", hdu="COUNTS"
)

As the FITS file fermi_2fhl_vela.fits.gz contains mutiple image extensions and a map can only represent a single image, we explicitely specify to read the extension called ‘COUNTS’.

The image is a WCSNDMap object:

In [6]:
vela_2fhl
Out[6]:
WcsNDMap

    geom  : WcsGeom
    axes  : lon, lat
    shape : (320, 180)
    ndim  : 2
    unit  : ''
    dtype : >f8

The shape of the image is 320x180 pixel and it is defined using a cartesian projection in galactic coordinates.

The geom attribute is a WcsGeom object:

In [7]:
vela_2fhl.geom
Out[7]:
WcsGeom

    axes       : lon, lat
    shape      : (320, 180)
    ndim       : 2
    coordsys   : GAL
    projection : CAR
    center     : 266.0 deg, -1.2 deg
    width      : 32.0 x 18.0 deg

Let’s take a closer look a the .data attribute:

In [8]:
vela_2fhl.data
Out[8]:
array([[0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       ...,
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.]])

That looks familiar! It just an ordinary 2 dimensional numpy array, which means you can apply any known numpy method to it:

In [9]:
print(
    "Total number of counts in the image: {:.0f}".format(vela_2fhl.data.sum())
)
Total number of counts in the image: 1567

To show the image on the screen we can use the plot method. It basically calls plt.imshow, passing the vela_2fhl.data attribute but in addition handles axis with world coordinates using wcsaxes and defines some defaults for nicer plots (e.g. the colormap ‘afmhot’):

In [10]:
vela_2fhl.plot();
../_images/notebooks_first_steps_20_0.png

To make the structures in the image more visible we will smooth the data using a Gausian kernel with a radius of 0.5 deg. Again smooth() is a wrapper around existing functionality from the scientific Python libraries. In this case it is Scipy’s gaussian_filter method. For convenience the kernel shape can be specified with as string and the smoothing radius with a quantity. It returns again a map object, that we can plot directly the same way we did above:

In [11]:
vela_2fhl_smoothed = vela_2fhl.smooth(kernel="gauss", width=0.2 * u.deg)
In [12]:
vela_2fhl_smoothed.plot();
../_images/notebooks_first_steps_23_0.png

The smoothed plot already looks much nicer, but still the image is rather large. As we are mostly interested in the inner part of the image, we will cut out a quadratic region of the size 9 deg x 9 deg around Vela. Therefore we use Map.cutout to make a cutout map:

In [13]:
# define center and size of the cutout region
center = SkyCoord(265.0, -2.0, unit="deg", frame="galactic")
vela_2fhl_cutout = vela_2fhl_smoothed.cutout(center, 9 * u.deg)
vela_2fhl_cutout.plot();
../_images/notebooks_first_steps_25_0.png

To make this exercise a bit more scientifically useful, we will load a second image containing WMAP data from the same region:

In [14]:
vela_wmap = Map.read("$GAMMAPY_DATA/images/Vela_region_WMAP_K.fits")

# define a norm to stretch the data, so it is better visible
norm = simple_norm(vela_wmap.data, stretch="sqrt", max_percent=99.9)
vela_wmap.plot(cmap="viridis", norm=norm);
../_images/notebooks_first_steps_27_0.png

In order to make the structures in the data better visible we used the simple_norm() method, which allows to stretch the data for plotting. This is very similar to the methods that e.g. ds9 provides. In addition we used a different colormap called ‘viridis’. An overview of different colomaps can be found here.

Now let’s check the details of the WMAP image:

In [15]:
vela_wmap
Out[15]:
WcsNDMap

    geom  : WcsGeom
    axes  : lon, lat
    shape : (300, 300)
    ndim  : 2
    unit  : 'mK'
    dtype : >f4

As you can see it is defined using a tangential projection and ICRS coordinates, which is different from the projection used for the vela_2fhl image. To compare both images we have to reproject one image to the WCS of the other. This can be achieved with the reproject method:

In [16]:
# reproject and cut out the part we're interested in:
vela_wmap_reprojected = vela_wmap.reproject(vela_2fhl.geom)
vela_wmap_reprojected_cutout = vela_wmap_reprojected.cutout(center, 9 * u.deg)
vela_wmap_reprojected_cutout.plot(cmap="viridis", norm=norm);
../_images/notebooks_first_steps_31_0.png

Finally we will combine both images in single plot, by plotting WMAP contours on top of the smoothed Fermi-LAT 2FHL image:

In [17]:
fig, ax, _ = vela_2fhl_cutout.plot()
ax.contour(vela_wmap_reprojected_cutout.data, cmap="Blues");
../_images/notebooks_first_steps_33_0.png

Exercises

  • Add a marker and circle at the Vela pulsar position (you can find examples in the WCSAxes documentation).

Event lists

Almost any high-level gamma-ray data analysis starts with the raw measured counts data, which is stored in event lists. In Gammapy event lists are represented by the gammapy.data.EventList class.

In this section we will learn how to:

  • Read event lists from FITS files
  • Access and work with the EventList attributes such as .table and .energy
  • Filter events lists using convenience methods

Let’s start with the import from the gammapy.data submodule:

In [18]:
from gammapy.data import EventList

Very similar to the sky map class an event list can be created, by passing a filename to the .read() method:

In [19]:
events_2fhl = EventList.read("$GAMMAPY_DATA/fermi_2fhl/2fhl_events.fits.gz")

This time the actual data is stored as an astropy.table.Table object. It can be accessed with .table attribute:

In [20]:
events_2fhl.table
Out[20]:
Table length=60978
ENERGYRADECLBTHETAPHIZENITH_ANGLEEARTH_AZIMUTH_ANGLETIMEEVENT_IDRUN_IDRECON_VERSIONCALIB_VERSION [3]EVENT_CLASS [32]EVENT_TYPE [32]CONVERSION_TYPELIVETIMEDIFRSP0DIFRSP1DIFRSP2DIFRSP3DIFRSP4
MeVdegdegdegdegdegdegdegdegss
float32float32float32float32float32float32float32float32float32float64int32int32int16int16boolboolint16float64float32float32float32float32float32
145927.23291.661942.23405574.5436711.8677838.04547583.5358355.638725314.03378239561457.86561257485143723955956500 .. 0False .. TrueFalse .. True0275.69808897376062.6965721e-113238.24580.00.00.0
221273.3646.985752-40.638943247.48888-58.87391734.10511224.2093768.2524198.31926239562739.08500722752143223955956500 .. 0False .. TrueFalse .. True064.797493159770971.5357299e-122774.19850.00.00.0
57709.242121.8414349.22879169.8680132.30165571.5636334.29248436.71730825.543858239563180.30194944869069323955956500 .. 0False .. TrueFalse .. True030.572186470031748.110957e-12253.22120.00.00.0
221223.7583.56263-4.217438207.7828-19.07714520.5089492.1604632.303345239.14058239563382.21257913920842423955956500 .. 0False .. TrueFalse .. True027.4125095903873441.6607507e-112980.12430.00.00.0
698996.9320.89468-1.32788851.221825-33.9718335.36213158.7414712.08670972.20295239566572.9507265248048323956564500 .. 0False .. TrueFalse .. True0106.475481122732162.2654334e-132706.14360.00.00.0
119158.54318.8112812.3028462.63608-24.4160226.589584213.8941717.715623.940882239572348.06027594172527623957167000 .. 0False .. TrueFalse .. True0185.34642729163172.7567707e-113439.28610.00.00.0
56175.598279.2512247.88348876.691522.0738729.10340361.00478762.173084321.10422239572763.43077427601723957273600 .. 0False .. TrueFalse .. True024.4507339596748352.0826456e-104071.24540.00.00.0
1418123.2100.31091-47.44805256.468-21.26408861.225597294.1795390.475266144.14915239573788.81279647178156923957273600 .. 0False .. TrueFalse .. True068.271614640951163.200215e-141086.23070.00.00.0
62164.945331.49234-41.22639359.41953-53.40485828.140808229.9265352.014217189.05397239578601.16829255200070023957766300 .. 0False .. TrueFalse .. True090.332262665033341.2147898e-103566.07230.00.00.0
.....................................................................
51296.76679.03107578.93273133.8682122.23985351.17257267.8136699.76019357.79028444418973.82216597128485344441859000 .. 0False .. TrueFalse .. True0181.688983500003812.1412723e-102586.88260.00.00.0
60315.69243.6808-50.56688332.429660.282680224.8501255.6834374.880394195.14026444421777.7614562658294944441859000 .. 0False .. TrueFalse .. False157.335890293121342.3585365e-083541.0450.00.00.0
90000.086282.69763-33.198742.6621876-14.3338678.491435343.5590247.39651191.0325444422182.73806727750746644441859000 .. 0False .. TrueFalse .. True0187.602469146251683.6212314e-103792.5680.00.00.0
61988.746247.97972-48.109093336.1460.02203387633.649937144.2706180.396614221.39618444422758.1452106869914744441859000 .. 0False .. TrueFalse .. True039.209832727909092.2642107e-083395.06960.00.00.0
54282.88159.92404-58.362797286.362150.2055538324.119644287.1378265.084694177.52434444425794.79357773252223744442461900 .. 0False .. TrueFalse .. True0196.20966887474064.825799e-093672.78220.00.00.0
146728.25244.84776-46.58761335.754242.603261245.253945.336441591.87099137.03206444425911.81856924270521044442461900 .. 0False .. TrueFalse .. False165.63278573751454.4594994e-102899.3330.00.00.0
135432.8883.5278127.905334179.52916-2.691055817.49110852.08580453.306004313.8216444430968.9684862593918844443059900 .. 0False .. TrueFalse .. False197.644683122634891.5798855e-103515.59640.00.00.0
61592.113231.21422-5.4552135357.435540.64731646.63564141.0466362.758415256.6312444433607.90634906544394444443059900 .. 0False .. TrueFalse .. False128.7290657758712772.8202804e-102793.4520.00.00.0
80480.79228.24373-45.04397327.5608510.95282137.314854193.7140283.3882221.57036444433702.0691026561244344443059900 .. 0False .. TrueFalse .. False1122.891819298267362.2609459e-103176.42650.00.00.0
124449.16238.00813-51.03712329.429472.300600532.452194199.5043380.97682214.4802444433764.4327705572336144443059900 .. 0False .. TrueFalse .. True0185.255487203598028.549079e-103366.30150.00.00.0

You can do len over event_2fhl.table to find the total number of events.

In [21]:
print("Total number of events: {}".format(len(events_2fhl.table)))
Total number of events: 60978

And we can access any other attribute of the Table object as well:

In [22]:
events_2fhl.table.colnames
Out[22]:
['ENERGY',
 'RA',
 'DEC',
 'L',
 'B',
 'THETA',
 'PHI',
 'ZENITH_ANGLE',
 'EARTH_AZIMUTH_ANGLE',
 'TIME',
 'EVENT_ID',
 'RUN_ID',
 'RECON_VERSION',
 'CALIB_VERSION',
 'EVENT_CLASS',
 'EVENT_TYPE',
 'CONVERSION_TYPE',
 'LIVETIME',
 'DIFRSP0',
 'DIFRSP1',
 'DIFRSP2',
 'DIFRSP3',
 'DIFRSP4']

For convenience we can access the most important event parameters as properties on the EventList objects. The attributes will return corresponding Astropy objects to represent the data, such as astropy.units.Quantity, astropy.coordinates.SkyCoord or astropy.time.Time objects:

In [23]:
events_2fhl.energy.to("GeV")
Out[23]:
$$[145.92725,~221.27338,~57.709244,~\dots,~61.592117,~80.480789,~124.44917] \; \mathrm{GeV}$$
In [24]:
events_2fhl.galactic
# events_2fhl.radec
Out[24]:
<SkyCoord (Galactic): (l, b) in deg
    [( 74.54326949,  11.86794629), (247.48874019, -58.87409431),
     (169.86765712,  32.30144389), ..., (357.43496217,  40.64753602),
     (327.56037412,  10.95297324), (329.42901812,   2.30075607)]>
In [25]:
events_2fhl.time
Out[25]:
<Time object: scale='tt' format='mjd' value=[54682.7028015  54682.71763043 54682.72273711 ... 57053.90824179
 57053.90933163 57053.91005343]>

In addition EventList provides convenience methods to filter the event lists. One possible use case is to find the highest energy event within a radius of 0.5 deg around the vela position:

In [26]:
# select all events within a radius of 0.5 deg around center
events_vela_2fhl = events_2fhl.select_sky_cone(
    center=center, radius=0.5 * u.deg
)

# sort events by energy
events_vela_2fhl.table.sort("ENERGY")

# and show highest energy photon
events_vela_2fhl.energy[-1].to("GeV")
Out[26]:
$$342.76625 \; \mathrm{GeV}$$

Exercises

  • Make a counts energy spectrum for the galactic center region, within a radius of 10 deg.

Source catalogs

Gammapy provides a convenient interface to access and work with catalog based data.

In this section we will learn how to:

  • Load builtins catalogs from gammapy.catalog
  • Sort and index the underlying Astropy tables
  • Access data from individual sources

Let’s start with importing the 2FHL catalog object from the gammapy.catalog submodule:

In [27]:
from gammapy.catalog import SourceCatalog2FHL

First we initialize the Fermi-LAT 2FHL catalog and directly take a look at the .table attribute:

In [28]:
fermi_2fhl = SourceCatalog2FHL(
    "$GAMMAPY_DATA/catalogs/fermi/gll_psch_v08.fit.gz"
)
fermi_2fhl.table
Out[28]:
Table length=360
Source_NameRAJ2000DEJ2000GLONGLATPos_err_68TSSpectral_IndexUnc_Spectral_IndexIntr_Spectral_Index_D11Unc_Intr_Spectral_Index_D11Intr_Spectral_Index_G12Unc_Intr_Spectral_Index_G12Flux50Unc_Flux50Energy_Flux50Unc_Energy_Flux50Flux50_171GeVUnc_Flux50_171GeV [2]Sqrt_TS50_171GeVFlux171_585GeVUnc_Flux171_585GeV [2]Sqrt_TS171_585GeVFlux585_2000GeVUnc_Flux585_2000GeV [2]Sqrt_TS585_2000GeVNpredHEP_EnergyHEP_ProbROIASSOCASSOC_PROB_BAYASSOC_PROB_LRCLASSRedshiftNuPeak_obs3FGL_Name1FHL_NameTeVCat_Name
degdegdegdegdeg1 / (cm2 s)1 / (cm2 s)erg / (cm2 s)erg / (cm2 s)1 / (cm2 s)1 / (cm2 s)1 / (cm2 s)1 / (cm2 s)1 / (cm2 s)1 / (cm2 s)GeVHz
bytes18float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32int16bytes25float32float32bytes8float32float32bytes18bytes18bytes18
2FHL J0008.1+47092.043747.1642115.339355-15.0687570.0611140228.646.242.753.963.192.164.211.23e-116.71e-121.21e-126.71e-133.3634447e-12-1.5366806e-12 .. 2.1609453e-125.3535364.3494674e-18nan .. 4.7538935e-120.08.448714e-18nan .. 7.291014e-120.04.068.150.991MG4 J000800+47120.997219740.8348271bll2.12511884200000000.03FGL J0008.0+47131FHL J0007.7+4709
2FHL J0009.3+50312.343550.5217116.12411-11.7932020.04543919553.975.081.66nannannannan1.91e-117.82e-122.03e-128.79e-138.362822e-12-2.9896227e-12 .. 3.895122e-127.3513172.9145808e-17nan .. 5.1000337e-120.03.5087458e-16nan .. 4.874578e-120.06.472.761.01NVSS J000922+5030280.999723730.7348077bll0.01412536400000000.03FGL J0009.3+50301FHL J0009.2+5032
2FHL J0018.5+29474.635529.7879114.46349-32.542350.03709363630.892.580.992.411.042.41.041.06e-116.15e-122.05e-121.72e-129.65438e-12-5.5534162e-12 .. 5.5534162e-125.7657861.1790023e-15nan .. 5.378652e-120.01.6046534e-16nan .. 6.120081e-120.03.0127.321.03RBS 00420.99986820.97852194bll0.15.9156075e+163FGL J0018.4+29471FHL J0018.6+2946
2FHL J0022.0+00065.50010.1059107.171715-61.861750.0511852229.961.860.570.950.720.880.711.97e-119.56e-126.86e-125.29e-121.6119727e-11-7.1725507e-12 .. 9.9534886e-125.38219643.6392152e-12-4.3863624e-12 .. 4.3863624e-121.38539428.423558e-16nan .. 7.342399e-120.04.8180.130.8625BZGJ0022+00060.999280.90008944bll-g0.3064.315193e+16
2FHL J0033.6-19218.4115-19.357594.28002-81.222370.034838412148.313.320.692.560.882.330.925.46e-111.5e-117.62e-122.69e-124.0016098e-11-1.0161534e-11 .. 1.223782e-1112.1725022.1390131e-12nan .. 8.258118e-120.90795812.439548e-17nan .. 6.8422585e-120.013.8170.010.992KUV 00311-19380.9997590.9814242bll0.618317639000000000.03FGL J0033.6-19211FHL J0033.6-1921TeV J0033-1921
2FHL J0035.8+59498.962559.8312120.97197-2.98121550.031602595402.42.230.21nannannannan1.25e-101.9e-113.11e-117.23e-129.4229395e-11-1.5256577e-11 .. 1.7157154e-1117.3124492.6699127e-11-7.628179e-12 .. 9.450845e-1210.3908783.7260905e-16nan .. 4.6744392e-120.046.5247.620.9641ES 0033+5950.999958340.9928678bll0.01.3182593e+173FGL J0035.9+59491FHL J0035.9+5950TeV J0035+5950
2FHL J0040.3+404910.094940.8315120.676285-21.9918120.03551484326.762.120.81nannannannan1.05e-116.3e-122.84e-122.67e-127.415768e-12-4.077804e-12 .. 6.4518156e-124.9544233.0030787e-12-2.317754e-12 .. 4.466438e-121.70835474.7316626e-16nan .. 5.7980946e-120.03.2258.770.853B3 0037+4050.99873790.9346999bcu I0.01.03FGL J0040.3+40491FHL J0040.3+4049
2FHL J0043.9+342410.975534.4109121.16442-28.4349840.05924166739.54.571.613.461.852.951.911.83e-118.24e-122.03e-129.93e-139.657617e-12-4.316866e-12 .. 4.316866e-126.31152448.758609e-17nan .. 5.2433453e-120.09.438122e-16nan .. 5.687869e-120.05.4109.970.93GB6 J0043+34260.998593570.8388443fsrq0.96664565484000000.03FGL J0043.8+34251FHL J0043.7+3425
2FHL J0045.2+212711.316121.4555121.01704-41.3932950.03780455110.433.070.64nannannannan4.14e-111.26e-116.29e-122.45e-123.1153188e-11-8.930081e-12 .. 1.101035e-1110.2404472.9971193e-12-3.030543e-12 .. 3.030543e-122.7089024.683478e-17nan .. 6.4231385e-120.011.4246.750.995GB6 J0045+21270.99960960.9651269bll0.01.002304e+163FGL J0045.3+21261FHL J0045.2+2126
.....................................................................................................................
2FHL J2322.5+3436350.62834.613102.87579-24.7717630.07179981528.772.330.82.130.852.110.851.42e-117.46e-123.24e-122.48e-121.3706217e-11-5.990534e-12 .. 8.273254e-125.5110891.5044521e-15nan .. 5.2556817e-120.03.3439588e-16nan .. 6.3523587e-120.04.1166.20.99133TXS 2320+3430.99663890.87790126bll-g0.0981047129700000000.03FGL J2322.5+34361FHL J2322.5+3436
2FHL J2322.7-4916350.698-49.2706334.60815-62.0491870.03894901336.844.581.69nannannannan1.75e-118.3e-121.94e-129.96e-139.1300864e-12-3.7335608e-12 .. 5.0173784e-126.05222946.65757e-17nan .. 5.2713697e-120.06.347128e-16nan .. 5.772431e-120.05.1106.330.9138SUMSS J232254-4916290.999433930.9377265bll0.04466832000000000.03FGL J2322.9-4917
2FHL J2323.4+5848350.87458.808111.74413-2.14031340.034838412183.622.450.3nannannannan7.81e-111.53e-111.64e-114.68e-125.936891e-11-1.2110057e-11 .. 1.38986435e-1111.6237981.0376127e-11-4.3784516e-12 .. 6.143983e-125.81435352.9030862e-12-2.0241562e-12 .. 3.9820235e-123.50833728.8662.121.0135Cas Anan0.9998325snrnannan3FGL J2323.4+58491FHL J2323.3+5849TeV J2323+588
2FHL J2323.8+4209350.97242.1629106.05886-17.8223720.04560164770.614.211.164.141.154.131.153.05e-111.05e-113.55e-121.35e-121.620174e-11-5.247084e-12 .. 6.6191224e-128.1193782.0001782e-12-1.4127128e-12 .. 2.779269e-122.56848862.1890578e-18nan .. 5.540821e-120.09.3230.90.921331ES 2321+4190.999560.9615062bll0.0594841728400000000.03FGL J2323.9+42111FHL J2323.8+4210
2FHL J2324.7-4041351.195-40.6934350.1568-67.583650.0358658480.933.180.832.940.872.90.872.97e-111.08e-114.34e-122.03e-122.1339108e-11-7.099395e-12 .. 9.104349e-128.8538272.7183436e-12-2.1171383e-12 .. 4.116685e-121.65791583.547171e-17nan .. 6.3514e-120.08.0118.481.01381ES 2322-4090.999466540.9855157bll0.1735878317639000000000.03FGL J2324.7-40401FHL J2324.6-4041
2FHL J2329.2+3754352.30837.9157105.53183-22.162680.03853897839.43.291.192.991.282.921.281.43e-117.17e-122.02e-121.25e-121.1130363e-11-4.6961983e-12 .. 6.5287966e-126.31149444.4041454e-16nan .. 5.477368e-120.02.6406502e-17nan .. 5.9254654e-120.04.3142.130.98133NVSS J232914+3754140.999791740.95636314bll0.2648912505400000000.03FGL J2329.2+37541FHL J2329.1+3754
2FHL J2340.8+8014355.20380.2447119.8377717.799930.03489344269.794.21.284.01.363.941.371.95e-117.24e-122.26e-129.72e-131.1639776e-11-3.811828e-12 .. 4.8279145e-128.3874531.2570346e-16nan .. 3.7181217e-120.01.1362121e-15nan .. 4.047232e-120.07.980.850.861251RXS J234051.4+8015130.99987450.97943515bll0.2743427676800000000.03FGL J2340.7+80161FHL J2341.3+8016
2FHL J2343.5+3438355.89834.6484107.42183-26.1716580.07150558427.434.992.364.882.434.792.441.33e-117.32e-121.41e-128.56e-135.9425394e-12-2.732224e-12 .. 3.8524665e-125.2346985.086273e-17nan .. 8.363173e-120.03.1470887e-16nan .. 5.6851962e-120.03.972.661.01331RXS J234332.5+3439570.999147650.9554292bll0.3661029200060000000.03FGL J2343.7+3437
2FHL J2347.1+5142356.7551.7081112.879944-9.901590.03354639209.841.850.251.740.261.730.267.48e-111.54e-112.62e-118.56e-124.788841e-11-1.1559573e-11 .. 1.3389954e-1111.2820442.4289425e-11-7.681043e-12 .. 9.877774e-128.85769753.5138778e-12-3.5528204e-12 .. 3.5528204e-122.665715725.2652.310.9911ES 2344+5140.999860170.98808235bll0.0447079464000000000.03FGL J2347.0+51421FHL J2347.0+5142TeV J2346+5142
2FHL J2352.0-7558358.019-75.9718307.623-40.6110880.073373328.493.371.24nannannannan1.18e-116.14e-121.63e-121.03e-129.00308e-12-3.9132994e-12 .. 5.477288e-125.3893533.9078217e-16nan .. 4.95279e-120.03.2339844e-17nan .. 5.167223e-120.03.9134.721.0137nannanunknannan3FGL J2351.9-7601

This looks very familiar again. The data is just stored as an astropy.table.Table object. We have all the methods and attributes of the Table object available. E.g. we can sort the underlying table by TS to find the top 5 most significant sources:

In [29]:
# sort table by TS
fermi_2fhl.table.sort("TS")

# invert the order to find the highest values and take the top 5
top_five_TS_2fhl = fermi_2fhl.table[::-1][:5]

# print the top five significant sources with association and source class
top_five_TS_2fhl[["Source_Name", "ASSOC", "CLASS"]]
Out[29]:
Table length=5
Source_NameASSOCCLASS
bytes18bytes25bytes8
2FHL J1104.4+3812Mkn 421bll
2FHL J0534.5+2201Crabpwn
2FHL J1653.9+3945Mkn 501bll
2FHL J1555.7+1111PG 1553+113bll
2FHL J2158.8-3013PKS 2155-304bll

If you are interested in the data of an individual source you can access the information from catalog using the name of the source or any alias source name that is defined in the catalog:

In [30]:
mkn_421_2fhl = fermi_2fhl["2FHL J1104.4+3812"]

# or use any alias source name that is defined in the catalog
mkn_421_2fhl = fermi_2fhl["Mkn 421"]
print(mkn_421_2fhl.data["TS"])
5600.98

Exercises

  • Try to load the Fermi-LAT 3FHL catalog and check the total number of sources it contains.
  • Select all the sources from the 2FHL catalog which are contained in the Vela region. Add markers for all these sources and try to add labels with the source names. The function ax.text() might be helpful.
  • Try to find the source class of the object at position ra=68.6803, dec=9.3331

Spectral models and flux points

In the previous section we learned how access basic data from individual sources in the catalog. Now we will go one step further and explore the full spectral information of sources. We will learn how to:

  • Plot spectral models
  • Compute integral and energy fluxes
  • Read and plot flux points

As a first example we will start with the Crab Nebula:

In [31]:
crab_2fhl = fermi_2fhl["Crab"]
print(crab_2fhl.spectral_model)
PowerLaw2

Parameters:

           name     value     error       unit    min max
        --------- --------- --------- ----------- --- ---
        amplitude 1.310e-09 6.830e-11 1 / (cm2 s) nan nan
            index 2.130e+00 7.000e-02             nan nan
             emin 5.000e-02 0.000e+00         TeV nan nan
             emax 2.000e+00 0.000e+00         TeV nan nan

Covariance:

           name   amplitude   index      emin      emax
        --------- --------- --------- --------- ---------
        amplitude 4.665e-21 0.000e+00 0.000e+00 0.000e+00
            index 0.000e+00 4.900e-03 0.000e+00 0.000e+00
             emin 0.000e+00 0.000e+00 0.000e+00 0.000e+00
             emax 0.000e+00 0.000e+00 0.000e+00 0.000e+00

The crab_2fhl.spectral_model is an instance of the gammapy.spectrum.models.PowerLaw2 model, with the parameter values and errors taken from the 2FHL catalog.

Let’s plot the spectral model in the energy range between 50 GeV and 2000 GeV:

In [32]:
ax_crab_2fhl = crab_2fhl.spectral_model.plot(
    energy_range=[50, 2000] * u.GeV, energy_power=0
)
../_images/notebooks_first_steps_64_0.png

We assign the return axes object to variable called ax_crab_2fhl, because we will re-use it later to plot the flux points on top.

To compute the differential flux at 100 GeV we can simply call the model like normal Python function and convert to the desired units:

In [33]:
crab_2fhl.spectral_model(100 * u.GeV).to("cm-2 s-1 GeV-1")
Out[33]:
$$6.8700477 \times 10^{-12} \; \mathrm{\frac{1}{GeV\,s\,cm^{2}}}$$

Next we can compute the integral flux of the Crab between 50 GeV and 2000 GeV:

In [34]:
crab_2fhl.spectral_model.integral(emin=50 * u.GeV, emax=2000 * u.GeV).to(
    "cm-2 s-1"
)
Out[34]:
$$1.31 \times 10^{-9} \; \mathrm{\frac{1}{s\,cm^{2}}}$$

We can easily convince ourself, that it corresponds to the value given in the Fermi-LAT 2FHL catalog:

In [35]:
crab_2fhl.data["Flux50"]
Out[35]:
$$1.31 \times 10^{-9} \; \mathrm{\frac{1}{s\,cm^{2}}}$$

In addition we can compute the energy flux between 50 GeV and 2000 GeV:

In [36]:
crab_2fhl.spectral_model.energy_flux(emin=50 * u.GeV, emax=2000 * u.GeV).to(
    "erg cm-2 s-1"
)
Out[36]:
$$3.5295399 \times 10^{-10} \; \mathrm{\frac{erg}{s\,cm^{2}}}$$

Next we will access the flux points data of the Crab:

In [37]:
print(crab_2fhl.flux_points)
FluxPoints(sed_type="dnde", n_points=3)

If you want to learn more about the different flux point formats you can read the specification here.

No we can check again the underlying astropy data structure by accessing the .table attribute:

In [38]:
crab_2fhl.flux_points.table
Out[38]:
Table length=3
e_mine_maxfluxflux_errnflux_errpis_ulflux_ule_refdndednde_errndnde_errpdnde_ul
GeVGeV1 / (cm2 s)1 / (cm2 s)1 / (cm2 s)1 / (cm2 s)GeV1 / (cm2 GeV s)1 / (cm2 GeV s)1 / (cm2 GeV s)1 / (cm2 GeV s)
float64float64float64float32float32boolfloat64float64float64float64float64float64
50.0171.09.94072046900385e-105.7595e-115.947264e-11Falsenan92.466210044534658.077278257256764e-124.679850482507369e-134.832417130565079e-13nan
171.0585.02.4387539210302123e-102.8254246e-113.0435404e-11Falsenan316.28310103450045.791573933479777e-136.70984284998247e-147.227826148494206e-14nan
585.02000.05.275358622158777e-111.3340122e-111.6047759e-11Falsenan1081.66538263919693.665491192689583e-149.269152052720986e-151.1150505975699883e-14nan

Finally let’s combine spectral model and flux points in a single plot and scale with energy_power=2 to obtain the spectral energy distribution:

In [39]:
ax = crab_2fhl.spectral_model.plot(
    energy_range=[50, 2000] * u.GeV, energy_power=2
)
crab_2fhl.flux_points.plot(ax=ax, energy_power=2);
../_images/notebooks_first_steps_78_0.png

Exercises

  • Plot the spectral model and flux points for PKS 2155-304 for the 3FGL and 2FHL catalogs. Try to plot the error of the model (aka “Butterfly”) as well. Note this requires the uncertainties package to be installed on your machine.

What next?

This was a quick introduction to some of the high-level classes in Astropy and Gammapy.

  • To learn more about those classes, go to the API docs (links are in the introduction at the top).
  • To learn more about other parts of Gammapy (e.g. Fermi-LAT and TeV data analysis), check out the other tutorial notebooks.
  • To see what’s available in Gammapy, browse the Gammapy docs or use the full-text search.
  • If you have any questions, ask on the mailing list.