Additional examples#

Following our analysis of the curious case of HD 131339 “b” in the tutorial, below are additional examples of published data that could be analyzed with backtracks. If you use the package in your work (or want to and need help), please reach out to us, and we can include your case here!

[1]:
# start by importing the System object from backtracks:
from backtracks import System

Fit multiple known background stars: Baade’s Window (HD 165054)#

Turns out that sometimes, interloping background sources are useful (if you know about them already)! In this case, the bright foreground star HD 165054 lies between our line of sight and Baade’s Window, a clearing in the dust-lanes of our own galaxy from which we can see into the galactic buldge (where there are lots of stars). A direct imaging instrument with a small field of view can be difficult to calibrate. Most absolute astroemtric calibrations are performed on wide fields of stars (like the LMC or globular clusters), which aren’t dense enough to be useful for instruments designed to stare very closely at individual stars. HD 1645054 provides a nice alternative, being a bright star that an instrument like GPI can lock on to, but with plenty of (faint, but not too faint) background stars that follow predictable background helices that can be referenced to observations from precalibrated instruments with wider FOVs. This kind of analysis was presented in Nguyen et al. (2020).

[2]:
!wget https://github.com/wbalmer/backtracks/raw/refs/heads/main/tests/hd165054_orbitizelike.csv
--2026-03-31 16:44:50--  https://github.com/wbalmer/backtracks/raw/refs/heads/main/tests/hd165054_orbitizelike.csv
Resolving github.com (github.com)... 140.82.114.3
Connecting to github.com (github.com)|140.82.114.3|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://raw.githubusercontent.com/wbalmer/backtracks/refs/heads/main/tests/hd165054_orbitizelike.csv [following]
--2026-03-31 16:44:50--  https://raw.githubusercontent.com/wbalmer/backtracks/refs/heads/main/tests/hd165054_orbitizelike.csv
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.109.133, 185.199.110.133, 185.199.111.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1134 (1.1K) [text/plain]
Saving to: ‘hd165054_orbitizelike.csv.1’

hd165054_orbitizeli 100%[===================>]   1.11K  --.-KB/s    in 0s

2026-03-31 16:44:51 (108 MB/s) - ‘hd165054_orbitizelike.csv.1’ saved [1134/1134]

BG 0#

[3]:
# this input file has two candidates, so we specify the obj_num kwarg here:
obj_num = 0
# we'll use this optional argument that accepts a candidate file with epochs in ISO formatted time (YYYY-MM-DD)
yy_epochs=True
# this is a pretty dense field, so we'll shrink the window for the gaia query
nearby_window=0.15

track = System(target_name="HD165054",
               candidate_file="hd165054_orbitizelike.csv",
               obj_num=obj_num,
               nearby_window=nearby_window,
               yy_epochs=yy_epochs,
               fileprefix='./')
[BACKTRACKS INFO]: Examining object = 0 in input file.
[BACKTRACKS INFO]: Resolved the target star 'HD165054' in Simbad!
[BACKTRACKS INFO]: Resolved target's Gaia ID from Simbad, Gaia DR3 4062433888304427648
INFO: Query finished. [astroquery.utils.tap.core]
[BACKTRACKS INFO]: gathered Gaia DR3 data for HD165054
   * Gaia source ID = 4062433888304427648
   * Reference epoch = 2016.0
   * RA = 271.3188 deg
   * Dec = -28.6867 deg
   * PM RA = 27.09 mas/yr
   * PM Dec = -87.79 mas/yr
   * Parallax = 19.70 mas
   * RV = 54.46 km/s
INFO: Query finished. [astroquery.utils.tap.core]
[BACKTRACKS INFO]: gathered 22668 Gaia objects from the 0.15 sq. deg. nearby HD165054
[BACKTRACKS INFO]: Finished nearby background gaia statistics
[BACKTRACKS INFO]: Queried distance prior parameters, L=5327.85, alpha=1.94, beta=2.52
[BACKTRACKS INFO]: Estimating candidate position if stationary in RA,Dec @ 2016.0 from observation #0
[BACKTRACKS INFO]: Opened ephemeris file
[4]:
fig_stationary = track.generate_stationary_plot(days_backward=0.5*365.,
                                                days_forward=6*365,
                                                step_size=10.,
                                                filepost='.png')
[BACKTRACKS INFO]: Generating Stationary plot
[BACKTRACKS INFO]: Stationary track reduced chi squared is 70.61
[BACKTRACKS INFO]: Stationary plot saved to ./
_images/additional-examples_8_1.png

The stationary track fits the morphology of the data, but we could probably improve the fit by sampling the proper motion and parallax. This will allow us to calibrate (or validate the astrometric solution) of other instruments observing this field in the future.

[5]:
import multiprocessing as mp
results = track.fit(dlogz=1e-1, npool=mp.cpu_count(),
                    dynamic=False, nlive=100,
                    mpi_pool=False,
                    resume=False,
                    sample_method='rslice')

# save our sampler results
track.save_results(fileprefix='./')
[BACKTRACKS INFO]: Beginning sampling
iter: 2457 | +100 | bound: 74 | nc: 1 | ncall: 172167 | eff(%):  1.486 | loglstar:   -inf < -43.780 <    inf | logz: -65.896 +/-  0.451 | dlogz:  0.001 >  0.100
[BACKTRACKS INFO]: Saving results to ./HD165054_cc0_dynestyrun_results.pkl
[6]:
# plot up only the trackplot to show the results
from backtracks.plotting import trackplot
from astropy.time import Time
plot_0 = trackplot(track,
                   ref_epoch = Time(track.ref_epoch, format='jd').jd,
                   days_backward=1.*365.,
                   days_forward=8.*365.,
                   step_size=50., # we can tune this down or up to slow/speed up the rendering
                   plot_radec=False,
                   plot_stationary=True,
                   fileprefix='./',
                   filepost='.png'
                  )
[BACKTRACKS INFO]: Stationary track reduced chi squared is 70.61
[BACKTRACKS INFO]: Median track reduced chi squared is 1.88
_images/additional-examples_11_1.png

BG 1#

[7]:
# this input file has two candidates, so we specify the obj_num kwarg here:
obj_num = 1
# we'll use this optional argument that accepts a candidate file with epochs in ISO formatted time (YYYY-MM-DD)
yy_epochs=True
# this is a pretty dense field, so we'll shrink the window for the gaia query
nearby_window=0.15

track = System(target_name="HD165054",
               candidate_file="hd165054_orbitizelike.csv",
               obj_num=obj_num,
               nearby_window=nearby_window,
               yy_epochs=yy_epochs,
               fileprefix='./')
[BACKTRACKS INFO]: Examining object = 1 in input file.
[BACKTRACKS INFO]: Resolved the target star 'HD165054' in Simbad!
[BACKTRACKS INFO]: Resolved target's Gaia ID from Simbad, Gaia DR3 4062433888304427648
INFO: Query finished. [astroquery.utils.tap.core]
[BACKTRACKS INFO]: gathered Gaia DR3 data for HD165054
   * Gaia source ID = 4062433888304427648
   * Reference epoch = 2016.0
   * RA = 271.3188 deg
   * Dec = -28.6867 deg
   * PM RA = 27.09 mas/yr
   * PM Dec = -87.79 mas/yr
   * Parallax = 19.70 mas
   * RV = 54.46 km/s
INFO: Query finished. [astroquery.utils.tap.core]
[BACKTRACKS INFO]: gathered 22668 Gaia objects from the 0.15 sq. deg. nearby HD165054
[BACKTRACKS INFO]: Finished nearby background gaia statistics
[BACKTRACKS INFO]: Queried distance prior parameters, L=5327.85, alpha=1.94, beta=2.52
[BACKTRACKS INFO]: Estimating candidate position if stationary in RA,Dec @ 2016.0 from observation #0
[BACKTRACKS INFO]: Opened ephemeris file
[8]:
import multiprocessing as mp
results = track.fit(dlogz=1e-1, npool=mp.cpu_count(),
                    dynamic=False, nlive=100,
                    mpi_pool=False,
                    resume=False,
                    sample_method='rslice')

# save our sampler results
track.save_results(fileprefix='./')
[BACKTRACKS INFO]: Beginning sampling
iter: 2640 | +100 | bound: 79 | nc: 1 | ncall: 187523 | eff(%):  1.462 | loglstar:   -inf < -49.803 <    inf | logz: -73.731 +/-  0.472 | dlogz:  0.001 >  0.100
[BACKTRACKS INFO]: Saving results to ./HD165054_cc1_dynestyrun_results.pkl
[9]:
# plot up only the trackplot to show the results
plot_1 = trackplot(track,
                   ref_epoch = Time(track.ref_epoch, format='jd').jd,
                   days_backward=1.*365.,
                   days_forward=8.*365.,
                   step_size=10.,
                   plot_radec=False,
                   plot_stationary=True,
                   fileprefix='./',
                   filepost='.png'
                  )
[BACKTRACKS INFO]: Stationary track reduced chi squared is 126.86
[BACKTRACKS INFO]: Median track reduced chi squared is 0.92
_images/additional-examples_15_1.png

Fit 2 parameter stationary background: 2MASS J0602#

Sanghi et al. (2024) found a companion candidate around the M-dwarf 2MASS J06022455-1634494 using an optimized reference differential imaging library; they concluded that the candidate was a likely background source.

[10]:
!wget https://github.com/wbalmer/backtracks/raw/refs/heads/main/tests/0602cc1.csv
--2026-03-31 16:51:50--  https://github.com/wbalmer/backtracks/raw/refs/heads/main/tests/0602cc1.csv
Resolving github.com (github.com)... 140.82.114.4
Connecting to github.com (github.com)|140.82.114.4|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://raw.githubusercontent.com/wbalmer/backtracks/refs/heads/main/tests/0602cc1.csv [following]
--2026-03-31 16:51:51--  https://raw.githubusercontent.com/wbalmer/backtracks/refs/heads/main/tests/0602cc1.csv
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.109.133, 185.199.110.133, 185.199.111.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 208 [text/plain]
Saving to: ‘0602cc1.csv.2’

0602cc1.csv.2       100%[===================>]     208  --.-KB/s    in 0s

2026-03-31 16:51:51 (28.3 MB/s) - ‘0602cc1.csv.2’ saved [208/208]

[11]:
track = System(target_name="2MASS J06022455-1634494",
               candidate_file="0602cc1.csv",
               nearby_window=0.5,
               ndim=2, # we can set this optional arg, in anticipation of fitting for only a stationary background track
               fileprefix='./')
[BACKTRACKS INFO]: Examining object = 1 in input file.
[BACKTRACKS INFO]: Resolved the target star '2MASS J06022455-1634494' in Simbad!
[BACKTRACKS INFO]: Resolved target's Gaia ID from Simbad, Gaia DR3 2991362056431878912
INFO: Query finished. [astroquery.utils.tap.core]
[BACKTRACKS INFO]: gathered Gaia DR3 data for 2MASS J06022455-1634494
   * Gaia source ID = 2991362056431878912
   * Reference epoch = 2016.0
   * RA = 90.6023 deg
   * Dec = -16.5807 deg
   * PM RA = -8.22 mas/yr
   * PM Dec = -67.49 mas/yr
   * Parallax = 24.87 mas
   * RV = -10.48 km/s
INFO: Query finished. [astroquery.utils.tap.core]
[BACKTRACKS INFO]: gathered 3565 Gaia objects from the 0.5 sq. deg. nearby 2MASS J06022455-1634494
[BACKTRACKS INFO]: Finished nearby background gaia statistics
[BACKTRACKS INFO]: Queried distance prior parameters, L=1.60, alpha=0.38, beta=4.12
[BACKTRACKS INFO]: Estimating candidate position if stationary in RA,Dec @ 2016.0 from observation #0
[BACKTRACKS INFO]: Opened ephemeris file
[BACKTRACKS INFO]: made cat entry for host
[BACKTRACKS INFO]: transformed cat entry for host
[12]:
fig_stationary = track.generate_stationary_plot(days_backward=1*365.,
                                                days_forward=2*365,
                                                step_size=10.,
                                                filepost='.png')
[BACKTRACKS INFO]: Generating Stationary plot
[BACKTRACKS INFO]: Stationary track reduced chi squared is 3.34
[BACKTRACKS INFO]: Stationary plot saved to ./
_images/additional-examples_20_1.png

It seems like the stationary background track fits the available data pretty well… but let’s try to fit it just for kicks.

[13]:
import multiprocessing as mp
results = track.fit(dlogz=1e-1, npool=mp.cpu_count(),
                    dynamic=False, nlive=100,
                    mpi_pool=False,
                    resume=False,
                    sample_method='rslice')

# save our sampler results
track.save_results(fileprefix='./')
[BACKTRACKS INFO]: Beginning sampling
iter: 1718 | +100 | bound: 46 | nc: 1 | ncall: 41141 | eff(%):  4.430 | loglstar:   -inf < -22.474 <    inf | logz: -37.216 +/-  0.370 | dlogz:  0.001 >  0.100
[BACKTRACKS INFO]: Saving results to ./2MASS_J06022455-1634494_cc1_dynestyrun_results.pkl
[14]:
# plot up our results
from backtracks.plotting import trackplot
from astropy.time import Time

plot_c = trackplot(track,
                   ref_epoch = Time(track.ref_epoch, format='jd').jd,
                   days_backward=1.*365.,
                   days_forward=2.*365.,
                   step_size=10.,
                   plot_radec=False,
                   plot_stationary=True,
                   fileprefix='./',
                   filepost='.png'
                  )
[BACKTRACKS INFO]: Stationary track reduced chi squared is 3.34
[BACKTRACKS INFO]: Median track reduced chi squared is 0.49
_images/additional-examples_23_1.png
[15]:
# plot up our results
from backtracks.plotting import trackplot
from astropy.time import Time

plot_c = trackplot(track,
                   ref_epoch = Time(track.ref_epoch, format='jd').jd,
                   days_backward=1.*365.,
                   days_forward=2.*365.,
                   step_size=10.,
                   plot_radec=False,
                   plot_stationary=True,
                   fileprefix='./',
                   filepost='.png'
                  )
[BACKTRACKS INFO]: Stationary track reduced chi squared is 3.34
[BACKTRACKS INFO]: Median track reduced chi squared is 0.49
_images/additional-examples_24_1.png

High precision astrometry: demoting YSES 2b#

Kenworthy et al. (2025) revealed that the planet candidate YSES 2b was a high proper motion background star using high precision observations from VLTI/GRAVITY.

backtracks uses novas to ensure that high precision measurements are properly treated. novas accounts for many higher order effects that could become important at precisions of a tens of microarcseconds like gravitational deflection of light, the precession of the Earth’s rotation axis, nutation from the Moon’s orbit, and aberration from the Sun and the Earth’s motion.

[16]:
!wget https://github.com/wbalmer/backtracks/raw/refs/heads/main/tests/hd165054_orbitizelike.csv
--2026-03-31 16:53:12--  https://github.com/wbalmer/backtracks/raw/refs/heads/main/tests/hd165054_orbitizelike.csv
Resolving github.com (github.com)... 140.82.113.4
Connecting to github.com (github.com)|140.82.113.4|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://raw.githubusercontent.com/wbalmer/backtracks/refs/heads/main/tests/hd165054_orbitizelike.csv [following]
--2026-03-31 16:53:12--  https://raw.githubusercontent.com/wbalmer/backtracks/refs/heads/main/tests/hd165054_orbitizelike.csv
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.109.133, 185.199.110.133, 185.199.111.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1134 (1.1K) [text/plain]
Saving to: ‘hd165054_orbitizelike.csv.2’

hd165054_orbitizeli 100%[===================>]   1.11K  --.-KB/s    in 0s

2026-03-31 16:53:12 (120 MB/s) - ‘hd165054_orbitizelike.csv.2’ saved [1134/1134]

[17]:
track = System(target_name="YSES2",
               candidate_file="yses2b_orbitizelike.csv",
               nearby_window=0.5,
               fileprefix='./')
[BACKTRACKS INFO]: Examining object = 1 in input file.
[BACKTRACKS INFO]: Resolved the target star 'YSES2' in Simbad!
[BACKTRACKS INFO]: Resolved target's Gaia ID from Simbad, Gaia DR3 5236792880333011968
INFO: Query finished. [astroquery.utils.tap.core]
[BACKTRACKS INFO]: gathered Gaia DR3 data for YSES2
   * Gaia source ID = 5236792880333011968
   * Reference epoch = 2016.0
   * RA = 171.9803 deg
   * Dec = -66.4346 deg
   * PM RA = -34.03 mas/yr
   * PM Dec = 2.32 mas/yr
   * Parallax = 9.15 mas
   * RV = 12.93 km/s
INFO: Query finished. [astroquery.utils.tap.core]
[BACKTRACKS INFO]: gathered 28263 Gaia objects from the 0.5 sq. deg. nearby YSES2
[BACKTRACKS INFO]: Finished nearby background gaia statistics
[BACKTRACKS INFO]: Queried distance prior parameters, L=1425.85, alpha=0.91, beta=2.09
[BACKTRACKS INFO]: Estimating candidate position if stationary in RA,Dec @ 2016.0 from observation #0
[BACKTRACKS INFO]: Opened ephemeris file
[18]:
fig_stationary = track.generate_stationary_plot(days_backward=0.5*365.,
                                                days_forward=6*365,
                                                step_size=10.,
                                                filepost='.png')
[BACKTRACKS INFO]: Generating Stationary plot
[BACKTRACKS INFO]: Stationary track reduced chi squared is 2524154.49
[BACKTRACKS INFO]: Stationary plot saved to ./
_images/additional-examples_29_1.png
[19]:
import multiprocessing as mp
results = track.fit(dlogz=5e-3, npool=mp.cpu_count(),
                    dynamic=False, nlive=400,
                    mpi_pool=False,
                    resume=False,
                    sample_method='rslice')

# save our sampler results
track.save_results(fileprefix='./')
[BACKTRACKS INFO]: Beginning sampling
iter: 42168 | bound: 590 | nc: 68 | ncall: 3650897 | eff(%):  1.155 | loglstar:   -inf < -121.847 <    inf | logz: -221.015 +/-  0.491 | dlogz:  0.006 >  0.005                                       /Users/wbalmer/miniconda3/envs/bt-pytest/lib/python3.12/site-packages/dynesty/internal_samplers.py:1144: UserWarning: The slice sample interval was expanded more than 1000 times
  warnings.warn('The slice sample interval was expanded more '
/Users/wbalmer/miniconda3/envs/bt-pytest/lib/python3.12/site-packages/dynesty/internal_samplers.py:839: UserWarning: Enabling doubling strategy of slice sampling from Neal(2003)
  warnings.warn('Enabling doubling strategy of slice '
iter: 43082 | +400 | bound: 606 | nc: 1 | ncall: 3751434 | eff(%):  1.159 | loglstar:   -inf < -118.740 <    inf | logz: -221.012 +/-  0.491 | dlogz:  0.000 >  0.005
[BACKTRACKS INFO]: Saving results to ./YSES2_cc1_dynestyrun_results.pkl
[20]:
fig_track, fig_post, fig_diag, fig_prior, fig_hood = \
    track.generate_plots(days_backward=1.*365.,
                         days_forward=10.*365,
                         step_size=10.,
                         plot_radec=False,
                         plot_stationary=False,
                         fileprefix='./',
                         filepost='.png')
[BACKTRACKS INFO]: Generating Plots
/Users/wbalmer/miniconda3/envs/bt-pytest/lib/python3.12/site-packages/erfa/core.py:133: ErfaWarning: ERFA function "dtf2d" yielded 12 of "dubious year (Note 6)"
  warn(f'ERFA function "{func_name}" yielded {wmsg}', ErfaWarning)
[BACKTRACKS INFO]: Stationary track reduced chi squared is 2524154.49
[BACKTRACKS INFO]: Median track reduced chi squared is 20.96
/Users/wbalmer/codebank/backtracks/backtracks/plotting.py:81: RuntimeWarning: divide by zero encountered in divide
  ppf = 1000./transform_gengamm(u, backtracks.L, backtracks.alpha, backtracks.beta)
[BACKTRACKS INFO]: Plots saved to ./
_images/additional-examples_31_5.png
_images/additional-examples_31_6.png
_images/additional-examples_31_7.png
_images/additional-examples_31_8.png
_images/additional-examples_31_9.png
[ ]: