The basics

Creating figures

ProPlot works by creating a proplot.figure.Figure subclass of the matplotlib figure class Figure, and a proplot.axes.Axes subclass of the matplotlib axes class Axes. All plotting in ProPlot begins by generating an instance of the new figure class filled with instances of the new axes classes using the subplots command, which is modeled after matplotlib.pyplot.subplots. ProPlot’s subplots command can be used as follows:

  • Without any arguments, subplots returns a figure with a single subplot.

  • With ncols or nrows, subplots returns a figure with a simple grid of subplots.

  • With array, subplots returns an arbitrarily complex grid of subplots. This is a 2D array representing a “picture” of the subplot layout, where each unique integer indicates a GridSpec slot that is occupied by the corresponding subplot and 0 indicates an empty space.

In the below examples, we create subplot grids with subplots and modify the axes labels. See the formatting guide and subplots container sections for details.

Note

ProPlot figure backgrounds are only gray when displayed by the matplotlib backend – the default background color is white when the figure is saved. This is done by setting [rc[‘figure.facecolor’]](https://matplotlib.org/tutorials/introductory/customizing.html?highlight=figure.facecolor#the-matplotlibrc-file) to gray, in order to improve contrast when working with figures. ProPlot also makes the default saved figure background transparent by setting [rc[‘savefig.transparent’]](https://matplotlib.org/tutorials/introductory/customizing.html?highlight=savefig.transparent#the-matplotlibrc-file) to True and changes the default [rc[‘savefig.format’]](https://matplotlib.org/tutorials/introductory/customizing.html?highlight=savefig.format#the-matplotlibrc-file) from PNG to PDF for the following reasons:

  1. Vector graphic formats are infinitely scalable.

  2. Vector graphic formats are preferred by academic journals.

  3. Most academic journals accept PDF figures alongside the traditional EPS format.

  4. The EPS format does not support transparent graphic elements.

In case you do need raster graphics, ProPlot sets the default [rc[‘savefig.dpi’]](https://matplotlib.org/tutorials/introductory/customizing.html?highlight=savefig.dpi#the-matplotlibrc-file) to 1200 dots per inch, which is recommended by most journals as the minimum resolution for rasterized figures containing lines and text. See the configuration section for how to change any of these settings.

  1. [1]:
  1. # Generate sample data
  2. import numpy as np
  3. state = np.random.RandomState(51423)
  4. data = 2 * (state.rand(100, 5) - 0.5).cumsum(axis=0)
  1. [2]:
  1. # Single subplot
  2. import proplot as plot
  3. fig, ax = plot.subplots()
  4. ax.plot(data, lw=2)
  5. ax.format(suptitle='Single subplot', xlabel='x axis', ylabel='y axis')

_images/basics_4_0.svg

  1. [3]:
  1. # Simple subplot grid
  2. import proplot as plot
  3. fig, axs = plot.subplots(ncols=2)
  4. axs[0].plot(data, lw=2)
  5. axs[0].format(xticks=20, xtickminor=False)
  6. axs.format(
  7. suptitle='Simple subplot grid', title='Title',
  8. xlabel='x axis', ylabel='y axis'
  9. )

_images/basics_5_0.svg

  1. [4]:
  1. # Complex grid
  2. import proplot as plot
  3. array = [ # the "picture" (0 == nothing, 1 == subplot A, 2 == subplot B, etc.)
  4. [1, 1, 2, 2],
  5. [0, 3, 3, 0],
  6. ]
  7. fig, axs = plot.subplots(array, axwidth=1.8)
  8. axs.format(
  9. abc=True, abcloc='ul', suptitle='Complex subplot grid',
  10. xlabel='xlabel', ylabel='ylabel'
  11. )
  12. axs[2].plot(data, lw=2)
  1. [4]:
  1. (<matplotlib.lines.Line2D at 0x7f636bdd8c70>,
  2. <matplotlib.lines.Line2D at 0x7f636bdda040>,
  3. <matplotlib.lines.Line2D at 0x7f636bdda3d0>,
  4. <matplotlib.lines.Line2D at 0x7f636bdda760>,
  5. <matplotlib.lines.Line2D at 0x7f636bddaaf0>)

_images/basics_6_1.svg

  1. [5]:
  1. # Really complex grid
  2. import proplot as plot
  3. array = [ # the "picture" (1 == subplot A, 2 == subplot B, etc.)
  4. [1, 1, 2],
  5. [1, 1, 6],
  6. [3, 4, 4],
  7. [3, 5, 5],
  8. ]
  9. fig, axs = plot.subplots(array, width=5, span=False)
  10. axs.format(
  11. suptitle='Really complex subplot grid',
  12. xlabel='xlabel', ylabel='ylabel', abc=True
  13. )
  14. axs[0].plot(data, lw=2)
  1. [5]:
  1. (<matplotlib.lines.Line2D at 0x7f636bfbadc0>,
  2. <matplotlib.lines.Line2D at 0x7f636bf60fa0>,
  3. <matplotlib.lines.Line2D at 0x7f636bf60580>,
  4. <matplotlib.lines.Line2D at 0x7f636bf601c0>,
  5. <matplotlib.lines.Line2D at 0x7f636bf60b50>)

_images/basics_7_1.svg

Plotting data

Matplotlib has two different APIs: an object-oriented API and a MATLAB-style pyplot API (which uses the object-oriented API internally). Plotting in ProPlot is just like plotting in matplotlib with the object-oriented API. Rather than creating a brand new interface, ProPlot simply builds upon the existing matplotlib constructs of the Axes and the Figure by adding new commands and new options to existing commands, without changing the usage or syntax. This means a shallow learning curve for the average matplotlib user.

In the below example, we create a 4-panel figure with the familiar matplotlib commands plot, scatter, pcolormesh, and contourf. See the 1d plotting and 2d plotting sections for details on the plotting features added by ProPlot.

  1. [6]:
  1. import proplot as plot
  2. import numpy as np
  3. # Sample data
  4. N = 20
  5. state = np.random.RandomState(51423)
  6. data = (state.rand(N, N) - 0.5).cumsum(axis=0).cumsum(axis=1)
  7. # Example plots
  8. cycle = plot.Cycle('greys', left=0.2, N=5)
  9. fig, axs = plot.subplots(ncols=2, nrows=2, share=0, width=5)
  10. axs[0].plot(data[:, :5], linewidth=2, linestyle='--', cycle=cycle)
  11. axs[1].scatter(data[:, :5], marker='x', cycle=cycle)
  12. axs[2].pcolormesh(data, cmap='greys')
  13. axs[3].contourf(data, cmap='greys')
  14. axs.format(abc=True, xlabel='xlabel', ylabel='ylabel', suptitle='Quick plotting demo')

_images/basics_9_0.svg

Formatting plots

Every Axes returned by subplots has a format method. This is your one-stop-shop for changing axes settings. Keyword arguments passed to format are interpreted as follows:

  1. Any keyword matching the name of an rc setting is used to update the axes. If the name has “dots”, you can omit them (e.g. titleloc='left' to change the [rc[‘title.loc’]](https://proplot.readthedocs.io/en/latest/configuration.html?highlight=title.loc#rc-proplot) property). See the configuration section for details.

  2. Valid keywords arguments are passed to proplot.axes.CartesianAxes.format, proplot.axes.PolarAxes.format, or proplot.axes.GeoAxes.format. These change settings that are specific to the axes type. For example:

    • To change the x axis bounds on a CartesianAxes, use e.g. xlim=(0, 5).

    • To change the radial bounds on a PolarAxes, use e.g. rlim=(0, 10).

    • To change the meridional bounds on a GeoAxes, use e.g. lonlim=(-90, 0).

  1. Remaining keyword arguments are passed to the base proplot.axes.Axes.format method. Axes is the base class for all other axes classes. This changes things that are the same for all axes types, like titles and a-b-c subplot labels (e.g. title='Title').

The format methods let you use simple shorthands for changing all kinds of settings at once, instead of one-liner setter methods like ax.set_title() and ax.set_xlabel(). They are also integrated with the Locator, Formatter, and Scale constructor functions (see the Cartesian axis settings section for details).

The below example shows the many different keyword arguments accepted by format, and demonstrates how format can be used to succinctly and efficiently customize your plots.

  1. [7]:
  1. import proplot as plot
  2. import numpy as np
  3. fig, axs = plot.subplots(ncols=2, nrows=2, share=0, tight=True, axwidth=2)
  4. state = np.random.RandomState(51423)
  5. N = 60
  6. x = np.linspace(1, 10, N)
  7. y = (state.rand(N, 5) - 0.5).cumsum(axis=0)
  8. axs[0].plot(x, y, linewidth=1.5)
  9. axs.format(
  10. suptitle='Format command demo',
  11. abc=True, abcloc='ul', abcstyle='A.',
  12. title='Main', ltitle='Left', rtitle='Right', # different titles
  13. urtitle='Title A', lltitle='Title B', lrtitle='Title C', # extra titles
  14. collabels=['Column label 1', 'Column label 2'],
  15. rowlabels=['Row label 1', 'Row label 2'],
  16. xlabel='x-axis', ylabel='y-axis',
  17. xscale='log',
  18. xlim=(1, 10), xticks=1,
  19. ylim=(-3, 3), yticks=plot.arange(-3, 3),
  20. yticklabels=('a', 'bb', 'c', 'dd', 'e', 'ff', 'g'),
  21. ytickloc='both', yticklabelloc='both',
  22. xtickdir='inout', xtickminor=False, ygridminor=True,
  23. )

_images/basics_11_0.svg

Changing rc settings

A special object named rc is created whenever you import ProPlot. rc is similar to the matplotlib rcParams dictionary, but can be used to change both matplotlib settings and ProPlot settings. rc also provides a style parameter that can be used to switch between matplotlib stylesheets. See the configuration section for details.

To modify a setting for just one subplot, you can pass it to the Axes format method. To temporarily modify setting(s) for a block of code, use context. To modify setting(s) for the entire python session, just assign it to the rc object or use update. To reset everything to the default state, use reset. See the below example.

  1. [8]:
  1. import proplot as plot
  2. import numpy as np
  3. # Update global settings in several different ways
  4. plot.rc.cycle = 'colorblind'
  5. plot.rc.color = 'gray6'
  6. plot.rc.update({'fontname': 'Source Sans Pro', 'fontsize': 11})
  7. plot.rc['figure.facecolor'] = 'gray3'
  8. plot.rc.axesfacecolor = 'gray4'
  9. # plot.rc.save() # save the current settings to ~/.proplotrc
  10. # Apply settings to figure with context()
  11. with plot.rc.context({'suptitle.size': 13}, toplabelcolor='gray6', linewidth=1.5):
  12. fig, axs = plot.subplots(ncols=2, aspect=1, width=6, span=False, sharey=2)
  13. # Plot lines
  14. N, M = 100, 6
  15. state = np.random.RandomState(51423)
  16. values = np.arange(1, M + 1)
  17. for i, ax in enumerate(axs):
  18. data = np.cumsum(state.rand(N, M) - 0.5, axis=0)
  19. lines = ax.plot(data, linewidth=3, cycle='Grays')
  20. # Apply settings to axes with format()
  21. axs.format(
  22. grid=False, xlabel='x label', ylabel='y label',
  23. collabels=['Column label 1', 'Column label 2'],
  24. suptitle='Rc settings demo',
  25. suptitlecolor='gray7',
  26. abc=True, abcloc='l', abcstyle='A)',
  27. title='Title', titleloc='r', titlecolor='gray7'
  28. )
  29. ay = axs[-1].twinx()
  30. ay.format(ycolor='red', linewidth=1.5, ylabel='secondary axis')
  31. ay.plot((state.rand(100) - 0.2).cumsum(), color='r', lw=3)
  32. # Reset persistent modifications from head of cell
  33. plot.rc.reset()

_images/basics_13_0.svg

  1. [9]:
  1. import proplot as plot
  2. import numpy as np
  3. # plot.rc.style = 'style' # set the style everywhere
  4. # Set up figure
  5. styles = ('ggplot', 'seaborn', '538', 'bmh')
  6. state = np.random.RandomState(51423)
  7. data = state.rand(10, 5)
  8. fig, axs = plot.subplots(ncols=2, nrows=2, span=False, share=False)
  9. # Apply different styles to different axes with format()
  10. axs.format(suptitle='Stylesheets demo')
  11. for ax, style in zip(axs, styles):
  12. ax.format(style=style, xlabel='xlabel', ylabel='ylabel', title=style)
  13. ax.plot(data, linewidth=3)

_images/basics_14_0.svg

Subplots containers

Instead of an ndarray of axes, subplots returns a SubplotsContainer instance. This container behaves like an Axes object when it contains just one axes, and behaves like a list otherwise. It supports both 1D indexing (e.g. axs[1]) and 2D indexing (e.g. axs[0, 1]), and is row-major by default. Slicing a SubplotsContainer returns another container (e.g. axs[:, 0]), and Axes methods can be called simultaneously for all axes in the container by calling the method from the container (e.g. axs.format(abc=True)).

In the below example, the SubplotsContainer returned by subplots is used to cusomtize several axes at once with proplot.axes.Axes.format.

  1. [10]:
  1. import proplot as plot
  2. import numpy as np
  3. state = np.random.RandomState(51423)
  4. fig, axs = plot.subplots(ncols=4, nrows=4, axwidth=1.2)
  5. axs.format(
  6. xlabel='xlabel', ylabel='ylabel', suptitle='SubplotsContainer demo',
  7. grid=False, xlim=(0, 50), ylim=(-4, 4)
  8. )
  9. # Various ways to select subplots in the container
  10. axs[:, 0].format(facecolor='blush', color='gray7', linewidth=1)
  11. axs[0, :].format(facecolor='sky blue', color='gray7', linewidth=1)
  12. axs[0].format(color='black', facecolor='gray5', linewidth=1.4)
  13. axs[1:, 1:].format(facecolor='gray1')
  14. for ax in axs[1:, 1:]:
  15. ax.plot((state.rand(50, 5) - 0.5).cumsum(axis=0), cycle='Grays', lw=2)

_images/basics_16_0.svg