-
Notifications
You must be signed in to change notification settings - Fork 224
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
Experimental subplot implementation that mimics matplotlib's style #427
Conversation
Hi Wei Ji, thanks for doing this! I’ve been looking through this a bit now. I like the subplots function! But I think we shouldn’t do sca as well. A major fault of matplotlib is having too many ways of doing the same thing. We can stick close to their api but need to be careful not to repeat their mistakes. |
Yes, the good ol Zen of Python - "There should be one-- and preferably only one --obvious way to do it.". I definitely prefer using However, the Edit: I've started a forum thread at https://forum.generic-mapping-tools.org/t/pygmt-as-a-high-level-api-for-geovisualization/590/2 to discuss this further after PyGMT Meeting #1. |
Wrapping the `subplot` function! Original GMT `subplot` function can be found at https://docs.generic-mapping-tools.org/latest/subplot.html. Current implementation has a 'directive' statement to tell subplot whether to 'begin', 'set' or 'end' a subplot, and the position/number of row(s) and column(s) can be set too. Also created an alias for dimensions (F).
Include test to check that map frame setting is applied to all subplot figures when using 'begin' subplot directive.
3889f97
to
233b9aa
Compare
Translated and adapted from https://github.com/gmt-china/GMT_Docs/blob/master/source/tutorial/subplot.rst. Covers basics of using pygmt subplot begin, set and end. Still need to handle gmt "set" using index instead of just row and col.
Experimenting with a more matplotlib-like syntax for managing subplots, namely the `fig, axs = plt.subplots()` style of defining subplots! A high-level `subplots` function is defined in pygmtplots.py, that wraps around the new class SubPlot (inherited from the main Figure class to include subplot functionality). Re-aliased F to figsize (previously called dimensions). Also updated tests and tutorials to reference this new syntax.
Used to advance to the selected subplot panel. Technically only allowed when in subplot mode. See https://docs.generic-mapping-tools.org/latest/gmt.html#c-full.
233b9aa
to
18ab9d6
Compare
Ping @MarkWieczorek, I noticed that SHTOOLS has a tutorial on creating subplots using PyGMT's using X and Y offsets at https://nbviewer.jupyter.org/github/SHTOOLS/SHTOOLS/blob/master/examples/notebooks/plotting-maps.ipynb#Creating-Subplots. Right now this PR is attempting to have a syntax like Would be great to get hear your thoughts on this, e.g. would you like to do |
This looks good to me! I would be happy to test this with shtools, but this will have to wait until mid october.... |
bb4d496
to
aaa2059
Compare
Also modified `basemap` to allow no frame (B) when ax (c) is used (i.e. with subplot).
Also added in the `ax=True` tip for auto selection of next subplot, and fixed some typos in previous commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, I'm marking this as ready to review, though there are still some rough spots. The translation over from https://docs.gmt-china.org/latest/tutorial/subplot/ is complete, and I think it's worth the team taking a look. Let me know if I should cherry-pick stuff out into separate PRs to make it easier to review.
Note that there are some functionality from https://docs.generic-mapping-tools.org/latest/subplot.html that aren't covered yet:
-Fs
(subfigsize?) at https://docs.generic-mapping-tools.org/latest/subplot.html#f- The matplotlib way of plotting using something like
ax[0, 1].plot()
- quite tricky to implement!!
############################################################################### | ||
# .. note:: | ||
# | ||
# There are bugs that have not been fixed in the above example. | ||
# | ||
# In subplot mode, the size of each subgraph is controlled by the | ||
# ``figsize`` option of :meth:`pygmt.subplots`. Users can override this and | ||
# use``projection`` to specify the size of an individual subplot, but this | ||
# size will not be remembered. If the next command does not specify | ||
# ``projection``, the default size of the subplot mode will be used, and | ||
# the resulting plot will be inccorect. | ||
# | ||
# The current workaround is to use the same ``projection`` option in all | ||
# commands for the subplot. For example, we forced subplot (a) to have a | ||
# different size using ``projection="15c/3c``. The next command within the | ||
# subplot (e.g. ``text``) must also use ``projection="x15c/3c"``, otherwise | ||
# the placement will be wrong. | ||
|
||
############################################################################### |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can take this out first, if we want to wait for upstream GMT to support nested subplots at GenericMappingTools/gmt#1280.
fig, axs = pygmt.subplots(nrows=2, ncols=2, figsize=("15c", "6c"), autolabel=True) | ||
fig.basemap( | ||
region=[0, 10, 0, 10], projection="X15c/3c", frame=["af", "WSne"], ax=axs[0, 0] | ||
) | ||
fig.text(text="TEXT", x=5, y=5, projection="X15c/3c") | ||
fig.basemap(region=[0, 5, 0, 5], projection="X?", frame=["af", "WSne"], ax=axs[1, 0]) | ||
fig.basemap(region=[0, 5, 0, 5], projection="X?", frame=["af", "WSne"], ax=axs[1, 1]) | ||
fig.end_subplot() | ||
fig.show() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to fix this example, since it's currently labelling the subplots as 'a)', 'c)', 'd)' (and the 'a)' position is wrong). The obvious way would be to use fig.sca
(i.e. subplot set
), but if we want to avoid it as per #427 (comment), then it's going to require more thought.
############################################################################### | ||
# The ``fig.sca`` command activates a specified subplot, and all subsequent | ||
# plotting commands will take place in that subplot. This is similar to | ||
# matplotlib's ``plt.sca`` method. In order to specify a subplot, you will need | ||
# to provide the identifier for that subplot via the ``ax`` argument. This can | ||
# be found in the ``axs`` variable referenced by the ``row`` and ``col`` | ||
# number. | ||
|
||
############################################################################### | ||
# .. 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) at | ||
# ``row=0`` and ``col=2``, so that all subsequent plotting commands happen | ||
# there, you can use the following command: | ||
|
||
############################################################################### | ||
# .. code-block:: default | ||
# | ||
# fig.sca(ax=axs[0, 2]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self to remove mention of fig.sca
, if we're going to hide this away as per #427 (comment).
Wrapping the `subplot` function, in a `with` statement! Original GMT `subplot` function can be found at https://docs.generic-mapping-tools.org/6.1/subplot.html. This is my 3rd attempt at implementing `subplot` in PyGMT, with commits heavily re-adapted/cherry-picked from #412 and #427.
Wrapping the `subplot` function, in a `with` statement! Original GMT `subplot` function can be found at https://docs.generic-mapping-tools.org/6.1/subplot.html. This is my 3rd attempt at implementing `subplot` in PyGMT, with commits heavily re-adapted/cherry-picked from #412 and #427.
Wrapping the `subplot` function, in a `with` statement! Original GMT `subplot` function can be found at https://docs.generic-mapping-tools.org/6.1/subplot.html. This is the 3rd attempt at implementing `subplot` in PyGMT, with commits heavily re-adapted/cherry-picked from #412 and #427. * Add fig.subplot and fig.set_panel to API docs * Alias fixedlabel (A), clearance (C), verbose (V) for set_panel * Turn fig.set_panel into a context manager * Alias projection (J), region (R), verbose (V), x/yshift (X/Y) for subplot * Allow for spaces in title and labels without needing double quotes Mitigates against #247. * Allow for list inputs into fig.set_panel(panel=...) * Rename sca to set_panel and ax to panel * Fix bug that prevented boolean to -A from working * Add note that subplot panel is activated until further notice * Validate subplot nrows/ncols and figsize/subsize argument inputs * Revise advanced subplot layout subsection to use two subplots calls Co-authored-by: Dongdong Tian <[email protected]>
Wrapping the `subplot` function, in a `with` statement! Original GMT `subplot` function can be found at https://docs.generic-mapping-tools.org/6.1/subplot.html. This is the 3rd attempt at implementing `subplot` in PyGMT, with commits heavily re-adapted/cherry-picked from GenericMappingTools#412 and GenericMappingTools#427. * Add fig.subplot and fig.set_panel to API docs * Alias fixedlabel (A), clearance (C), verbose (V) for set_panel * Turn fig.set_panel into a context manager * Alias projection (J), region (R), verbose (V), x/yshift (X/Y) for subplot * Allow for spaces in title and labels without needing double quotes Mitigates against GenericMappingTools#247. * Allow for list inputs into fig.set_panel(panel=...) * Rename sca to set_panel and ax to panel * Fix bug that prevented boolean to -A from working * Add note that subplot panel is activated until further notice * Validate subplot nrows/ncols and figsize/subsize argument inputs * Revise advanced subplot layout subsection to use two subplots calls Co-authored-by: Dongdong Tian <[email protected]>
Description of proposed changes
Experimenting with a more matplotlib-like syntax for managing subplots (an offshoot from #412). Preview of tutorial is at https://pygmt-git-fancysubplots.gmt.now.sh/tutorials/subplots.html, which is actually translated and adapted from the great example at https://docs.gmt-china.org/latest/tutorial/subplot/ (in Chinese). Specifically, this mimics the
fig, axs = plt.subplots()
style of defining subplots! An example of how it looks like currently:produces:
The code isn't perfect yet, and I'm very open to suggestions on how to go about improving this implementation. Specifically, it would be cool if we could do
ax.plot()
like in matplotlib. Calling expert Pythonistas for tips 👋As it currently stands, there's a high-level
subplots
function in subplot.py (somewhat based on the matplotlibplt.subplots
equivalent at https://github.com/matplotlib/matplotlib/blob/v3.2.1/lib/matplotlib/pyplot.py#L1044). This wraps around the new class SubPlot (inherited from the main Figure class to include subplot functionality). Note that sinceset
is a Python reserved character so I've usedsca
instead to set the current active subplot, following matplotlib.Also cross-referencing Julia wrapper/implementation at https://www.generic-mapping-tools.org/GMT.jl/latest/#GMT.subplot.
Parameters/Aliases to wrap:
References:
TODO:
ax
to the-c
command in GMT plotting functionsax[0, 1].plot()
directly instead of usingfig.sca(ax)
.Addresses #366 (comment), Supersedes and Closes #412, Fixes #20.
Reminders
make format
andmake check
to make sure the code follows the style guide.doc/api/index.rst
.