gavo.utils.pgsphere module

Bindings for the pgsphere library and psycopg2.

Basically, once per program run, you need to call preparePgSphere(connection), and you’re done.

All native representation is in rad.

class gavo.utils.pgsphere.PgSAdapter[source]

Bases: object

A base class for objects adapting pgSphere objects.

The all need a pgType attribute and two static methods _adaptToPgSphere(obj) and _castFromPgSphere(value, cursor).

You must also define a sequence checkedAttributes; all attributes mentioned there must be equal for two adapted values to be equal (equality testing here really is mainly for unit tests with hand-crafted values).

Also, all subclasses you should provide an asPoly returning a spherical polygon. This is used when uploading VOTables with REGION columns.

In practice, you also want:

FromDALI(cls, daliSeq):

a classmethod turning the DALI votable representation (typically, float arrays in degrees) into a corresponding object.


the inverse of fromDALI


returns a representation of the geometry as used in SODA parameters.


returns the “SODA-form” for this circle.

This is a string containing blank-separated float literals; the floats are what asDALI returns, and hence this is built on top of asDALI. We don’t worry about the fact that the coordinates just might be non-ICRS.

checkedAttributes: List[str] = []
pgType: Optional[str] = None
class gavo.utils.pgsphere.SBox(corner1: SPoint, corner2: SPoint)[source]

Bases: PgSAdapter

A spherical box from pgSphere.

The constructor accepts the two corner points.

asDALI() Tuple[float, float, float, float][source]
asPoly() SPoly[source]
asSTCS(systemString: str) str[source]
checkedAttributes: List[str] = ['corner1', 'corner2']
classmethod fromDALI(daliSeq: Sequence[Component]) SBox[source]
classmethod fromSIAPPars(ra: float, dec: float, raSize: float, decSize: float) SBox[source]

returns an SBox corresponding to what SIAP passes in.

In particular, all values are in degrees, and a cartesian projection is assumed.

This is for use with SIAP and tries to partially implement that silly prescription of “folding” over at the poles. If that happens, a TwoSBoxes exception is raised. It contains two SBoxes that should be ORed. I agree that sucks. Let’s fix SIAP.

pattern = re.compile('\\([^()]+\\)')
pgType: Optional[str] = 'sbox'
class gavo.utils.pgsphere.SCircle(center: SPoint, radius: Component)[source]

Bases: PgSAdapter

A spherical circle from pgSphere.

The constructor accepts an SPoint center and a radius in rad.

asDALI() Tuple[float, float, float][source]

returns the “DALI-form” for this circle.

This is an array containing the center coordinates and the radius in degrees.

asPgSphere() str[source]
asPoly(nSegments: int = 32) SPoly[source]
asSMoc(order: int = 6, inclusive: bool = False)[source]

returns an SMoc instance for this circle.

order is the maximum order of the moc returned.

asSTCS(systemString: str) str[source]
checkedAttributes: List[str] = ['center', 'radius']
classmethod fromDALI(daliSeq: Sequence[Optional[Component]]) Optional[SCircle][source]

returns a circle from its DALI float sequence.

Any None in daliSeq makes this a None to help with VOTable null value handling.

classmethod fromPointSet(points: Sequence[SPoint]) SCircle[source]

returns an SCircle covering all the SPoints in points.

(max radius: pi/2).

pattern = re.compile('<(\\([^)]*\\))\\s*,\\s*([0-9.e-]+)>')
pgType: Optional[str] = 'scircle'
class gavo.utils.pgsphere.SMoc(moc: MOC)[source]

Bases: PgSAdapter

a MOC with a pgsphere interface.

The default constructor accepts a pymoc.MOC instance, which is accessible as the moc attribute. The database interface uses the ASCII serialisation, for which there’s the fromASCII constructor.

asASCII() str[source]

returns an ascii serialisation of this MOC.

asDALI() str[source]

returns the string representation of this MOC.

This isn’t what DALI actually says at this point, but we suspect it will say that at some point.

asFITS() bytes[source]

returns a standard FITS (table) representation of this MOC.

asNUNIQs() List[int][source]

returns a list of integers usable as nuniqs.

asPoly() SPoly[source]
asSMoc(order: int = 6) SMoc[source]

returns a copy of self, normalised for order.

asSTCS(frame: str) str[source]
checkedAttributes: List[str] = ['moc']
classmethod fromASCII(literal: str) SMoc[source]

returns an SMoc from a quasi-standard ASCII serialisation.

classmethod fromCells(order: int, pixels: List[int], maxOrder: Optional[int] = None) SMoc[source]

returns a SMoc instance from a collection of pixels at order.

Pass maxOrder to set an explicit max order for the resulting MOC.

classmethod fromDALI(literal: str) SMoc[source]

returns an SMoc from a MOC string.

(see asDALI)

classmethod fromFITS(literal: bytes) SMoc[source]

returns an SMoc from a string containing a FITS-serialised MOC.

getPlot(**kwargs) bytes[source]

returns a png string with a plot visualising this moc.

property maxOrder: int
pgType: Optional[str] = 'smoc'
class gavo.utils.pgsphere.SPoint(x: Component, y: Component)[source]

Bases: PgSAdapter

A point on a sphere from pgSphere.

>>> SPoint(1, 1).asSTCS("ICRS")
'Position ICRS 57.2957795131 57.2957795131'
>>> SPoint.fromDegrees(1, -1).asSTCS("ICRS")
'Position ICRS 1. -1.'
asCooPair() Tuple[float, float][source]

returns this point as (long, lat) in degrees.

asDALI() Tuple[float, float][source]
asPgSphere() str[source]
asSTCS(systemString: str) str[source]
asUnitSphereVec() UnitSphericalRepresentation[source]

returns self as a triple of cx, cy, cz on the unit sphere.

checkedAttributes: List[str] = ['x', 'y']
classmethod fromDALI(coos: Sequence[Component])[source]
classmethod fromDegrees(x: Optional[Component], y: Optional[Component]) Optional[SPoint][source]
classmethod fromDegreesP(x: Component, y: Component) SPoint[source]

fromDegrees when it’s certain that there’s no None x and y.

classmethod fromUnitVector(uvec: UnitSphericalRepresentation) SPoint[source]

returns an SPoint for a 3-unit sphere vector.

p() str[source]
pattern = re.compile('\\s*\\(\\s*([0-9.eNa-]+)\\s*,\\s*([0-9.eNa-]+)\\s*\\)')
pgType: Optional[str] = 'spoint'
class gavo.utils.pgsphere.SPoly(points: Sequence[SPoint])[source]

Bases: PgSAdapter

A spherical polygon from pgSphere.

The constructor accepts a list points of SPoints.

asCooPairs() List[Tuple[float, float]][source]

returns the vertices as a sequence of (long, lat) pairs in degrees.

This form is required by some functions from base.coords.

asDALI() List[float][source]

returns the DALI form of this polygon.

This is a sequence of floats of the vertex coordinates in degrees.

asPgSphere() str[source]
asPoly() SPoly[source]
asSMoc(order: int = 6, inclusive: bool = False) SMoc[source]

returns an SMoc instance for this polygon.

order is the maximum order of the moc returned.

asSTCS(systemString: str) str[source]
checkedAttributes: List[str] = ['points']
classmethod fromDALI(daliSeq: List[Component]) Optional[SPoly][source]

returns a polygon from a DALI float-sequence

This returns None for empty daliSeqs to help with VOTable NULL value handling.

getCenter() List[float][source]

returns an estimate for some sort of center of this polygon.

This is computed as the mean of the vertices (in unit sphere representation), which, depending on the polygon, may be very far from the polygon’s center of mass. Also, you can kill this by having all points sit on a great circle, etc.

So: handle with care. Doing this properly is hard.

pattern = re.compile('\\([^)]+\\)')
pgType: Optional[str] = 'spoly'
exception gavo.utils.pgsphere.TwoSBoxes(box1: SBox, box2: SBox)[source]

Bases: ExecutiveAction

is raised when an SBox is constructed from center and size such that it overlaps the pole.

gavo.utils.pgsphere.preparePgSphere(conn: Connection) None[source]
gavo.utils.pgsphere.removeTrailingZeroes(s: str) str[source]

remove zeroes in front of whitespace or the string end.

This is used for cosmetics in STC-S strings.

>>> removeTrailingZeroes("23.3420   21.2 12.00000")
'23.342   21.2 12.'