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 61 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
Copy link
Contributor

github-actions bot commented Nov 20, 2024

Summary of changed images

This is an auto-generated report of images that have changed on the DVC remote

Status Path
added pygmt/tests/baseline/test_hlines_clip.png
added pygmt/tests/baseline/test_hlines_geographic_global_d.png
added pygmt/tests/baseline/test_hlines_geographic_global_g.png
added pygmt/tests/baseline/test_hlines_multiple_lines.png
added pygmt/tests/baseline/test_hlines_one_line.png
added pygmt/tests/baseline/test_hlines_polar_projection.png

Image diff(s)

Added images

  • test_hlines_clip.png

  • test_hlines_geographic_global_d.png

  • test_hlines_geographic_global_g.png

  • test_hlines_multiple_lines.png

  • test_hlines_one_line.png

  • test_hlines_polar_projection.png

Modified images

Path Old New

Report last updated at commit 7a20b8c

@seisman seisman added this to the 0.14.0 milestone Nov 21, 2024
@seisman seisman added the needs review This PR has higher priority and needs review. label Nov 21, 2024
@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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Brand new feature needs review This PR has higher priority and needs review.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants