Skip to content
Romesh Abeysuriya edited this page Nov 6, 2015 · 4 revisions

The feather object stores the output from the fitting routine. It is called feather because it is a light-weight wrapper around the fit_data struct. The name was originally temporary, but it has stuck because there are many different components within BrainTrack and the distinctive name makes it easy to remember.

Role

The main role of the feather object is to group together a series of fits. Each fit returns a fit_data and plot_data struct, but when performing state tracking, you get a sequence of structs that are temporally related. The feather object stores all of these structs and encapsulates the relationship between them. The main functionality provided by the feather class is

  • A wrapper to arrays of fit_data and plot_data structs
  • An interface for analysis routines
  • A standardized way to store and exchange fit data

The feather object incorporates a lot of helper methods. These are

  • Concatenating multiple feather objects
  • Retrieving a subset of the data (which is returned as another feather)
  • Inserting fit_data and plot_data

Using a feather

You can initialize an empty feather using

bt.feather

This means that you can preallocate an array of feathers if you want, using

f(10) = bt.feather

for example. The constructor for a feather has 3 arguments

f = bt.feather(fit_data,plot_data,time)

The fit data and plot data should be the structs returned by bt.fit_spectrum. The time is useful if you are not starting at t=1 or if your times are not uniformly spaced. Providing the time value is optional - if you don't provide a time, it will be assumed that the time increment is 1 second starting at t=1.

For subsequent fits, you can insert the data using

f.insert(fit_data,plot_data,time,idx)

This will preallocate arrays inside the feather, and insert the fit data and plot data at the specified index. In general, you should not need to specify the index unless you are intentionally overwriting an existing fit.

The feather class dynamically grows the arrays to provide decent performance when using feather.subrange() or otherwise adding many points. This is a significant feature because there can be over 20000 fits contained in a single feather. When you call feather.insert, the internal arrays are dynamically grown in powers of 2. The actual length of the arrays is stored in feather.prealloc_size. The amount of data contained is stored in feather.latest. If you run feather.compress() then the arrays are truncated so that feather.prealloc_size=feather.latest, which saves memory once you are done adding things to the feather.

If you want to obtain a new feather with only a subset of the data, you can use

f2 = f.subrange(indexes)

This will create a new feather using the first of the specified indexes, and then insert each of the subsequent specified fits. The result is a new feather that only contains the requested indexes.

File 'pointers'

The clouds whose data is stored in plot_data are important to be able to plot. However, they consume quite a lot of data, which is a huge issue for fits that have over 20000 spectra. To deal with this, instead of storing the actual structs in the feather, you can instead store the file name of a .mat file that contains the plot_data variable. This files are then automatically loaded by bt.viewer. To use this functionality, you can simply insert a string containing the full file name of the .mat file. Everything else works as usual.

  • The file is automatically split into the parent folder and the file name itself. All of the files need to be stored in the same folder
  • This folder is stored in feather.path_prefix. If you move the fit folder somewhere else, simply change feather.path_prefix appropriately. This way you don't need to change the path in all of the plot_data strings
  • If plot_data contains strings, the method feather.fill iterates over the strings and loads the plot data into memory, converting the feather into one which stores the actual plot data. This provides better performance for visualization, but is only recommended if you have a few (e.g. < 500) spectra in the feather

Analysis routines

The feather class provides several analysis routines. These are approximately structured into three tiers

  1. Methods that return different representations of the fit data that are suitable for plotting
  2. Low-level plotting methods for scatter and line plots
  3. High-level plotting methods for finished figures

Methods for returning data

The fit data in the feather object is stored as an array of fit_data structs, which is not always the most convenient way to work with the data. To assist with custom plotting routines, a number of helper functions are provided:

  • fitted_params - Returns a matrix of fitted parameters. The row corresponds to the time, and column to the parameter
  • fitted_params_from_posterior - Returns a matrix of the peak of the marginal posterior distribution for each parameter. Rows correspond to time, and column to parameter. These will be more stable than the fitted parameters, but in general they may not provide good fits because of the interdependencies between model parameters
  • xyz - Returns a matrix of XYZ values for each time
  • state_blocks - Returns a two column matrix with start and stop indexes for contiguous states. The first column is the start index, and the second is the stop index. The meaning of this matrix is that all indexes between the first and second column (for a given row) have the same state as the start index. For example, if the output was [1 10; 11 20] then the first 10 fits all have the same state as the first fit, and fits 11-20 all have the same state as fit 11
  • state_colors - Return an array where each entry corresponds to the row index of bt_utils.state_cdata for the state. Alternatively, this can be also be regarded as a scalar numerical representation of the sleep stage
  • state_str - Return a cell array where each entry corresponds to a string describing the state e.g. 'W' or 'W-S1 (22/8)'
  • chisq - Return an array where each entry corresponds to the chisq value for the fits

Low-level plotting

The intermediate plotting functions generate scatter and line plots, but leverage the data methods provided above. The low-level plotting commands are:

  • scatter_statecolored - Takes in 2 or 3 arrays, and plots either a 2D or a 3D scatter in which the colour corresponds to the sleep stage (using state_colors). The number of data points should be the same as the number of points in the feather (if you want to plot a subset of values, use subrange() to obtain a feather object for the corresponding indices)
  • plot_statecolored - which plots the input arrays using the colors specified by the states contained within the feather. The lines are plotted based on state_blocks which minimizes the number of line objects (thus maximizing performance)

High-level plotting

The feather object contains a number of methods that produce useful analysis figures for fits. Examples of the most common plots are provided in the walkthrough.

  • plot_track - plots a color-coded track in XYZ space (uses plot_statecolored internally)
  • point_cloud - plots a color-coded scatter plot of all of the fitted parameters in XYZ space (uses scatter_statecolored internally)
  • blobs - this function generates convex hulls, grouped by sleep stage. This can be used to generate individualized versions of the blobs in Abeysuriya et. al. (2015).
  • clouds - generates a cloud plot using binned translucent cubes. This is most useful for visualizing densities when points are very closely spaced (and therefore turn into a single blob of color when displayed using a scatter plot)
  • cones - generates a velocity plot in XYZ using cones, where the size of the cone indicates the velocity, and the orientation of the cone indicates the direction of the trajectory.
  • timecourse - Plots the time courses of each of the fit parameters (uses plot_statecolored internally)
  • plot - this method acts as in interface for bt.viewer, with the additional feature that the plot() method stores a reference to the generated figure within the feather object, so that if you specify a time index e.g. feather.plot(1), subsequently running feather.plot(2) will update the existing figure instead of opening a new one. Unlike simply plotting in the current axis, this functionality will work even if you have multiple feather objects and multiple viewers open simultaneously.
  • head_plot - This generates an interactive figure for analyzing multielectrode data.
Clone this wiki locally