Python tools for working with exoplanet data from various sources including NASA's Exoplanet Archive, TESS, and Gaia.
Install exotools with pip:
pip install exotoolsThe simplest way to get started is using the default in-memory storage. Data will be cached in memory, and lost at the termination of the program.
from exotools import PlanetarySystemsDataset
# Create dataset with default in-memory storage
dataset = PlanetarySystemsDataset()
# Download a small sample of known exoplanets
exo_db = dataset.download_known_exoplanets(limit=10)
# Access the data
print(f"Downloaded {len(exo_db)} exoplanet records")
print("First few host star names:", exo_db.view["hostname"][:5])
# Convert to pandas for analysis
df = exo_db.to_pandas()
print(df.head())For larger datasets or persistent storage, use one of the available storage backends:
from exotools import PlanetarySystemsDataset
from exotools.io import Hdf5Storage
# Create HDF5 storage backend
storage = Hdf5Storage("exoplanet_data.h5")
dataset = PlanetarySystemsDataset(storage=storage)
# Download and store data persistently
exo_db = dataset.download_known_exoplanets(limit=100)
# Later, load the same data from storage
exo_db = dataset.load_known_exoplanets_dataset()ExoTools supports multiple storage backends to fit different use cases:
Fast but temporary storage - data is lost when the program ends:
from exotools import PlanetarySystemsDataset
# Uses MemoryStorage by default
dataset = PlanetarySystemsDataset()Recommended for local development and analysis - fastest read access for the "download once, reuse multiple times" workflow:
from exotools.io import FeatherStorage
from exotools import PlanetarySystemsDataset
storage = FeatherStorage("data_directory")
dataset = PlanetarySystemsDataset(storage=storage)Recommended for managing multiple datasets in a single file or when transferring between machines (e.g., in HPC environments):
from exotools.io import Hdf5Storage
from exotools import PlanetarySystemsDataset
storage = Hdf5Storage("my_data.h5")
dataset = PlanetarySystemsDataset(storage=storage)Human-readable CSV format with metadata - slower but offers maximum portability and inspection capabilities:
from exotools.io import EcsvStorage
from exotools import PlanetarySystemsDataset
storage = EcsvStorage("data_directory")
dataset = PlanetarySystemsDataset(storage=storage)Access confirmed exoplanets from NASA's Exoplanet Archive:
from exotools import PlanetarySystemsDataset
from exotools.io import Hdf5Storage
storage = Hdf5Storage("exoplanet_data.h5")
dataset = PlanetarySystemsDataset(storage=storage)
# Download confirmed exoplanets
exo_db = dataset.download_known_exoplanets(store=True)
# Load from storage
exo_db = dataset.load_known_exoplanets_dataset()
# Access specific data
tess_planets = exo_db.get_tess_planets()
print(f"Found {len(tess_planets)} planets discovered by TESS")Cross-match with Gaia DR3 stellar parameters:
# Download with Gaia stellar data
exo_db = dataset.download_known_exoplanets(with_gaia_star_data=True)
# Load Gaia data separately
gaia_db = dataset.load_gaia_dataset_of_known_exoplanets()
# Get stellar distances from Gaia
distances = gaia_db.view["distance_gspphot"]
print(f"Stellar distances: {distances[:5]}")Work with TESS Objects of Interest:
from exotools import CandidateExoplanetsDataset
dataset = CandidateExoplanetsDataset(storage=storage)
# Download candidate exoplanets
candidates_db = dataset.download_candidate_exoplanets(store=True)
# Load from storage
candidates_db = dataset.load_candidate_exoplanets_dataset()
print(f"Found {len(candidates_db)} candidate exoplanets")Access Gaia DR3 stellar parameters for specific stars:
from exotools import GaiaParametersDataset
# Optional: authenticate for higher query limits
GaiaParametersDataset.authenticate("your_username", "your_password")
dataset = GaiaParametersDataset(storage=storage)
# Download Gaia data for specific Gaia source IDs
gaia_ids = [1234567890123456789, 2345678901234567890]
gaia_db = dataset.download_gaia_parameters(gaia_ids)
# Load from storage
gaia_db = dataset.load_gaia_parameters_dataset()
# Access stellar parameters
print(f"Downloaded {len(gaia_db)} stellar records")
print("Stellar masses:", gaia_db.view["mass_flame"][:5])
print("Stellar distances:", gaia_db.view["distance_gspphot"][:5])
print("Effective temperatures:", gaia_db.view["teff_gspphot"][:5])
# Access computed properties
print("Habitable zone inner edges:", gaia_db.view["hz_inner"][:5])
print("Habitable zone outer edges:", gaia_db.view["hz_outer"][:5])Access TESS Input Catalog (requires MAST authentication):
from exotools import TicCatalogDataset
# Authenticate with MAST (required for TIC queries)
TicCatalogDataset.authenticate_casjobs("your_username", "your_password")
dataset = TicCatalogDataset(storage=storage)
# Search for targets by stellar mass
tic_db = dataset.download_tic_targets(
star_mass_range=(0.8, 1.2), # Solar masses
limit=50,
store=True
)
# Download specific TIC targets by ID
tic_ids = [1234567, 2345678, 3456789]
tic_db = dataset.download_tic_targets_by_ids(tic_ids)Get observation metadata for lightcurve downloads:
from exotools import TicObservationsDataset
# Optional: authenticate for faster downloads
TicObservationsDataset.authenticate_mast("your_mast_token")
dataset = TicObservationsDataset(storage=storage)
# Get observation metadata for specific TIC IDs
tic_ids = exo_db.view["tic_id"][:10] # First 10 TIC IDs
obs_db = dataset.download_observation_metadata(tic_ids)
print(f"Found {len(obs_db)} TESS observations")Download TESS lightcurve FITS files:
from exotools import LightcurveDataset
from pathlib import Path
# Lightcurves are stored as FITS files in the filesystem
lc_dataset = LightcurveDataset(
lc_storage_path=Path("lightcurves"),
verbose=True
)
# Download lightcurves for the observations
lc_db = lc_dataset.download_lightcurves_from_tic_db(obs_db)
print(f"Downloaded {len(lc_db)} lightcurves")
# Load previously downloaded lightcurves
lc_db = lc_dataset.load_lightcurve_dataset()
# Work with individual lightcurves and time conversions
for lc_plus in lc_db.lightcurves[:3]: # First 3 lightcurves
print(f"Original time system: {lc_plus.time_system}")
# Convert time formats in place (new API)
lc_plus.to_jd_time() # Convert to Julian Date
print(f"After JD conversion: {lc_plus.time_system}")
lc_plus.to_btjd_time() # Convert to Barycentric TESS Julian Date
print(f"After BTJD conversion: {lc_plus.time_system}")
lc_plus.to_bjd_time() # Convert to Barycentric Julian Date
print(f"After BJD conversion: {lc_plus.time_system}")Access exoplanet data through an intuitive object-oriented interface:
from exotools import PlanetarySystemsDataset
dataset = PlanetarySystemsDataset(storage=storage)
# Download data with Gaia cross-matching (required for star systems)
exo_db = dataset.download_known_exoplanets(with_gaia_star_data=True)
# Load star system representation
star_systems = dataset.load_star_system_dataset()
# Access star systems by name
kepler_system = star_systems.get_star_system_from_star_name("Kepler-90")
# Access star properties with uncertainties
star = kepler_system.star
print(f"Star: {star.name}")
print(f" Radius: {star.radius.central} ± {star.radius.upper - star.radius.central}")
print(f" Mass: {star.mass.central} ± {star.mass.upper - star.mass.central}")
# Access planets in the system
for planet in kepler_system.planets:
print(f"Planet: {planet.name}")
print(f" Radius: {planet.radius.central}")
print(f" Mass: {planet.mass.central}")
print(f" Orbital Period: {planet.orbital_period.central}")from exotools import (
PlanetarySystemsDataset,
CandidateExoplanetsDataset,
TicObservationsDataset,
LightcurveDataset
)
from exotools.io import Hdf5Storage
from pathlib import Path
# Shared storage for metadata
storage = Hdf5Storage("exoplanet_data.h5")
# Download known exoplanets
known_dataset = PlanetarySystemsDataset(storage=storage)
exo_db = known_dataset.download_known_exoplanets(limit=50)
# Download candidates
candidate_dataset = CandidateExoplanetsDataset(storage=storage)
candidates_db = candidate_dataset.download_candidate_exoplanets(limit=50)
# Get TESS observations for known exoplanets
obs_dataset = TicObservationsDataset(storage=storage)
obs_db = obs_dataset.download_observation_metadata(exo_db.view["tic_id"][:10])
# Download lightcurves
lc_dataset = LightcurveDataset(Path("lightcurves"))
lc_db = lc_dataset.download_lightcurves_from_tic_db(obs_db)from exotools.io import Hdf5Storage, FeatherStorage
from exotools import PlanetarySystemsDataset
# Configure HDF5 storage with custom path
hdf5_storage = Hdf5Storage("custom/path/exodata.h5")
# Configure Feather storage with custom directory
feather_storage = FeatherStorage("custom/data/directory")
# Use different storage for different datasets
exo_dataset = PlanetarySystemsDataset(storage=hdf5_storage)
candidate_dataset = CandidateExoplanetsDataset(storage=feather_storage)MIT License
If you use exotools in your research, please cite it as follows:
@misc{cardin2025exotools,
author = {Christian Cardin},
title = {ExoTools: Astronomical data access and analysis toolkit},
year = {2025},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/sechlol/exotools}},
note = {Version 0.1.2},
}