Source code for playground.tv.frames.FrameBase

from ...imports import *


[docs]class FrameBase(Talker): frametype = 'base' timeunit = 'day' aspectratio = 1 def __init__(self, name='', ax=None, data=None, illustration=None, plotingredients=[], **kwargs): ''' Initialize this Frame, which can be one (of multiple) frames in an Illustration. Before plotting, each frame needs to have an `ax` defined saying where it should be plotted and (generally) some `data` associated with it. Parameters ---------- name : str A name to give this Frame. ax : matplotlib.axes.Axes instance All plotting will happen inside this ax. If set to None, the `self.ax attribute` will need to be set manually before plotting. data : flexible It can be custom object (e.g. a Stamp), or simple arrays, or a list of HDULists, or something else, depending on what this actual Frame does with it in `plot` and `update`. illustration : an Illustration The illustration in which this frame will be embedded. We keep track of this (sometimes) because we might want information that's shared across the whole illustration to be accessible to this individual frame when plotting. plotingredients : list A list of keywords indicating features that will be plotted in this frame. It can be modified either now when initializing the frame, or any time before calling `i.plot()` from the illustration. **kwargs go nowhere (?) ''' # initialize the Talker Talker.__init__(self, prefixformat='{:>32}') # store a name for this frame self.name = name # assign this frame an axes to sit in self.ax = ax # this is likely a Sequence of some kind self.data = data # is there another overarching frame this one should be aware of? self.illustration = illustration # what ingredients should be included when plotting? self.plotingredients = plotingredients # keep track of a list of frames included in this one (e.g. zooms) self.includes = [] # keep track of what's been plotted self.plotted = {} @property def offset(self): ''' Get a time offset, to use as a zero-point. Returns ------- offset : float An appropriate time zero-point (in JD). ''' # is an offset already defined? try: return self._offset except AttributeError: # is there a minimum of the illustration's times? try: self._offset = np.min(self.illustration._get_times().jd) except (AttributeError, ValueError): # otherwise, use only this frame to estimate the offset try: self._offset = np.min(self._get_times().jd) except ValueError: self._offset = 0.0 self.speak('defining {} as the time offset'.format(self._offset)) return self._offset def _timestring(self, time): ''' Return a string, given an input time. Parameters ---------- time : astropy Time A particular time. Returns ------- timestring : str A string describing the times. ''' if self.data._timeisfake: timestep = self._find_timestep(time) return '#{:.0f}'.format(self._get_times()[timestep].gps) else: days = time.jd - self.offset inunits = (days * u.day).to(self.timeunit) return 't={:.5f}{:+.5f}'.format(self.offset, inunits) def __repr__(self): ''' Default string representation for this frame. ''' return '<{} Frame | data={} | name={}>'.format(self.frametype, self.data, self.name) def __str__(self): return '<F"{}">'.format(self.name)
[docs] def plot(self): ''' This should be redefined in a class that inherits from FrameBase. ''' raise RuntimeError( "Don't know how to `plot` {}".format(self.frametype))
[docs] def update(self, *args, **kwargs): ''' This should be redefined in a class that inherits from FrameBase. ''' raise RuntimeError( "Don't know how to `update` {}".format(self.frametype))
def _find_timestep(self, time): ''' Given a time, identify its index. Parameters ---------- time : float A single time (in JD?). Returns ------- index : int The index of the *closest* time point. ''' return self.data._find_timestep(time) def _get_times(self): ''' Get the available times associated with this frame. ''' # does the data have a time axis defined? try: return self.data.time # if not, return an empty time except AttributeError: return Time([], format='gps') def _timesandcadence(self, round=None): ''' Get all the unique times available across all the frames, along with a suggested cadence set by the minimum (rounded) differences between times. Parameters ---------- round : float All times will be rounded to this value. Times separated by less than this value will be considered identical. ''' # store this calculation with the illustration, so it doesn't need repeating try: self._precaculatedtimesandcadence except AttributeError: self._precaculatedtimesandcadence = {} try: times, cadence = self._precaculatedtimesandcadence[round] except KeyError: gps = self._get_times().gps if round is None: diffs = np.diff(np.sort(gps)) round = np.min(diffs[diffs > 0]) baseline = np.min(gps) rounded = round * np.round((gps - baseline) / round) + baseline uniquegpstimes = np.unique(rounded) cadence = np.min(np.diff(uniquegpstimes)) * u.s times = Time(uniquegpstimes, format='gps') self._precaculatedtimesandcadence[round] = times, cadence return times, cadence def _transformimage(self, image): ''' Some frames will want to flip or rotate an image before display. This handles that transformation. (This should probably be set up as an matplotlib.axes transform type of thing.) ''' return image def _transformxy(self, x, y): ''' This handles the same transformation as that which goes into transform image, but for x and y arrays. ''' return x, y def _get_orientation(self): ''' Figure out the orientation of the overarching illustration. ''' try: return self.illustration.orientation except: return 'horizontal' #'vertical'