Beautified frontpage plots and two pylab examples #7740

Merged
merged 1 commit into from Jan 13, 2017
View
@@ -0,0 +1,5 @@
+contour_frontpage.png
+histogram_frontpage.png
+membrane_frontpage.png
+surface3d_frontpage.png
+
Deleted file not rendered
Deleted file not rendered
Deleted file not rendered
View
@@ -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 */
Deleted file not rendered
View
@@ -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'<script>.*?</script>', '', 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. "
@@ -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
@@ -23,12 +23,12 @@
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)
ax.set_xlim(-3, 3)
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
@@ -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
@@ -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
@@ -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()
@@ -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')