diff --git a/doc/_static/.gitignore b/doc/_static/.gitignore new file mode 100644 index 000000000000..bbdc34458abc --- /dev/null +++ b/doc/_static/.gitignore @@ -0,0 +1,5 @@ +contour_frontpage.png +histogram_frontpage.png +membrane_frontpage.png +surface3d_frontpage.png + diff --git a/doc/_static/contour_frontpage.png b/doc/_static/contour_frontpage.png deleted file mode 100644 index dfa518a2176e..000000000000 Binary files a/doc/_static/contour_frontpage.png and /dev/null differ diff --git a/doc/_static/histogram_frontpage.png b/doc/_static/histogram_frontpage.png deleted file mode 100644 index a4ff5ed9f32b..000000000000 Binary files a/doc/_static/histogram_frontpage.png and /dev/null differ diff --git a/doc/_static/membrane_frontpage.png b/doc/_static/membrane_frontpage.png deleted file mode 100644 index d1119b7ac479..000000000000 Binary files a/doc/_static/membrane_frontpage.png and /dev/null differ diff --git a/doc/_static/mpl.css b/doc/_static/mpl.css index 0b5bce477ede..bf571bcbe8cc 100644 --- a/doc/_static/mpl.css +++ b/doc/_static/mpl.css @@ -738,8 +738,8 @@ div.responsive_screenshots { margin: auto; /* Do not go beyond 1:1 scale (and ensure a 1x4 tight layout) */ - max-width: 648px; /* at most 4 x 1:1 subfig width */ - max-height: 139px; /* at most 1 x 1:1 subfig height */ + max-width: 640px; /* at most 4 x 1:1 subfig width */ + max-height: 120px; /* at most 1 x 1:1 subfig height */ } /* To avoid subfigure parts outside of the responsive_screenshots */ diff --git a/doc/_static/surface3d_frontpage.png b/doc/_static/surface3d_frontpage.png deleted file mode 100644 index 065c6f17113b..000000000000 Binary files a/doc/_static/surface3d_frontpage.png and /dev/null differ diff --git a/doc/make.py b/doc/make.py index 8882c86f6da3..27dd1b7719a0 100755 --- a/doc/make.py +++ b/doc/make.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +"""Wrapper script for calling Sphinx. """ from __future__ import print_function import glob @@ -7,9 +8,12 @@ import sys import re import argparse +import subprocess import matplotlib + def copy_if_out_of_date(original, derived): + """Copy file only if newer as target or if target does not exist. """ if (not os.path.exists(derived) or os.stat(derived).st_mtime < os.stat(original).st_mtime): try: @@ -22,7 +26,9 @@ def copy_if_out_of_date(original, derived): else: raise + def check_build(): + """Create target build directories if necessary. """ build_dirs = ['build', 'build/doctrees', 'build/html', 'build/latex', 'build/texinfo', '_static', '_templates'] for d in build_dirs: @@ -31,14 +37,58 @@ def check_build(): except OSError: pass + def doctest(): + """Execute Sphinx 'doctest' target. """ os.system('sphinx-build -b doctest -d build/doctrees . build/doctest') + def linkcheck(): + """Execute Sphinx 'linkcheck' target. """ os.system('sphinx-build -b linkcheck -d build/doctrees . build/linkcheck') + +# For generating PNGs of the top row of index.html: +FRONTPAGE_PY_PATH = "../examples/frontpage/" # python scripts location +FRONTPAGE_PNG_PATH = "_static/" # png files location +# png files and corresponding generation scripts: +FRONTPAGE_PNGS = {"surface3d_frontpage.png": "plot_3D.py", + "contour_frontpage.png": "plot_contour.py", + "histogram_frontpage.png": "plot_histogram.py", + "membrane_frontpage.png": "plot_membrane.py"} + + +def generate_frontpage_pngs(only_if_needed=True): + """Executes the scripts for PNG generation of the top row of index.html. + + If `only_if_needed` is `True`, then the PNG file is only generated, if it + doesn't exist or if the python file is newer. + + Note that the element `div.responsive_screenshots` in the file + `_static/mpl.css` has the height and cumulative width of the used PNG files + as attributes. This ensures that the magnification of those PNGs is <= 1. + """ + for fn_png, fn_py in FRONTPAGE_PNGS.items(): + pn_png = os.path.join(FRONTPAGE_PNG_PATH, fn_png) # get full paths + pn_py = os.path.join(FRONTPAGE_PY_PATH, fn_py) + + # Read file modification times: + mtime_py = os.path.getmtime(pn_py) + mtime_png = (os.path.getmtime(pn_png) if os.path.exists(pn_png) else + mtime_py - 1) # set older time, if file doesn't exist + + if only_if_needed and mtime_py <= mtime_png: + continue # do nothing if png is newer + + # Execute python as subprocess (preferred over os.system()): + subprocess.check_call(["python", pn_py]) # raises CalledProcessError() + os.rename(fn_png, pn_png) # move file to _static/ directory + + def html(buildername='html'): + """Build Sphinx 'html' target. """ check_build() + generate_frontpage_pngs() rc = '../lib/matplotlib/mpl-data/matplotlibrc' default_rc = os.path.join(matplotlib._get_data_path(), 'matplotlibrc') @@ -62,20 +112,24 @@ def html(buildername='html'): shutil.copy('../CHANGELOG', 'build/%s/_static/CHANGELOG' % buildername) + def htmlhelp(): + """Build Sphinx 'htmlhelp' target. """ html(buildername='htmlhelp') # remove scripts from index.html with open('build/htmlhelp/index.html', 'r+') as fh: content = fh.read() fh.seek(0) content = re.sub(r'', '', content, - flags=re.MULTILINE| re.DOTALL) + flags=re.MULTILINE | re.DOTALL) fh.write(content) fh.truncate() + def latex(): + """Build Sphinx 'latex' target. """ check_build() - #figs() + # figs() if sys.platform != 'win32': # LaTeX format. if os.system('sphinx-build -b latex -d build/doctrees . build/latex'): @@ -92,9 +146,11 @@ def latex(): else: print('latex build has not been tested on windows') + def texinfo(): + """Build Sphinx 'texinfo' target. """ check_build() - #figs() + # figs() if sys.platform != 'win32': # Texinfo format. if os.system( @@ -112,7 +168,9 @@ def texinfo(): else: print('texinfo build has not been tested on windows') + def clean(): + """Remove generated files. """ shutil.rmtree("build", ignore_errors=True) shutil.rmtree("examples", ignore_errors=True) for pattern in ['mpl_examples/api/*.png', @@ -126,21 +184,27 @@ def clean(): for filename in glob.glob(pattern): if os.path.exists(filename): os.remove(filename) + for fn in FRONTPAGE_PNGS.keys(): # remove generated PNGs + pn = os.path.join(FRONTPAGE_PNG_PATH, fn) + if os.path.exists(pn): + os.remove(os.path.join(pn)) + -def all(): - #figs() +def build_all(): + """Build Sphinx 'html' and 'latex' target. """ + # figs() html() latex() funcd = { - 'html' : html, - 'htmlhelp' : htmlhelp, - 'latex' : latex, - 'texinfo' : texinfo, - 'clean' : clean, - 'all' : all, - 'doctest' : doctest, + 'html': html, + 'htmlhelp': htmlhelp, + 'latex': latex, + 'texinfo': texinfo, + 'clean': clean, + 'all': build_all, + 'doctest': doctest, 'linkcheck': linkcheck, } @@ -168,8 +232,8 @@ def all(): # This is special processing that applies on platforms that don't deal # with git symlinks -- probably only MS windows. delete = False - with open(link, 'r') as content: - delete = target == content.read() + with open(link, 'r') as link_content: + delete = target == link_content.read() if delete: symlink_warnings.append('deleted: doc/{0}'.format(link)) os.unlink(link) @@ -186,7 +250,7 @@ def all(): if sys.platform == 'win32' and len(symlink_warnings) > 0: print('The following items related to symlinks will show up ' 'as spurious changes in your \'git status\':\n\t{0}' - .format('\n\t'.join(symlink_warnings))) + .format('\n\t'.join(symlink_warnings))) parser = argparse.ArgumentParser(description='Build matplotlib docs') parser.add_argument("cmd", help=("Command to execute. Can be multiple. " diff --git a/examples/frontpage/plot_3D.py b/examples/frontpage/plot_3D.py index ddc3ee112577..d08b52f54b24 100644 --- a/examples/frontpage/plot_3D.py +++ b/examples/frontpage/plot_3D.py @@ -24,7 +24,7 @@ region = np.s_[5:50, 5:50] x, y, z = x[region], y[region], z[region] -fig, ax = plt.subplots(subplot_kw=dict(projection='3d'), figsize=(1.62, 1.38)) +fig, ax = plt.subplots(subplot_kw=dict(projection='3d')) ls = LightSource(270, 45) # To use a custom hillshading mode, override the built-in shading and pass @@ -35,4 +35,4 @@ ax.set_xticks([]) ax.set_yticks([]) ax.set_zticks([]) -fig.savefig("surface3d_frontpage.png") +fig.savefig("surface3d_frontpage.png", dpi=25) # results in 160x120 px image diff --git a/examples/frontpage/plot_contour.py b/examples/frontpage/plot_contour.py index 4e86fe1f8569..9622cc015088 100644 --- a/examples/frontpage/plot_contour.py +++ b/examples/frontpage/plot_contour.py @@ -23,7 +23,7 @@ levels = np.linspace(-2.0, 1.601, 40) norm = cm.colors.Normalize(vmax=abs(Z).max(), vmin=-abs(Z).max()) -fig, ax = plt.subplots(figsize=(1.62, 1.38)) +fig, ax = plt.subplots() cset1 = ax.contourf( X, Y, Z, levels, norm=norm) @@ -31,4 +31,4 @@ ax.set_ylim(-3, 3) ax.set_xticks([]) ax.set_yticks([]) -fig.savefig("contour_frontpage.png") +fig.savefig("contour_frontpage.png", dpi=25) # results in 160x120 px image diff --git a/examples/frontpage/plot_histogram.py b/examples/frontpage/plot_histogram.py index b9ff71174faa..e9c5299df7d6 100644 --- a/examples/frontpage/plot_histogram.py +++ b/examples/frontpage/plot_histogram.py @@ -13,10 +13,10 @@ random_state = np.random.RandomState(19680801) X = random_state.randn(10000) -fig, ax = plt.subplots(figsize=(1.62, 1.38)) +fig, ax = plt.subplots() ax.hist(X, bins=25, normed=True) x = np.linspace(-5, 5, 1000) ax.plot(x, 1 / np.sqrt(2*np.pi) * np.exp(-(x**2)/2), linewidth=4) ax.set_xticks([]) ax.set_yticks([]) -fig.savefig("histogram_frontpage.png") +fig.savefig("histogram_frontpage.png", dpi=25) # results in 160x120 px image diff --git a/examples/frontpage/plot_membrane.py b/examples/frontpage/plot_membrane.py index f469ad1a087b..522ba78fb856 100644 --- a/examples/frontpage/plot_membrane.py +++ b/examples/frontpage/plot_membrane.py @@ -16,10 +16,10 @@ x = np.fromfile(datafile, np.float32) # 0.0005 is the sample interval -fig, ax = plt.subplots(figsize=(1.62, 1.38)) +fig, ax = plt.subplots() ax.plot(x, linewidth=4) ax.set_xlim(5000, 6000) ax.set_ylim(-0.6, 0.1) ax.set_xticks([]) ax.set_yticks([]) -fig.savefig("membrane_frontpage.png") +fig.savefig("membrane_frontpage.png", dpi=25) # results in 160x120 px image diff --git a/examples/pie_and_polar_charts/pie_demo_features.py b/examples/pie_and_polar_charts/pie_demo_features.py index 97b374aead33..89750ca6c162 100644 --- a/examples/pie_and_polar_charts/pie_demo_features.py +++ b/examples/pie_and_polar_charts/pie_demo_features.py @@ -16,48 +16,40 @@ rotated counter-clockwise by 90 degrees, and the frog slice starts on the positive y-axis. """ +import numpy as np import matplotlib.pyplot as plt - -# The slices will be ordered and plotted counter-clockwise. +# Pie chart, where the slices will be ordered and plotted counter-clockwise: labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' sizes = [15, 30, 45, 10] explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs') -plt.pie(sizes, explode=explode, labels=labels, - autopct='%1.1f%%', shadow=True, startangle=90) -# Set aspect ratio to be equal so that pie is drawn as a circle. -plt.axis('equal') - -fig = plt.figure() -ax = fig.gca() -import numpy as np - -# Fixing random state for reproducibility -np.random.seed(19680801) - - -ax.pie(np.random.random(4), explode=explode, labels=labels, - autopct='%1.1f%%', shadow=True, startangle=90, - radius=0.25, center=(0, 0), frame=True) -ax.pie(np.random.random(4), explode=explode, labels=labels, - autopct='%1.1f%%', shadow=True, startangle=90, - radius=0.25, center=(1, 1), frame=True) -ax.pie(np.random.random(4), explode=explode, labels=labels, - autopct='%1.1f%%', shadow=True, startangle=90, - radius=0.25, center=(0, 1), frame=True) -ax.pie(np.random.random(4), explode=explode, labels=labels, - autopct='%1.1f%%', shadow=True, startangle=90, - radius=0.25, center=(1, 0), frame=True) - -ax.set_xticks([0, 1]) -ax.set_yticks([0, 1]) -ax.set_xticklabels(["Sunny", "Cloudy"]) -ax.set_yticklabels(["Dry", "Rainy"]) -ax.set_xlim((-0.5, 1.5)) -ax.set_ylim((-0.5, 1.5)) - -# Set aspect ratio to be equal so that pie is drawn as a circle. -ax.set_aspect('equal') +fg1, ax1 = plt.subplots() +ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', + shadow=True, startangle=90) +ax1.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle. + + +# Plot four Pie charts in a 2x2 grid: +pie_data = [np.roll(sizes, i) for i in range(4)] # generate some data +pie_centerpos = [(0, 0), (0, 1), (1, 0), (1, 1)] # the grid positions + +fg2, ax2 = plt.subplots() +for data, cpos in zip(pie_data, pie_centerpos): + _, txts = ax2.pie(data, explode=explode, shadow=True, startangle=90, + radius=0.35, center=cpos, frame=True, labeldistance=.7) + # Make texts include number and labels: + for t, l, d in zip(txts, labels, data): + t.set_text("%s\n %.1f%%" % (l, d)) + t.set_horizontalalignment("center") + t.set_fontsize(8) + +ax2.set_xticks([0, 1]) +ax2.set_yticks([0, 1]) +ax2.set_xticklabels(["Sunny", "Cloudy"]) +ax2.set_yticklabels(["Dry", "Rainy"]) +ax2.set_xlim((-0.5, 1.5)) +ax2.set_ylim((-0.5, 1.5)) +ax2.set_aspect('equal') # Equal aspect ratio ensures that the pie is a circle. plt.show() diff --git a/examples/pylab_examples/polar_demo.py b/examples/pylab_examples/polar_demo.py index 149f505b2ba3..b2b5843e8fa1 100644 --- a/examples/pylab_examples/polar_demo.py +++ b/examples/pylab_examples/polar_demo.py @@ -5,12 +5,14 @@ import matplotlib.pyplot as plt -r = np.arange(0, 3.0, 0.01) +r = np.arange(0, 2, 0.01) theta = 2 * np.pi * r ax = plt.subplot(111, projection='polar') ax.plot(theta, r) -ax.set_rmax(2.0) +ax.set_rmax(2) +ax.set_rticks([0.5, 1, 1.5, 2]) # less radial ticks +ax.set_rlabel_position(-22.5) # get radial labels away from plotted line ax.grid(True) ax.set_title("A line plot on a polar axis", va='bottom')