In [1]:
%matplotlib inline
%config InlineBackend.figure_format = "retina"

from matplotlib import rcParams
rcParams["savefig.dpi"] = 100
rcParams["font.size"] = 20

In [171]:
import kplr
import numpy as np
import matplotlib.pyplot as pl
from simplexy import simplexy

In [113]:
client = kplr.API()
tpf = client.k2_star(202137899).get_target_pixel_files()[0]


WARNING:root:Unrecognized parameter: 'stpropflag'
WARNING:root:Unrecognized parameter: 'stpropflag'

In [277]:
data = tpf.read()
time = data["TIME"]
flux = data["FLUX"]
ferr = data["FLUX_ERR"]
quality = data["QUALITY"]

m = np.all((flux == 0.0) + np.isnan(flux), axis=(1, 2)) + np.isnan(time) + (quality > 0)
t = time[~m]
i = np.argmax(np.diff(t))
i = np.arange(len(time))[~m][i+1]
i = -1000
time = time[i:]
flux = flux[i:]
ferr = ferr[i:]
quality = quality[i:]
print(i, time[0])


(-1000, 1951.7765877587954)

In [278]:
def run_one(img):
    m = np.isfinite(img)
    m[m] *= (img[m] > 0.0)
    if not np.any(m):
        return None
    img[~m] = np.median(img[m])
    return np.array([list(row) for row in simplexy(img, )])

Generate a graph of coordinate locations.


In [279]:
graph = []
for i in range(len(flux)):
    if quality[i] != 0:
        graph.append([])
        continue
    img = flux[i]
    r = run_one(img)
    graph.append(r if r is not None else [])

Traverse the graph greedily.


In [289]:
nt = len(graph)
ns = min(map(len, filter(len, graph)))
coords = np.nan + np.zeros((nt, ns, 4))
metric = np.array([1.0, 1.0, 1e-8])

current = None
for t, node in enumerate(graph):
    if not len(node):
        continue
    if current is None:
        current = node[:ns, :]
        coords[t] = current
        continue
    
    # Compute the set of distances between this node and the current position.
    r = np.sum((node[:, None, :3] - current[None, :, :3])**2 * metric[None, None, :], axis=-1)
    
    # Loop over the permutations and greedily choose the best update.
    rows, cols = np.arange(r.shape[0]), np.arange(r.shape[1])
    update = np.nan + np.zeros(ns)
    while any(np.isnan(update)):
        row, col = np.unravel_index(np.argmin(r), r.shape)
        update[cols[col]] = rows[row]
        r = np.delete(r, row, axis=0)
        r = np.delete(r, col, axis=1)
        rows = np.delete(rows, row)
        cols = np.delete(cols, col)
    update = np.array(update, dtype=int)
    
    # Compute the total cost.
    cost = np.sum((current[:, :3] - node[update, :3])**2 * metric[None, :])
    if cost > 10.0:
        continue
        
    # Update the current locations.
    current = node[update]
    coords[t] = current

Generate a mask of times that are OK.


In [294]:
good_times = np.all(np.isfinite(coords), axis=(1, 2))

Find the mean motion of the frame.


In [295]:
center = np.array(coords[:, 0, :2])
center -= np.mean(center[good_times], axis=0)
# center = np.sum(coords[:, :, :2] * coords[:, :, 2][:, :, None], axis=1) / np.sum(coords[:, :, 2], axis=1)[:, None]
dx = coords[:, :, :2] - center[:, None, :]
offsets = np.median(dx[np.all(np.isfinite(dx), axis=(1, 2))], axis=0)

In [296]:
pl.plot(time, coords[:, 1, 2], ".k")


Out[296]:
[<matplotlib.lines.Line2D at 0x149b1f690>]

In [299]:
pl.scatter(center[:, 0], center[:, 1], c=time)


Out[299]:
<matplotlib.collections.PathCollection at 0x14e110ad0>

Make a movie!


In [301]:
i = 0
for t, img in enumerate(flux):
    m = np.isfinite(img)
    m[m] *= (img[m] > 0.0)
    if not np.any(m):
        continue
    img[~m] = np.median(img[m])
    pl.clf()
    pl.imshow(np.log(img.T), cmap="gray_r", interpolation="nearest")
    pl.plot(coords[t, :, 0], coords[t, :, 1], "+b")
    pl.plot(center[t, 0] + offsets[:, 0], center[t, 1] + offsets[:, 1], "+r")
    pl.title("EPIC 202137899")
    pl.savefig("frames/{0:05d}.png".format(i))
    i += 1


---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
<ipython-input-301-073ad056a126> in <module>()
     11     pl.plot(center[t, 0] + offsets[:, 0], center[t, 1] + offsets[:, 1], "+r")
     12     pl.title("EPIC 202137899")
---> 13     pl.savefig("frames/{0:05d}.png".format(i))
     14     i += 1

/Users/dfm/anaconda/lib/python2.7/site-packages/matplotlib/pyplot.pyc in savefig(*args, **kwargs)
    559 def savefig(*args, **kwargs):
    560     fig = gcf()
--> 561     return fig.savefig(*args, **kwargs)
    562 
    563 

/Users/dfm/anaconda/lib/python2.7/site-packages/matplotlib/figure.pyc in savefig(self, *args, **kwargs)
   1419             self.set_frameon(frameon)
   1420 
-> 1421         self.canvas.print_figure(*args, **kwargs)
   1422 
   1423         if frameon:

/Users/dfm/anaconda/lib/python2.7/site-packages/matplotlib/backend_bases.pyc in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, **kwargs)
   2218                 orientation=orientation,
   2219                 bbox_inches_restore=_bbox_inches_restore,
-> 2220                 **kwargs)
   2221         finally:
   2222             if bbox_inches and restore_bbox:

/Users/dfm/anaconda/lib/python2.7/site-packages/matplotlib/backends/backend_agg.pyc in print_png(self, filename_or_obj, *args, **kwargs)
    503 
    504     def print_png(self, filename_or_obj, *args, **kwargs):
--> 505         FigureCanvasAgg.draw(self)
    506         renderer = self.get_renderer()
    507         original_dpi = renderer.dpi

/Users/dfm/anaconda/lib/python2.7/site-packages/matplotlib/backends/backend_agg.pyc in draw(self)
    449 
    450         try:
--> 451             self.figure.draw(self.renderer)
    452         finally:
    453             RendererAgg.lock.release()

/Users/dfm/anaconda/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs)
     53     def draw_wrapper(artist, renderer, *args, **kwargs):
     54         before(artist, renderer)
---> 55         draw(artist, renderer, *args, **kwargs)
     56         after(artist, renderer)
     57 

/Users/dfm/anaconda/lib/python2.7/site-packages/matplotlib/figure.pyc in draw(self, renderer)
   1032         dsu.sort(key=itemgetter(0))
   1033         for zorder, a, func, args in dsu:
-> 1034             func(*args)
   1035 
   1036         renderer.close_group('figure')

/Users/dfm/anaconda/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs)
     53     def draw_wrapper(artist, renderer, *args, **kwargs):
     54         before(artist, renderer)
---> 55         draw(artist, renderer, *args, **kwargs)
     56         after(artist, renderer)
     57 

/Users/dfm/anaconda/lib/python2.7/site-packages/matplotlib/axes.pyc in draw(self, renderer, inframe)
   2084 
   2085         for zorder, a in dsu:
-> 2086             a.draw(renderer)
   2087 
   2088         renderer.close_group('axes')

/Users/dfm/anaconda/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs)
     53     def draw_wrapper(artist, renderer, *args, **kwargs):
     54         before(artist, renderer)
---> 55         draw(artist, renderer, *args, **kwargs)
     56         after(artist, renderer)
     57 

/Users/dfm/anaconda/lib/python2.7/site-packages/matplotlib/image.pyc in draw(self, renderer, *args, **kwargs)
    353         gc.set_clip_rectangle(self.axes.bbox.frozen())
    354         gc.set_clip_path(self.get_clip_path())
--> 355         gc.set_alpha(self.get_alpha())
    356 
    357         if self._check_unsampled_image(renderer):

/Users/dfm/anaconda/lib/python2.7/site-packages/matplotlib/backend_bases.pyc in set_alpha(self, alpha)
    849             self._forced_alpha = True
    850         else:
--> 851             self._alpha = 1.0
    852             self._forced_alpha = False
    853         self.set_foreground(self._orig_color)

KeyboardInterrupt: 

In [302]:
offsets


Out[302]:
array([[  9.19728072,  10.93345629],
       [ 18.98560174,  20.5891565 ],
       [ 17.00016053,  18.04751097],
       [ 21.18055852,  12.857293  ]])

In [ ]: