Creating Catalogues
===================
The two main elements required to start preparing a TFCat feature
collection is the choice of the CRS and the list of feature geometries
(with its set of time and spectral coordinates). In the following code
snippet, a CRS object is created with a time axis using the ``unix``
timestamp representation, a spectral axis (frequency in kHz) and a
reference position set to the Juno spacecraft.
.. code-block:: python
:caption: Example CRS definition
from tfcat import CRS
crs = CRS({
"type": "local",
"properties": {
"name": "Time-Frequency",
"time_coords_id": "unix",
"spectral_coords": {
"type": "frequency",
"unit": "kHz"
},
"ref_position_id": "juno",
}
})
In the following example, we create a TFCat feature with a TFCat Polygon
geometry and two custom feature *properties* called ``feature_type``
and ``integrated_flux_density``. The set of coordinates are available as
two variables called ``tt`` and ``ff``, containing respectively the time
coordinates (as a unix timestamp), and the frequency coordinates
(in kHz). Note, that a Polygon geometry requires that the last coordinate
point of the input sequence should be the same as the first one (closed
polygon condition). It also requires that the segments forming the polygon
are not crossing over (no cross-over condition). The polygon must also be
curled counter-clockwise. We use the *shapely* package to check those
conditions.
.. code-block:: python
:caption: Creating a TFCat Polygon
from tfcat import Polygon, Feature
from shapely.geometry import LinearRing
# packing coordinates into a list
coords = list(zip(tt, ff))
# checking if polygon is valid
if not LinearRing(coords).isvalid:
raise ValueError("Polygon is invalid")
# checking if list of coordinates is curled in the direct trigonometric sense (counter-clockwise)
if not LinearRing(coords).is_ccw:
coords = coords[::-1]
# creating the TFCat Feature
feature = Feature(
geometry=Polygon([coords]),
properties={
"feature_type": "Io-A",
"integrated_flux_density": 1.22e-19,
},
)
Each *properties* must be defined at the main level of the feature collection object, using
a set of TFCat Field objects, as shown below.
.. code-block:: python
:caption: Defining the TFCat Fields
fields = {
"feature_type": {
"info": "Feature Type",
"datatype": "str",
"ucd": "meta.id",
},
"integrated_flux_density": {
"info": "Integrated Flux Density",
"datatype": "float",
"ucd": "phot.flux.density;stat.mean",
"unit": "W m-2 Hz-1",
}
}
The feature collection can also include main level *properties*, listing global metadata
for the collection, such as the author, the instrument, etc. The next code snippet shows a set
of collection level properties. We recommend to use keywords compliant with the `EPNcore metadata
dictionary `_. For authors, we recommend to use a list of
dictionaries containing *GivenName*, *FamilyName*, *ORCID* and *Affiliation* (using
`Research Organisation Registry identifier `_ when possible).
.. code-block:: python
:caption: Defining main level properties
properties = {
"instrument_host_name": "Juno",
"instrument_name": "Waves",
"title": "Catalogue of Juno Radio emissions",
"authors": [
{
"GivenName": "Corentin K.",
"FamilyName": "Louis",
"ORCID": "https://orcid.org/0000-0002-9552-8822",
"Affiliation": "https://ror.org/051sx6d27"
},
],
"target_name": "Jupiter",
"target_class": "planet",
"target_region": "magnetosphere",
"feature_name": "radio emissions",
"bib_reference": "TBD",
"publisher": "PADC/MASER",
"version": "1.0"
}
Finally, the collection can be built, assuming a list of features is available
in an iterable called ``features``. The JSON schema URI should also be referenced.
.. code-block:: python
:caption: Finalizing TFCat collection
from tfcat import FeatureCollection
SCHEMA_URI = "https://voparis-ns.obspm.fr/maser/tfcat/v1.0/schema#"
# creating the collection
collection = FeatureCollection(
schema=SCHEMA_URI,
features=features,
properties=properties,
fields=fields,
crs=crs
)
Writing the collection into a file is straightforward, since tje TFCat module implements the
same interfaces as the *json* python module for file system interactions (i.e., ``dump()``,
``dumps()``, ``load()``, ``loads()`` methods):
.. code-block:: python
:caption: Dumping into File
# write out the collection on disk
from tfcat import dump
filename = "tfcat.json"
with open(filename, "w") as f:
dump(collection, f)