Skip to content

Wrap subplot #412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Plotting data and laying out the map:
Figure.logo
Figure.image
Figure.shift_origin
Figure.subplot
Figure.text
Figure.meca

Expand Down
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
projections/index.rst
tutorials/coastlines.rst
tutorials/plot.rst
tutorials/subplots.rst

.. toctree::
:maxdepth: 2
Expand Down
87 changes: 87 additions & 0 deletions examples/tutorials/subplots.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""
Subplots
========

When you're preparing a figure for a paper, there will often be times when
you'll need to put many individual plots into one large figure, and label them
'abcd'. These individual plots are called subplots.

There are two main ways to handle subplots in GMT:

- Use :meth:`pygmt.Figure.shift_origin` to manually move each individual plot
to the right position.
- Use :meth:`pygmt.Figure.subplot` to define the layout of the subplots.

The first method is easier to use and should handle simple cases involving a
couple of subplots. For more advanced subplot layouts however, we recommend the
use of :meth:`pygmt.Figure.subplot` which offers finer grained control, and
this is what the tutorial below will cover.
"""

###############################################################################
# Let's start by importing the PyGMT library and initiating a figure.

import pygmt

fig = pygmt.Figure()

###############################################################################
# Define subplot layout
# ---------------------
#
# The ``fig.subplot(directive="begin")`` command is used to setup the layout,
# size, and other attributes of the figure. It divides the whole canvas into
# regular grid areas with n rows and m columns. Each grid area can contain an
# individual subplot. For example:

fig.subplot(directive="begin", row=2, col=3, dimensions="s5c/3c", frame="lrtb")

###############################################################################
# will define our figure to have a 2 row and 3 column grid layout.
# ``dimensions="s5c/3c"`` specifies that each 's'ubplot will have a width of
# 5cm and height of 3cm. Alternatively, you can set ``dimensions="f15c/6c"`` to
# define the overall size of the 'f'igure to be 15cm wide by 6cm high. Using
# ``frame="lrtb"`` allows us to customize the map frame for all subplots. The
# figure layout will look like the following:

for index in range(2 * 3):
i = index // 3 # row
j = index % 3 # column
fig.subplot(directive="set", row=i, col=j)
fig.text(
x=0.5, y=0.5, text=f"index: {index}, row: {i}, col: {j}", region=[0, 1, 0, 1]
)
fig.subplot(directive="end")
fig.show()

###############################################################################
# The ``fig.subplot(directive="set")`` command activates a specified subplot,
# and all subsequent plotting commands will take place in that subplot. In
# order to specify a subplot, you will need to know the identifier for each
# subplot. This can be done by setting the ``row`` and ``col`` arguments.

###############################################################################
# .. note::
#
# The row and column numbering starts from 0. So for a subplot layout with
# N rows and M columns, row numbers will go from 0 to N-1, and column
# numbers will go from 0 to M-1.

###############################################################################
# For example, to activate the subplot on the top right corner (index: 2) so
# that all subsequent plotting commands happen there, you can use the following
# command:

###############################################################################
# .. code-block:: default
#
# fig.subplot(directive="set", row=0, col=2)

###############################################################################
# Finally, remember to use ``fig.subplot(directive="end")`` to exit the subplot
# mode.

###############################################################################
# .. code-block:: default
#
# fig.subplot(directive="end")
54 changes: 54 additions & 0 deletions pygmt/base_plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,60 @@ def legend(self, spec=None, position="JTR+jTR+o0.2c", box="+gwhite+p1p", **kwarg
lib.call_module("legend", arg_str)

@fmt_docstring
@use_alias(F="dimensions", B="frame")
def subplot(self, directive: str, row: int = None, col: int = None, **kwargs):
"""
Manage modern mode figure subplot configuration and selection.

The subplot module is used to split the current figure into a
rectangular layout of subplots that each may contain a single
self-contained figure. A subplot setup is started with the begin
directive that defines the layout of the subplots, while positioning to
a particular subplot for plotting is done via the set directive. The
subplot process is completed via the end directive.

Full option list at :gmt-docs:`subplot.html`

{aliases}

Parameters
----------
directive : str
Either 'begin', 'set' or 'end'.
row : int
The number of rows if using the 'begin' directive, or the row
number if using the 'set' directive. First row is 0, not 1.
col : int
The number of columns if using the 'begin' directive, or the column
number if using the 'set' directive. First column is 0, not 1.
dimensions : str
``[f|s]width(s)/height(s)[+fwfracs/hfracs][+cdx/dy][+gfill][+ppen]
[+wpen]``
Specify the dimensions of the figure when using the 'begin'
directive. There are two different ways to do this: (f) Specify
overall figure dimensions or (s) specify the dimensions of a single
subplot.
"""
if directive not in ("begin", "set", "end"):
raise GMTInvalidInput(
f"Unrecognized subplot directive '{directive}',\
should be either 'begin', 'set', or 'end'"
)

with Session() as lib:
rowcol = "" # default is blank, e.g. when directive == "end"
if row is not None and col is not None:
if directive == "begin":
rowcol = f"{row}x{col}"
elif directive == "set":
rowcol = f"{row},{col}"
arg_str = " ".join(
a for a in [directive, rowcol, build_arg_string(kwargs)] if a
)
lib.call_module(module="subplot", args=arg_str)

@fmt_docstring
@use_alias(R="region", J="projection", B="frame")
@use_alias(
R="region",
J="projection",
Expand Down
Binary file added pygmt/tests/baseline/test_subplot_basic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pygmt/tests/baseline/test_subplot_frame.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions pygmt/tests/test_subplot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""
Tests subplot
"""
import pytest

from .. import Figure
from ..exceptions import GMTInvalidInput


@pytest.mark.mpl_image_compare
def test_subplot_basic():
"""
Create a subplot figure with 1 row and 2 columns.
"""
fig = Figure()
fig.subplot(directive="begin", row=1, col=2, dimensions="f6c/3c")
fig.subplot(directive="set", row=0, col=0)
fig.basemap(region=[0, 3, 0, 3], frame=True)
fig.subplot(directive="set", row=0, col=1)
fig.basemap(region=[0, 3, 0, 3], frame=True)
fig.subplot(directive="end")
return fig


@pytest.mark.mpl_image_compare
def test_subplot_frame():
"""
Check that map frame setting is applied to all subplot figures
"""
fig = Figure()
fig.subplot(directive="begin", row=1, col=2, dimensions="f6c/3c", frame="WSne")
fig.subplot(directive="set", row=0, col=0)
fig.basemap(region=[0, 3, 0, 3], frame="+tplot0")
fig.subplot(directive="set", row=0, col=1)
fig.basemap(region=[0, 3, 0, 3], frame="+tplot1")
fig.subplot(directive="end")
return fig


def test_subplot_incorrect_directive():
"""
Check that subplot fails when an incorrect directive is used
"""
fig = Figure()
with pytest.raises(GMTInvalidInput):
fig.subplot(directive="start")