Skip to content

Commit aa5b193

Browse files
committed
BUGFIX: make plot directive naively "responsive"
1 parent 2631206 commit aa5b193

File tree

5 files changed

+63
-10
lines changed

5 files changed

+63
-10
lines changed

lib/matplotlib/sphinxext/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from pathlib import Path
2+
3+
_static_path = Path(__file__).resolve().parent / Path('static')

lib/matplotlib/sphinxext/plot_directive.py

+23-10
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@
156156
import matplotlib
157157
from matplotlib.backend_bases import FigureManagerBase
158158
import matplotlib.pyplot as plt
159-
from matplotlib import _api, _pylab_helpers, cbook
159+
from matplotlib import _api, _pylab_helpers, cbook, sphinxext
160160

161161
matplotlib.use("agg")
162162
align = _api.deprecated(
@@ -254,6 +254,13 @@ def run(self):
254254
raise self.error(str(e))
255255

256256

257+
def _copy_css_file(app, exc):
258+
if exc is None and app.builder.format == 'html':
259+
src = sphinxext._static_path / Path('plot_directive.css')
260+
dst = app.outdir / Path('_static')
261+
shutil.copy(src, dst)
262+
263+
257264
def setup(app):
258265
setup.app = app
259266
setup.config = app.config
@@ -269,9 +276,9 @@ def setup(app):
269276
app.add_config_value('plot_apply_rcparams', False, True)
270277
app.add_config_value('plot_working_directory', None, True)
271278
app.add_config_value('plot_template', None, True)
272-
273279
app.connect('doctree-read', mark_plot_labels)
274-
280+
app.add_css_file('plot_directive.css')
281+
app.connect('build-finished', _copy_css_file)
275282
metadata = {'parallel_read_safe': True, 'parallel_write_safe': True,
276283
'version': matplotlib.__version__}
277284
return metadata
@@ -337,7 +344,6 @@ def split_code_at_show(text):
337344
# Template
338345
# -----------------------------------------------------------------------------
339346

340-
341347
TEMPLATE = """
342348
{{ source_code }}
343349
@@ -374,7 +380,7 @@ def split_code_at_show(text):
374380
)
375381
{%- endif -%}
376382
377-
{{ caption }}
383+
{{ caption }} {# appropriate leading whitespace added beforehand #}
378384
{% endfor %}
379385
380386
.. only:: not html
@@ -383,9 +389,9 @@ def split_code_at_show(text):
383389
.. figure:: {{ build_dir }}/{{ img.basename }}.*
384390
{% for option in options -%}
385391
{{ option }}
386-
{% endfor %}
392+
{% endfor -%}
387393
388-
{{ caption }}
394+
{{ caption }} {# appropriate leading whitespace added beforehand #}
389395
{% endfor %}
390396
391397
"""
@@ -521,7 +527,7 @@ def render_figures(code, code_path, output_dir, output_base, context,
521527
"""
522528
formats = get_plot_formats(config)
523529

524-
# -- Try to determine if all images already exist
530+
# Try to determine if all images already exist
525531

526532
code_pieces = split_code_at_show(code)
527533

@@ -624,6 +630,13 @@ def run(arguments, content, options, state_machine, state, lineno):
624630
default_fmt = formats[0][0]
625631

626632
options.setdefault('include-source', config.plot_include_source)
633+
if 'class' in options:
634+
# classes are parsed into a list of string, and output by simply
635+
# printing the list, abusing the fact that RST guarantees to strip
636+
# non-conforming characters
637+
options['class'] = ['plot-directive'] + options['class']
638+
else:
639+
options.setdefault('class', ['plot-directive'])
627640
keep_context = 'context' in options
628641
context_opt = None if not keep_context else options['context']
629642

@@ -743,8 +756,8 @@ def run(arguments, content, options, state_machine, state, lineno):
743756
errors = [sm]
744757

745758
# Properly indent the caption
746-
caption = '\n'.join(' ' + line.strip()
747-
for line in caption.split('\n'))
759+
caption = '\n' + '\n'.join(' ' + line.strip()
760+
for line in caption.split('\n'))
748761

749762
# generate output restructuredtext
750763
total_lines = []
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* plot_directive.css
3+
* ~~~~~~~~~~~~
4+
*
5+
* Stylesheet controlling images created using the `plot` directive within
6+
* Sphinx.
7+
*
8+
*/
9+
10+
img.plot-directive {
11+
border: 0;
12+
max-width: 100%;
13+
}

lib/matplotlib/tests/test_sphinxext.py

+4
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,7 @@ def plot_file(num):
5858
assert b'Plot 17 uses the caption option.' in html_contents
5959
# check if figure caption made it into html file
6060
assert b'This is the caption for plot 18.' in html_contents
61+
# check if the custom classes made it into the html file
62+
assert b'plot-directive my-class my-other-class' in html_contents
63+
# check that the multi-image caption is applied twice
64+
assert html_contents.count(b'This caption applies to both plots.') == 2

lib/matplotlib/tests/tinypages/some_plots.rst

+20
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,23 @@ using the :caption: option:
141141

142142
.. plot:: range4.py
143143
:caption: This is the caption for plot 18.
144+
145+
Plot 19 uses shows that the "plot-directive" class is still appended, even if
146+
we request other custom classes:
147+
148+
.. plot:: range4.py
149+
:class: my-class my-other-class
150+
151+
Should also have a caption.
152+
153+
Plot 20 shows that the default template correctly prints the multi-image
154+
scenario:
155+
156+
.. plot::
157+
:caption: This caption applies to both plots.
158+
159+
plt.figure()
160+
plt.plot(range(6))
161+
162+
plt.figure()
163+
plt.plot(range(4))

0 commit comments

Comments
 (0)