Skip to content

Commit

Permalink
merge dev into release
Browse files Browse the repository at this point in the history
merge dev into release
  • Loading branch information
versey-sherry authored Mar 6, 2023
2 parents 30a9a3f + 9757d4e commit 6681a72
Show file tree
Hide file tree
Showing 19 changed files with 1,121 additions and 1,477 deletions.
57 changes: 31 additions & 26 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,16 @@


# -- General configuration ---------------------------------------------------

on_rtd = input('Generating a pdf? (y/[n])')
if on_rtd == 'y':
on_rtd = False
else:
on_rtd = True

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
if on_rtd:
extensions = [
'sphinx.ext.napoleon',
'sphinx.ext.autodoc',
'sphinx.ext.autosummary',
'sphinx_click.ext'
]
else:
extensions = [
extensions = [
'sphinx.ext.napoleon',
'sphinx.ext.autodoc',
'sphinx.ext.autosummary',
'rst2pdf.pdfbuilder',
'sphinx_click.ext'
]


# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

Expand All @@ -73,11 +56,33 @@
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# Source: https://gist.github.com/alfredodeza/7fb5c667addb1c6963b9
# index - master document
# rst2pdf - Documentation
# MoSeq2-Viz Documentation - title of the pdf
# Datta Lab - author name in the pdf
pdf_documents = [('index', u'Documentation', u'MoSeq2-Viz Documentation', u'Datta Lab'),]
html_static_path = []

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# 'fontpkg': '\\usepackage{euler}'

# The font size ('10pt', '11pt' or '12pt').

# 'pointsize': '12pt',

# fontpkg': r'''
# \setmainfont{Arial Regular}
# \setsansfont{Arial Regular}
# \setmonofont{Menlo Regular}
# ''',

# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',

# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}

latex_documents = [
('index', u'moseq2-viz.tex', u'moseq2-viz Documentation', u'Datta Lab', 'manual'),
]
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Welcome to moseq2-viz's documentation!
======================================

.. toctree::
:maxdepth: 2
:maxdepth: 3
:caption: Contents:

modules
Expand Down
30 changes: 27 additions & 3 deletions docs/moseq2_viz.model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,34 @@ Model - Dist Module
:undoc-members:
:show-inheritance:

Model - Label Utilities Module
------------------------------------
Model - embed Module
-----------------------------

.. automodule:: moseq2_viz.model.embed
:members:
:undoc-members:
:show-inheritance:

Model - Fingerprint and Classifier Module
-----------------------------

.. automodule:: moseq2_viz.model.fingerprint_classifier
:members:
:undoc-members:
:show-inheritance:

Model - Stats Module
-----------------------------

.. automodule:: moseq2_viz.model.stat
:members:
:undoc-members:
:show-inheritance:

Model - Transition Graph Module
-----------------------------

.. automodule:: moseq2_viz.model.label_util
.. automodule:: moseq2_viz.model.trans_graph
:members:
:undoc-members:
:show-inheritance:
Expand Down
91 changes: 36 additions & 55 deletions moseq2_viz/cli.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
'''
CLI front-end operations. This module contains all the functionality and configurable parameters
users can alter to most accurately process their data.
Note: These functions simply read all the parameters into a dictionary,
and then call the corresponding wrapper function with the given input parameters.
'''
"""
CLI for visualizing the results.
"""

import os
import click
Expand All @@ -21,65 +15,61 @@ def new_init(self, *args, **kwargs):
orig_init(self, *args, **kwargs)
self.show_default = True


click.core.Option.__init__ = new_init


@click.group()
@click.version_option()
def cli():
pass

@cli.command(name="add-group", help='Change group name in index file given a key-value pair')
@cli.command(name="add-group", help='Change group name for the sessions in index file (moseq2-index.yaml)')
@click.argument('index-file', type=click.Path(exists=True, resolve_path=True))
@click.option('--key', '-k', type=str, default='SubjectName', help='Key to search for value')
@click.option('--value', '-v', type=str, default='Mouse', help='Value to search for', multiple=True)
@click.option('--group', '-g', type=str, default='Group1', help='Group name to map to')
@click.option('--key', '-k', type=str, default='SubjectName', help='metadata field to search for value to match')
@click.option('--value', '-v', type=str, default='Mouse', help='Value to match for', multiple=True)
@click.option('--group', '-g', type=str, default='Group1', help='Group name to set')
@click.option('--exact', '-e', type=bool, is_flag=True, help='Exact match only')
@click.option('--lowercase', type=bool, is_flag=True, help='Lowercase text filter')
@click.option('--lowercase', type=bool, is_flag=True, help='Set metadata info to lower case for matching')
@click.option('-n', '--negative', type=bool, is_flag=True, help='Negative match (everything that does not match is included)')
def add_group(index_file, **config_data):

add_group_wrapper(index_file, config_data)

@cli.command(name="get-best-model", help='Returns the model with the closest median duration to the PC Changepoints, given a directory containing multiple models')
@cli.command(name="get-best-model", help='Get the model closest to model-free Changepoints, given the objective')
@click.argument('model-dir', type=click.Path(exists=True, resolve_path=True))
@click.argument('cp-path', type=click.Path(exists=True, resolve_path=True))
@click.argument('output-file', type=click.Path(exists=False, resolve_path=True))
@click.option('--plot-all', is_flag=True, help="Plot all included model results")
@click.option('--ext', type=str, default='p', help="Model extensions found in input directory")
@click.option('--ext', type=str, default='p', help="Model extensions to look for in input directory")
@click.option('--fps', type=int, default=30, help="Frames per second")
@click.option('--objective', type=str, default='duration (mean match)', help="can be either duration or jsd. The objective finds the best model based on durations or the jensen-shannon divergence")
@click.option('--objective', type=str, default='duration (mean match)', help="The objective finds the best model when comparing with model-free changepoints")
def get_best_fit_model(model_dir, cp_path, output_file, plot_all, ext, fps, objective):

get_best_fit_model_wrapper(model_dir, cp_path, output_file, plot_all, ext, fps, objective)


# recurse through directories, find h5 files with completed extractions, make a manifest
# and copy the contents to a new directory
@cli.command(name="copy-h5-metadata-to-yaml", help='Copies metadata within an h5 file to a yaml file.')
@cli.command(name="copy-h5-metadata-to-yaml", help='Copy metadata within an h5 file to a yaml file.')
@click.option('--input-dir', '-i', type=click.Path(), default=os.getcwd(), help='Directory to find h5 files')
def copy_h5_metadata_to_yaml(input_dir):
copy_h5_metadata_to_yaml_wrapper(input_dir)


@cli.command(name='make-crowd-movies', help='Writes movies of overlaid examples of the rodent perform a given syllable')
@cli.command(name='make-crowd-movies', help='write movies of overlaid examples of the rodent perform a given syllable')
@click.argument('index-file', type=click.Path(exists=True, resolve_path=True))
@click.argument('model-path', type=click.Path(exists=True, resolve_path=True))
@click.option('--max-syllable', type=int, default=40, help="Index of max syllable to render")
@click.option('--max-examples', '-m', type=int, default=40, help="Number of examples to show")
@click.option('--processes', type=int, default=None, help="Number of processes to use for rendering crowd movies. Default None uses every process")
@click.option('--separate-by', type=click.Choice(['default', 'groups', 'sessions', 'subjects']), default='default', help="Generate crowd movies from individual group sources.")
@click.option('--specific-syllable', type=int, default=None, help="Index of max syllable to render")
@click.option('--session-names', '-s', default=[], type=str, help="SessionNames to create crowd movies from", multiple=True)
@click.option('--sort', type=bool, default=True, help="Sort syllables by usage")
@click.option('--max-syllable', type=int, default=40, help="index of the max syllable to include")
@click.option('--max-examples', '-m', type=int, default=40, help="number of examples to show")
@click.option('--processes', type=int, default=None, help="number of processes to use for rendering crowd movies. Default None uses every process")
@click.option('--separate-by', type=click.Choice(['default', 'groups', 'sessions', 'subjects']), default='default', help="generate crowd movies by specified grouping")
@click.option('--specific-syllable', type=int, default=None, help="index of the specific syllable to render")
@click.option('--session-names', '-s', default=[], type=str, help="specific sessions to create crowd movies from", multiple=True)
@click.option('--sort', type=bool, default=True, help="sort syllables by usage")
@click.option('--count', type=click.Choice(['usage', 'frames']), default='usage', help='How to quantify syllable usage')
@click.option('--output-dir', '-o', type=click.Path(), default=os.path.join(os.getcwd(), 'crowd_movies'), help="Path to store files")
@click.option('--gaussfilter-space', default=(0, 0), type=(float, float), help="Spatial filter for data (Gaussian)")
@click.option('--medfilter-space', default=[0], type=int, help="Median spatial filter", multiple=True)
@click.option('--gaussfilter-space', default=(0, 0), type=(float, float), help="x sigma and y sigma for Gaussian spatial filter to apply to data")
@click.option('--medfilter-space', default=[0], type=int, help="kernel size for median spatial filter", multiple=True)
@click.option('--min-height', type=int, default=5, help="Minimum height for scaling videos")
@click.option('--max-height', type=int, default=80, help="Minimum height for scaling videos")
@click.option('--raw-size', type=(int, int), default=(512, 424), help="Size of original videos")
@click.option('--max-height', type=int, default=80, help="Maximum height for scaling videos")
@click.option('--raw-size', type=(int, int), default=(512, 424), help="frame dimension of original videos")
@click.option('--scale', type=float, default=1, help="Scaling from pixel units to mm")
@click.option('--cmap', type=str, default='jet', help="Name of valid Matplotlib colormap for false-coloring images")
@click.option('--max-dur', default=60, help="Exclude syllables longer than this number of frames (None for no limit)")
Expand All @@ -90,28 +80,24 @@ def copy_h5_metadata_to_yaml(input_dir):
@click.option('--pad', default=30, help='Pad crowd movie videos with this many frames.')
@click.option('--seed', default=0, type=int, help='Defines random seed for selecting syllable instances to plot')
def make_crowd_movies(index_file, model_path, output_dir, **config_data):

make_crowd_movies_wrapper(index_file, model_path, output_dir, config_data)

print(f'Crowd movies successfully generated in {output_dir}.')


@cli.command(name='plot-scalar-summary', help="Plots a scalar summary of the index file data.")
@cli.command(name='plot-scalar-summary', help="Plot a scalar summary scatter plot for each group.")
@click.argument('index-file', type=click.Path(exists=True, resolve_path=True))
@click.option('--output-file', type=click.Path(), default=os.path.join(os.getcwd(), 'scalars'))
@click.option('-c', '--colors', type=str, default=None, help="Colors to plot groups with.", multiple=True)
def plot_scalar_summary(index_file, output_file, colors):

plot_scalar_summary_wrapper(index_file, output_file, colors=colors)
print('Sucessfully plotted scalar summary')


@cli.command(name='plot-group-position-heatmaps', help="Plots position heatmaps for each group in the index file")
@cli.command(name='plot-group-position-heatmaps', help="Plots position heatmaps for each group")
@click.argument('index-file', type=click.Path(exists=True, resolve_path=True))
@click.option('--output-file', type=click.Path(), default=os.path.join(os.getcwd(), 'group_heat_map'))
@click.option('--normalize', type=bool, is_flag=True, help="normalize the PDF so that min and max values range from 0-1")
def plot_group_position_heatmaps(index_file, output_file, normalize):

plot_mean_group_position_pdf_wrapper(index_file, output_file, normalize=normalize)
print('Sucessfully plotted mean group heatmaps')

Expand All @@ -120,21 +106,19 @@ def plot_group_position_heatmaps(index_file, output_file, normalize):
@click.option('--output-file', type=click.Path(), default=os.path.join(os.getcwd(), 'session_heat_map'))
@click.option('--normalize', type=bool, is_flag=True, help="normalize the PDF so that min and max values range from 0-1")
def plot_verbose_position_heatmaps(index_file, output_file, normalize):

plot_verbose_pdfs_wrapper(index_file, output_file, normalize=normalize)
print('Sucessfully plotted mean group heatmaps')


@cli.command(name='plot-transition-graph', help="Plots the transition graph depicting the transition probabilities between syllables.")
@cli.command(name='plot-transition-graph', help="Plot the transition graph depicting the transition probabilities between syllables.")
@click.argument('index-file', type=click.Path(exists=True, resolve_path=True))
@click.argument('model-fit', type=click.Path(exists=True, resolve_path=True))
@click.option('--max-syllable', type=int, default=40, help="Index of max syllable to render")
@click.option('-g', '--group', type=str, default=None, help="Name of group(s) to show", multiple=True)
@click.option('-g', '--group', type=str, default=None, help="the groups to include in the transition graph", multiple=True)
@click.option('--output-file', type=click.Path(), default=os.path.join(os.getcwd(), 'transitions'), help="Filename to store plot")
@click.option('--normalize', type=click.Choice(['bigram', 'rows', 'columns']), default='bigram', help="How to normalize transition probabilities")
@click.option('--edge-threshold', type=float, default=.001, help="Threshold for edges to show")
@click.option('--usage-threshold', type=float, default=0, help="Threshold for nodes to show")
@click.option('--layout', type=str, default='spring', help="Default networkx layout algorithm")
@click.option('--layout', type=str, default='spring', help="networkx layout algorithm")
@click.option('--keep-orphans', '-k', type=bool, is_flag=True, help="Show orphaned nodes")
@click.option('--orphan-weight', type=float, default=0, help="Weight for non-existent connections")
@click.option('--arrows', type=bool, is_flag=True, help="Show arrows")
Expand All @@ -143,27 +127,24 @@ def plot_verbose_position_heatmaps(index_file, output_file, normalize):
@click.option('--edge-scaling', type=float, default=250, help="Scale factor from transition probabilities to edge width")
@click.option('--node-scaling', type=float, default=1e5, help="Scale factor for nodes by usage")
@click.option('--scale-node-by-usage', type=bool, default=True, help="Scale node sizes by usages probabilities")
@click.option('--width-per-group', type=float, default=8, help="Width (in inches) for figure canvas per group")
@click.option('--width-per-group', type=float, default=8, help="Width for figure canvas per group")
def plot_transition_graph(index_file, model_fit, output_file, **config_data):

plot_transition_graph_wrapper(index_file, model_fit, output_file, config_data)

@cli.command(name='plot-stats', help="Plots syllable usages with different sorting,coloring and grouping capabilities")
@cli.command(name='plot-stats', help="Plot syllable usages with different sorting,coloring and grouping capabilities")
@click.argument('index-file', type=click.Path(exists=True, resolve_path=True))
@click.argument('model-fit', type=click.Path(exists=True, resolve_path=True))
@click.option('--stat', type=str, default='usage', help="Statistic to plot.")
@click.option('--stat', type=str, default='usage', help="Statistic to plot")
@click.option('--output-file', type=click.Path(), default=os.path.join(os.getcwd(), 'syll_stat'), help="Filename to store plot")
@click.option('--sort', type=bool, default=True, help="Sort syllables by usage")
@click.option('--figsize', type=tuple, default=(10, 5), help="Size in inches (w x h) of the plotted figure.")
@click.option('--figsize', type=tuple, default=(10, 5), help="Figure size of the plotted figure.")
@click.option('--count', type=click.Choice(['usage', 'frames']), default='usage', help='How to relabel syllables')
@click.option('--max-syllable', type=int, default=40, help="Index of max syllable to render")
@click.option('-g', '--group', type=str, default=None, help="Name of group(s) to show", multiple=True)
@click.option('-o', '--ordering', type=str, default='stat', help="How to order syllables in plot")
@click.option('--ctrl-group', type=str, default=None, help="Name of control group. Only if ordering = 'diff'")
@click.option('--exp-group', type=str, default=None, help="Name of experimental group. Only if ordering = 'diff'")
@click.option('-c', '--colors', type=str, default=None, help="Colors to plot groups with.", multiple=True)
@click.option('--ctrl-group', type=str, default=None, help="Name of control group")
@click.option('--exp-group', type=str, default=None, help="Name of experimental group")
@click.option('-c', '--colors', type=str, default=None, help="Colors to plot groups with", multiple=True)
def plot_stats(index_file, model_fit, output_file, **cli_kwargs):

plot_syllable_stat_wrapper(model_fit, index_file, output_file, **cli_kwargs)

click.echo(f'Syllable {cli_kwargs["stat"]} graph created successfully')
Loading

0 comments on commit 6681a72

Please sign in to comment.