Skip to content

Commit 2e25ae0

Browse files
committed
DOC: adding get_rst.py sphinx extension to build example gallery with mayavi screen capture
1 parent 727e2bd commit 2e25ae0

File tree

5 files changed

+236
-3
lines changed

5 files changed

+236
-3
lines changed

doc/conf.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
# Add any Sphinx extension module names here, as strings. They can be extensions
3030
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
3131
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.coverage',
32-
'ipython_console_highlighting']
32+
'ipython_console_highlighting', 'gen_rst']
3333

3434
# Add any paths that contain templates here, relative to this directory.
3535
templates_path = ['_templates']
@@ -47,6 +47,9 @@
4747
project = u'PySurfer'
4848
copyright = u'2011, Michael Waskom, Alexandre Gramfort, Scott Burns'
4949

50+
# Generate the plots for the gallery
51+
plot_gallery = True
52+
5053
# The version info for the project you're documenting, acts as replacement for
5154
# |version| and |release|, also used in various other places throughout the
5255
# built documents.

doc/index.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ PySurfer offers both a command-line interface designed to broadly
1212
replicate Freesurfer's Tksurfer program as well as a Python library
1313
for writing scripts to efficiently explore complex datasets.
1414

15-
Contents:
16-
1715
.. toctree::
1816
:maxdepth: 2
1917

18+
auto_examples/index.rst
19+
2020
Indices and tables
2121
==================
2222

doc/sphinxext/gen_rst.py

+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
"""
2+
Example generation
3+
4+
Generate the rst files for the examples by iterating over the python
5+
example files.
6+
7+
Files that generate images should start with 'plot'
8+
9+
"""
10+
import os
11+
import shutil
12+
import traceback
13+
14+
fileList = []
15+
16+
import matplotlib
17+
matplotlib.use('Agg')
18+
19+
import token, tokenize
20+
21+
rst_template = """
22+
23+
.. _example_%(short_fname)s:
24+
25+
%(docstring)s
26+
27+
**Python source code:** :download:`%(fname)s <%(fname)s>`
28+
29+
.. literalinclude:: %(fname)s
30+
:lines: %(end_row)s-
31+
"""
32+
33+
plot_rst_template = """
34+
35+
.. _example_%(short_fname)s:
36+
37+
%(docstring)s
38+
39+
.. image:: images/%(image_name)s
40+
:align: center
41+
42+
**Python source code:** :download:`%(fname)s <%(fname)s>`
43+
44+
.. literalinclude:: %(fname)s
45+
:lines: %(end_row)s-
46+
"""
47+
48+
49+
def extract_docstring(filename):
50+
""" Extract a module-level docstring, if any
51+
"""
52+
lines = file(filename).readlines()
53+
start_row = 0
54+
if lines[0].startswith('#!'):
55+
lines.pop(0)
56+
start_row = 1
57+
58+
docstring = ''
59+
first_par = ''
60+
tokens = tokenize.generate_tokens(lines.__iter__().next)
61+
for tok_type, tok_content, _, (erow, _), _ in tokens:
62+
tok_type = token.tok_name[tok_type]
63+
if tok_type in ('NEWLINE', 'COMMENT', 'NL', 'INDENT', 'DEDENT'):
64+
continue
65+
elif tok_type == 'STRING':
66+
docstring = eval(tok_content)
67+
# If the docstring is formatted with several paragraphs, extract
68+
# the first one:
69+
paragraphs = '\n'.join(line.rstrip()
70+
for line in docstring.split('\n')).split('\n\n')
71+
if len(paragraphs) > 0:
72+
first_par = paragraphs[0]
73+
break
74+
return docstring, first_par, erow+1+start_row
75+
76+
77+
def generate_example_rst(app):
78+
""" Generate the list of examples, as well as the contents of
79+
examples.
80+
"""
81+
root_dir = os.path.join(app.builder.srcdir, 'auto_examples')
82+
example_dir = os.path.abspath(app.builder.srcdir + '/../' + 'examples')
83+
try:
84+
plot_gallery = eval(app.builder.config.plot_gallery)
85+
except TypeError:
86+
plot_gallery = bool(app.builder.config.plot_gallery)
87+
if not os.path.exists(example_dir):
88+
os.makedirs(example_dir)
89+
if not os.path.exists(root_dir):
90+
os.makedirs(root_dir)
91+
92+
# we create an index.rst with all examples
93+
fhindex = file(os.path.join(root_dir, 'index.rst'), 'w')
94+
fhindex.write("""\
95+
96+
Examples
97+
========
98+
99+
.. _examples-index:
100+
""")
101+
# Here we don't use an os.walk, but we recurse only twice: flat is
102+
# better than nested.
103+
generate_dir_rst('.', fhindex, example_dir, root_dir, plot_gallery)
104+
for dir in sorted(os.listdir(example_dir)):
105+
if dir == '.svn':
106+
continue
107+
if os.path.isdir(os.path.join(example_dir, dir)):
108+
generate_dir_rst(dir, fhindex, example_dir, root_dir, plot_gallery)
109+
fhindex.flush()
110+
111+
112+
def generate_dir_rst(dir, fhindex, example_dir, root_dir, plot_gallery):
113+
""" Generate the rst file for an example directory.
114+
"""
115+
target_dir = os.path.join(root_dir, dir)
116+
src_dir = os.path.join(example_dir, dir)
117+
if not os.path.exists(os.path.join(src_dir, 'README.txt')):
118+
print 80*'_'
119+
print ('Example directory %s does not have a README.txt file'
120+
% src_dir)
121+
print 'Skipping this directory'
122+
print 80*'_'
123+
return
124+
fhindex.write("""
125+
126+
%s
127+
128+
.. toctree::
129+
130+
""" % file(os.path.join(src_dir, 'README.txt')).read())
131+
if not os.path.exists(target_dir):
132+
os.makedirs(target_dir)
133+
for fname in sorted(os.listdir(src_dir)):
134+
if fname.endswith('py'):
135+
generate_file_rst(fname, target_dir, src_dir, plot_gallery)
136+
fhindex.write(' %s\n' % (os.path.join(dir, fname[:-3])))
137+
138+
139+
def generate_file_rst(fname, target_dir, src_dir, plot_gallery):
140+
""" Generate the rst file for a given example.
141+
"""
142+
image_name = fname[:-2] + 'png'
143+
global rst_template, plot_rst_template
144+
this_template = rst_template
145+
last_dir = os.path.split(src_dir)[-1]
146+
# to avoid leading . in file names
147+
if last_dir == '.': last_dir = ''
148+
else: last_dir += '_'
149+
short_fname = last_dir + fname
150+
src_file = os.path.join(src_dir, fname)
151+
example_file = os.path.join(target_dir, fname)
152+
shutil.copyfile(src_file, example_file)
153+
if plot_gallery and fname.startswith('plot'):
154+
# generate the plot as png image if file name
155+
# starts with plot and if it is more recent than an
156+
# existing image.
157+
if not os.path.exists(
158+
os.path.join(target_dir, 'images')):
159+
os.makedirs(os.path.join(target_dir, 'images'))
160+
image_file = os.path.join(target_dir, 'images', image_name)
161+
if (not os.path.exists(image_file) or
162+
os.stat(image_file).st_mtime <=
163+
os.stat(src_file).st_mtime):
164+
print 'plotting %s' % fname
165+
import matplotlib.pyplot as plt
166+
plt.close('all')
167+
try:
168+
from enthought.mayavi import mlab
169+
mlab.close(all=True)
170+
except:
171+
pass
172+
173+
try:
174+
execfile(example_file, {'pl' : plt})
175+
facecolor = plt.gcf().get_facecolor() # hack to keep black bg
176+
if facecolor == (0.0, 0.0, 0.0, 1.0):
177+
plt.savefig(image_file, facecolor='black')
178+
else:
179+
plt.savefig(image_file)
180+
181+
try:
182+
from enthought.mayavi import mlab
183+
e = mlab.get_engine()
184+
if len(e.scenes) > 0:
185+
mlab.savefig(image_file, size=(400, 400))
186+
except:
187+
pass
188+
189+
except:
190+
print 80*'_'
191+
print '%s is not compiling:' % fname
192+
traceback.print_exc()
193+
print 80*'_'
194+
this_template = plot_rst_template
195+
196+
docstring, short_desc, end_row = extract_docstring(example_file)
197+
198+
f = open(os.path.join(target_dir, fname[:-2] + 'rst'),'w')
199+
f.write( this_template % locals())
200+
f.flush()
201+
202+
203+
def setup(app):
204+
app.connect('builder-inited', generate_example_rst)
205+
app.add_config_value('plot_gallery', True, 'html')

examples/annotation.py examples/plot_annotation.py

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
from os.path import join as pjoin
1111
from surfer import viz
1212

13+
###############################################################################
14+
# Look for files on drive
1315
subj_dir = os.environ["SUBJECTS_DIR"]
1416
subject_id = 'fsaverage'
1517

@@ -20,7 +22,11 @@
2022
data_path = pjoin(subj_dir, subject_id)
2123
annot_path = pjoin(data_path, "label", "%s.aparc.annot" % "lh")
2224

25+
###############################################################################
26+
# Visualize
2327
brain = viz.Brain(sub, hemi, surf)
2428
brain.add_annotation(annot_path, borders=True)
29+
30+
###############################################################################
2531
# show all views
2632
brain.show_view('lateral')

examples/plot_basics.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""
2+
=======================
3+
Basics of vizualization
4+
=======================
5+
6+
"""
7+
print __doc__
8+
9+
from surfer import Brain
10+
11+
sub = 'fsaverage'
12+
hemi = 'lh'
13+
surf = 'inflated'
14+
15+
brain = Brain(sub, hemi, surf)
16+
17+
###############################################################################
18+
# show all views
19+
brain.show_view('lateral')

0 commit comments

Comments
 (0)