Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ab549ac

Browse files
committed
Merge pull request #3916 from matthew-brett/plot-directive-old-figures
ENH : add option to close figures in plot directive
2 parents 9b661e7 + 5e4a602 commit ab549ac

File tree

14 files changed

+536
-17
lines changed

14 files changed

+536
-17
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ matrix:
2323
env: BUILD_DOCS=true
2424

2525
install:
26-
- pip install -q --use-mirrors nose python-dateutil $NUMPY pep8 pyparsing pillow
26+
- pip install -q --use-mirrors nose python-dateutil $NUMPY pep8 pyparsing pillow sphinx
2727
- sudo apt-get update && sudo apt-get -qq install inkscape libav-tools gdb
2828
# We use --no-install-recommends to avoid pulling in additional large latex docs that we don't need
2929

@@ -33,7 +33,7 @@ install:
3333
- |
3434
if [[ $BUILD_DOCS == true ]]; then
3535
sudo apt-get install -qq --no-install-recommends dvipng texlive-latex-base texlive-latex-extra texlive-fonts-recommended graphviz
36-
pip install sphinx numpydoc linkchecker
36+
pip install numpydoc linkchecker
3737
wget http://mirrors.kernel.org/ubuntu/pool/universe/f/fonts-humor-sans/fonts-humor-sans_1.0-1_all.deb
3838
sudo dpkg -i fonts-humor-sans_1.0-1_all.deb
3939
wget https://googlefontdirectory.googlecode.com/hg/ofl/felipa/Felipa-Regular.ttf

doc/users/whats_new.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ New backend selection
6666
The environment variable :envvar:`MPLBACKEND` can now be used to set the
6767
matplotlib backend.
6868

69+
New ``close-figs`` argument for plot directive
70+
----------------------------------------------
71+
72+
Matplotlib has a sphinx extension ``plot_directive`` that creates plots for
73+
inclusion in sphinx documents. Matplotlib 1.5 adds a new option to the plot
74+
directive - ``close-figs`` - that closes any previous figure windows before
75+
creating the plots. This can help avoid some surprising duplicates of plots
76+
when using ``plot_directive``.
6977

7078
.. _whats-new-1-4:
7179

lib/matplotlib/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,7 @@ def tk_window_focus():
14401440
'matplotlib.tests.test_transforms',
14411441
'matplotlib.tests.test_triangulation',
14421442
'matplotlib.tests.test_widgets',
1443+
'matplotlib.sphinxext.tests.test_tinypages',
14431444
'mpl_toolkits.tests.test_mplot3d',
14441445
'mpl_toolkits.tests.test_axes_grid1',
14451446
]

lib/matplotlib/sphinxext/plot_directive.py

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,11 @@
6262
If provided, the code will be run in the context of all
6363
previous plot directives for which the `:context:` option was
6464
specified. This only applies to inline code plot directives,
65-
not those run from files. If the ``:context: reset`` is specified,
66-
the context is reset for this and future plots.
65+
not those run from files. If the ``:context: reset`` option is
66+
specified, the context is reset for this and future plots, and
67+
previous figures are closed prior to running the code.
68+
``:context:close-figs`` keeps the context but closes previous figures
69+
before running the code.
6770
6871
nofigs : bool
6972
If specified, the code block will be run, but no figures will
@@ -190,11 +193,9 @@ def _option_boolean(arg):
190193

191194

192195
def _option_context(arg):
193-
if arg in [None, 'reset']:
196+
if arg in [None, 'reset', 'close-figs']:
194197
return arg
195-
else:
196-
raise ValueError("argument should be None or 'reset'")
197-
return directives.choice(arg, ('None', 'reset'))
198+
raise ValueError("argument should be None or 'reset' or 'close-figs'")
198199

199200

200201
def _option_format(arg):
@@ -333,8 +334,8 @@ def remove_coding(text):
333334
"""
334335
Remove the coding comment, which six.exec_ doesn't like.
335336
"""
336-
return re.sub(
337-
"^#\s*-\*-\s*coding:\s*.*-\*-$", "", text, flags=re.MULTILINE)
337+
sub_re = re.compile("^#\s*-\*-\s*coding:\s*.*-\*-$", flags=re.MULTILINE)
338+
return sub_re.sub("", text)
338339

339340
#------------------------------------------------------------------------------
340341
# Template
@@ -524,7 +525,8 @@ def clear_state(plot_rcparams, close=True):
524525

525526

526527
def render_figures(code, code_path, output_dir, output_base, context,
527-
function_name, config, context_reset=False):
528+
function_name, config, context_reset=False,
529+
close_figs=False):
528530
"""
529531
Run a pyplot script and save the low and high res PNGs and a PDF
530532
in *output_dir*.
@@ -600,11 +602,16 @@ def render_figures(code, code_path, output_dir, output_base, context,
600602

601603
if context_reset:
602604
clear_state(config.plot_rcparams)
605+
plot_context.clear()
606+
607+
close_figs = not context or close_figs
603608

604609
for i, code_piece in enumerate(code_pieces):
605610

606611
if not context or config.plot_apply_rcparams:
607-
clear_state(config.plot_rcparams, close=not context)
612+
clear_state(config.plot_rcparams, close_figs)
613+
elif close_figs:
614+
plt.close('all')
608615

609616
run_code(code_piece, code_path, ns, function_name)
610617

@@ -644,8 +651,8 @@ def run(arguments, content, options, state_machine, state, lineno):
644651
nofigs = 'nofigs' in options
645652

646653
options.setdefault('include-source', config.plot_include_source)
647-
context = 'context' in options
648-
context_reset = True if (context and options['context'] == 'reset') else False
654+
keep_context = 'context' in options
655+
context_opt = None if not keep_context else options['context']
649656

650657
rst_file = document.attributes['source']
651658
rst_dir = os.path.dirname(rst_file)
@@ -729,9 +736,15 @@ def run(arguments, content, options, state_machine, state, lineno):
729736

730737
# make figures
731738
try:
732-
results = render_figures(code, source_file_name, build_dir, output_base,
733-
context, function_name, config,
734-
context_reset=context_reset)
739+
results = render_figures(code,
740+
source_file_name,
741+
build_dir,
742+
output_base,
743+
keep_context,
744+
function_name,
745+
config,
746+
context_reset=context_opt == 'reset',
747+
close_figs=context_opt == 'close-figs')
735748
errors = []
736749
except PlotError as err:
737750
reporter = state.memo.reporter
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Make tests a package
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
""" Tests for tinypages build using sphinx extensions """
2+
3+
import shutil
4+
import tempfile
5+
6+
from os.path import (join as pjoin, dirname, isdir)
7+
8+
from subprocess import call, Popen, PIPE
9+
10+
from nose import SkipTest
11+
from nose.tools import assert_true
12+
13+
HERE = dirname(__file__)
14+
TINY_PAGES = pjoin(HERE, 'tinypages')
15+
16+
17+
def setup():
18+
# Check we have the sphinx-build command
19+
try:
20+
ret = call(['sphinx-build', '--help'], stdout=PIPE, stderr=PIPE)
21+
except OSError:
22+
raise SkipTest('Need sphinx-build on path for these tests')
23+
if ret != 0:
24+
raise RuntimeError('sphinx-build does not return 0')
25+
26+
27+
def file_same(file1, file2):
28+
with open(file1, 'rb') as fobj:
29+
contents1 = fobj.read()
30+
with open(file2, 'rb') as fobj:
31+
contents2 = fobj.read()
32+
return contents1 == contents2
33+
34+
35+
class TestTinyPages(object):
36+
# Test build and output of tinypages project
37+
38+
@classmethod
39+
def setup_class(cls):
40+
cls.page_build = tempfile.mkdtemp()
41+
try:
42+
cls.html_dir = pjoin(cls.page_build, 'html')
43+
cls.doctree_dir = pjoin(cls.page_build, 'doctrees')
44+
# Build the pages with warnings turned into errors
45+
cmd = ['sphinx-build', '-W', '-b', 'html',
46+
'-d', cls.doctree_dir,
47+
TINY_PAGES,
48+
cls.html_dir]
49+
proc = Popen(cmd, stdout=PIPE, stderr=PIPE)
50+
out, err = proc.communicate()
51+
except Exception as e:
52+
shutil.rmtree(cls.page_build)
53+
raise e
54+
if proc.returncode != 0:
55+
shutil.rmtree(cls.page_build)
56+
raise RuntimeError('sphinx-build failed with stdout:\n'
57+
'{0}\nstderr:\n{1}\n'.format(
58+
out, err))
59+
60+
@classmethod
61+
def teardown_class(cls):
62+
shutil.rmtree(cls.page_build)
63+
64+
def test_some_plots(self):
65+
assert_true(isdir(self.html_dir))
66+
67+
def plot_file(num):
68+
return pjoin(self.html_dir, 'some_plots-{0}.png'.format(num))
69+
70+
range_10, range_6, range_4 = [plot_file(i) for i in range(1, 4)]
71+
# Plot 5 is range(6) plot
72+
assert_true(file_same(range_6, plot_file(5)))
73+
# Plot 7 is range(4) plot
74+
assert_true(file_same(range_4, plot_file(7)))
75+
# Plot 11 is range(10) plot
76+
assert_true(file_same(range_10, plot_file(11)))
77+
# Plot 12 uses the old range(10) figure and the new range(6) figure
78+
assert_true(file_same(range_10, plot_file('12_00')))
79+
assert_true(file_same(range_6, plot_file('12_01')))
80+
# Plot 13 shows close-figs in action
81+
assert_true(file_same(range_4, plot_file(13)))
82+
# Plot 14 has included source
83+
with open(pjoin(self.html_dir, 'some_plots.html'), 'rt') as fobj:
84+
html_contents = fobj.read()
85+
assert_true('# Only a comment' in html_contents)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
_build/
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Test project for matplotlib sphinx extensions
2+
3+
A tiny sphinx project from ``sphinx-quickstart`` with all default answers.

lib/matplotlib/sphinxext/tests/tinypages/_static/.gitignore

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
##############################
2+
Static directory for tinypages
3+
##############################
4+
5+
We need this README file to make sure the ``_static`` directory gets created
6+
in the installation. The tests check for warnings in builds, and, when the
7+
``_static`` directory is absent, this raises a warning.

0 commit comments

Comments
 (0)