MoonPy
One-stop shop for downloading, detrending, visualizing, and fitting exoplanet and exomoon light curves.
Install / Use
/learn @alexteachey/MoonPyREADME

Welcome to MoonPy!
last update: 9 August 2022. Developed by Alex Teachey.
This document will walk you through the basics of using the MoonPy code.
MoonPy is designed to make downloading, plotting, detrending, and fitting EXOPLANET and EXOMOON models to light curves a breeze. These are routine tasks, but often require a lot of coding to get going with. Sometimes you just want to take a quick look and have all the numbers at your fingertips -- enter MoonPy!
Of course, the easier a tool is to use right out of the gate, the more control you are handing over to the code / programmer. As such, MoonPy is first and foremost an initial vetting tool. Please keep this in mind! There is plenty of customization available to the user but bear in mind that the the defaults may not be appropriate for your particular problem. Moreover, results should always be sanity checked.
MoonPy simply would not exist if not for a number of incredibly powerful packages that have been developed by other scientists (more on that below). Thank you to all those developers! And if you use MoonPy in your research please remember to cite/acknowledge the authors of the packages that have been utilized here. We'd appreciate a shoutout, too... please cite:
A special shoutout is due to Hippke & Heller for introducing the Pandora code, as well as Gordon & Agol for introducing the gefera code. These are the first publicly-available codes for modeling exomoon light curves, which is a big deal. The original aim of the MoonPy package was to make exomoon modeling widely accessible, and it is now possible to realize that objective thanks to their codes. MoonPy is providing a wrapper that makes it even easier to implement their already user-friendly codes.
Let's walk through the basics.
Installation
Installation is now easier than ever. Begin by cloning the GitHub repository wherever you see fit. For example, within the desired directory, call:
>>> git clone https://github.com/alexteachey/MoonPy
Then navigate to the MoonPy directory you have just cloned, and within the terminal type
python install_moonpy.py
This will 1) create a new conda environment for MoonPy with a name of your choosing, 2) install a variety of required and recommended packages within that environment, and 3) create the path so that your Python can see MoonPy as an Python-importable package. After this is complete, simply
conda activate ENV_NAME
where ENV_NAME is the name of the conda environment you have just established. You should now be able to type
from moonpy import *
And you're off to the races. Please note: The first time you boot up MoonPy it may take a few moments to load. After that it should be much faster!
If the installation process above fails, dependencies below can be installed individually.
- LINUX USERS: To ensure MoonPy loads correctly, users may need to call*
python pathmaker.pywithin the MoonPy directory, and with the desired conda environment activated. If you opt to install VESPA (recommended), you may also need to callpython vespa_script_updater.pyto fix a deprecated keyword in some vespa scripts. This should be done within the separate VESPA conda environment. (breakdowns include a deprecated 'representation' keyword, and/or a missing 'TESS' keyword. These errors are fixed by vespa_script_updater.py .
A list of package dependencies is listed at the bottom of this page.
NB: Frequent Updates!
Be advised that MoonPy is being updated all the time, and if I'm being honest, I'm not always adhering to best practices in terms of maintaing stable and beta versions. By using MoonPy you acknowledge that you are on this ride with me... things may break from time to time, and if they do, I would appreciate hearing about them. This also means, it's important to keep MoonPy up-to date by cloning the latest version of the repository.
OVERVIEW
Below you will find the details of some of these tools. At present the user will want to utilize the following functionality:
- Initialize a light curve object using
MoonpyLC() - Access adopted NASA Exoplanet Archive attributes using the same column names from the archive.
- plot the light curve using
plot_lc(). - generate a Lomb-Scargle periodogram using
genLS(). - Detrend the light curve using
detrend() - fit a planet transit model (using the
exoplanetpackage) to the light curve usingrun_planet_fit(). - fit PLANET and MOON models (using
Pandoraorgefera, andUltraNest) usingfit(modelcode='Pandora', model='M'). - compute the Bayes factor to find evidence for/against the moon using
moon_evidence(). - run a false positive calculation with VESPA using
run_vespa(). Must activate separate vespa environment. - access a variety of handy tools in the
mp_tools.pymodule.
And more!
QUICKSTART
Initialize a light curve object.
MoonPy is built around manipulating light curves as objects. To start, simply import moonpy:
>>> from moonpy import *
Then you can initialize an object:
>>> lc_object=MoonpyLC(targetID='target_name', clobber='n')
targetID can take a range of common names for stars / planets(e.g. 'Kepler-1625b', 'KOI-5084.01', 'KIC4760478', 'TOI-216.01', 'TIC55652896', 'EPIC201170410'...)
MoonPy will try to infer which telescope's data should be accessed based on the name of the object (KICs, KOIs, and Kepler- planets get Kepler data, K2 or EPIC numbers retrieve K2 data, TOIs and TICs access TESS data), but you may also specify the telescope if the target name is not one of these, or if you want to search for data from a different telescope. For example, some Kepler planets were also observed by TESS, so simply specify telescope='tess', etc, for more controlled access.
It is also possible to use MoonPy tools on a light curve that the user supplies. In this case, the user will want to supply arrays for lc_times, lc_fluxes, and lc_errors when initializing a MoonpyLC object. In addition, the usr_dict containing important parameters for the planet can be included (keys are "period", "tau0", "impact", "duration_hours", "rprstar", "sma_AU", and "rp_rearth"). If these are not supplied, the user will be prompted to enter them.
Visualizing your data
You can then plot the light curve with
>>> lc_object.plot_lc()
A plot of all the available data should appear, and known transits should be flagged. If the light curve has already been detrended (see below), you will see two plots, the top one being the raw data with the trend line overplotted, the bottom one showing the detrended light curve. If planet and / or moon models have been produced, they are also overplotted by default.
You can also generate a Lomb-Scargle periodogram simply by calling
>>> lc_object.genLS()
This produces quarter-by-quarter plots that may indicate the presence of periodic signals (likely rotational information about the star).
After you have run a planet or moon model (see below), you can generate an animation of that model (using median values from the posteriors) using
>>> lc_object.animate_moon().
Data Manipulation
To detrend a light curve, simply call
>>> lc_object.detrend(dmeth='cofiam')
A variety of detrending methods are available ('cofiam', 'median_value', 'phasma', 'polyAM', 'polyLOC', moving_median', and 'methmarg'). Users are strongly advised to examine the results of the detrending before using for science!
Then you can plot_lc() again to see both the original data, the trend model, and the detrended light curve.
Accessing Planet Attributes
You can see the full list of attributes associated with this object (values, arrays, and functions) by calling
>>> lc_object.print_attributes()
Many of these attributes are taken directly from the NASA Exoplanet Archive, and have the same name. Therefore you can call up many values of interest for this target simply by calling the attribute of choice, for example:
>>> k1625.pl_orbper
287.378949
MoonPy also automatically queries the SIMBAD astronomical database to identify aliases for the planet/star in question. You can see these with
>>> lc_object.find_aliases().
MoonPy also automatically identifies all other confirmed planets in the system, and should flag them when plotted. To see any neighbors, you can call
>>> k1625.find_neighbors()
You may call lc_object.get_neighbors(), which will generate a dictionary of neighbor light curve objects, each with their own attributes. For example
>>> k167e.neighbor_dict
returns
{'K167b': <moonpy.MoonpyLC object at 0x7f80a5ff17f0>, 'K167c': <moonpy.MoonpyLC object at 0x7f80a3ab87c0>, 'K167d': <moonpy.MoonpyLC object at 0x7f80a3ab89a0>}
Model Fitting
From here, you might opt to run a planet transit fit with Exoplanet. Simply call
>>> lc_object.run_planet_fit()
And you're off to the races. These fits tend to take a few minutes, and jointly fit a planet transit model with a GP trend model.
For a more in-depth analysis, you can **fit planet and moon models using Pandora and ```UltraN
Related Skills
node-connect
342.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
claude-opus-4-5-migration
85.3kMigrate prompts and code from Claude Sonnet 4.0, Sonnet 4.5, or Opus 4.1 to Opus 4.5
frontend-design
85.3kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
model-usage
342.5kUse CodexBar CLI local cost usage to summarize per-model usage for Codex or Claude, including the current (most recent) model or a full model breakdown. Trigger when asked for model-level usage/cost data from codexbar, or when you need a scriptable per-model summary from codexbar cost JSON.
