Interfacing with Private Data

Interfacing with Private Data#

One of the main goals of OTTER is to make it easy to compare private data with the OTTER catalog, essentially interfacing with the OTTER dataset and private data together but without making your private data public!

Setup#

[1]:
%load_ext autoreload
%autoreload 2

import os
import pandas as pd
import matplotlib.pyplot as plt
import otter

Let’s say you’ve recently gotten two new observations of the TDE 2018hyz with the Very Large Array. You’ve reduced the data and extracted it and you’re curious how it looks compared to the previous radio observations of TDE 2018hyz. I’ve generated a fake dataset stored in the CSV format that OTTER expects (for both upload and interfacing with private data). Let’s start by reading those in and displaying them. Note that the required columns for the metadata are:

"name"
"ra"
"dec"
"ra_unit"
"dec_unit"
"coord_bibcode"

and the required columns for the photometry are:

"name"
"date"
"date_format"
"filter"
"filter_eff"
"filter_eff_units",
"flux"
"flux_err"
"flux_unit"

And then there are a bunch of optional columns, as listed on the upload page of the OTTER website. Note that these two tables will be merged based on the “name” column, so make sure those match appropriately.

[2]:
meta = pd.read_csv("sample_meta.csv")
meta
[2]:
name ra dec ra_unit dec_unit coord_bibcode redshift redshift_bibcode discovery_date discovery_date_format discovery_date_bibcode classification classification_bibcode
0 2018hyz 10:06:50.87 01:41:34.08 hour deg 2018TNSTR1708....1B 0.04573 2018TNSCR1764....1A 2018-11-06 15:21:36.000 iso 2018TNSTR1708....1B TDE 2018TNSCR1764....1A
[3]:
phot = pd.read_csv("sample_phot.csv")
phot
[3]:
name flux flux_unit flux_err date date_format filter filter_eff filter_eff_units
0 2018hyz 1 mJy 0.01 2025-05-20 iso L 1.5 GHz
1 2018hyz 10 mJy 0.01 2025-05-23 iso L 1.5 GHz

Combining this with the OTTER dataset#

To combine this with the otter dataset, we use the Otter.from_csvs static method

[ ]:
# Connect to the otter database normally
db = otter.Otter()

# then use the Otter.from_csvs static method to read in the csvs simultaneously and tell otter where they are stored
db = otter.Otter.from_csvs(
    metafile = "sample_meta.csv",
    photfile = "sample_phot.csv",
    local_outpath = os.path.join(os.getcwd(), "private_otter_data"),
    db = db
)

print()
print(f"Your private data is stored in {db.DATADIR}")

Note the above warning, which shows that since we didn’t provide a bibcode for the photometry, it assumes that it is private and uses a special keyword for the bibcodes. However, you will have to add a bibcode column to the photometry csv file before uploading to OTTER.

Now that the Otter class (e.g. db in this notebook) knows about your private dataset, we can query otter almost exactly the same as normal. The only caveat is that we have to add query_private=True whenever we pass a query to the API.

As an example, let’s request all of the radio photometry.

[5]:
allphot = db.get_phot(
    names="2018hyz",
    obs_type="radio",
    flux_unit="mJy",
    query_private=True,
    return_type="pandas"
)
allphot[allphot.reference == 'private']
Unable to apply the source mapping because 'private'
[5]:
name converted_flux converted_flux_err converted_date converted_wave converted_freq converted_flux_unit converted_date_unit converted_wave_unit converted_freq_unit filter_name obs_type upperlimit reference human_readable_refs telescope
838 2018hyz 1.0 0.01 60815.0 1.998616e+08 1.5 mJy MJD nm GHz L radio False private private NaN
839 2018hyz 10.0 0.01 60818.0 1.998616e+08 1.5 mJy MJD nm GHz L radio False private private NaN

And, you can see that your private data is now accessible via the normal otter API!

Let’s plot up all of the L-band data for 18hyz

[6]:
allphot[allphot.filter_name == "L"]
[6]:
name converted_flux converted_flux_err converted_date converted_wave converted_freq converted_flux_unit converted_date_unit converted_wave_unit converted_freq_unit filter_name obs_type upperlimit reference human_readable_refs telescope
756 2018hyz 5.325 0.041 59686.00 2.306096e+08 1.3000 mJy MJD nm GHz L radio False 2022ApJ...938...28C 2022ApJ...938...28C MeerKAT
793 2018hyz 4.850 0.220 59586.84 1.810888e+08 1.6555 mJy MJD nm GHz L radio False 2024ApJ...974..241A 2024ApJ...974..241A RACS.high
812 2018hyz 0.960 0.210 59223.84 2.192267e+08 1.3675 mJy MJD nm GHz L radio False 2024ApJ...974..241A 2024ApJ...974..241A RACS.mid
764 2018hyz 4.753 0.084 59530.00 2.188266e+08 1.3700 mJy MJD nm GHz L radio False 2022ApJ...938...28C 2022ApJ...938...28C VLA
765 2018hyz 8.416 0.119 59603.00 2.188266e+08 1.3700 mJy MJD nm GHz L radio False 2022ApJ...938...28C 2022ApJ...938...28C VLA
766 2018hyz 8.740 0.093 59655.00 2.188266e+08 1.3700 mJy MJD nm GHz L radio False 2022ApJ...938...28C 2022ApJ...938...28C VLA
767 2018hyz 4.896 0.072 59530.00 1.850571e+08 1.6200 mJy MJD nm GHz L radio False 2022ApJ...938...28C 2022ApJ...938...28C VLA
768 2018hyz 8.416 0.119 59603.00 1.850571e+08 1.6200 mJy MJD nm GHz L radio False 2022ApJ...938...28C 2022ApJ...938...28C VLA
769 2018hyz 8.712 0.112 59655.00 1.850571e+08 1.6200 mJy MJD nm GHz L radio False 2022ApJ...938...28C 2022ApJ...938...28C VLA
770 2018hyz 4.799 0.078 59530.00 1.594641e+08 1.8800 mJy MJD nm GHz L radio False 2022ApJ...938...28C 2022ApJ...938...28C VLA
771 2018hyz 8.134 0.087 59603.00 1.594641e+08 1.8800 mJy MJD nm GHz L radio False 2022ApJ...938...28C 2022ApJ...938...28C VLA
772 2018hyz 8.649 0.109 59655.00 1.594641e+08 1.8800 mJy MJD nm GHz L radio False 2022ApJ...938...28C 2022ApJ...938...28C VLA
791 2018hyz 7.656 0.200 59603.00 2.676718e+08 1.1200 mJy MJD nm GHz L radio False 2022ApJ...938...28C 2022ApJ...938...28C VLA
792 2018hyz 8.449 0.236 59655.00 2.676718e+08 1.1200 mJy MJD nm GHz L radio False 2022ApJ...938...28C 2022ApJ...938...28C VLA
838 2018hyz 1.000 0.010 60815.00 1.998616e+08 1.5000 mJy MJD nm GHz L radio False private private NaN
839 2018hyz 10.000 0.010 60818.00 1.998616e+08 1.5000 mJy MJD nm GHz L radio False private private NaN
[7]:
fig, ax = plt.subplots()

disc_date = db.get_meta(names="18hyz")[0].get_discovery_date().mjd

otter.plot_light_curve(
    date = allphot.converted_date - disc_date,
    flux = allphot.converted_flux,
    flux_err = allphot.converted_flux_err,
    marker = "o",
    linestyle = "none",
    fig=fig,
    ax=ax
)

ax.set_xlim(10,3000)
ax.set_xscale("log")
ax.set_yscale("log")
../_images/examples_private_data_11_0.png

And now you can see our points on the far right! They don’t really make any sense with the trend, but that’s okay because it’s fake data :)

[ ]: