Skip to content

Commit

Permalink
Merge pull request #34 from jchodera/docs-skeleton
Browse files Browse the repository at this point in the history
Basic docs skeleton
  • Loading branch information
jchodera committed Jun 2, 2015
2 parents 4d53247 + ba0b2f0 commit 6b4af63
Show file tree
Hide file tree
Showing 4 changed files with 320 additions and 11 deletions.
10 changes: 7 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -104,15 +108,15 @@

# 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
# documentation.
#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
# "<project> v<release> documentation".
Expand All @@ -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
Expand Down
69 changes: 61 additions & 8 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -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 <quickstart.html>`_

Get involved
------------
* Download the code or for a repo on `GitHub <https://github.com/bhmm/bhmm>`_
* See BHMM in `action <examples/index.html>`_
* Report a bug or request a feature on the `GitHub issue tracker <https://github.com/bhmm/bhmm/issues>`_

--------------------------------------------------------------------------------

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
</div>

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
==================
Expand Down
177 changes: 177 additions & 0 deletions docs/sphinxext/notebook_sphinxext.py
Original file line number Diff line number Diff line change
@@ -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('<head>', 1)[1].split('</head>',1)[0]
body = output.split('<body>', 1)[1].split('</body>',1)[0]

# http://imgur.com/eR9bMRH
header = header.replace('<style', '<style scoped="scoped"')
header = header.replace('body {\n overflow: visible;\n padding: 8px;\n}\n', '')

# Filter out styles that conflict with the sphinx theme.
filter_strings = [
'navbar',
'body{',
'alert{',
'uneditable-input{',
'collapse{',
]
filter_strings.extend(['h%s{' % (i+1) for i in range(6)])

header_lines = filter(
lambda x: not any([s in x for s in filter_strings]), header.split('\n'))
header = '\n'.join(header_lines)

# concatenate raw html lines
lines = ['<div class="ipynotebook">']
lines.append(header)
lines.append(body)
lines.append('</div>')
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)

75 changes: 75 additions & 0 deletions docs/sphinxext/notebookcell_sphinxext.py
Original file line number Diff line number Diff line change
@@ -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')

0 comments on commit 6b4af63

Please sign in to comment.