From 5a89ef61a6d87ebab2e370417cc28b9f1dcd5b03 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Tue, 15 May 2012 00:52:30 -0400 Subject: [PATCH 1/5] DOC: Replace use of gen_rst with plot2rst extension. --- doc/ext/plot2rst.py | 502 +++++++++++++++++++++ doc/source/conf.py | 4 +- doc/source/themes/agogo/static/agogo.css_t | 1 + 3 files changed, 506 insertions(+), 1 deletion(-) create mode 100644 doc/ext/plot2rst.py diff --git a/doc/ext/plot2rst.py b/doc/ext/plot2rst.py new file mode 100644 index 00000000..05f1bae6 --- /dev/null +++ b/doc/ext/plot2rst.py @@ -0,0 +1,502 @@ +""" +Example generation from python files. + +Generate the rst files for the examples by iterating over the python +example files. Files that generate images should start with 'plot'. + +To generate your own examples, add ``'mpltools.sphinx.plot2rst'``` to the list +of ``extensions``in your Sphinx configuration file. In addition, make sure the +example directory(ies) in `plot2rst_paths` (see below) points to a directory +with examples named `plot_*.py` and include an `index.rst` file. + +This code was adapted from scikits-image, which took it from scikits-learn. + +Options +------- +The ``plot2rst`` extension accepts the following options: + +plot2rst_paths : length-2 tuple, or list of tuples + Tuple or list of tuples of paths to (python plot, generated rst) files, + i.e. (source, destination). Note that both paths are relative to Sphinx + 'source' directory. Defaults to ('../examples', 'auto_examples') + +plot2rst_rcparams : dict + Matplotlib configuration parameters. See + http://matplotlib.sourceforge.net/users/customizing.html for details. + +plot2rst_default_thumb : str + Path (relative to doc root) of default thumbnail image. + +plot2rst_thumb_scale : float + Scale factor for thumbnail (e.g., 0.2 to scale plot to 1/5th the + original size). + +plot2rst_plot_tag : str + When this tag is found in the example file, the current plot is saved and + tag is replaced with plot path. Defaults to 'PLOT2RST.current_figure'. + + +Suggested CSS definitions +------------------------- + + div.body h2 { + border-bottom: 1px solid #BBB; + clear: left; + } + + /*---- example gallery ----*/ + + .gallery.figure { + float: left; + margin: 1em; + } + + .gallery.figure img{ + display: block; + margin-left: auto; + margin-right: auto; + width: 200px; + } + + .gallery.figure .caption { + width: 200px; + text-align: center !important; + } + +""" +import os +import shutil +import token +import tokenize + +import numpy as np +import matplotlib +matplotlib.use('Agg') +import matplotlib.pyplot as plt +from matplotlib import image + + +LITERALINCLUDE = """ +.. literalinclude:: {src_name} + :lines: {code_start}- + +""" + +CODE_LINK = """ + +**Python source code:** :download:`download <{0}>` +(generated using ``mpltools`` |version|) + +""" + +TOCTREE_TEMPLATE = """ +.. toctree:: + :hidden: + + %s + +""" + +IMAGE_TEMPLATE = """ +.. image:: images/%s + :align: center + +""" + +GALLERY_IMAGE_TEMPLATE = """ +.. figure:: %(thumb)s + :figclass: gallery + :target: ./%(source)s.html + + :ref:`example_%(link_name)s` + +""" + + +class Path(str): + """Path object for manipulating directory and file paths.""" + + def __init__(self, path): + super(Path, self).__init__(path) + + @property + def isdir(self): + return os.path.isdir(self) + + @property + def exists(self): + """Return True if path exists""" + return os.path.exists(self) + + def pjoin(self, *args): + """Join paths. `p` prefix prevents confusion with string method.""" + return self.__class__(os.path.join(self, *args)) + + def psplit(self): + """Split paths. `p` prefix prevents confusion with string method.""" + return [self.__class__(p) for p in os.path.split(self)] + + def makedirs(self): + if not self.exists: + os.makedirs(self) + + def listdir(self): + return os.listdir(self) + + def format(self, *args, **kwargs): + return self.__class__(super(Path, self).format(*args, **kwargs)) + + def __add__(self, other): + return self.__class__(super(Path, self).__add__(other)) + + def __iadd__(self, other): + return self.__add__(other) + + +def setup(app): + app.connect('builder-inited', generate_example_galleries) + + app.add_config_value('plot2rst_paths', + ('../examples', 'auto_examples'), True) + app.add_config_value('plot2rst_rcparams', {}, True) + app.add_config_value('plot2rst_default_thumb', None, True) + app.add_config_value('plot2rst_thumb_scale', 0.25, True) + app.add_config_value('plot2rst_plot_tag', 'PLOT2RST.current_figure', True) + app.add_config_value('plot2rst_index_name', 'index', True) + + +def generate_example_galleries(app): + cfg = app.builder.config + + doc_src = Path(os.path.abspath(app.builder.srcdir)) # path/to/doc/source + + if isinstance(cfg.plot2rst_paths, tuple): + cfg.plot2rst_paths = [cfg.plot2rst_paths] + for src_dest in cfg.plot2rst_paths: + plot_path, rst_path = [Path(p) for p in src_dest] + example_dir = doc_src.pjoin(plot_path) + rst_dir = doc_src.pjoin(rst_path) + generate_examples_and_gallery(example_dir, rst_dir, cfg) + + +def generate_examples_and_gallery(example_dir, rst_dir, cfg): + """Generate rst from examples and create gallery to showcase examples.""" + if not example_dir.exists: + print "No example directory found at", example_dir + return + rst_dir.makedirs() + + # we create an index.rst with all examples + gallery_index = file(rst_dir.pjoin('index'+cfg.source_suffix), 'w') + + # Here we don't use an os.walk, but we recurse only twice: flat is + # better than nested. + write_gallery(gallery_index, example_dir, rst_dir, cfg) + for d in sorted(example_dir.listdir()): + example_sub = example_dir.pjoin(d) + if example_sub.isdir: + rst_sub = rst_dir.pjoin(d) + rst_sub.makedirs() + write_gallery(gallery_index, example_sub, rst_sub, cfg, depth=1) + gallery_index.flush() + + +def write_gallery(gallery_index, src_dir, rst_dir, cfg, depth=0): + """Generate the rst files for an example directory, i.e. gallery. + + Write rst files from python examples and add example links to gallery. + + Parameters + ---------- + gallery_index : file + Index file for plot gallery. + src_dir : 'str' + Source directory for python examples. + rst_dir : 'str' + Destination directory for rst files generated from python examples. + cfg : config object + Sphinx config object created by Sphinx. + """ + index_name = cfg.plot2rst_index_name + cfg.source_suffix + gallery_template = src_dir.pjoin(index_name) + if not os.path.exists(gallery_template): + print src_dir + print 80*'_' + print ('Example directory %s does not have a %s file' + % (src_dir, index_name)) + print 'Skipping this directory' + print 80*'_' + return + + gallery_description = file(gallery_template).read() + gallery_index.write('\n\n%s\n\n' % gallery_description) + + rst_dir.makedirs() + examples = [fname for fname in sorted(src_dir.listdir(), key=_plots_first) + if fname.endswith('py')] + ex_names = [ex[:-3] for ex in examples] # strip '.py' extension + if depth == 0: + sub_dir = Path('') + else: + sub_dir_list = src_dir.psplit()[-depth:] + sub_dir = Path('/'.join(sub_dir_list) + '/') + gallery_index.write(TOCTREE_TEMPLATE % (sub_dir + '\n '.join(ex_names))) + + for src_name in examples: + write_example(src_name, src_dir, rst_dir, cfg) + + link_name = sub_dir.pjoin(src_name) + link_name = link_name.replace(os.path.sep, '_') + if link_name.startswith('._'): + link_name = link_name[2:] + + info = {} + info['thumb'] = sub_dir.pjoin('images/thumb', src_name[:-3] + '.png') + info['source'] = sub_dir + src_name[:-3] + info['link_name'] = link_name + gallery_index.write(GALLERY_IMAGE_TEMPLATE % info) + + +def _plots_first(fname): + """Decorate filename so that examples with plots are displayed first.""" + if not (fname.startswith('plot') and fname.endswith('.py')): + return 'zz' + fname + return fname + + +def write_example(src_name, src_dir, rst_dir, cfg): + """Write rst file from a given python example. + + Parameters + ---------- + src_name : str + Name of example file. + src_dir : 'str' + Source directory for python examples. + rst_dir : 'str' + Destination directory for rst files generated from python examples. + cfg : config object + Sphinx config object created by Sphinx. + """ + last_dir = src_dir.psplit()[-1] + # to avoid leading . in file names, and wrong names in links + if last_dir == '.' or last_dir == 'examples': + last_dir = Path('') + else: + last_dir += '_' + + src_path = src_dir.pjoin(src_name) + example_file = rst_dir.pjoin(src_name) + shutil.copyfile(src_path, example_file) + + image_dir = rst_dir.pjoin('images') + thumb_dir = image_dir.pjoin('thumb') + image_dir.makedirs() + thumb_dir.makedirs() + + base_image_name = os.path.splitext(src_name)[0] + image_path = image_dir.pjoin(base_image_name + '_{0}.png') + + basename, py_ext = os.path.splitext(src_name) + rst_path = rst_dir.pjoin(basename + cfg.source_suffix) + + if _plots_are_current(src_path, image_path) and rst_path.exists: + return + + blocks = split_code_and_text_blocks(example_file) + if blocks[0][2].startswith('#!'): + blocks.pop(0) # don't add shebang line to rst file. + + rst_link = '.. _example_%s:\n\n' % (last_dir + src_name) + figure_list, rst = process_blocks(blocks, src_path, image_path, cfg) + + has_inline_plots = any(cfg.plot2rst_plot_tag in b[2] for b in blocks) + if has_inline_plots: + example_rst = ''.join([rst_link, rst]) + else: + # print first block of text, display all plots, then display code. + first_text_block = [b for b in blocks if b[0] == 'text'][0] + label, (start, end), content = first_text_block + figure_list = save_all_figures(image_path) + rst_blocks = [IMAGE_TEMPLATE % f.lstrip('/') for f in figure_list] + + example_rst = rst_link + example_rst += eval(content) + example_rst += ''.join(rst_blocks) + code_info = dict(src_name=src_name, code_start=end) + example_rst += LITERALINCLUDE.format(**code_info) + + example_rst += CODE_LINK.format(src_name) + + f = open(rst_path,'w') + f.write(example_rst) + f.flush() + + thumb_path = thumb_dir.pjoin(src_name[:-3] + '.png') + first_image_file = image_dir.pjoin(figure_list[0].lstrip('/')) + if first_image_file.exists: + image.thumbnail(first_image_file, thumb_path, cfg.plot2rst_thumb_scale) + + if not thumb_path.exists: + if cfg.plot2rst_default_thumb is None: + print "WARNING: No plots found and default thumbnail not defined." + print "Specify 'plot2rst_default_thumb' in Sphinx config file." + else: + shutil.copy(cfg.plot2rst_default_thumb, thumb_path) + + +def _plots_are_current(src_path, image_path): + first_image_file = Path(image_path.format(1)) + needs_replot = (not first_image_file.exists or + _mod_time(first_image_file) <= _mod_time(src_path)) + return not needs_replot + + +def _mod_time(file_path): + return os.stat(file_path).st_mtime + + +def split_code_and_text_blocks(source_file): + """Return list with source file separated into code and text blocks. + + Returns + ------- + blocks : list of (label, (start, end+1), content) + List where each element is a tuple with the label ('text' or 'code'), + the (start, end+1) line numbers, and content string of block. + """ + block_edges, idx_first_text_block = get_block_edges(source_file) + + with open(source_file) as f: + source_lines = f.readlines() + + # Every other block should be a text block + idx_text_block = np.arange(idx_first_text_block, len(block_edges), 2) + blocks = [] + slice_ranges = zip(block_edges[:-1], block_edges[1:]) + for i, (start, end) in enumerate(slice_ranges): + block_label = 'text' if i in idx_text_block else 'code' + # subtract 1 from indices b/c line numbers start at 1, not 0 + content = ''.join(source_lines[start-1:end-1]) + blocks.append((block_label, (start, end), content)) + return blocks + + +def get_block_edges(source_file): + """Return starting line numbers of code and text blocks + + Returns + ------- + block_edges : list of int + Line number for the start of each block. Note the + idx_first_text_block : {0 | 1} + 0 if first block is text then, else 1 (second block better be text). + """ + block_edges = [] + with open(source_file) as f: + token_iter = tokenize.generate_tokens(f.readline) + for token_tuple in token_iter: + t_id, t_str, (srow, scol), (erow, ecol), src_line = token_tuple + if (token.tok_name[t_id] == 'STRING' and scol == 0): + # Add one point to line after text (for later slicing) + block_edges.extend((srow, erow+1)) + idx_first_text_block = 0 + # when example doesn't start with text block. + if not block_edges[0] == 1: + block_edges.insert(0, 1) + idx_first_text_block = 1 + # when example doesn't end with text block. + if not block_edges[-1] == erow: # iffy: I'm using end state of loop + block_edges.append(erow) + return block_edges, idx_first_text_block + + +def process_blocks(blocks, src_path, image_path, cfg): + """Run source, save plots as images, and convert blocks to rst. + + Parameters + ---------- + blocks : list of block tuples + Code and text blocks from example. See `split_code_and_text_blocks`. + src_path : str + Path to example file. + image_path : str + Path where plots are saved (format string which accepts figure number). + cfg : config object + Sphinx config object created by Sphinx. + + Returns + ------- + figure_list : list + List of figure names saved by the example. + rst_text : str + Text with code wrapped code-block directives. + """ + src_dir, src_name = src_path.psplit() + if not src_name.startswith('plot'): + return [], '' + + # index of blocks which have inline plots + inline_tag = cfg.plot2rst_plot_tag + idx_inline_plot = [i for i, b in enumerate(blocks) + if inline_tag in b[2]] + + image_dir, image_fmt_str = image_path.psplit() + + figure_list = [] + plt.rcdefaults() + plt.rcParams.update(cfg.plot2rst_rcparams) + plt.close('all') + + example_globals = {} + rst_blocks = [] + fig_num = 1 + for i, (blabel, brange, bcontent) in enumerate(blocks): + if blabel == 'code': + exec(bcontent, example_globals) + rst_blocks.append(codestr2rst(bcontent)) + else: + if i in idx_inline_plot: + plt.savefig(image_path.format(fig_num)) + figure_name = image_fmt_str.format(fig_num) + fig_num += 1 + figure_list.append(figure_name) + figure_link = os.path.join('images', figure_name) + bcontent = bcontent.replace(inline_tag, figure_link) + rst_blocks.append(docstr2rst(bcontent)) + return figure_list, '\n'.join(rst_blocks) + + +def codestr2rst(codestr): + """Return reStructuredText code block from code string""" + code_directive = ".. code-block:: python\n\n" + indented_block = '\t' + codestr.replace('\n', '\n\t') + return code_directive + indented_block + + +def docstr2rst(docstr): + """Return reStructuredText from docstring""" + idx_whitespace = len(docstr.rstrip()) - len(docstr) + whitespace = docstr[idx_whitespace:] + return eval(docstr) + whitespace + + +def save_all_figures(image_path): + """Save all matplotlib figures. + + Parameters + ---------- + image_path : str + Path where plots are saved (format string which accepts figure number). + """ + figure_list = [] + image_dir, image_fmt_str = image_path.psplit() + fig_mngr = matplotlib._pylab_helpers.Gcf.get_all_fig_managers() + for fig_num in (m.num for m in fig_mngr): + # Set the fig_num figure as the current figure as we can't + # save a figure that's not the current figure. + plt.figure(fig_num) + plt.savefig(image_path.format(fig_num)) + figure_list.append(image_fmt_str.format(fig_num)) + return figure_list + diff --git a/doc/source/conf.py b/doc/source/conf.py index 92a0e1db..727b4bc4 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -32,7 +32,7 @@ except: # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.pngmath', 'numpydoc', - 'sphinx.ext.autosummary', 'plot_directive', 'gen_rst'] + 'sphinx.ext.autosummary', 'plot_directive', 'plot2rst'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -257,3 +257,5 @@ matplotlib.rcParams.update({ """ plot_include_source = True plot_formats = [('png', 100)] + +plot2rst_index_name = 'README' diff --git a/doc/source/themes/agogo/static/agogo.css_t b/doc/source/themes/agogo/static/agogo.css_t index e35202c2..2ff4abad 100644 --- a/doc/source/themes/agogo/static/agogo.css_t +++ b/doc/source/themes/agogo/static/agogo.css_t @@ -79,6 +79,7 @@ h1, h2, h3, h4 { font-weight: normal; color: {{ theme_headercolor2 }}; margin-bottom: .8em; + clear: left; } h1 { From 84074871f2b78eb8290e24b30aeec72b90de2ccc Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Tue, 15 May 2012 22:24:54 -0400 Subject: [PATCH 2/5] DOC: convert segmentation example to tutorial-style example. --- .../applications/plot_coins_segmentation.py | 183 +++++++++++------- 1 file changed, 111 insertions(+), 72 deletions(-) diff --git a/doc/examples/applications/plot_coins_segmentation.py b/doc/examples/applications/plot_coins_segmentation.py index f2d65658..f46bbd33 100644 --- a/doc/examples/applications/plot_coins_segmentation.py +++ b/doc/examples/applications/plot_coins_segmentation.py @@ -3,57 +3,40 @@ Comparing edge-based segmentation and region-based segmentation =============================================================== -In this example, we will see how to segment objects from a background. -We use the ``coins`` image from ``skimage.data``. This image shows -several coins outlined against a darker background. The segmentation of -the coins cannot be done directly from the histogram of grey values, -because the background shares enough grey levels with the coins that a -thresholding segmentation is not sufficient. Simply thresholding the image -leads either to missing significant parts of the coins, or to merging parts -of the background with the coins. - -We first try an edge-based segmentation. We use the Canny detector to -delineate the contours of the coins. These contours are filled using -mathematical morphology (``scipy.ndimage.binary_fill_holes``). Small spurious -objects are easily removed by applying a threshold on the size of -unconnected objects. However, this method is not very robust, since contours -that are not perfectly closed are not filled correctly. This happens for one -of the coins. - -We therefore try a second method, that is region-based. Here we use the -watershed transform. An elevation map is provided by the Sobel gradient -of the image. Markers of the background and the coins are determined from -the extreme parts of the histogram of grey values. - -This second method works even better, and the coins can be segmented and -labeled individually. - +In this example, we will see how to segment objects from a background. We use +the ``coins`` image from ``skimage.data``, which shows several coins outlined +against a darker background. """ - import numpy as np -from scipy import ndimage import matplotlib.pyplot as plt -import skimage -from skimage.filter import canny, sobel -from skimage.morphology import watershed -#------------------ Loading data -------------------------------- from skimage import data -coins = data.coins() -#------------ Histogram of grey values --------------------------- -histo = np.histogram(coins, bins=np.arange(0, 256)) +coins = data.coins() +hist = np.histogram(coins, bins=np.arange(0, 256)) plt.figure(figsize=(8, 3)) plt.subplot(121) plt.imshow(coins, cmap=plt.cm.gray, interpolation='nearest') plt.axis('off') plt.subplot(122) -plt.plot(histo[1][:-1], histo[0], lw=2) +plt.plot(hist[1][:-1], hist[0], lw=2) plt.title('histogram of grey values') -#------------------ Tentative thresholding -------------------------------- +""" +.. image:: PLOT2RST.current_figure + +Thresholding +============ + +A simple way to segment the coins is to choose a threshold based on the +histogram of grey values. Unfortunately, thresholding this image gives a binary +image that either misses significant parts of the coins or merges parts of the +background with the coins: + +""" + plt.figure(figsize=(6, 3)) plt.subplot(121) plt.imshow(coins > 100, cmap=plt.cm.gray, interpolation='nearest') @@ -63,73 +46,126 @@ plt.subplot(122) plt.imshow(coins > 150, cmap=plt.cm.gray, interpolation='nearest') plt.title('coins > 150') plt.axis('off') +margins = dict(hspace=0.01, wspace=0.01, top=1, bottom=0, left=0, right=1) +plt.subplots_adjust(**margins) -plt.subplots_adjust(hspace=0.01, wspace=0.01, top=1, bottom=0, left=0, - right=1) +""" +.. image:: PLOT2RST.current_figure -#------------------ Edge-based segmentation -------------------------------- +Edge-based segmentation +======================= + +Next, we try to delineate the contours of the coins using edge-based +segmentation. To do this, we first get the edges of features using the Canny +edge-detector. +""" + +from skimage.filter import canny edges = canny(coins/255.) +plt.figure(figsize=(4, 3)) +plt.imshow(edges, cmap=plt.cm.gray, interpolation='nearest') +plt.axis('off') +plt.title('Canny detector') + +""" +.. image:: PLOT2RST.current_figure + +These contours are then filled using mathematical morphology. +""" + +from scipy import ndimage + fill_coins = ndimage.binary_fill_holes(edges) +plt.figure(figsize=(4, 3)) +plt.imshow(fill_coins, cmap=plt.cm.gray, interpolation='nearest') +plt.axis('off') +plt.title('Filling the holes') + +""" +.. image:: PLOT2RST.current_figure + +Small spurious objects are easily removed by setting a minimum size for valid +objects. +""" + label_objects, nb_labels = ndimage.label(fill_coins) sizes = np.bincount(label_objects.ravel()) mask_sizes = sizes > 20 mask_sizes[0] = 0 coins_cleaned = mask_sizes[label_objects] -plt.figure(figsize=(7, 3.)) -plt.subplot(131) -plt.imshow(edges, cmap=plt.cm.gray, interpolation='nearest') -plt.axis('off') -plt.title('Canny detector') -plt.subplot(132) -plt.imshow(fill_coins, cmap=plt.cm.gray, interpolation='nearest') -plt.axis('off') -plt.title('Filling the holes') -plt.subplot(133) +plt.figure(figsize=(4, 3)) plt.imshow(coins_cleaned, cmap=plt.cm.gray, interpolation='nearest') plt.axis('off') plt.title('Removing small objects') -plt.subplots_adjust(hspace=0.01, wspace=0.01, top=1, bottom=0, left=0, - right=1) + +""" +.. image:: PLOT2RST.current_figure + +However, this method is not very robust, since contours that are not perfectly +closed are not filled correctly, as is the case for one unfilled coin above. -#------------------ Region-based segmentation -------------------------------- +Region-based segmentation +========================= + +We therefore try a region-based method using the +watershed transform. First, we find an elevation map using the Sobel gradient of the +image. + +""" + +from skimage.filter import sobel + +elevation_map = sobel(coins) + +plt.figure(figsize=(4, 3)) +plt.imshow(elevation_map, cmap=plt.cm.jet, interpolation='nearest') +plt.axis('off') +plt.title('elevation_map') + +""" +.. image:: PLOT2RST.current_figure + +Next we find markers of the background and the coins based on the extreme parts +of the histogram of grey values. +""" markers = np.zeros_like(coins) markers[coins < 30] = 1 markers[coins > 150] = 2 -elevation_map = sobel(coins) - - -segmentation = watershed(elevation_map, markers) - - -plt.figure(figsize=(7, 3)) -plt.subplot(131) +plt.figure(figsize=(4, 3)) plt.imshow(markers, cmap=plt.cm.spectral, interpolation='nearest') plt.axis('off') plt.title('markers') -plt.subplot(132) -plt.imshow(elevation_map, cmap=plt.cm.jet, interpolation='nearest') -plt.axis('off') -plt.title('elevation_map') -plt.subplot(133) + +""" +.. image:: PLOT2RST.current_figure + +Finally, we use the watershed transform to fill regions of the elevation map starting from the markers determined above: + +""" +from skimage.morphology import watershed +segmentation = watershed(elevation_map, markers) + +plt.figure(figsize=(4, 3)) plt.imshow(segmentation, cmap=plt.cm.gray, interpolation='nearest') plt.axis('off') plt.title('segmentation') -plt.subplots_adjust(hspace=0.01, wspace=0.01, top=1, bottom=0, left=0, - right=1) +""" +.. image:: PLOT2RST.current_figure -# ------------------- Removing a few small holes --------------------- +This last method works even better, and the coins can be segmented and +labeled individually. + +""" segmentation = ndimage.binary_fill_holes(segmentation - 1) - -#------------------ Labeling the coins -------------------------------- labeled_coins, _ = ndimage.label(segmentation) plt.figure(figsize=(6, 3)) @@ -141,8 +177,11 @@ plt.subplot(122) plt.imshow(labeled_coins, cmap=plt.cm.spectral, interpolation='nearest') plt.axis('off') -plt.subplots_adjust(hspace=0.01, wspace=0.01, top=1, bottom=0, left=0, - right=1) +plt.subplots_adjust(**margins) +""" +.. image:: PLOT2RST.current_figure + +""" plt.show() From db2f7dde6b4be6f4b6fc90f581e1d24001769ab3 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Tue, 15 May 2012 22:45:06 -0400 Subject: [PATCH 3/5] DOC: Set rcparams for better default plots. --- doc/source/conf.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/source/conf.py b/doc/source/conf.py index 727b4bc4..aa96481b 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -259,3 +259,6 @@ plot_include_source = True plot_formats = [('png', 100)] plot2rst_index_name = 'README' +plot2rst_rcparams = {'image.cmap' : 'gray', + 'image.interpolation' : 'none'} + From ca25314310d5c58d136d6d86e968248c13331927 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Tue, 15 May 2012 22:47:30 -0400 Subject: [PATCH 4/5] Remove gen_rst --- doc/ext/gen_rst.py | 299 --------------------------------------------- doc/source/conf.py | 6 - 2 files changed, 305 deletions(-) delete mode 100644 doc/ext/gen_rst.py diff --git a/doc/ext/gen_rst.py b/doc/ext/gen_rst.py deleted file mode 100644 index de34d4b8..00000000 --- a/doc/ext/gen_rst.py +++ /dev/null @@ -1,299 +0,0 @@ -""" -Example generation for the scikit image. - -Generate the rst files for the examples by iterating over the python -example files. - -Files that generate images should start with 'plot'. - -This code was taken from the scikit-learn. - -""" -import os -import shutil -import traceback -import glob - -import matplotlib -matplotlib.use('Agg') - -import token, tokenize - -rst_template = """ - -.. _example_%(short_fname)s: - -%(docstring)s - -**Python source code:** :download:`%(fname)s <%(fname)s>` -(generated using ``skimage`` |version|) - -.. literalinclude:: %(fname)s - :lines: %(end_row)s- - """ - -plot_rst_template = """ - -.. _example_%(short_fname)s: - -%(docstring)s - -%(image_list)s - -**Python source code:** :download:`%(fname)s <%(fname)s>` -(generated using ``skimage`` |version|) - -.. literalinclude:: %(fname)s - :lines: %(end_row)s- - """ - - -toctree_template = """ - -.. toctree:: - :hidden: - - %s - -""" - -# The following strings are used when we have several pictures: we use -# an html div tag that our CSS uses to turn the lists into horizontal -# lists. -HLIST_HEADER = """ -.. rst-class:: horizontal - -""" - -HLIST_IMAGE_TEMPLATE = """ - * - - .. image:: images/%s - :scale: 50 -""" - -SINGLE_IMAGE = """ -.. image:: images/%s - :align: center -""" - -def extract_docstring(filename): - """ Extract a module-level docstring, if any - """ - lines = file(filename).readlines() - start_row = 0 - if lines[0].startswith('#!'): - lines.pop(0) - start_row = 1 - - docstring = '' - first_par = '' - tokens = tokenize.generate_tokens(lines.__iter__().next) - for tok_type, tok_content, _, (erow, _), _ in tokens: - tok_type = token.tok_name[tok_type] - if tok_type in ('NEWLINE', 'COMMENT', 'NL', 'INDENT', 'DEDENT'): - continue - elif tok_type == 'STRING': - docstring = eval(tok_content) - # If the docstring is formatted with several paragraphs, extract - # the first one: - paragraphs = '\n'.join(line.rstrip() - for line in docstring.split('\n')).split('\n\n') - if len(paragraphs) > 0: - first_par = paragraphs[0] - break - return docstring, first_par, erow+1+start_row - - -def generate_example_rst(app): - """ Generate the list of examples, as well as the contents of - examples. - """ - root_dir = os.path.join(app.builder.srcdir, 'auto_examples') - example_dir = os.path.abspath(app.builder.srcdir + '/../' + 'examples') - try: - plot_gallery = eval(app.builder.config.plot_gallery) - except TypeError: - plot_gallery = bool(app.builder.config.plot_gallery) - if not os.path.exists(example_dir): - os.makedirs(example_dir) - if not os.path.exists(root_dir): - os.makedirs(root_dir) - - # we create an index.rst with all examples - fhindex = file(os.path.join(root_dir, 'index.txt'), 'w') - fhindex.write("""\ - -Examples -======== - -.. _examples-index: -""") - # Here we don't use an os.walk, but we recurse only twice: flat is - # better than nested. - generate_dir_rst('.', fhindex, example_dir, root_dir, plot_gallery) - for dir in sorted(os.listdir(example_dir)): - if os.path.isdir(os.path.join(example_dir, dir)): - generate_dir_rst(dir, fhindex, example_dir, root_dir, plot_gallery) - fhindex.flush() - - -def generate_dir_rst(dir, fhindex, example_dir, root_dir, plot_gallery): - """ Generate the rst file for an example directory. - """ - if not dir == '.': - target_dir = os.path.join(root_dir, dir) - src_dir = os.path.join(example_dir, dir) - else: - target_dir = root_dir - src_dir = example_dir - if not os.path.exists(os.path.join(src_dir, 'README.txt')): - print 80*'_' - print ('Example directory %s does not have a README.txt file' - % src_dir) - print 'Skipping this directory' - print 80*'_' - return - - example_description = file(os.path.join(src_dir, 'README.txt')).read() - fhindex.write("""\n\n%s\n\n""" % example_description) - - if not os.path.exists(target_dir): - os.makedirs(target_dir) - - def sort_key(a): - # put last elements without a plot - if not a.startswith('plot') and a.endswith('.py'): - return 'zz' + a - return a - - examples = [fname for fname in sorted(os.listdir(src_dir), key=sort_key) - if fname.endswith('py')] - ex_names = [ex[:-3] for ex in examples] # strip '.py' extension - fhindex.write(toctree_template % '\n '.join(ex_names)) - - for fname in examples: - generate_file_rst(fname, target_dir, src_dir, plot_gallery) - thumb = os.path.join(dir, 'images', 'thumb', fname[:-3] + '.png') - link_name = os.path.join(dir, fname).replace(os.path.sep, '_') - fhindex.write('.. figure:: %s\n' % thumb) - if link_name.startswith('._'): - link_name = link_name[2:] - fhindex.write(' :figclass: gallery\n') - if dir != '.': - fhindex.write(' :target: ./%s/%s.html\n\n' % (dir, fname[:-3])) - else: - fhindex.write(' :target: ./%s.html\n\n' % link_name[:-3]) - fhindex.write(' :ref:`example_%s`\n\n' % link_name) - fhindex.write(""" -.. raw:: html - -
- """) # clear at the end of the section - - -def generate_file_rst(fname, target_dir, src_dir, plot_gallery): - """ Generate the rst file for a given example. - """ - base_image_name = os.path.splitext(fname)[0] - image_fname = '%s_%%s.png' % base_image_name - - this_template = rst_template - last_dir = os.path.split(src_dir)[-1] - # to avoid leading . in file names, and wrong names in links - if last_dir == '.' or last_dir == 'examples': - last_dir = '' - else: - last_dir += '_' - short_fname = last_dir + fname - src_file = os.path.join(src_dir, fname) - example_file = os.path.join(target_dir, fname) - shutil.copyfile(src_file, example_file) - - # The following is a list containing all the figure names - figure_list = [] - - image_dir = os.path.join(target_dir, 'images') - thumb_dir = os.path.join(image_dir, 'thumb') - if not os.path.exists(image_dir): - os.makedirs(image_dir) - if not os.path.exists(thumb_dir): - os.makedirs(thumb_dir) - image_path = os.path.join(image_dir, image_fname) - thumb_file = os.path.join(thumb_dir, fname[:-3] + '.png') - if plot_gallery and fname.startswith('plot'): - # generate the plot as png image if file name - # starts with plot and if it is more recent than an - # existing image. - first_image_file = image_path % 1 - - if (not os.path.exists(first_image_file) or - os.stat(first_image_file).st_mtime <= - os.stat(src_file).st_mtime): - # We need to execute the code - print 'plotting %s' % fname - import matplotlib.pyplot as plt - plt.close('all') - cwd = os.getcwd() - try: - # First CD in the original example dir, so that any file created - # by the example get created in this directory - os.chdir(os.path.dirname(src_file)) - execfile(os.path.basename(src_file), {'pl' : plt}) - os.chdir(cwd) - - # In order to save every figure we have two solutions : - # * iterate from 1 to infinity and call plt.fignum_exists(n) - # (this requires the figures to be numbered - # incrementally: 1, 2, 3 and not 1, 2, 5) - # * iterate over [fig_mngr.num for fig_mngr in - # matplotlib._pylab_helpers.Gcf.get_all_fig_managers()] - for fig_num in (fig_mngr.num for fig_mngr in - matplotlib._pylab_helpers.Gcf.get_all_fig_managers()): - # Set the fig_num figure as the current figure as we can't - # save a figure that's not the current figure. - plt.figure(fig_num) - plt.savefig(image_path % fig_num) - figure_list.append(image_fname % fig_num) - except: - print 80*'_' - print '%s is not compiling:' % fname - traceback.print_exc() - print 80*'_' - finally: - os.chdir(cwd) - else: - figure_list = [f[len(image_dir):] - for f in glob.glob(image_path % '[1-9]')] - #for f in glob.glob(image_path % '*')] - - # generate thumb file - this_template = plot_rst_template - from matplotlib import image - if os.path.exists(first_image_file): - image.thumbnail(first_image_file, thumb_file, 0.25) - - if not os.path.exists(thumb_file): - # create something not to replace the thumbnail - shutil.copy('source/auto_examples/images/blank_image.png', thumb_file) - - docstring, short_desc, end_row = extract_docstring(example_file) - - # Depending on whether we have one or more figures, we're using a - # horizontal list or a single rst call to 'image'. - if len(figure_list) == 1: - figure_name = figure_list[0] - image_list = SINGLE_IMAGE % figure_name.lstrip('/') - else: - image_list = HLIST_HEADER - for figure_name in figure_list: - image_list += HLIST_IMAGE_TEMPLATE % figure_name.lstrip('/') - - f = open(os.path.join(target_dir, fname[:-2] + 'txt'),'w') - f.write(this_template % locals()) - f.flush() - - -def setup(app): - app.connect('builder-inited', generate_example_rst) - app.add_config_value('plot_gallery', True, 'html') diff --git a/doc/source/conf.py b/doc/source/conf.py index aa96481b..c46ab806 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -23,12 +23,6 @@ sys.path.append(os.path.join(curpath, '..', 'ext')) # -- General configuration ----------------------------------------------------- -try: - import gen_rst -except: - pass - - # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.pngmath', 'numpydoc', From a903aa625d9b5ef5d531b96cfbf9e7587ed24534 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sun, 24 Jun 2012 20:46:38 -0400 Subject: [PATCH 5/5] Replace mpltools reference with skimage. --- doc/ext/plot2rst.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/ext/plot2rst.py b/doc/ext/plot2rst.py index 05f1bae6..67355289 100644 --- a/doc/ext/plot2rst.py +++ b/doc/ext/plot2rst.py @@ -4,8 +4,8 @@ Example generation from python files. Generate the rst files for the examples by iterating over the python example files. Files that generate images should start with 'plot'. -To generate your own examples, add ``'mpltools.sphinx.plot2rst'``` to the list -of ``extensions``in your Sphinx configuration file. In addition, make sure the +To generate your own examples, add this extension to the list of +``extensions``in your Sphinx configuration file. In addition, make sure the example directory(ies) in `plot2rst_paths` (see below) points to a directory with examples named `plot_*.py` and include an `index.rst` file. @@ -85,7 +85,7 @@ LITERALINCLUDE = """ CODE_LINK = """ **Python source code:** :download:`download <{0}>` -(generated using ``mpltools`` |version|) +(generated using ``skimage`` |version|) """