The python Package¶
rocks provides object-oriented access to the data stored in ssoCards and
datacloud catalogues. The implementation focuses on ease-of-access and speed: all attributes are accessible via the common dot notation, and queries to
SsODNet are run asynchronously.
The public API only consists of two functions and one class:
rocks.identify(): identify one or many asteroids based on user-provided identifiersrocks.Rock: eachRockrepresents one asteroid and contains the data of its ssoCardrocks.rocks(): a wrapper aroundrocks.identify()androcks.Rockto read in the data of many asteroids
Identification of asteroids¶
It is quite straight-forward: providing a single identifier
(or a list of many) returns a tuple containing the (asteroid name, asteroid number) (or a list of tuples).
>>> import rocks
>>> rocks.identify(11334)
('Rio de Janeiro', 11334)
>>> rocks.identify(["SCHWARTZ", "J95X00A", "47", 3.])
[('Schwartz', 13820), ('1995 XA', 24850), ('Aglaja', 47), ('Juno', 3)]
Note the alphabetical order: first returned is the name, then the number.
The Rock class¶
The Rock class is used to inspect the parameters of a single
asteroid. It is the (iron) core of the rocks package.
Creating a Rock instance¶
Rocks are created by passing the name, number, or SsODNet ID of the asteroid that they should represent.
>>> from rocks import Rock
>>> ceres = Rock(1)
>>> ceres
Rock(number=1, name='Ceres')
>>> vesta = Rock("1807 FA")
>>> vesta
Rock(number=4, name='Vesta')
Access of ssoCard parameters¶
During instantiation, the asteroid properties are retrieved from SsODNet and assigned to the attributes following the structure of the ssoCard.
>>> ceres.parameters.physical.taxonomy.class_
C
>>> vesta.parameters.dynamical.proper_elements.proper_semi_major_axis.value
2.3615126
Notice the .value suffix to retrieve the value of numerical parameters, just as in an ssoCard itself.
To reduce the typing effort, the parameters and physical/ dynamical
attributes can be skipped.
>>> vesta.parameters.physical.diameter
525.4
>>> vesta.diameter
525.4
More shortcuts are given below. Feel free to suggest new ones by opening an issue on the GitHub page.
Differences to the ssoCard structure arise in two cases:
the
ssoCarduses keywords which are protected inpython, such as theclasskeyword. These keywords have an underscore appended to them:class,id,min,maxthe
ssoCarduses keywords which are invalid variable names inpython, such as the name of colours: “c-o” becomes “c_o”. In general, characters such as-,/,., are replaced by_in parameter names.
Access of datacloud tables¶
The datacloud catalogues of an asteroid are not loaded by default when creating a
Rock instance, as each table requires an additional remote query. Tables can
be requested using the datacloud argument instead.
Single tables can be requested by passing the table name to the datacloud.
>>> ceres = Rock(1, datacloud='masses')
Multiple tables are retrieved by passing a list of table names.
>>> ceres = Rock(1, datacloud=['taxonomies', 'masses'])
>>> ceres.taxonomies.class_
['G', 'C', 'C', 'C', 'C', 'G', 'C']
>>> ceres.taxonomies.shortbib
['Tholen+1989', 'Bus&Binzel+2002', 'Lazzaro+2004', 'Lazzaro+2004',
'DeMeo+2009', 'Fornasier+2014', 'Fornasier+2014']
From a python view, the catalogues are subclassed of the pandas.DataFrame.
As such, the catalogues are iterable and return a catalogue per entry in each iteration.
>>> vesta = Rock(4, datacloud="diamalbedo")
>>> for entry in vesta.diameters:
print(f"{entry.diameter:.1f}km, observed via {entry.method} by {entry.shortbib}")
507.3km, observed via TE-IM by Drummond+1998
530.0km, observed via STM by Morrison+2007
510.0km, observed via TE-IM by Drummond+2008
468.3km, observed via STM by Tedesco+2001
520.4km, observed via STM by Ryan+2010
515.9km, observed via NEATM by Ryan+2010
521.7km, observed via NEATM by Usui+2011
525.4km, observed via SPACE by Russell+2012
562.6km, observed via NEATM by Alí-Lagoa+2018
505.4km, observed via OCC by Herald+2019
522.0km, observed via OCC by Herald+2019
Other convenient DataFrame methods such as groupby are also available. The difference between the DataCloudDataFrame and the original DataFrame are two added methods for the former: weighted_average and plot.
The datacloud tables have slightly different names in rocks.
datacloud Table |
Attribute Name |
aams |
|
astdys |
|
astorb |
|
binarymp_tab |
|
diamalbedo |
|
families |
|
masses |
|
mpcatobs |
|
pairs |
|
taxonomy |
|
Some attributes are called different in rocks than in the datacloud table:
The datacloud tables have slightly different names in rocks.
datacloud Table |
Attribute Name |
num |
|
sibling_num |
|
id |
|
lambda |
|
class |
|
from | |
|
Some observations in the catalogues might be preferred to others. For example, a
taxonomical classification using a visible-near-infrared spectrum is more
reliable than one based on visible colours. rocks includes opinionated
selections of preferred observations based on the observation methods, just as
the ssoCard does. Catalogues have preferred attributes, which are lists
containing True if the corresponding observation is preferred, and False
otherwise.
>>> ceres = Rock(1, datacloud='masses')
>>> len(ceres.masses.mass) # 20 observations of Ceres' mass in database
20
>>> for obs in ceres.masses:
if obs.preferred:
print(f"Mass: {obs.mass}, Method: {obs.method}, from {obs.shortbib}")
Mass: 9.384e+20, Method: SPACE, from Russell+2016
Note
As the diamalbedo catalogue contains both diameters and albedos, it contains the preferred_diameter and preferred_albedo attributes.
rocks offers an easy way to compute the weighted averages of the preferred property measurements, see for example: what’s the weighted average albedo of (6) Hebe?
Special use-cases¶
When passing the name or number, the asteroid is identified using
rocks.identify(). If the SsODNet ID of the asteroid is
provided, this check can be skipped by setting the skip_id_check argument to
True. This saves time when creating many Rock instances in a loop, as demonstrated in the Tutorials.
>>> mars_crosser_2016fj = Rock("2016_FJ", skip_id_check=True)
The user can further provide their own custom ssoCard to populate the Rock attributes.
The ssocard argument accepts a dictionary structure following the one of the
original ssoCards. The easiest way to achieve this is to edit a real ssoCard from SsODNet
and load it via the json module.
>>> import json
>>> import os
>>> with open("my_ssocard.json", "r") as file_:
>>> data = json.load(file_)
>>> mars_crosser_2016fj = Rock("2016_FJ", ssocard=data["2016_FJ"])
List of attribute shortcuts¶
ssoCard attribute |
Shortcut |
parameters.dynamical |
|
parameters.physical |
|
semi_major_axis |
|
eccentricity |
|
inclination |
|
proper_semi_major_axis |
|
proper_eccentricity |
|
proper_inclination |
|
Creating many Rocks¶
The rocks.rocks() function serves as a one-line replacement for a frequent approach: get a list of asteroid identifiers from a catalogue and create Rock instances from them.
>>> from rocks import rocks
>>> themis_family = [24, 62, 90, 104, 171, 222, 223, 316, 379,
383, 468, 492, 515, 526, 767, 846]
>>> themis_family = rocks(themis_family)
>>> themis_family
[Rock(number=316, name='Goberta'), Rock(number=492, name='Gismonda'),
Rock(number=767, name='Bondia'), Rock(number=90, name='Antiope'), ... ]
Accessing the properties can now be done with a loop or list comprehension.
>>> from collections import Counter
>>> themis_taxonomies = [t.taxonomy.class_ for t in themis_family]
>>> Counter(themis_taxonomies)
Counter({'C': 8, 'B': 2, 'Ch': 2, 'BU': 1, 'Xc': 1, 'Xk': 1, 'Cb': 1})
Any property not present in the ssoCard of an asteroid is set to NaN. This ensures that accessing attributes in a loop does not fail.