Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve some components of #228 #340

Merged
merged 32 commits into from
Sep 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c429a14
Fix docs math for isotropic TV
bwohlberg Sep 12, 2022
22e822b
Correct docs on isotropic/anisotripic
bwohlberg Sep 12, 2022
a93c363
Correct example title
bwohlberg Sep 12, 2022
e92c0f9
Improve some titles and header descriptions
bwohlberg Sep 12, 2022
da79467
Minor edit
bwohlberg Sep 13, 2022
1afaecb
Rename example
bwohlberg Sep 13, 2022
c288d93
Correct example title
bwohlberg Sep 13, 2022
a464d86
Clean up titles and header descriptions
bwohlberg Sep 13, 2022
16a346d
Update example index
bwohlberg Sep 13, 2022
9a9c053
Move significant functions to a separate module
bwohlberg Sep 13, 2022
e55c014
Fix imports
bwohlberg Sep 13, 2022
c2d99d0
Add script to update notebook markdown without re-run
bwohlberg Sep 13, 2022
86d53b3
Update readme
bwohlberg Sep 13, 2022
b370955
Avoid duplicate label warnings
bwohlberg Sep 13, 2022
560cff7
Re-arrange examples in index
bwohlberg Sep 13, 2022
32858dd
Clean up titles and header descriptions
bwohlberg Sep 13, 2022
dd9d657
Updated example index
bwohlberg Sep 13, 2022
72ed38f
Merge branch 'main' into brendt/issue#228
bwohlberg Sep 13, 2022
d3ec9a0
Update submodule
bwohlberg Sep 13, 2022
de8b486
Modify index and simplify some titles
bwohlberg Sep 13, 2022
8165b56
Fix bug in notebook build functions
bwohlberg Sep 13, 2022
c0f12f7
Update submodule
bwohlberg Sep 13, 2022
a857a9d
Update submodule
Sep 13, 2022
e4e5d8f
Update index
bwohlberg Sep 13, 2022
971c1f8
Improve index order
bwohlberg Sep 13, 2022
0864104
Improve index order
bwohlberg Sep 13, 2022
de68899
Update submodule
bwohlberg Sep 13, 2022
7f4d05e
Merge branch 'main' into brendt/issue#228
bwohlberg Sep 14, 2022
26f85c4
Changes in response to PR review
bwohlberg Sep 14, 2022
a1a9ed6
Update submodule
bwohlberg Sep 14, 2022
7d947b3
Update index
bwohlberg Sep 14, 2022
69a2c1a
Update submodule
bwohlberg Sep 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,17 @@ def patched_parse(self):

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["tmp", "*.tmp.*", "*.tmp", "index.ipynb", "exampledepend.rst"]
exclude_patterns = [
"tmp",
"*.tmp.*",
"*.tmp",
"index.ipynb",
"exampledepend.rst",
"blockarray.rst",
"operator.rst",
"functional.rst",
"optimizer.rst",
]

# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = False
Expand Down
40 changes: 20 additions & 20 deletions docs/source/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ Computed Tomography
:maxdepth: 1

examples/ct_abel_tv_admm
examples/ct_astra_pcg
examples/ct_astra_noreg_pcg
examples/ct_astra_tv_admm
examples/ct_astra_weighted_tv_admm
examples/ct_svmbir_tv_multi
examples/ct_svmbir_ppp_bm3d_admm_cg
examples/ct_svmbir_ppp_bm3d_admm_prox
examples/ct_fan_svmbir_ppp_bm3d_admm_prox
examples/ct_svmbir_tv_multi


Deconvolution
Expand All @@ -39,14 +39,14 @@ Deconvolution
:maxdepth: 1

examples/deconv_circ_tv_admm
examples/deconv_tv_admm
examples/deconv_tv_admm_tune
examples/deconv_microscopy_tv_admm
examples/deconv_microscopy_allchn_tv_admm
examples/deconv_ppp_bm3d_admm
examples/deconv_ppp_bm3d_pgm
examples/deconv_ppp_bm4d_admm
examples/deconv_ppp_dncnn_admm
examples/deconv_tv_admm
examples/deconv_tv_admm_tune
examples/deconv_ppp_bm4d_admm


Sparse Coding
Expand All @@ -67,12 +67,12 @@ Miscellaneous
:maxdepth: 1

examples/demosaic_ppp_bm3d_admm
examples/denoise_cplx_tv_pdhg
examples/superres_ppp_dncnn_admm
examples/denoise_l1tv_admm
examples/denoise_tv_admm
examples/denoise_tv_pgm
examples/denoise_tv_multi
examples/superres_ppp_dncnn_admm
examples/denoise_cplx_tv_pdhg
examples/video_rpca_admm


Expand All @@ -94,8 +94,8 @@ Plug and Play Priors
examples/ct_fan_svmbir_ppp_bm3d_admm_prox
examples/deconv_ppp_bm3d_admm
examples/deconv_ppp_bm3d_pgm
examples/deconv_ppp_bm4d_admm
examples/deconv_ppp_dncnn_admm
examples/deconv_ppp_bm4d_admm
examples/demosaic_ppp_bm3d_admm
examples/superres_ppp_dncnn_admm

Expand All @@ -111,15 +111,15 @@ Total Variation
examples/ct_astra_weighted_tv_admm
examples/ct_svmbir_tv_multi
examples/deconv_circ_tv_admm
examples/deconv_microscopy_tv_admm
examples/deconv_microscopy_allchn_tv_admm
examples/deconv_tv_admm
examples/deconv_tv_admm_tune
examples/denoise_cplx_tv_pdhg
examples/deconv_microscopy_tv_admm
examples/deconv_microscopy_allchn_tv_admm
examples/denoise_l1tv_admm
examples/denoise_tv_admm
examples/denoise_tv_pgm
examples/denoise_tv_multi
examples/denoise_cplx_tv_pdhg


Sparsity
Expand Down Expand Up @@ -150,24 +150,24 @@ ADMM
examples/ct_abel_tv_admm
examples/ct_astra_tv_admm
examples/ct_astra_weighted_tv_admm
examples/ct_svmbir_tv_multi
examples/ct_svmbir_ppp_bm3d_admm_cg
examples/ct_svmbir_ppp_bm3d_admm_prox
examples/ct_fan_svmbir_ppp_bm3d_admm_prox
examples/ct_svmbir_tv_multi
examples/deconv_circ_tv_admm
examples/deconv_tv_admm
examples/deconv_tv_admm_tune
examples/deconv_microscopy_tv_admm
examples/deconv_microscopy_allchn_tv_admm
examples/deconv_ppp_bm3d_admm
examples/deconv_ppp_bm4d_admm
examples/deconv_ppp_dncnn_admm
examples/deconv_tv_admm
examples/deconv_tv_admm_tune
examples/deconv_ppp_bm4d_admm
examples/sparsecode_admm
examples/demosaic_ppp_bm3d_admm
examples/superres_ppp_dncnn_admm
examples/denoise_l1tv_admm
examples/denoise_tv_admm
examples/denoise_tv_multi
examples/sparsecode_admm
examples/superres_ppp_dncnn_admm
examples/video_rpca_admm


Expand All @@ -188,8 +188,8 @@ PDHG
:maxdepth: 1

examples/ct_svmbir_tv_multi
examples/denoise_cplx_tv_pdhg
examples/denoise_tv_multi
examples/denoise_cplx_tv_pdhg


PGM
Expand All @@ -199,9 +199,9 @@ PGM
:maxdepth: 1

examples/deconv_ppp_bm3d_pgm
examples/denoise_tv_pgm
examples/sparsecode_pgm
examples/sparsecode_poisson_pgm
examples/denoise_tv_pgm


PCG
Expand All @@ -210,4 +210,4 @@ PCG
.. toctree::
:maxdepth: 1

examples/ct_astra_pcg
examples/ct_astra_noreg_pcg
3 changes: 3 additions & 0 deletions examples/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ A number of files in this directory assist in the mangement of the usage example
`makenotebooks.py <makenotebooks.py>`_
Auto-generate Jupyter notebooks from the example scripts.

`updatejnbmd.py <updatejnbmd.py>`_
Update markdown cells in notebooks from corresponding example scripts.

`makeindex.py <makeindex.py>`_
Auto-generate the docs example index ``docs/source/examples.rst`` from the example scripts index ``scripts/index.rst``.

Expand Down
223 changes: 223 additions & 0 deletions examples/jnb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2022 by SCICO Developers
# All rights reserved. BSD 3-clause License.
# This file is part of the SCICO package. Details of the copyright and
# user license can be found in the 'LICENSE' file distributed with the
# package.

"""Support functions for manipulating Jupyter notebooks."""


import re
from timeit import default_timer as timer

import nbformat
from nbconvert.preprocessors import CellExecutionError, ExecutePreprocessor
from py2jn.tools import py_string_to_notebook, write_notebook


def py_file_to_string(src):
"""Preprocess example script file and return result as a string."""

with open(src, "r") as srcfile:
# Drop header comment
for line in srcfile:
if line[0] != "#":
break # assume first non-comment line is a newline that can be dropped
# Insert notebook plot config after last import
lines = []
import_seen = False
for line in srcfile:
line = re.sub('^r"""', '"""', line) # remove r from r"""
line = re.sub(":cite:`([^`]+)`", r'<cite data-cite="\1"/>', line) # fix cite format
if import_seen:
# Once an import statement has been seen, break on encountering a line that
# is neither an import statement nor a newline, nor a component of an import
# statement extended over multiple lines, nor an os.environ statement, nor
# components of a try/except construction (note that handling of these final
# two cases is probably not very robust).
if not re.match(
r"(^import|^from|^\n$|^\W+[^\W]|^\)$|^os.environ|^try:$|^except)", line
):
lines.append(line)
break
else:
# Set flag indicating that an import statement has been seen once one has
# been encountered
if re.match("^(import|from)", line):
import_seen = True
lines.append(line)
# Backtrack through list of lines to find last import statement
n = 1
for line in lines[-2::-1]:
if re.match("^(import|from)", line):
break
else:
n += 1
# Insert notebook plotting config directly after last import statement
lines.insert(-n, "plot.config_notebook_plotting()\n")

# Process remainder of source file
for line in srcfile:
if re.match("^input\(", line): # end processing when input statement encountered
break
line = re.sub('^r"""', '"""', line) # remove r from r"""
line = re.sub(":cite:\`([^`]+)\`", r'<cite data-cite="\1"/>', line) # fix cite format
lines.append(line)

# Backtrack through list of lines to remove trailing newlines
n = 0
for line in lines[::-1]:
if re.match("^\n$", line):
n += 1
else:
break
lines = lines[0:-n]

return "".join(lines)


def script_to_notebook(src, dst):
"""Convert a Python example script into a Jupyter notebook."""

s = py_file_to_string(src)
nb = py_string_to_notebook(s)
write_notebook(nb, dst)


def read_notebook(fname):
"""Read a notebook from the specified notebook file."""

try:
nb = nbformat.read(fname, as_version=4)
except (AttributeError, nbformat.reader.NotJSONError):
raise RuntimeError("Error reading notebook file %s." % fname)
return nb


def execute_notebook(fname):
"""Execute the specified notebook file."""

with open(fname) as f:
nb = nbformat.read(f, as_version=4)
ep = ExecutePreprocessor()
try:
t0 = timer()
out = ep.preprocess(nb)
t1 = timer()
with open(fname, "w", encoding="utf-8") as f:
nbformat.write(nb, f)
except CellExecutionError:
print(f"ERROR executing {fname}")
return False
print(f"{fname} done in {(t1 - t0):.1e} s")
return True


def notebook_executed(nbfn):
"""Determine whether the notebook at `nbfn` has been executed."""

try:
nb = nbformat.read(nbfn, as_version=4)
except (AttributeError, nbformat.reader.NotJSONError):
raise RuntimeError("Error reading notebook file %s." % pth)
cells = nb["worksheets"][0]["cells"]
for n in range(len(nb["cells"])):
if cells[n].cell_type == "code" and cells[n].execution_count is None:
return False
return True


def same_notebook_code(nb1, nb2):
"""Return ``True`` if the code cells of notebook objects `nb1` and `nb2`
are all the same.
"""

if "cells" in nb1:
nb1c = nb1["cells"]
else:
nb1c = nb1["worksheets"][0]["cells"]
if "cells" in nb2:
nb2c = nb2["cells"]
else:
nb2c = nb2["worksheets"][0]["cells"]

# Notebooks do not match if the number of cells differ
if len(nb1c) != len(nb2c):
return False

# Iterate over cells in nb1
for n in range(len(nb1c)):
# Notebooks do not match if corresponding cells have different
# types
if nb1c[n]["cell_type"] != nb2c[n]["cell_type"]:
return False
# Notebooks do not match if source of corresponding code cells
# differ
if nb1c[n]["cell_type"] == "code" and nb1c[n]["source"] != nb2c[n]["source"]:
return False

return True


def same_notebook_markdown(nb1, nb2):
"""Return ``True`` if the markdown cells of notebook objects `nb1`
and `nb2` are all the same.
"""

if "cells" in nb1:
nb1c = nb1["cells"]
else:
nb1c = nb1["worksheets"][0]["cells"]
if "cells" in nb2:
nb2c = nb2["cells"]
else:
nb2c = nb2["worksheets"][0]["cells"]

# Notebooks do not match if the number of cells differ
if len(nb1c) != len(nb2c):
return False

# Iterate over cells in nb1
for n in range(len(nb1c)):
# Notebooks do not match if corresponding cells have different
# types
if nb1c[n]["cell_type"] != nb2c[n]["cell_type"]:
return False
# Notebooks do not match if source of corresponding code cells
# differ
if nb1c[n]["cell_type"] == "markdown" and nb1c[n]["source"] != nb2c[n]["source"]:
return False

return True


def replace_markdown_cells(src, dst):
"""Overwrite markdown cells in notebook object `dst` with corresponding
cells in notebook object `src`.
"""

if "cells" in src:
srccell = src["cells"]
else:
srccell = src["worksheets"][0]["cells"]
if "cells" in dst:
dstcell = dst["cells"]
else:
dstcell = dst["worksheets"][0]["cells"]

# It is an error to attempt markdown replacement if src and dst
# have different numbers of cells
if len(srccell) != len(dstcell):
raise ValueError("Notebooks do not have the same number of cells.")

# Iterate over cells in src
for n in range(len(srccell)):
# It is an error to attempt markdown replacement if any
# corresponding pair of cells have different type
if srccell[n]["cell_type"] != dstcell[n]["cell_type"]:
raise ValueError("Cell number %d of different type in src and dst.")
# If current src cell is a markdown cell, copy the src cell to
# the dst cell
if srccell[n]["cell_type"] == "markdown":
dstcell[n]["source"] = srccell[n]["source"]
Loading