Skip to content

Commit

Permalink
Merge pull request #25 from mattpitkin/circular_boundary
Browse files Browse the repository at this point in the history
Circular boundary
  • Loading branch information
mattpitkin authored May 8, 2018
2 parents b615f2c + 96af88b commit 7814cac
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 5 deletions.
22 changes: 22 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,28 @@ We can also get the whole ephemeris for the Crab with
DIST_DM 1.31
...

**Query pulsars within a circular boundary**

We can query the catalogue to only return pulsars within a `circular boundary <http://www.atnf.csiro.au/research/pulsar/psrcat/psrcat_help.html?type=normal#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 RAJ_ERR DECJ DECJ_ERR
---------- ----- ------- ------ --------
J1142+0119 11:42 0.0 +01:19 0.0

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

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

Or, in radians, as:

>>> c = [3.29406898, -0.05067418, 10.]

**Return a reference**

We can make use of the `ADS module <https://ads.readthedocs.io/en/latest/>`_ to return links to references for pulsars/pulsar parameters.
Expand Down
2 changes: 1 addition & 1 deletion psrqpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

""" A Python tool for interacting with the ATNF pulsar catalogue """

__version__ = "0.4.12"
__version__ = "0.5.1"

__citation__ = """@article{psrqpy,
author = {{Pitkin}, M.},
Expand Down
7 changes: 5 additions & 2 deletions psrqpy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
PSRNAMES_QUERY = r'&pulsar_names={psrnames}'
SORT_QUERY = r'&sort_attr={sortattr}&sort_order={sortorder}'
EPHEMERIS_QUERY = r'&submit_ephemeris={getephemeris}'
QUERY_FLUFF = r'&ephemeris=long&coords_unit=raj%2Fdecj&radius=&coords_1=&coords_2=&style=Long+with+errors&no_value=*&nohead=nohead&state=query&table_bottom.x=30&table_bottom.y=22'
COORD1_QUERY = r'&coords_1={coord1}'
COORD2_QUERY = r'&coords_2={coord2}'
RADIUS_QUERY = r'&radius={radius}'
QUERY_FLUFF = r'&ephemeris=long&coords_unit=raj%2Fdecj&style=Long+with+errors&no_value=*&nohead=nohead&state=query&table_bottom.x=30&table_bottom.y=22'

#: the full ATNF catalogue query URL
QUERY_URL = ATNF_URL + PARAMS_QUERY + USERDEFINED_QUERY + SORT_QUERY + CONDITION_QUERY + PSRNAMES_QUERY + EPHEMERIS_QUERY + QUERY_FLUFF
QUERY_URL = ATNF_URL + PARAMS_QUERY + USERDEFINED_QUERY + SORT_QUERY + CONDITION_QUERY + PSRNAMES_QUERY + EPHEMERIS_QUERY + RADIUS_QUERY + COORD1_QUERY + COORD2_QUERY + QUERY_FLUFF

# pulsar parameters (http://www.atnf.csiro.au/research/pulsar/psrcat/psrcat_help.html) that can be
# queried. For each parameter there is a dictionary giving:
Expand Down
70 changes: 68 additions & 2 deletions psrqpy/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
import requests
from bs4 import BeautifulSoup

from astropy.coordinates import SkyCoord
import astropy.units as aunits

from .config import *
from .utils import *

Expand Down Expand Up @@ -66,6 +69,21 @@ class QueryATNF(object):
ascending.
psrs (:obj:`list`): a list of pulsar names for which to get the requested parameters.
Defaults to None.
circular_boundary (:obj:`list`, tuple): a list containing three entries defining the centre
(in right ascension and declination), and radius of a circle in which to search for and
return pulsars. The first entry is the centre point right ascension as a string in
format 'hh:mm:ss' or a float in radians, the second entry is the centre point
declination as a string in format 'dd:mm:ss' or a float in radians, the final entry is
the circle's radius in degrees. Alternatively `coord1`, `coord2`, and `radius` can be
used.
coord1 (str): a string containing a right ascension in the format ('hh:mm:ss') that
centres a circular boundary in which to search for pulsars (requires coord2 and
radius to be set).
coord2 (str): a string containing a declination in the format ('dd:mm:ss') that
centres a circular boundary in which to search for pulsars (requires coord1 and
radius to be set).
radius (float): the radius (in degrees) of a circular boundary in which to search for
pulsars (requires coord1 and coord2 to be set).
include_errs (bool): Set if wanting parameter errors to be returned. Defaults to True.
include_refs (bool): Set if wanting parameter
`references <http://www.atnf.csiro.au/research/pulsar/psrcat/psrcat_ref.html>`_ to be
Expand All @@ -83,7 +101,8 @@ class QueryATNF(object):
def __init__(self, params=None, condition=None, psrtype=None, assoc=None, bincomp=None,
exactmatch=False, sort_attr='jname', sort_order='asc', psrs=None,
include_errs=True, include_refs=False, get_ephemeris=False, version=None,
adsref=False, loadfromfile=None):
adsref=False, loadfromfile=None, circular_boundary=None, coord1=None, coord2=None,
radius=0.):
self._psrs = psrs
self._include_errs = include_errs
self._include_refs = include_refs
Expand Down Expand Up @@ -115,6 +134,26 @@ def __init__(self, params=None, condition=None, psrtype=None, assoc=None, bincom

self._pulsars = None # gets set to a Pulsars object by get_pulsars()

# conditions for finding pulsars within a circular boundary
self._coord1 = coord1
self._coord2 = coord2
self._radius = radius
if isinstance(circular_boundary, list) or isinstance(circular_boundary, tuple):
if len(circular_boundary) != 3:
raise Exception("Circular boundary must contain three values")
self._coord1 = circular_boundary[0]
self._coord2 = circular_boundary[1]
self._radius = circular_boundary[2]
elif self._coord1 is None or self._coord2 is None or self._radius == 0.:
# if any are not set then we can't define a boundary
self._coord1 = self._coord2 = ''
self._radius = 0.
else:
if not isinstance(self._coord1, string_types) or not isinstance(self._coord2, string_types):
raise Exception("Circular boundary centre coordinates must be strings")
if not isinstance(self._radius, float) and not isinstance(self._radius, int):
raise Exception("Circular boundary radius must be a float or int")

# check parameters are allowed values
if isinstance(params, list):
if len(params) == 0:
Expand Down Expand Up @@ -190,7 +229,8 @@ def load(self, fname):
raise Exception("Error reading in pickle")

def generate_query(self, version='', params=None, condition='', sortorder='asc',
sortattr='JName', psrnames=None, **kwargs):
sortattr='JName', psrnames=None, coord1='', coord2='',
radius=0., **kwargs):
"""
Generate a query URL and return the content of the :class:`~requests.Response` from that
URL. If the required class attributes are set then they are used for generating the query,
Expand All @@ -205,6 +245,14 @@ def generate_query(self, version='', params=None, condition='', sortorder='asc',
sortorder (str): the order for sorting the results.
sortattr (str): the parameter on which to perform the sorting.
psrnames (list, str): a list of pulsar names to get parameters for
coord1 (str): a string containing a right ascension in the format ('hh:mm:ss') that
centres a circular boundary in which to search for pulsars (requires `coord2` and
`radius` to be set).
coord2 (str): a string containing a declination in the format ('dd:mm:ss') that
centres a circular boundary in which to search for pulsars (requires `coord1` and
`radius` to be set).
radius (float): the radius (in degrees) of a circular boundary in which to search for
pulsars (requires `coord1` and `coord2` to be set).
get_ephemeris (bool): a boolean stating whether to get pulsar ephemerides rather than
a table of parameter values (only works if pulsar names are given)
Expand Down Expand Up @@ -248,6 +296,24 @@ def generate_query(self, version='', params=None, condition='', sortorder='asc',
query_dict['sortorder'] = self._sort_order
self._sort_attr = self._sort_attr if sortattr == self._sort_attr else sortattr
query_dict['sortattr'] = self._sort_attr
self._coord1 = self._coord1 if not coord1 else coord1
self._coord2 = self._coord2 if not coord2 else coord2
self._radius = self._radius if not radius else radius

if self._coord1 and self._coord2 and self._radius:
raunit = aunits.hourangle if isinstance(self._coord1, string_types) else aunits.rad
decunit = aunits.deg if isinstance(self._coord2, string_types) else aunits.rad
try:
c = SkyCoord(self._coord1, self._coord2, unit=(raunit, decunit))
except ValueError:
raise Exception("Could not parse circular boundary centre")
# use %3A as ':' for the seperator
self._coord1 = '{}\%3A{}\%3A{}'.format(int(c.ra.hms[0]), int(c.ra.hms[1]), c.ra.hms[2])
self._coord2 = '{}\%3A{}\%3A{}'.format(int(c.dec.dms[0]), int(c.dec.dms[1]), c.dec.dms[2])

query_dict['coord1'] = self._coord1
query_dict['coord2'] = self._coord2
query_dict['radius'] = self._radius

if psrnames:
if isinstance(psrnames, string_types):
Expand Down

0 comments on commit 7814cac

Please sign in to comment.