From 3a02535231d1a53fbca4701370d90def2221b983 Mon Sep 17 00:00:00 2001 From: Jamal Mustafa Date: Sat, 23 Oct 2021 14:15:56 -0700 Subject: [PATCH] continue refactoring using style sheets - add base style with constrained_layout enabled - add style for the ticks examples - add style for a grid of figures - resize figures to a maximum width of 57 mm - small tweaks to arrow connections to accommodate change in figure size --- scripts/advanced-plots.py | 6 ++- scripts/annotation-arrow-styles.py | 18 +++++---- scripts/annotation-connection-styles.py | 22 ++++++---- scripts/basic-plots.py | 6 ++- scripts/interpolations.py | 20 +++++++--- scripts/projections.py | 27 +++++++------ scripts/tick-formatters.py | 48 +++++++++------------- scripts/tick-locators.py | 53 ++++++++++--------------- styles/base.mplstyle | 5 +++ styles/plotlet-grid.mplstyle | 10 +++++ styles/ticks.mplstyle | 17 ++++++++ 11 files changed, 135 insertions(+), 97 deletions(-) create mode 100644 styles/base.mplstyle create mode 100644 styles/plotlet-grid.mplstyle create mode 100644 styles/ticks.mplstyle diff --git a/scripts/advanced-plots.py b/scripts/advanced-plots.py index 73f35275..3ad36c06 100644 --- a/scripts/advanced-plots.py +++ b/scripts/advanced-plots.py @@ -11,7 +11,11 @@ import matplotlib.pyplot as plt -mpl.style.use(pathlib.Path(__file__).parent/'../styles/plotlet.mplstyle') +mpl.style.use([ + pathlib.Path(__file__).parent/'../styles/base.mplstyle', + pathlib.Path(__file__).parent/'../styles/plotlet.mplstyle', +]) + fig = plt.figure() d = 0.01 diff --git a/scripts/annotation-arrow-styles.py b/scripts/annotation-arrow-styles.py index 6bff9231..45a6c295 100644 --- a/scripts/annotation-arrow-styles.py +++ b/scripts/annotation-arrow-styles.py @@ -1,16 +1,17 @@ +import pathlib + +import matplotlib as mpl import matplotlib.pyplot as plt import matplotlib.patches as mpatches -styles = mpatches.ArrowStyle.get_styles() - -def demo_con_style(ax, connectionstyle): - ax.text(.05, .95, connectionstyle.replace(",", ",\n"), - family="Source Code Pro", - transform=ax.transAxes, ha="left", va="top", size="x-small") +mpl.style.use([ + pathlib.Path(__file__).parent/'../styles/base.mplstyle', + pathlib.Path(__file__).parent/'../styles/plotlet-grid.mplstyle', +]) -(fig, axes) = plt.subplots(5, 3, figsize=(4, 2.5), frameon=False) +(fig, axes) = plt.subplots(5, 3, figsize=(5.7/2.54, 1.5), frameon=True) for ax in axes.flatten(): ax.axis("off") for i, (ax, style) in enumerate(zip(axes.flatten(), mpatches.ArrowStyle.get_styles())): @@ -21,13 +22,14 @@ def demo_con_style(ax, connectionstyle): xy=(x0, y0), xycoords='data', xytext=(x1, y1), textcoords='data', arrowprops=dict(arrowstyle=style, + mutation_scale=10, color="black", shrinkA=5, shrinkB=5, patchA=None, patchB=None, connectionstyle="arc3,rad=0")) ax.text( (x1+x0)/2, y0-0.2, style, transform=ax.transAxes, - family="Source Code Pro", ha="center", va="top") + ha="center", va="top", fontsize=8) plt.savefig("../figures/annotation-arrow-styles.pdf") # plt.show() diff --git a/scripts/annotation-connection-styles.py b/scripts/annotation-connection-styles.py index 64fa3009..12aa5628 100644 --- a/scripts/annotation-connection-styles.py +++ b/scripts/annotation-connection-styles.py @@ -1,6 +1,15 @@ +import pathlib + +import matplotlib as mpl import matplotlib.pyplot as plt +mpl.style.use([ + pathlib.Path(__file__).parent/'../styles/base.mplstyle', + pathlib.Path(__file__).parent/'../styles/plotlet-grid.mplstyle', +]) + + def demo_con_style(ax, connectionstyle): x1, y1 = 0.3, 0.2 x2, y2 = 0.8, 0.6 @@ -9,29 +18,26 @@ def demo_con_style(ax, connectionstyle): xy=(x1, y1), xycoords='data', xytext=(x2, y2), textcoords='data', arrowprops=dict(arrowstyle="->", color="0.5", - shrinkA=5, shrinkB=5, + shrinkA=2, shrinkB=2, patchA=None, patchB=None, connectionstyle=connectionstyle), ) ax.text(.05, .95, connectionstyle.replace(",", ",\n"), - family="Source Code Pro", - transform=ax.transAxes, ha="left", va="top", size="x-small") - + transform=ax.transAxes, ha="left", va="top", size=4) -fig, axs = plt.subplots(3, 3, figsize=(5, 5)) +fig, axs = plt.subplots(3, 3, figsize=(5.7/2.54, 5.7/2.54)) demo_con_style(axs[0, 0], "arc3,rad=0") demo_con_style(axs[0, 1], "arc3,rad=0.3") demo_con_style(axs[0, 2], "angle3,angleA=0,angleB=90") demo_con_style(axs[1, 0], "angle,angleA=-90,angleB=180,rad=0") -demo_con_style(axs[1, 1], "angle,angleA=-90,angleB=180,rad=25") -demo_con_style(axs[1, 2], "arc,angleA=-90,angleB=0,armA=0,armB=40,rad=0") +demo_con_style(axs[1, 1], "angle,angleA=-90,angleB=180,rad=10") +demo_con_style(axs[1, 2], "arc,angleA=-90,angleB=0,armA=0,armB=20,rad=0") demo_con_style(axs[2, 0], "bar,fraction=0.3") demo_con_style(axs[2, 1], "bar,fraction=-0.3") demo_con_style(axs[2, 2], "bar,angle=180,fraction=-0.2") for ax in axs.flat: ax.set(xlim=(0, 1), ylim=(0, 1), xticks=[], yticks=[], aspect=1) -fig.tight_layout(pad=0.2) plt.savefig("../figures/annotation-connection-styles.pdf") # plt.show() diff --git a/scripts/basic-plots.py b/scripts/basic-plots.py index 1fbe48f6..64e07fcf 100644 --- a/scripts/basic-plots.py +++ b/scripts/basic-plots.py @@ -11,7 +11,11 @@ import matplotlib.pyplot as plt -mpl.style.use(pathlib.Path(__file__).parent/'../styles/plotlet.mplstyle') +mpl.style.use([ + pathlib.Path(__file__).parent/'../styles/base.mplstyle', + pathlib.Path(__file__).parent/'../styles/plotlet.mplstyle', +]) + fig = plt.figure() d = 0.01 diff --git a/scripts/interpolations.py b/scripts/interpolations.py index 2a135ef6..3b8874fe 100644 --- a/scripts/interpolations.py +++ b/scripts/interpolations.py @@ -1,6 +1,16 @@ +import pathlib + +import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np + +mpl.style.use([ + pathlib.Path(__file__).parent/'../styles/base.mplstyle', + pathlib.Path(__file__).parent/'../styles/plotlet-grid.mplstyle', +]) + + methods = [None, 'none', 'nearest', 'bilinear', 'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos'] @@ -9,14 +19,14 @@ Z = np.random.uniform(0, 1, (3, 3)) -fig, axs = plt.subplots(nrows=6, ncols=3, figsize=(4.5, 9), +fig, axs = plt.subplots(nrows=6, ncols=3, figsize=(5.7/2.54,5.7/2.54*2), +# fig, axs = plt.subplots(nrows=6, ncols=3, figsize=(4.5,9), subplot_kw={'xticks': [], 'yticks': []}) for ax, interp_method in zip(axs.flat, methods): ax.imshow(Z, interpolation=interp_method, cmap='viridis', - extent=[0, 9, 0, 9], rasterized=True) - ax.text(4.5, 1, str(interp_method), weight="bold", color="white", size=12, - transform=ax.transData, ha="center", va="center") + extent=[0,1,0,1], rasterized=True) + ax.text(0.5, 0.1, str(interp_method), weight="bold", color="white", size=6, + ha="center", va="center") -plt.tight_layout() plt.savefig("../figures/interpolations.pdf", dpi=600) # plt.show() diff --git a/scripts/projections.py b/scripts/projections.py index a262050c..78bec7ea 100644 --- a/scripts/projections.py +++ b/scripts/projections.py @@ -2,12 +2,20 @@ # Matplotlib cheat sheet # Released under the BSD License # ----------------------------------------------------------------------------- +import pathlib + import numpy as np import cartopy import matplotlib as mpl import matplotlib.pyplot as plt +mpl.style.use([ + pathlib.Path(__file__).parent/'../styles/base.mplstyle', + pathlib.Path(__file__).parent/'../styles/plotlet.mplstyle', +]) + + CARTOPY_SOURCE_TEMPLATE = 'https://naturalearth.s3.amazonaws.com/{resolution}_{category}/ne_{resolution}_{name}.zip' @@ -21,26 +29,22 @@ # Polar plot # ----------------------------------------------------------------------------- -mpl.rc('axes', linewidth=4.0) -fig = plt.figure(figsize=(4, 4)) -b = 0.025 -ax = fig.add_axes([b, b, 1-2*b, 1-2*b], projection="polar") +(fig, ax) = plt.subplots(subplot_kw={'projection': 'polar'}) T = np.linspace(0, 3*2*np.pi, 500) R = np.linspace(0, 2, len(T)) -ax.plot(T, R, color="C1", linewidth=6) +ax.plot(T, R, color="C1") ax.set_xticks(np.linspace(0, 2*np.pi, 2*8)) ax.set_xticklabels([]) ax.set_yticks(np.linspace(0, 2, 8)) ax.set_yticklabels([]) -ax.set_ylim(0, 2) -ax.grid(linewidth=1) +ax.set_ylim(0,2) +ax.grid(linewidth=0.2) plt.savefig("../figures/projection-polar.pdf") fig.clear() # 3D plot # ----------------------------------------------------------------------------- -mpl.rc('axes', linewidth=2.0) -ax = fig.add_axes([0, .1, 1, .9], projection="3d") +(fig, ax) = plt.subplots(subplot_kw={'projection': '3d'}) r = np.linspace(0, 1.25, 50) p = np.linspace(0, 2*np.pi, 50) R, P = np.meshgrid(r, p) @@ -58,9 +62,8 @@ # Cartopy plot # ----------------------------------------------------------------------------- -mpl.rc('axes', linewidth=3.0) -b = 0.025 -ax = fig.add_axes([b, b, 1-2*b, 1-2*b], frameon=False, +fig = plt.figure() +ax = fig.add_subplot(frameon=False, projection=cartopy.crs.Orthographic()) ax.add_feature(cartopy.feature.LAND, zorder=0, facecolor="C1", edgecolor="0.0", linewidth=0) diff --git a/scripts/tick-formatters.py b/scripts/tick-formatters.py index 8566554a..5cf27bca 100644 --- a/scripts/tick-formatters.py +++ b/scripts/tick-formatters.py @@ -3,33 +3,34 @@ # Author: Nicolas P. Rougier # License: BSD # ---------------------------------------------------------------------------- +import pathlib + import numpy as np +import matplotlib as mpl import matplotlib.pyplot as plt import matplotlib.ticker as ticker + +mpl.style.use([ + pathlib.Path(__file__).parent/'../styles/base.mplstyle', + pathlib.Path(__file__).parent/'../styles/ticks.mplstyle', +]) + + # Setup a plot such that only the bottom spine is shown def setup(ax): - ax.spines['right'].set_color('none') - ax.spines['left'].set_color('none') ax.yaxis.set_major_locator(ticker.NullLocator()) - ax.spines['top'].set_color('none') - ax.xaxis.set_ticks_position('bottom') - ax.tick_params(which='major', width=1.00, length=5) - ax.tick_params(which='minor', width=0.75, length=2.5, labelsize=10) ax.set_xlim(0, 5) ax.set_ylim(0, 1) ax.patch.set_alpha(0.0) -fig = plt.figure(figsize=(8, 5)) +fig = plt.figure(figsize=(5.7/2.54, 3.8/2.54)) fig.patch.set_alpha(0.0) n = 7 -fontsize = 18 -family = "Source Code Pro" - # Null formatter ax = fig.add_subplot(n, 1, 1) setup(ax) @@ -37,8 +38,7 @@ def setup(ax): ax.xaxis.set_minor_locator(ticker.MultipleLocator(0.25)) ax.xaxis.set_major_formatter(ticker.NullFormatter()) ax.xaxis.set_minor_formatter(ticker.NullFormatter()) -ax.text(0.0, 0.1, "ticker.NullFormatter()", family=family, - fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, "ticker.NullFormatter()", transform=ax.transAxes) # Fixed formatter ax = fig.add_subplot(n, 1, 2) @@ -50,8 +50,7 @@ def setup(ax): minors = [""] + ["%.2f" % (x-int(x)) if (x-int(x)) else "" for x in np.arange(0, 5, 0.25)] ax.xaxis.set_minor_formatter(ticker.FixedFormatter(minors)) -ax.text(0.0, 0.1, "ticker.FixedFormatter(['', '0', '1', ...])", - family=family, fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, "ticker.FixedFormatter(['', '0', '1', ...])", transform=ax.transAxes) # FuncFormatter can be used as a decorator @@ -65,8 +64,7 @@ def major_formatter(x, pos): ax.xaxis.set_major_locator(ticker.MultipleLocator(1.00)) ax.xaxis.set_minor_locator(ticker.MultipleLocator(0.25)) ax.xaxis.set_major_formatter(major_formatter) -ax.text(0.0, 0.1, 'ticker.FuncFormatter(lambda x, pos: "[%.2f]" % x)', - family=family, fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, 'ticker.FuncFormatter(lambda x, pos: "[%.2f]" % x)', transform=ax.transAxes) # FormatStr formatter @@ -75,8 +73,7 @@ def major_formatter(x, pos): ax.xaxis.set_major_locator(ticker.MultipleLocator(1.00)) ax.xaxis.set_minor_locator(ticker.MultipleLocator(0.25)) ax.xaxis.set_major_formatter(ticker.FormatStrFormatter(">%d<")) -ax.text(0.0, 0.1, "ticker.FormatStrFormatter('>%d<')", - family=family, fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, "ticker.FormatStrFormatter('>%d<')", transform=ax.transAxes) # Scalar formatter ax = fig.add_subplot(n, 1, 5) @@ -84,8 +81,7 @@ def major_formatter(x, pos): ax.xaxis.set_major_locator(ticker.AutoLocator()) ax.xaxis.set_minor_locator(ticker.AutoMinorLocator()) ax.xaxis.set_major_formatter(ticker.ScalarFormatter(useMathText=True)) -ax.text(0.0, 0.1, "ticker.ScalarFormatter()", - family=family, fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, "ticker.ScalarFormatter()", transform=ax.transAxes) # StrMethod formatter ax = fig.add_subplot(n, 1, 6) @@ -93,8 +89,7 @@ def major_formatter(x, pos): ax.xaxis.set_major_locator(ticker.MultipleLocator(1.00)) ax.xaxis.set_minor_locator(ticker.MultipleLocator(0.25)) ax.xaxis.set_major_formatter(ticker.StrMethodFormatter("{x}")) -ax.text(0.0, 0.1, "ticker.StrMethodFormatter('{x}')", - family=family, fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, "ticker.StrMethodFormatter('{x}')", transform=ax.transAxes) # Percent formatter ax = fig.add_subplot(n, 1, 7) @@ -102,12 +97,7 @@ def major_formatter(x, pos): ax.xaxis.set_major_locator(ticker.MultipleLocator(1.00)) ax.xaxis.set_minor_locator(ticker.MultipleLocator(0.25)) ax.xaxis.set_major_formatter(ticker.PercentFormatter(xmax=5)) -ax.text(0.0, 0.1, "ticker.PercentFormatter(xmax=5)", - family=family, fontsize=fontsize, transform=ax.transAxes) - -# Push the top of the top axes outside the figure because we only show the -# bottom spine. -fig.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=1.05) +ax.text(0.0, 0.1, "ticker.PercentFormatter(xmax=5)", transform=ax.transAxes) -plt.savefig("../figures/tick-formatters.pdf", transparent=True) +plt.savefig("../figures/tick-formatters.pdf") # plt.show() diff --git a/scripts/tick-locators.py b/scripts/tick-locators.py index 276f8a3b..c6521c01 100644 --- a/scripts/tick-locators.py +++ b/scripts/tick-locators.py @@ -3,50 +3,47 @@ # Author: Nicolas P. Rougier # License: BSD # ---------------------------------------------------------------------------- +import pathlib + import numpy as np +import matplotlib as mpl import matplotlib.pyplot as plt import matplotlib.ticker as ticker + +mpl.style.use([ + pathlib.Path(__file__).parent/'../styles/base.mplstyle', + pathlib.Path(__file__).parent/'../styles/ticks.mplstyle', +]) + + # Setup a plot such that only the bottom spine is shown def setup(ax): - ax.spines['right'].set_color('none') - ax.spines['left'].set_color('none') ax.yaxis.set_major_locator(ticker.NullLocator()) - ax.spines['top'].set_color('none') - ax.xaxis.set_ticks_position('bottom') - ax.tick_params(which='major', width=1.00) - ax.tick_params(which='major', length=5) - ax.tick_params(which='minor', width=0.75) - ax.tick_params(which='minor', length=2.5) ax.set_xlim(0, 5) ax.set_ylim(0, 1) ax.patch.set_alpha(0.0) -fig = plt.figure(figsize=(8, 5)) +fig = plt.figure(figsize=(5.7/2.54, 3.8/2.54)) fig.patch.set_alpha(0.0) n = 8 -fontsize = 18 -family = "Source Code Pro" - # Null Locator ax = plt.subplot(n, 1, 1) setup(ax) ax.xaxis.set_major_locator(ticker.NullLocator()) ax.xaxis.set_minor_locator(ticker.NullLocator()) -ax.text(0.0, 0.1, "ticker.NullLocator()", - family=family, fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, "ticker.NullLocator()", transform=ax.transAxes) # Multiple Locator ax = plt.subplot(n, 1, 2) setup(ax) ax.xaxis.set_major_locator(ticker.MultipleLocator(0.5)) ax.xaxis.set_minor_locator(ticker.MultipleLocator(0.1)) -ax.text(0.0, 0.1, "ticker.MultipleLocator(0.5)", - family=family, fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, "ticker.MultipleLocator(0.5)", transform=ax.transAxes) # Fixed Locator ax = plt.subplot(n, 1, 3) @@ -55,40 +52,35 @@ def setup(ax): ax.xaxis.set_major_locator(ticker.FixedLocator(majors)) minors = np.linspace(0, 1, 11)[1:-1] ax.xaxis.set_minor_locator(ticker.FixedLocator(minors)) -ax.text(0.0, 0.1, "ticker.FixedLocator([0, 1, 5])", - family=family, fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, "ticker.FixedLocator([0, 1, 5])", transform=ax.transAxes) # Linear Locator ax = plt.subplot(n, 1, 4) setup(ax) ax.xaxis.set_major_locator(ticker.LinearLocator(3)) ax.xaxis.set_minor_locator(ticker.LinearLocator(31)) -ax.text(0.0, 0.1, "ticker.LinearLocator(numticks=3)", - family=family, fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, "ticker.LinearLocator(numticks=3)", transform=ax.transAxes) # Index Locator ax = plt.subplot(n, 1, 5) setup(ax) ax.plot(range(0, 5), [0]*5, color='white') ax.xaxis.set_major_locator(ticker.IndexLocator(base=.5, offset=.25)) -ax.text(0.0, 0.1, "ticker.IndexLocator(base=0.5, offset=0.25)", - family=family, fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, "ticker.IndexLocator(base=0.5, offset=0.25)", transform=ax.transAxes) # Auto Locator ax = plt.subplot(n, 1, 6) setup(ax) ax.xaxis.set_major_locator(ticker.AutoLocator()) ax.xaxis.set_minor_locator(ticker.AutoMinorLocator()) -ax.text(0.0, 0.1, "ticker.AutoLocator()", - family=family, fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, "ticker.AutoLocator()", transform=ax.transAxes) # MaxN Locator ax = plt.subplot(n, 1, 7) setup(ax) ax.xaxis.set_major_locator(ticker.MaxNLocator(4)) ax.xaxis.set_minor_locator(ticker.MaxNLocator(40)) -ax.text(0.0, 0.1, "ticker.MaxNLocator(n=4)", - family=family, fontsize=fontsize, transform=ax.transAxes) +ax.text(0.0, 0.1, "ticker.MaxNLocator(n=4)", transform=ax.transAxes) # Log Locator ax = plt.subplot(n, 1, 8) @@ -96,12 +88,7 @@ def setup(ax): ax.set_xlim(10**3, 10**10) ax.set_xscale('log') ax.xaxis.set_major_locator(ticker.LogLocator(base=10.0, numticks=15)) -ax.text(0.0, 0.1, "ticker.LogLocator(base=10, numticks=15)", - family=family, fontsize=fontsize, transform=ax.transAxes) - -# Push the top of the top axes outside the figure because we only show the -# bottom spine. -plt.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=1.05) +ax.text(0.0, 0.1, "ticker.LogLocator(base=10, numticks=15)", transform=ax.transAxes) -plt.savefig("../figures/tick-locators.pdf", transparent=True) +plt.savefig("../figures/tick-locators.pdf") # plt.show() diff --git a/styles/base.mplstyle b/styles/base.mplstyle new file mode 100644 index 00000000..77cbdce4 --- /dev/null +++ b/styles/base.mplstyle @@ -0,0 +1,5 @@ +figure.constrained_layout.use: True +figure.constrained_layout.h_pad: 0 +figure.constrained_layout.w_pad: 0 +figure.constrained_layout.hspace: 0 +figure.constrained_layout.wspace: 0 diff --git a/styles/plotlet-grid.mplstyle b/styles/plotlet-grid.mplstyle new file mode 100644 index 00000000..c4133c3f --- /dev/null +++ b/styles/plotlet-grid.mplstyle @@ -0,0 +1,10 @@ +figure.constrained_layout.h_pad: 0.04 +figure.constrained_layout.w_pad: 0.04 +figure.constrained_layout.hspace: 0.04 +figure.constrained_layout.wspace: 0.04 + +font.family: Source Code Pro +font.size: 5 + +xtick.major.size: 0.0 +ytick.major.size: 0.0 diff --git a/styles/ticks.mplstyle b/styles/ticks.mplstyle new file mode 100644 index 00000000..a2fb14f9 --- /dev/null +++ b/styles/ticks.mplstyle @@ -0,0 +1,17 @@ +savefig.transparent: True + +font.family: Source Code Pro +font.size: 5 + +axes.linewidth: 0.5 +axes.spines.right: False +axes.spines.top: False +axes.spines.left: False +axes.spines.bottom: True + +xtick.labelsize: 3 +xtick.major.pad: 1 +xtick.major.width: 0.2 +xtick.major.size: 2 +xtick.minor.width: 0.1 +xtick.minor.size: 1