# The psrqpy package¶

A Python tool for interacting with the ATNF pulsar catalogue

This package provides a way to directly query the ATNF Pulsar Catalogue [1] using Python. It does this by downloading and parsing the full catalogue database, which itself is cached and can be reused. It is primarily aimed at astronomers wanting access to the latest pulsar information via a script, rather than through the standard web interface.

Other functionality that it includes:

# Installation¶

This package can be installed using pip via pip install psrqpy or conda using conda install -c conda-forge psrqpy. Alternatively the source code can be obtained from github, and installed using:

python setup.py install


with sudo if wanted to install system wide, and with the --user flag if just installing for an individual user.

## Requirements¶

The requirements for installing the code are:

The ads module and matplotlib are optional requirements to get the full functionality.

# Examples¶

>>> from psrqpy import QueryATNF
>>> query = QueryATNF()


From this query the database can then be accessed as an astropy.table.Table via

>>> table = query.table


or as a pandas.DataFrame via

>>> df = query.pandas


You can also specifically limit the query to any combination of the pulsar parameters listed here.

A simple example of such a limited query is to get the frequency ‘F0’ for all pulsars in the catalogue. This could be done with

>>> from psrqpy import QueryATNF
>>> query = QueryATNF(params=['F0'])


where the parameter names are case insensitive. This will also automatically include the database uncertainty on 'F0', stored as a variable called 'F0_ERR' (parameter uncertainties will always be stored using the uppercase version of the parameter name, with _ERR appended). Again, the table, now only containing 'F0' and 'F0_ERR', can be accessed with

>>> table = query.table


Note that the full catalogue is still stored in the psrqpy.QueryATNF (as a pandas.DataFrame) and can accessed with

>>> catalogue = query.catalogue


Other parameters could be selected using the same query object with, e.g.,

>>> query.query_params = ['F1', 'RAJ']
>>> print(query.table)
F1_ERR             RAJ      RAJ_ERR           F1
1 / s2                                      1 / s2
---------------------- ------------ ------- ----------------------
5e-18  00:02:58.17    0.02           -4.48354e-13
2.4933208594475155e-17   00:06:04.8     0.2 -4.357078201884523e-15
5e-16   00:07:01.7     0.2             -3.612e-12
--     00:11:34   114.0                     --
9e-20  00:14:17.75    0.04            -3.6669e-16
4e-20            0      --           -1.22783e-15
...          ...     ...                    ...
8e-19  23:39:38.74    0.01            -1.6952e-15
--     23:40:45     7.0                     --
--        23:43      --                     --
3e-20            2      --             -9.765e-16
--        23:52      --                     --
--        23:54     7.0                     --
9e-20 23:54:04.724   0.004          -1.821923e-14
Length = 2659 rows


The number of pulsars can easily be accessed, e.g.,

>>> numstring = 'Version {} of the ATNF catalogue contains {} pulsars'
>>> print(numstring.format(query.get_version, query.num_pulsars))
Version 1.59 of the ATNF catalogue contains 2659 pulsars


## More complex queries¶

Setting conditions

You can set logical conditions on the parameters that you query. Let’s say you want all pulsars with rotation frequencies between 100 and 200 Hz, then you could do the following:

>>> from psrqpy import QueryATNF
>>> query = QueryATNF(condition='F0 > 100 && F0 < 200')
>>> print(query.num_pulsars)
82


If you also wanted pulsars with this condition, but also in globular clusters, you could do

>>> query = QueryATNF(condition='F0 > 100 && F0 < 200', assoc='GC')
>>> print(len(query))
33


This is equivalent to having condition='F0 > 100 && F0 < 200 && assoc(GC)'.

Save a query

You can save a query as a pickled object for later use, e.g., if using a previous query we had done:

>>> query.save('atnfquery.pkl')


Then we could reload this with

>>> oldquery = QueryATNF(loadquery='atnfquery.pkl')


Query specific pulsars

We might just want to get information on certain pulsars, such as the Crab pulsar (J0534+2200) and J0537-6910, then we could get their sky positions with:

>>> from psrqpy import QueryATNF
>>> query = QueryATNF(params=['JNAME', 'RAJ', 'DECJ'], psrs=['J0534+2200', 'J0537-6910'])
>>> print(query.table)
RAJ_ERR     RAJ          DECJ     DECJ_ERR   JNAME
------- ------------ ------------ -------- ----------
0.005 05:34:31.973 +22:00:52.06     0.06 J0534+2200
0.11 05:37:47.416 -69:10:19.88      0.6 J0537-6910


You can also access these pulsars using the psrqpy.pulsar.Pulsars class. This will create a dictionary of psrqpy.pulsar.Pulsar objects keyed on the pulsar names. The attributes of the Pulsar objects are the parameters that have been retrieved by the query. But, the Pulsar objects themselves can query the ATNF Pulsar Catalogue if you request a parameter that they don’t already contain. E.g., so first lets get the psrqpy.pulsar.Pulsars:

>>> psrs = query.get_pulsars()
>>> for psr in psrs:
...     print(psr)
J0534+2200
J0537-6910

>>> print(psrs['J0534+2200'].keys()) # show attributes of the psr class
['DECJ', 'RAJ', 'DECJ_ERR', 'RAJ_ERR', 'JNAME']


What if we want the frequency of J0534+2200? Well, we just have to do

>>> crab = psrs['J0534+2200']
>>> print(crab.F0)
29.946923


We can also get the whole ephemeris for the Crab with

>>> print(query.get_ephemeris('J0534+2200'))
NAME      J0534+2200
JNAME     J0534+2200
BNAME     B0531+21
PSRJ      J0534+2200
PSRB      B0531+21
RAJ       05:34:31.973              0.005000000000000
DECJ      +22:00:52.06              0.060000000000000
PMRA      -14.699999999999999       0.800000000000000
PMDEC     2                         0.800000000000000
POSEPOCH  40706
ELONG     84.097631599851169
ELAT      -1.294467050350203
PMELONG   -14.597441126565251
PMELAT    2.646641750683564
GL        184.557559483180171
GB        -5.784269849609095
RAJD      83.633220833333311
DECJD     22.014461111111110
TYPE      HE[cdt69,fhm+69,hjm+70]
PML       -9.558486649099681
PMB       -11.345718707027030
DIST      2
DIST_DM   1.310000000000000
...


Note

This style of ephemeris is not completely equivalent to the pulsar ephemerides returned by the ATNF Pulsar Catalogue.

Query pulsars within a circular boundary

We can query the catalogue to only return pulsars within a circular boundary defined by a central right ascension and declination, and with a given radius (in degrees).

>>> from psrqpy import QueryATNF
>>> # set the boundary circle centre (RAJ then DECJ) and radius
>>> c = ['12:34:56.7', '-02:54:12.3', 10.]
>>> query = QueryATNF(params=['JNAME', 'RAJ', 'DECJ'], circular_boundary=c)
>>> print(query.table)
JNAME         RAJ      DECJ_ERR      DECJ      RAJ_ERR
---------- ------------- -------- -------------- -------
J1257-1027 12:57:04.7686       -- -10:27:05.7817      --
J1312+0051         13:12       --         +00:51      --


The circle’s coordinates can also be define as, e.g.:

>>> c = ['12h34m56.7s', '-02d54m12.3s', 10.]


Return a reference

We can make use of the ADS module to return links to references for pulsars/pulsar parameters. For example we could get the reference for the orbital period of J0737-3039A with

>>> from psrqpy import QueryATNF
>>> query = QueryATNF(params='PB', psrs='J0737-3039A', include_refs=True, adsref=True)
>>> print(query.parse_ref(query.table['PB_REF'])[0])
(" Kramer, M., Stairs, I. H., Manchester, R. N., McLaughlin, M. A., Lyne, A. G., Ferdman, R. D., Burgay, M., Lorimer, D. R., Possenti, A., D'Amico, N., Sarkissian, J. M., Hobbs, G. B., Reynolds, J. E., Freire, P. C. C. & Camilo, F., 2006. Tests of General Relativity from Timing the Double Pulsar. Science, 314, 97-102. ", 'https://ui.adsabs.harvard.edu/#abs/2006Sci...314...97K/')


Note

To use this feature you need to have an API key from NASA ADS labs. Getting this is described here.

Make a P-Pdot diagram

You can generate a lovely period vs. period derivative diagram based on the latest catalogue information using the ppdot() function in just three lines of code:

>>> from psrqpy import QueryATNF
>>> query = QueryATNF(params=['P0', 'P1', 'ASSOC', 'BINARY', 'TYPE', 'P1_I'])
>>> query.ppdot(showSNRs=True, showtypes='all')


where this shows all pulsar types and pulsars in supernova remnants, to give

# Differences with the ATNF Pulsar Catalogue¶

There are differences between some of the values returned by psrqpy and those calculated by the psrcat software used to generation the ATNF Pulsar Catalogue results. These are listed below:

• The cartesian Galactic coordinates returned by psrqpy.QueryATNF (XX, YY, and ZZ) do not match those returned by the ATNF Pulsar Catalogue and the psrcat software. The values returned by psrqpy are defined using the conventions in the astropy.coordinates.Galactocentric class. This uses a Galactic centre distance of 8.3 kpc compared to 8.5 kpc in psrcat and is rotated 90 degrees anticlockwise compared to psrcat.
• The Galactic coordinate proper motions returned by psrqpy.QueryATNF (PML and PMB) do not match those returned by the ATNF Pulsar Catalogue and the psrcat software. The values returned by psrqpy purely convert the observed proper motions in right ascension and declination (or elliptic longitude and latitude) into equivalent values in the Galactic coordinate system (via the astropy.coordinates.Galactic class). However, the values returned by the ATNF Pulsar Catalogue and the psrcat software are in the Galactic cooridinate system, but additionally have the local solar system velocity and Galactic rotation of the pulsar removed from them as described in Section 3 of [2].

# Development and Support¶

Code development is done via the package’s GitHib repository. Any contributions can be made via a fork and pull request model from that repository, and must adhere to the MIT license. Any problems with the code or support requests can be submitted via the repository’s Issue tracker.

# Test suite¶

There are tests supplied that cover many of the functions within PSRQpy. These can be run from the base directory of the repository (after installing the pytest and pytest-socket modules, e.g., with pip) by just calling:

pytest

These tests are not included in the pip installed version of the code.

## References¶

 [1] Manchester, Hobbs, Teoh & Hobbs, AJ, 129, 1993-2006 (2005), arXiv:astro-ph/0412641
 [2] Harrison, Lyne & Anderson, MNRAS, 261, 113-124 (1993)