diff --git a/docs/conf.py b/docs/conf.py index a6ae036..0748339 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,6 +15,10 @@ import sys import os +sys.path.insert(0, os.path.abspath('sphinxext')) # for sphinx extensions +sys.path.insert(0, os.path.abspath('themes/sphinx_rtd_theme-0.1.5')) # for themes +import sphinx_rtd_theme + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. @@ -104,7 +108,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -112,7 +116,7 @@ #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". @@ -123,7 +127,7 @@ # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +html_logo = '_static/bhmm-logo.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 diff --git a/docs/index.rst b/docs/index.rst index d37126f..b2fde80 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,17 +1,70 @@ -.. bhmm documentation master file, created by - sphinx-quickstart on Tue Feb 17 11:49:20 2015. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. +#### +BHMM +#### -Welcome to bhmm's documentation! -================================ +**Bayesian hidden Markov models** -Contents: +Features +-------- +* Bayesian extensions of hidden Markov models (HMMs) that allow for the characterization of statistical uncertianty +* Tools for the analysis of single-molecule force spectroscopy +Get Going +--------- +* `Get BHMM up and running now `_ + +Get involved +------------ +* Download the code or for a repo on `GitHub `_ +* See BHMM in `action `_ +* Report a bug or request a feature on the `GitHub issue tracker `_ + +-------------------------------------------------------------------------------- + +Documentation +------------- + +.. toctree:: + :maxdepth: 1 + + quickstart + installation + running + theory + algorithms + analysis + validation + references + acknowledgments + whatsnew + faq + zbibliography + +API Reference +------------- +.. toctree:: + :maxdepth: 1 + + bhmm + +Developing +---------- .. toctree:: - :maxdepth: 2 + :maxdepth: 1 + + bhmm_design + building_docs + style + +-------------------------------------------------------------------------------- +.. raw:: html + +License +------- +BHMM is licensed under the Lesser GNU General Public License (LGPL v2.1+). +See the `BHMM` file distributed with YANK for more details. Indices and tables ================== diff --git a/docs/sphinxext/notebook_sphinxext.py b/docs/sphinxext/notebook_sphinxext.py new file mode 100644 index 0000000..e2785c3 --- /dev/null +++ b/docs/sphinxext/notebook_sphinxext.py @@ -0,0 +1,177 @@ +import os +import shutil +import glob + +from sphinx.util.compat import Directive +from docutils import nodes +from docutils.parsers.rst import directives +from IPython.nbconvert import html, python + +from runipy.notebook_runner import NotebookRunner + + +HERE = os.path.dirname(os.path.abspath(__file__)) +IPYTHON_NOTEBOOK_DIR = "%s/../../examples" % HERE + +class NotebookDirective(Directive): + """Insert an evaluated notebook into a document + + This uses runipy and nbconvert to transform a path to an unevaluated notebook + into html suitable for embedding in a Sphinx document. + """ + required_arguments = 1 + optional_arguments = 1 + option_spec = {'skip_exceptions' : directives.flag} + + def run(self): + # check if raw html is supported + if not self.state.document.settings.raw_enabled: + raise self.warning('"%s" directive disabled.' % self.name) + + # get path to notebook + source_dir = os.path.dirname( + os.path.abspath(self.state.document.current_source)) + nb_basename = os.path.basename(self.arguments[0]) + rst_file = self.state_machine.document.attributes['source'] + rst_dir = os.path.abspath(os.path.dirname(rst_file)) + nb_abs_path = os.path.join(IPYTHON_NOTEBOOK_DIR, nb_basename) + + # Move files around. + rel_dir = os.path.relpath(rst_dir, setup.confdir) + rel_path = os.path.join(rel_dir, nb_basename) + dest_dir = os.path.join(setup.app.builder.outdir, rel_dir) + dest_path = os.path.join(dest_dir, nb_basename) + + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + + # Copy unevaluated script + try: + shutil.copyfile(nb_abs_path, dest_path) + except IOError: + raise RuntimeError("Unable to copy notebook to build destination. %s -> %s" % (nb_abs_path, dest_path)) + + dest_path_eval = dest_path.replace('.ipynb', '_evaluated.ipynb') + dest_path_script = dest_path.replace('.ipynb', '.py') + rel_path_eval = nb_basename.replace('.ipynb', '_evaluated.ipynb') + rel_path_script = nb_basename.replace('.ipynb', '.py') + + # Create python script vesion + unevaluated_text = nb_to_html(nb_abs_path) + script_text = nb_to_python(nb_abs_path) + f = open(dest_path_script, 'wb') + f.write(script_text.encode('utf8')) + f.close() + + skip_exceptions = 'skip_exceptions' in self.options + + try: + evaluated_text = evaluate_notebook(nb_abs_path, dest_path_eval, + skip_exceptions=skip_exceptions) + except: + # bail + return [] + + # Create link to notebook and script files + link_rst = "(" + \ + formatted_link(nb_basename) + "; " + \ + formatted_link(rel_path_eval) + "; " + \ + formatted_link(rel_path_script) + \ + ")" + + self.state_machine.insert_input([link_rst], rst_file) + + # create notebook node + attributes = {'format': 'html', 'source': 'nb_path'} + nb_node = notebook_node('', evaluated_text, **attributes) + (nb_node.source, nb_node.line) = \ + self.state_machine.get_source_and_line(self.lineno) + + # add dependency + self.state.document.settings.record_dependencies.add(nb_abs_path) + + # clean up png files left behind by notebooks. + png_files = glob.glob("*.png") + fits_files = glob.glob("*.fits") + h5_files = glob.glob("*.h5") + for file in png_files: + os.remove(file) + + return [nb_node] + + + +class notebook_node(nodes.raw): + pass + +def nb_to_python(nb_path): + """convert notebook to python script""" + exporter = python.PythonExporter() + output, resources = exporter.from_filename(nb_path) + return output + +def nb_to_html(nb_path): + """convert notebook to html""" + exporter = html.HTMLExporter(template_file='full') + output, resources = exporter.from_filename(nb_path) + header = output.split('', 1)[1].split('',1)[0] + body = output.split('', 1)[1].split('',1)[0] + + # http://imgur.com/eR9bMRH + header = header.replace(''] + lines.append(header) + lines.append(body) + lines.append('') + return '\n'.join(lines) + +def evaluate_notebook(nb_path, dest_path=None, skip_exceptions=False): + # Create evaluated version and save it to the dest path. + # Always use --pylab so figures appear inline + # perhaps this is questionable? + nb_runner = NotebookRunner(nb_in=nb_path, pylab=True) + nb_runner.run_notebook(skip_exceptions=skip_exceptions) + if dest_path is None: + dest_path = 'temp_evaluated.ipynb' + nb_runner.save_notebook(dest_path) + ret = nb_to_html(dest_path) + if dest_path is 'temp_evaluated.ipynb': + os.remove(dest_path) + return ret + +def formatted_link(path): + return "`%s <%s>`__" % (os.path.basename(path), path) + +def visit_notebook_node(self, node): + self.visit_raw(node) + +def depart_notebook_node(self, node): + self.depart_raw(node) + +def setup(app): + setup.app = app + setup.config = app.config + setup.confdir = app.confdir + + app.add_node(notebook_node, + html=(visit_notebook_node, depart_notebook_node)) + + app.add_directive('notebook', NotebookDirective) + diff --git a/docs/sphinxext/notebookcell_sphinxext.py b/docs/sphinxext/notebookcell_sphinxext.py new file mode 100644 index 0000000..5d122a3 --- /dev/null +++ b/docs/sphinxext/notebookcell_sphinxext.py @@ -0,0 +1,75 @@ +import os +import glob +import io + +from sphinx.util.compat import Directive +from docutils.parsers.rst import directives + +from IPython.nbformat import current + +from notebook_sphinxext import notebook_node, visit_notebook_node, \ + depart_notebook_node, evaluate_notebook + + +class NotebookCellDirective(Directive): + """Insert an evaluated notebook cell into a document + + This uses runipy and nbconvert to transform an inline python + script into html suitable for embedding in a Sphinx document. + """ + required_arguments = 0 + optional_arguments = 1 + has_content = True + option_spec = {'skip_exceptions': directives.flag} + + def run(self): + # check if raw html is supported + if not self.state.document.settings.raw_enabled: + raise self.warning('"%s" directive disabled.' % self.name) + + # Construct notebook from cell content + content = "\n".join(self.content) + with open("temp.py", "w") as f: + f.write(content) + + convert_to_ipynb('temp.py', 'temp.ipynb') + + skip_exceptions = 'skip_exceptions' in self.options + + try: + evaluated_text = \ + evaluate_notebook('temp.ipynb', skip_exceptions=skip_exceptions) + except: + # bail + return [] + + # create notebook node + attributes = {'format': 'html', 'source': 'nb_path'} + nb_node = notebook_node('', evaluated_text, **attributes) + (nb_node.source, nb_node.line) = \ + self.state_machine.get_source_and_line(self.lineno) + + # clean up + files = glob.glob("*.png") + ['temp.py', 'temp.ipynb'] + for file in files: + os.remove(file) + + return [nb_node] + + +def setup(app): + setup.app = app + setup.config = app.config + setup.confdir = app.confdir + + app.add_node(notebook_node, + html=(visit_notebook_node, depart_notebook_node)) + + app.add_directive('notebook-cell', NotebookCellDirective) + + +def convert_to_ipynb(py_file, ipynb_file): + with io.open(py_file, 'r', encoding='utf-8') as f: + notebook = current.reads(f.read(), format='py') + with io.open(ipynb_file, 'w', encoding='utf-8') as f: + current.write(notebook, f, format='ipynb')