A tool for predicting exoplanet transits

(Created 2026-03-21)

Quite a while back, I wrote a python script to calculate when an exoplanet will transit in front of its star.

I haven’t found many easy-to-use resources on the topic but it’s true I didn’t look too deep either. Anyway, here’s a short guide on making this whole thing work.

It requires you have a copy of the NASA exoplanet database in the same directory as the script. You can access it from here: https://exoplanetarchive.ipac.caltech.edu/. Just click on ‘Confirmed planets’ at the top, then on ‘Download table’ on the page that opens up. Make sure to select the CSV file format and ‘Download all columns’ as well as ‘Download all rows’. The file should be less than 100MB in size.

Create a directory somewhere on your system, cd into it and then create a python virtual environment:

mkdir my-dir
cd my-dir
python3 -m venv ./venv

Then, create a ‘main.py’ file inside the same folder and copy the python script from the bottom of this page:

nano main.py

Switch into the venv with:

source venv/bin/activate

And now install the required packages with pip:

pip3 install julian datetime

Finally, copy the exoplanet CSV file you downloaded earlier into the same directory as the script (my-dir). With this, you’re ready to run the script itself:

python3 main.py

The program

import csv, sys
import julian, datetime
import math

class CsvUtils:
    def read(filename, ignore_comments=True, comment_start='#'):
        csv_data = []
        with open(filename, mode='r') as csv_file:
            for line in csv_file:
                if not line.startswith(comment_start) and ignore_comments:
                    csv_data.append(line)
                elif not ignore_comments:
                    csv_data.append(line)
        return csv_data

    def splitRow(csv_data, row=0, split_char=',', replace_chars=['\n']):
        for replace_char in replace_chars:
            values = csv_data[row].replace(replace_char, '')
        return values.split(split_char)
    
    def createSearchDict(header_values):
        dictionary = {}
        for x in range(0, len(header_values)):
            dictionary[header_values[x].replace('\n', '')] = x
        return dictionary

if __name__ == '__main__':
    print('Loading...')
    csv_data = CsvUtils.read('exoplanets.csv')
    header_values = CsvUtils.splitRow(csv_data)
    search_dict = CsvUtils.createSearchDict(header_values)

    exoplanets = []
    current_jd = julian.to_jd(datetime.datetime.now(datetime.timezone.utc), fmt='jd')
    for x in range(1, len(csv_data)):
        row = CsvUtils.splitRow(csv_data, row=x)

        orbital_period = row[search_dict['pl_orbper']]
        transit_midpoint = row[search_dict['pl_tranmid']]
        if not orbital_period == '' and not transit_midpoint == '':
            last_transit_ago = current_jd - float(transit_midpoint)
            orbit_number = last_transit_ago / float(orbital_period)
            exoplanets.append((row[search_dict['rowid']], math.ceil(orbit_number) - orbit_number))
    exoplanets = sorted(exoplanets, key=lambda exoplanet: exoplanet[1], reverse=False)
    print("Complete!")

    while True:
        print("Enter: 'q' to exit, or 'h' for help.")
        user_input = input('=')
        if user_input == "q":
            break
        elif user_input == "h":
            print("Input an exoplanet designation at the '=' prompt. e.g. kepler-186f.")
            continue
        found = False
        found_index = 0
        user_input = user_input.replace(' ', '').replace('-', '').upper()
        for x in range(0, len(csv_data)):
            row = CsvUtils.splitRow(csv_data, row=x)
            if row[search_dict['pl_name']].replace(' ', '').replace('-', '').upper() == user_input:
                found = True
                found_index = x
                break
        if found:
            print('Found!')
            user_input = int(input('Number of transits to calculate: '))

            t0 = float(row[search_dict['pl_tranmid']])
            period = float(row[search_dict['pl_orbper']])

            first_orbit_num = math.ceil((current_jd - t0) / period)

            future_transits = [t0 + (first_orbit_num + n) * period for n in range(user_input)]

            for transit_jd in future_transits:
                print('Transit on:', julian.from_jd(transit_jd))
        else:
            print('Not found!')

Thanks for reading and happy exoplanet transit calculating!