Skip to content
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

Add Figure.hlines for plotting horizontal lines #923

Open
wants to merge 68 commits into
base: main
Choose a base branch
from

Conversation

michaelgrund
Copy link
Member

@michaelgrund michaelgrund commented Feb 17, 2021

Description of proposed changes

This PR implements the Figure.hlines method to plot horizontal line(s). This is a high-level wrapper of Figure.plot, and is inspired by matplotlib.pyplot.hlines.

Address #670.

Features

  • Plot one or multiple lines (specified by y)
  • The X-limits of lines can be set by xmin/xmax, and then default to the x-limits of the current plot (i.e., fig.region[0:2])
  • Support Cartesian coordinates (as straight lines), geographic projection (as lines along constant latitude), and polar projection (as lines along constant radius).
  • The line's pen attribute can be set via pen
  • A legend entry can be added via label
  • Parameters no_clip/transparency/perspective are also supported

Limitations

  • When plotting multiple lines, only one single pen/label is allowed. It's possible to allow different pen or label (by passing a sequence of pen or label), but I feel it makes the codes too complicated. Users who need different pens/labels can call Figure.hlines multiple times.
  • When plottting multiple lines, we call Figure.plot multiple times in a loop. As mentioned in Add Figure.hlines for plotting horizontal lines #923 (comment), it's possible to use np.nan as separators for each line, then we can call Figure.plot once. However, GMT will complain about NaN records when plotting lines in geographic projections because GMT needs to resample the lines before plotting.
  • When plottling lines in geographic or polar projections, just passing two points is not enough, since GMT defaults to plot the minor great-circle arcs. As shown below, we need to at least 4 points for geographic projections.
import pygmt
import numpy as np

fig = pygmt.Figure()
fig.basemap(region="d", projection="H15c", frame=True)

# Passing 2, 3 or 4 data points to plot horizontal lines.
for npoints in [2, 3, 4]:
    fig.plot(x=np.linspace(0, 360, npoints), y=[npoints * 10] * npoints, pen="1p,red", straight_line="m")
fig.show()
  • npoints=2: Line is not plotted, because in geographic projections, longitude is periodic, so longitude 0=360.
  • npoints=3: i.e., passing x=[0, 180, 360], only one minor arc is drawn
  • npoints=4: i.e., passing x=[0, 90, 180, 360], works
    hlines-resampling

Example

Here is an example showing how it works in Cartesian/polar/geographic projections. See the tests for more examples.

import pygmt

fig = pygmt.Figure()

# Cartesian projection
fig.basemap(region=[0, 10, 0, 10], projection="X10c/10c", frame=True)
fig.hlines(y=1, pen="1p,black", label="Line 1")
fig.hlines(y=2, xmin=2, xmax=8, pen="1p,red,-", label="Line 2")
fig.hlines(y=[3, 4], xmin=3, xmax=7, pen="1p,black,.", label="Line 3")
fig.hlines(y=[5, 6], xmin=4, xmax=9, pen="1p,red", label="Line 4")
fig.hlines(y=[7, 8], xmin=[0, 1], xmax=[7, 8], pen="1p,blue", label="Line 5")
fig.legend()

fig.shift_origin(xshift="w+2c")
# Geographic 
fig.basemap(region="g", projection="R15c", frame=True)
fig.hlines(50, xmin=0, xmax=360, pen="1p")

fig.shift_origin(xshift="w+2c")
# Polar
fig.basemap(region=[0, 360, 0, 1], projection="P10c", frame=True)
fig.hlines(0.5, xmin=0, xmax=80, pen="1p")
fig.show()

hlines

Preview: https://pygmt-dev--923.org.readthedocs.build/en/923/api/generated/pygmt.Figure.hlines.html

Reminders

  • Run make format and make check to make sure the code follows the style guide.
  • Add tests for new features or tests that would have caught the bug that you're fixing.
  • Add new public functions/methods/classes to doc/api/index.rst.
  • Write detailed docstrings for all functions/methods.
  • If wrapping a new module, open a 'Wrap new GMT module' issue and submit reasonably-sized PRs.
  • If adding new functionality, add an example to docstrings or tutorials.
  • Use underscores (not hyphens) in names of Python files and directories.

Slash Commands

You can write slash commands (/command) in the first line of a comment to perform
specific operations. Supported slash command is:

  • /format: automatically format and lint the code

As discussed in #670 here's a new module (**hlines**) to plot a single or a set of horizontal lines with only defining the desired y-value(s). For discussion I only add the module for horizontal lines at the moment, however, the adjustments to prepare the same for vertical lines is done very quickly.
@michaelgrund michaelgrund marked this pull request as draft February 17, 2021 18:31
@michaelgrund michaelgrund added the feature Brand new feature label Feb 17, 2021
@seisman seisman added this to the 0.4.0 milestone Feb 17, 2021
@seisman seisman changed the title Add new modules to plot horizontal and vertical lines Add new modules to plot horizontal lines Feb 18, 2021
@seisman seisman changed the title Add new modules to plot horizontal lines Add Figure.hlines for plotting horizontal lines Feb 18, 2021
@seisman
Copy link
Member

seisman commented Feb 18, 2021

@michaelgrund Nice work! I just changed the PR title so that we can focus on one feature Figure.hlines in this PR.

@seisman
Copy link
Member

seisman commented Feb 18, 2021

Furthermore, currently the whole procedure is performed in a loop since it's not possible to pass multi-segment lines to the plot function so far (except using an input file).

It's possible to use np.NaN record to separate segments:

import numpy as np
import pygmt

x = np.array([2, 4, 4, np.NaN, 5, 6])
y = np.array([3, 5, 7, np.NaN, 4, 2])

fig = pygmt.Figure()
fig.basemap(region=[0, 10, 0, 10], frame=True)
fig.plot(x, y, pen="2p")
fig.show()

but I'm not sure if other features (lines with different colors) are supported.

@michaelgrund
Copy link
Member Author

Furthermore, currently the whole procedure is performed in a loop since it's not possible to pass multi-segment lines to the plot function so far (except using an input file).

It's possible to use np.NaN record to separate segments:

import numpy as np
import pygmt

x = np.array([2, 4, 4, np.NaN, 5, 6])
y = np.array([3, 5, 7, np.NaN, 4, 2])

fig = pygmt.Figure()
fig.basemap(region=[0, 10, 0, 10], frame=True)
fig.plot(x, y, pen="2p")
fig.show()

but I'm not sure if other features (lines with different colors) are supported.

Ok will check that and, if possible, adjust the code.

pygmt/src/hlines.py Outdated Show resolved Hide resolved
@seisman seisman marked this pull request as ready for review November 21, 2024 13:36
@seisman seisman requested a review from a team November 28, 2024 04:14
Co-authored-by: Yvonne Fröhlich <[email protected]>
@yvonnefroehlich
Copy link
Member

@seisman related to your comment in #3593 (comment) should this new high-level method for specifically plotting horizontal lines be included in the "Plotting Lines" tutorial? Or do we want to have a separate gallery example showing the different interpretation of horizontal lines in different coordinate systems?

@seisman
Copy link
Member

seisman commented Nov 29, 2024

Or do we want to have a separate gallery example showing the different interpretation of horizontal lines in different coordinate systems?

I prefer this one

@seisman
Copy link
Member

seisman commented Dec 1, 2024

The plan is to implement hlines and vlines, then add a gallery example for plotting horizontal and vertical lines in Cartesian, polar and geographic projections.

@michaelgrund
Copy link
Member Author

michaelgrund commented Dec 2, 2024

Thanks for pushing this forward @seisman after almost 3.5 years. I'm fine with all the changes, especially with removing too complicated parts I added initially. Since I'm the author of this PR I cannot give an approval.

The plan is to implement hlines and vlines, then add a gallery example for plotting horizontal and vertical lines in Cartesian, polar and geographic projections.

If I remember correctly the gallery example I provided within this PR was the left one in the example figure of the first post. After implementing vlines adding this together with some geographic and polar plots might be a good gallery example.

@seisman seisman added final review call This PR requires final review and approval from a second reviewer and removed needs review This PR has higher priority and needs review. labels Dec 2, 2024
@seisman
Copy link
Member

seisman commented Dec 2, 2024

I've marked this PR as "final review call", but will keep this PR open for more days since most of you are busy with the AGU workshop.

Please 👍 if you have time reviewing this PR and think it's ready for merge. Or we can revisit the PR after AGU.

Copy link
Member Author

@michaelgrund michaelgrund left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

pygmt/src/hlines.py Outdated Show resolved Hide resolved
pygmt/src/hlines.py Outdated Show resolved Hide resolved
pygmt/src/hlines.py Outdated Show resolved Hide resolved
pygmt/src/hlines.py Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Brand new feature final review call This PR requires final review and approval from a second reviewer
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants