No project description provided
Project description
OTTER API
Open mulTiwavelength Transient Event Repository
A Python API for the OTTER.
Installation
To install the OTTER API use
git clone https://github.com/astro-otter/otter.git
cd otter
python -m pip install .
This will be changed into the more convenient python -m pip install astro-otter
at a later date!
For developers, please also enable the pre-commit hooks using
pre-commit install
Tutorial
Connecting to the OTTER
# import the API
from otter import Otter, Transient
# connect to the database
# this username and password is just for now and will be updated later!
db = Otter(username='user@otter', password='insecure')
A typical workflow
First use Otter.getMeta
to query
# can query by ANY name associated with an object
db.getMeta(names=['ASASSN-15oi', 'AT2020opy'])
[{'name': {'default_name': 'ASASSN-15oi', 'alias': [{'value': 'ASASSN-15oi', 'reference': 'ASASSN'}]}, 'coordinate': {'equitorial': [{'ra': '20 39 09.096', 'dec': '-30 45 20.71', 'epoch': 'J2000', 'system': 'ICRS', 'ra_units': 'hourangle', 'dec_units': 'deg', 'reference': ['2021NatAs...5..491H'], 'computed': False, 'default': True, 'uuid': 'a06be641-1601-4737-9a1a-bd25c5dd61e6'}], 'galactic': [{'l': 13.01154485751856, 'b': -35.41877256185317, 'l_units': 'deg', 'b_units': 'deg', 'reference': 'a06be641-1601-4737-9a1a-bd25c5dd61e6', 'computed': True}]}, 'epoch': {'date_discovery': [{'value': 57248.2, 'date_format': 'MJD', 'reference': ['2021NatAs...5..491H'], 'computed': False}]}, 'distance': {'redshift': [{'value': '0.0484', 'reference': ['2021NatAs...5..491H'], 'computed': False, 'default': True}]}, 'classification': [{'object_class': 'TDE', 'confidence': 1, 'reference': ['2021NatAs...5..491H'], 'default': True}]},
{'name': {'default_name': 'AT2020opy', 'alias': [{'value': 'AT2020opy', 'reference': 'TNS'}]}, 'coordinate': {'equitorial': [{'ra': '15 56 25.728', 'dec': '+23 22 21.15', 'epoch': 'J2000', 'system': 'ICRS', 'ra_units': 'hourangle', 'dec_units': 'deg', 'reference': ['2023MNRAS.518..847G'], 'computed': False, 'default': True, 'uuid': '4f414ede-e0f0-4423-b2cc-f3ad309f0936'}], 'galactic': [{'l': 38.411569358993255, 'b': 48.23253616380999, 'l_units': 'deg', 'b_units': 'deg', 'reference': '4f414ede-e0f0-4423-b2cc-f3ad309f0936', 'computed': True}]}, 'epoch': {'date_discovery': [{'value': 59038.23, 'date_format': 'MJD', 'reference': ['2023MNRAS.518..847G'], 'computed': False}]}, 'distance': {'redshift': [{'value': '0.159', 'reference': ['2023MNRAS.518..847G'], 'computed': False, 'default': True}]}, 'classification': [{'object_class': 'TDE', 'confidence': 1, 'reference': ['2023MNRAS.518..847G'], 'default': True}]}]
We can also do a cone search
from astropy.coordinates import SkyCoord
import astropy.units as u
coord = SkyCoord(239, 23, unit=('deg', 'deg'))
rad = (1*u.deg).to(u.arcsec).value
db.getMeta(coords=coord, radius=rad)
[{'name': {'default_name': 'AT2020opy', 'alias': [{'value': 'AT2020opy', 'reference': 'TNS'}]}, 'coordinate': {'equitorial': [{'ra': '15 56 25.728', 'dec': '+23 22 21.15', 'epoch': 'J2000', 'system': 'ICRS', 'ra_units': 'hourangle', 'dec_units': 'deg', 'reference': ['2023MNRAS.518..847G'], 'computed': False, 'default': True, 'uuid': '4f414ede-e0f0-4423-b2cc-f3ad309f0936'}], 'galactic': [{'l': 38.411569358993255, 'b': 48.23253616380999, 'l_units': 'deg', 'b_units': 'deg', 'reference': '4f414ede-e0f0-4423-b2cc-f3ad309f0936', 'computed': True}]}, 'epoch': {'date_discovery': [{'value': 59038.23, 'date_format': 'MJD', 'reference': ['2023MNRAS.518..847G'], 'computed': False}]}, 'distance': {'redshift': [{'value': '0.159', 'reference': ['2023MNRAS.518..847G'], 'computed': False, 'default': True}]}, 'classification': [{'object_class': 'TDE', 'confidence': 1, 'reference': ['2023MNRAS.518..847G'], 'default': True}]}]
Or search within a redshift range (or just a maximum or minimum)
# can search a redshift range
db.getMeta(minZ=0.5, maxZ=0.9)
[{'name': {'default_name': 'Sw J1112-82', 'alias': [{'value': 'Sw J1112-82', 'reference': 'Swift'}]}, 'coordinate': {'equitorial': [{'ra': '11 11 47.6', 'dec': '-82 38 44.44', 'epoch': 'J2000', 'system': 'ICRS', 'ra_units': 'hourangle', 'dec_units': 'deg', 'reference': ['2017MNRAS.472.4469B'], 'computed': False, 'default': True, 'uuid': '3bb02aa4-eb60-4f09-acdf-d1431a6addc4'}], 'galactic': [{'l': 299.6337165869647, 'b': -20.420594756871665, 'l_units': 'deg', 'b_units': 'deg', 'reference': '3bb02aa4-eb60-4f09-acdf-d1431a6addc4', 'computed': True}]}, 'epoch': {'date_discovery': [{'value': '55729.5', 'date_format': 'MJD', 'reference': ['2017MNRAS.472.4469B'], 'computed': False}]}, 'distance': {'redshift': [{'value': '0.89', 'reference': ['2017MNRAS.472.4469B'], 'computed': False, 'default': True}]}, 'classification': [{'object_class': 'TDE', 'confidence': 1, 'reference': ['2017MNRAS.472.4469B'], 'default': True}]}]
We can even get all objects that have spectra associated with them
# just get objects that have spectra associated with them
db.getMeta(hasSpec=True)
[]
This should be empty because at the time of developing this tutorial there were no spectra in
OTTER. Similarly, we can get all objects that have photometry associated with them with
db.getMeta(hasPhot=True)
.
These outputs may appear like dictionaries but they're actually customized!
Besides the typical dictionary methods the following methods are also implemented for Transient objects.
help(Transient)
Help on class Transient in module otter.transient:
class Transient(collections.abc.MutableMapping)
| Transient(d={}, name=None)
|
| Method resolution order:
| Transient
| collections.abc.MutableMapping
| collections.abc.Mapping
| collections.abc.Collection
| collections.abc.Sized
| collections.abc.Iterable
| collections.abc.Container
| builtins.object
|
| Methods defined here:
|
| __add__(self, other, strict_merge=True)
| Merge this transient object with another transient object
|
| Args:
| other [Transient]: A Transient object to merge with
| strict_merge [bool]: If True it won't let you merge objects that
| intuitively shouldn't be merged (ie. different
| transient events).
|
| __delitem__(self, keys)
|
| __getitem__(self, keys)
|
| __init__(self, d={}, name=None)
| Overwrite the dictionary init
|
| Args:
| d [dict]: A transient dictionary
|
| __iter__(self)
|
| __len__(self)
|
| __repr__(self, html=False)
| Return repr(self).
|
| __setitem__(self, key, value)
|
| cleanPhotometry(self, flux_unit='mag(AB)', date_unit='MJD')
| Ensure the photometry associated with this transient is all in the same units/system/etc
|
| getMeta(self, keys=None)
| Get the metadata (no photometry or spectra)
|
| This essentially just wraps on __getitem__ but with some checks
|
| Args:
| keys [list[str]] : list of keys
|
| getSkyCoord(self, coord_type='equitorial', idx=0)
| Convert the coordinates to an astropy SkyCoord
|
| keys(self)
| D.keys() -> a set-like object providing a view on D's keys
|
| plotPhotometry(self, flux_unit='mag(AB)', date_unit='datetime', **kwargs)
| Plot the photometry associated with this transient (if any)
|
| Args:
| flux_unit [str]: Valid astropy unit string for the flux (y-axis) units.
| Default: 'ABmag'
| date_unit [str]: Valid astropy unit string for the date (x-axis) units.
| Default: 'MJD'
Some other advantages of the Transient objects are
t = db.getMeta(minZ=0.5, maxZ=0.9)[0]
print(type(t))
print()
# say you want to get the equitorial coordinates
# you can do it classically
print(t['coordinate']['equitorial'])
# or you can use the hdf5 style
print(t['coordinate/equitorial'])
<class 'otter.transient.Transient'>
[{'ra': '11 11 47.6', 'dec': '-82 38 44.44', 'epoch': 'J2000', 'system': 'ICRS', 'ra_units': 'hourangle', 'dec_units': 'deg', 'reference': ['2017MNRAS.472.4469B'], 'computed': False, 'default': True, 'uuid': '3bb02aa4-eb60-4f09-acdf-d1431a6addc4'}]
[{'ra': '11 11 47.6', 'dec': '-82 38 44.44', 'epoch': 'J2000', 'system': 'ICRS', 'ra_units': 'hourangle', 'dec_units': 'deg', 'reference': ['2017MNRAS.472.4469B'], 'computed': False, 'default': True, 'uuid': '3bb02aa4-eb60-4f09-acdf-d1431a6addc4'}]
You can even get multiple fields at once like with astropy Tables or pandas DataFrames
# You can also get multiple fields at once
t[['name/default_name', 'coordinate/equitorial', 'distance']]
{'name/default_name': 'Sw J1112-82', 'coordinate/equitorial': [{'ra': '11 11 47.6', 'dec': '-82 38 44.44', 'epoch': 'J2000', 'system': 'ICRS', 'ra_units': 'hourangle', 'dec_units': 'deg', 'reference': ['2017MNRAS.472.4469B'], 'computed': False, 'default': True, 'uuid': '3bb02aa4-eb60-4f09-acdf-d1431a6addc4'}], 'distance': {'redshift': [{'value': '0.89', 'reference': ['2017MNRAS.472.4469B'], 'computed': False, 'default': True}]}}
You can also add two Transient objects to merge them
t1, t2 = db.query(names=['ASASSN-15oi', 'AT2020opy'])
try:
t1 + t2
except ValueError as ve:
print('The following error is actually expected!')
print('We dont want you to be able to combine any old transients!')
print()
print('Error Message:')
print(ve)
The following error is actually expected!
We dont want you to be able to combine any old transients!
Error Message:
These two transients are not within 5 arcseconds! They probably do not belong together! If they do You can set strict_merge=False to override the check
This error message is expected! If you want to override it then you can do
t2['photometry'][0]['reference'] = '2021NatAs...5..491H'
t3 = t1.__add__(t2, strict_merge=False)
Obviously, this result doesn't makes sense! This has the data from two completely different transients in it. So, be careful using strict_merge=False
!
Can then get photometry
This does the conversion for you!!!
db.getPhot?
Get the photometry of the objects matching the arguments. This will do the
unit conversion for you!
Args:
flux_units [astropy.unit.Unit]: Either a valid string to convert
or an astropy.unit.Unit
date_units [astropy.unit.Unit]: Either a valid string to convert to a date
or an astropy.unit.Unit
return_type [str]: Either 'astropy' or 'pandas'. If astropy, returns an
astropy Table. If pandas, returns a pandas DataFrame.
Default is 'astropy'.
**kwargs : Arguments to pass to Otter.query(). Can be:
names [list[str]]: A list of names to get the metadata for
coords [SkyCoord]: An astropy SkyCoord object with coordinates to match to
radius [float]: The radius in arcseconds for a cone search, default is 0.05"
minZ [float]: The minimum redshift to search for
maxZ [float]: The maximum redshift to search for
refs [list[str]]: A list of ads bibcodes to match to. Will only return
metadata for transients that have this as a reference.
hasSpec [bool]: if True, only return transients that have spectra.
Return:
The photometry for the requested transients that match the arguments.
Will be an astropy Table sorted by transient default name.
This means you can easily grab photometry in consistent units to plot!
import matplotlib.pyplot as plt
flux_unit = u.ABmag #u.erg/u.s/u.cm**2/u.Hz #'erg/s/cm^2/Hz'
tab = db.getPhot(flux_unit=flux_unit, date_unit='datetime', names=['ASASSN-15oi', 'ASASSN-14li'], return_type='pandas')
tab
reference | date | filter_key | computed | obs_type | upperlimit | freq_eff | freq_units | human_readable_refs | converted_flux | converted_date | name | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2016ApJ...819L..25A | 57124.871000 | 5.0GHz | False | radio | False | 5.0 | GHz | Alexander et al. (2016) | 15.697417 | 2015-04-12 20:54:14.400000 | ASASSN-14li |
1 | 2016ApJ...819L..25A | 57190.830000 | 5.0GHz | False | radio | False | 5.0 | GHz | Alexander et al. (2016) | 15.797567 | 2015-06-17 19:55:12.000000 | ASASSN-14li |
2 | 2016ApJ...819L..25A | 57229.750000 | 5.0GHz | False | radio | False | 5.0 | GHz | Alexander et al. (2016) | 15.915797 | 2015-07-26 18:00:00.000000 | ASASSN-14li |
3 | 2016ApJ...819L..25A | 57286.514583 | 5.0GHz | False | radio | False | 5.0 | GHz | Alexander et al. (2016) | 16.152094 | 2015-09-21 12:20:59.997120 | ASASSN-14li |
4 | 2016ApJ...819L..25A | 57362.700000 | 5.0GHz | False | radio | False | 5.0 | GHz | Alexander et al. (2016) | 16.547278 | 2015-12-06 16:48:00.000000 | ASASSN-14li |
0 | 2021NatAs...5..491H | 57256.200000 | 6.1GHz | False | radio | True | 6.1 | GHz | Horesh et al. (2021) | 20.103715 | 2015-08-22 04:48:00.000000 | ASASSN-15oi |
1 | 2021NatAs...5..491H | 57271.200000 | 6.1GHz | False | radio | True | 6.1 | GHz | Horesh et al. (2021) | 20.009244 | 2015-09-06 04:48:00.000000 | ASASSN-15oi |
2 | 2021NatAs...5..491H | 57338.200000 | 6.1GHz | False | radio | True | 6.1 | GHz | Horesh et al. (2021) | 19.454622 | 2015-11-12 04:48:00.000000 | ASASSN-15oi |
3 | 2021NatAs...5..491H | 57430.200000 | 4.8GHz | False | radio | False | 4.8 | GHz | Horesh et al. (2021) | 16.282787 | 2016-02-12 04:48:00.000000 | ASASSN-15oi |
4 | 2021NatAs...5..491H | 57438.200000 | 4.8GHz | False | radio | False | 4.8 | GHz | Horesh et al. (2021) | 16.515601 | 2016-02-20 04:48:00.000000 | ASASSN-15oi |
5 | 2021NatAs...5..491H | 57445.200000 | 5.5GHz | False | radio | False | 5.5 | GHz | Horesh et al. (2021) | 16.537560 | 2016-02-27 04:48:00.000000 | ASASSN-15oi |
6 | 2021NatAs...5..491H | 57481.200000 | 5.5GHz | False | radio | False | 5.5 | GHz | Horesh et al. (2021) | 16.610182 | 2016-04-03 04:48:00.000000 | ASASSN-15oi |
7 | 2021NatAs...5..491H | 57531.200000 | 5.0GHz | False | radio | False | 5.0 | GHz | Horesh et al. (2021) | 16.571355 | 2016-05-23 04:48:00.000000 | ASASSN-15oi |
8 | 2021NatAs...5..491H | 57617.200000 | 5.0GHz | False | radio | False | 5.0 | GHz | Horesh et al. (2021) | 16.924287 | 2016-08-17 04:48:00.000000 | ASASSN-15oi |
9 | 2021NatAs...5..491H | 57824.200000 | 5.0GHz | False | radio | False | 5.0 | GHz | Horesh et al. (2021) | 17.854247 | 2017-03-12 04:48:00.000000 | ASASSN-15oi |
10 | 2021NatAs...5..491H | 58665.200000 | 3.0GHz | False | radio | False | 3.0 | GHz | Horesh et al. (2021) | 14.142275 | 2019-07-01 04:48:00.000000 | ASASSN-15oi |
fig, ax = plt.subplots()
for key, table in tab.groupby('name'):
ax.plot(table['converted_date'], table['converted_flux'], label=key, marker='o', linestyle='none')
ax.set_ylabel(f'Flux Density [{flux_unit}]')
ax.set_xlabel('Date')
ax.set_xticks(ax.get_xticks(), ax.get_xticklabels(), rotation=45)
ax.legend();
General Queries (shouldn't be used unless you know what you're doing!)
The structure of a more generalized query to OTTER is
# General queries
Otter.query?
Wraps on the super.AQLQuery and queries the OTTER database more intuitively.
WARNING! This does not do any conversions for you!
This is how it differs from the `getMeta` method. Users should prefer to use
`getMeta`, `getPhot`, and `getSpec` independently because it is a better
workflow and can return the data in an astropy table with everything in the
same units.
Args:
names [list[str]]: A list of names to get the metadata for
coords [SkyCoord]: An astropy SkyCoord object with coordinates to match to
radius [float]: The radius in arcseconds for a cone search, default is 0.05"
minZ [float]: The minimum redshift to search for
maxZ [float]: The maximum redshift to search for
refs [list[str]]: A list of ads bibcodes to match to. Will only return
metadata for transients that have this as a reference.
hasPhot [bool]: if True, only returns transients which have photometry.
hasSpec [bool]: if True, only return transients that have spectra.
Return:
Get all of the raw (unconverted!) json data for objects that match the criteria.
An example of this is
res = db.query(names=['ASASSN-15oi', 'AT2020opy'])
print(len(res))
print(type(res[0]))
2
<class 'otter.transient.Transient'>
res[0].keys()
dict_keys(['_key', '_id', '_rev', 'schema_version', 'name', 'coordinate', 'distance', 'classification', 'reference_alias', 'epoch', 'photometry', 'filter_alias'])
However, Notice how this is simply the raw results!!! This means you need to be very careful with the results you get from these queries because no conversion is done!
res[0]
{'_key': '3776907', '_id': 'tdes/3776907', '_rev': '_hD8NTy2---', 'schema_version': {'value': '0', 'comment': 'Original Dataset'}, 'name': {'default_name': 'ASASSN-15oi', 'alias': [{'value': 'ASASSN-15oi', 'reference': 'ASASSN'}]}, 'coordinate': {'equitorial': [{'ra': '20 39 09.096', 'dec': '-30 45 20.71', 'epoch': 'J2000', 'system': 'ICRS', 'ra_units': 'hourangle', 'dec_units': 'deg', 'reference': ['2021NatAs...5..491H'], 'computed': False, 'default': True, 'uuid': 'a06be641-1601-4737-9a1a-bd25c5dd61e6'}], 'galactic': [{'l': 13.01154485751856, 'b': -35.41877256185317, 'l_units': 'deg', 'b_units': 'deg', 'reference': 'a06be641-1601-4737-9a1a-bd25c5dd61e6', 'computed': True}]}, 'distance': {'redshift': [{'value': '0.0484', 'reference': ['2021NatAs...5..491H'], 'computed': False, 'default': True}]}, 'classification': [{'object_class': 'TDE', 'confidence': 1, 'reference': ['2021NatAs...5..491H'], 'default': True}], 'reference_alias': [{'name': '2021NatAs...5..491H', 'human_readable_name': 'Horesh et al. (2021)'}], 'epoch': {'date_discovery': [{'value': 57248.2, 'date_format': 'MJD', 'reference': ['2021NatAs...5..491H'], 'computed': False}]}, 'photometry': [{'reference': '2021NatAs...5..491H', 'raw': [0.033, 0.036, 0.06, 1.114, 0.899, 0.881, 0.824, 0.854, 0.617, 0.262, 8], 'raw_units': ['mJy', 'mJy', 'mJy', 'mJy', 'mJy', 'mJy', 'mJy', 'mJy', 'mJy', 'mJy', 'mJy'], 'date': [57256.2, 57271.2, 57338.2, 57430.2, 57438.2, 57445.2, 57481.2, 57531.2, 57617.2, 57824.2, 58665.2], 'date_format': ['MJD', 'MJD', 'MJD', 'MJD', 'MJD', 'MJD', 'MJD', 'MJD', 'MJD', 'MJD', 'MJD'], 'filter_key': ['6.1GHz', '6.1GHz', '6.1GHz', '4.8GHz', '4.8GHz', '5.5GHz', '5.5GHz', '5.0GHz', '5.0GHz', '5.0GHz', '3.0GHz'], 'computed': [False, False, False, False, False, False, False, False, False, False, False], 'obs_type': ['radio', 'radio', 'radio', 'radio', 'radio', 'radio', 'radio', 'radio', 'radio', 'radio', 'radio'], 'upperlimit': [True, True, True, False, False, False, False, False, False, False, False]}], 'filter_alias': [{'filter_key': '6.1GHz', 'freq_eff': 6.1, 'freq_units': 'GHz'}, {'filter_key': '4.8GHz', 'freq_eff': 4.8, 'freq_units': 'GHz'}, {'filter_key': '5.5GHz', 'freq_eff': 5.5, 'freq_units': 'GHz'}, {'filter_key': '5.0GHz', 'freq_eff': 5, 'freq_units': 'GHz'}, {'filter_key': '3.0GHz', 'freq_eff': 3, 'freq_units': 'GHz'}]}
Some helpful methods
To get the Astropy SkyCoord object for a specific transient you can use
skycoord = t1.getSkyCoord()
skycoord
<SkyCoord (ICRS): (ra, dec) in deg
(309.7879, -30.75575278)>
Or, to get the html code for plotting the photometry for a transient
html = res[0].plotPhotometry()
html[:100] # only show the first part of it
'<div> <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: \'l'
Uploading/Editing Data
If you have admin access to OTTER you can also upload new data! An example of this is that we first need to create a new Transient object.
from otter import Otter, Transient
from copy import deepcopy
from collections import Counter
import awkward as ak
import warnings
import numpy as np
import re
from astropy.coordinates import SkyCoord
import json
# generate some test cases
db = Otter()
t1 = db.query(names='2022xkq')[0] #
t2 = deepcopy(t1)
print(t1.keys())
# change t2 for testing
t2['name'] = {'default_name':'2022xkq',
'alias': [{'value':'foo', 'reference': 'x'},
{'value': '2022xkq', 'reference': 'x'}]}
t2['reference_alias'].append({'name': 'x',
'human_readable_name': 'test, name (year)'}) # add an extra value
del t2['photometry']
t2['for_test'] = {'test': 'bar'} # add a test key that isn't in t1
t2['coordinate/equitorial'][0]['reference'] = 'noah'
t2['filter_alias'].append({'filter_key': 'foo'})
t2['schema_version/value'] = 100
t2['epoch'] = {'date_peak': [{'value': 56983,
'date_format': 'MJD',
'reference': ['2016ApJ...819L..25A',
'2016Sci...351...62V',
'2016ApJ...832L..10R',
'2018MNRAS.475.4011B'],
'computed': False}],
'date_discovery': [{'value': 56983,
'date_format': 'MJD',
'reference': ['2016ApJ...819L..25A',
'2016Sci...351...62V',
'2016ApJ...832L..10R',
'2018MNRAS.475.4011B'],
'computed': False}],
'date_discovery': [{'value': 56984,
'date_format': 'MJD',
'reference': ['2016ApJ...819L..25A',
'2016Sci...351...62V',
'2016ApJ...832L..10R',
'2018MNRAS.475.4011B'],
'computed': False}]
}
t2['distance'] = {
"redshift": [
{
"value": "0.0207",
"reference": [
"Noah"
],
"computed": False
},
{
"value": "0.02",
"reference": [
"Noah"
],
"computed": False
}
],
"dispersion_measure": [
{
"value": "0.0206",
"reference": [
"Noah"
],
"computed": False
}
]
}
t2['classification'] = [{'object_class':'SN',
'confidence': 1,
'reference': 'Noah'
}]
t2['photometry'] = {'phot_0': {'telescope': 'Noahs Telescope',
'reference': 'Noah',
'flux': [{'filter': 'z',
'telescope': 'Noahs Telescope',
'upperlimit': True,
'date': 59864.4914116667,
'date_format': 'MJD',
'raw': 20.01,
'raw_units': 'mag(AB)',
'filter_key': 'NoahsTelescope.z',
'obs_type': 'uvoir'}]},
'phot_1': {'telescope': 'CAHA',
'reference': 'Noah',
'flux': [{'filter': 'H',
'telescope': 'CAHA',
'upperlimit': False,
'date': 59898.12077,
'date_format': 'MJD',
'raw': 14.87048,
'raw_err': 0.0187,
'raw_units': 'mag(AB)',
'filter_key': 'CAHA.H',
'obs_type': 'uvoir'}]}
}
Now we need to connect to OTTER with admin access and upload the new transient object.
db = Otter(username='admin@otter', password='insecure')
#db.upload(t2)
Repo Organization
Directory | Contents |
---|---|
py/otter |
A pip installable API for interfacing with the ArangoDB database |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for astro_otter-0.0.2-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4d4afaa8b95db6ea0846510504c6af93351977a3bd3c48cc091e381a16661f84 |
|
MD5 | f7817c911105954c6f4618b3980c5ed7 |
|
BLAKE2b-256 | bc405019d95de30fceadc1b15b875470e37b26f03e650c253545828b55c9d823 |