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
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
7ed3b49
Add new modules to plot horizontal and vertical lines
michaelgrund Feb 17, 2021
096b9de
added further content
michaelgrund Feb 17, 2021
92fa9c0
added some first tests
michaelgrund Feb 17, 2021
975b305
some formatting
michaelgrund Feb 17, 2021
f25a89c
corrected typo
michaelgrund Feb 17, 2021
3cee081
Merge branch 'master' into hlines-module
michaelgrund Feb 18, 2021
a0c29fc
Merge branch 'master' into hlines-module
michaelgrund Feb 20, 2021
51dcb6a
Merge branch 'master' into hlines-module
michaelgrund Feb 20, 2021
4fdc984
Merge branch 'master' into hlines-module
michaelgrund Feb 23, 2021
154d05e
Merge branch 'master' into hlines-module
michaelgrund Apr 3, 2021
ddd04b4
Merge branch 'master' into hlines-module
michaelgrund Apr 5, 2021
d0bc35c
moved gallery example to new subfolder /lines
michaelgrund Apr 7, 2021
450d8de
Merge branch 'master' into hlines-module
michaelgrund Apr 7, 2021
f75fbe1
disable pylint warnings
michaelgrund Apr 7, 2021
a375a77
replace hyphen by underscore in gallery example file name
michaelgrund Apr 7, 2021
71113dd
disable pylint warnings
michaelgrund Apr 7, 2021
1438d43
formatting
michaelgrund Apr 7, 2021
e3a564e
Merge branch 'master' into hlines-module
michaelgrund Apr 9, 2021
d6a8fa5
Merge branch 'master' into hlines-module
michaelgrund Apr 19, 2021
ff13180
Merge branch 'master' into hlines-module
michaelgrund Apr 21, 2021
1881e95
Merge branch 'master' into hlines-module
michaelgrund Apr 22, 2021
7222e9b
Merge branch 'main' into hlines-module
michaelgrund Aug 10, 2021
65eb85d
update hlines module
michaelgrund Aug 10, 2021
2353587
Merge branch 'hlines-module' of https://github.com/GenericMappingTool…
michaelgrund Aug 10, 2021
49008ed
formatting
michaelgrund Aug 10, 2021
457bf72
adjust docstring
michaelgrund Aug 10, 2021
f2c84a7
adjust priliminary tests
michaelgrund Aug 10, 2021
50dccf9
Merge branch 'main' into hlines-module
michaelgrund Aug 11, 2021
e7726c0
update
michaelgrund Aug 11, 2021
60d6e55
Merge branch 'hlines-module' of https://github.com/GenericMappingTool…
michaelgrund Aug 11, 2021
46f8702
formatting
michaelgrund Aug 11, 2021
5648778
Merge branch 'main' into hlines-module
michaelgrund Aug 17, 2021
d553e28
Merge branch 'main' into hlines-module
michaelgrund Aug 20, 2021
d493a1c
Update pygmt/src/hlines.py
michaelgrund Sep 4, 2024
92bfca5
Merge branch 'main' into hlines-module
seisman Nov 20, 2024
ed7de94
Fix styling
seisman Nov 20, 2024
1ae727a
Simplify the logic of codes
seisman Nov 20, 2024
8fee6a8
Remove the gallery example
seisman Nov 20, 2024
67b1497
Finalize hlines source code
seisman Nov 20, 2024
cd0ce35
Fix hlines
seisman Nov 20, 2024
e60b064
Add tests for Figure.hlines
seisman Nov 20, 2024
f28dce0
Fix the order in the API docs
seisman Nov 20, 2024
4816dbb
Skip doctest
seisman Nov 20, 2024
49c2e97
Improve type hints
seisman Nov 20, 2024
a40ff00
Simplify type hints
seisman Nov 21, 2024
d657fe3
Support for horizontal lines in geographic projections
seisman Nov 21, 2024
a8bd1a0
Add tests for polar projection
seisman Nov 21, 2024
457e8eb
Fix tests for polar
seisman Nov 21, 2024
a2b7223
Add tests for no_clip
seisman Nov 21, 2024
258a64f
Improve docstrings
seisman Nov 21, 2024
ad09ece
Merge branch 'main' into hlines-module
seisman Nov 21, 2024
4e26a6f
Merge branch 'main' into hlines-module
seisman Nov 21, 2024
9e17bdf
Use straight_line='p' although it makes no difference
seisman Nov 22, 2024
25cbeb4
Transparency should be set by 'pen' instead
seisman Nov 22, 2024
afe7592
Merge branch 'main' into hlines-module
seisman Nov 22, 2024
6556500
Refactor the codes for handling y/xmin/xmax
seisman Nov 23, 2024
fc1898c
Simplify the checking
seisman Nov 23, 2024
7ef0406
Fix reference to Figure.plot
seisman Nov 23, 2024
354e090
Merge branch 'main' into hlines-module
seisman Nov 25, 2024
7a20b8c
Merge branch 'main' into hlines-module
seisman Nov 28, 2024
762bf4e
Fix a typo [skip ci]
seisman Nov 28, 2024
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 @@ -31,6 +31,7 @@ Plotting data and laying out the map:
Figure.grdview
Figure.image
Figure.inset
Figure.hlines
Figure.legend
Figure.logo
Figure.meca
Expand Down
29 changes: 29 additions & 0 deletions examples/gallery/line/horizontal-lines.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""
Plot horizontal lines
---------------------

The :meth:`pygmt.Figure.hlines` method can plot horizontal lines based on
a given y value. Optionally, the lower and upper limits of the lines can be
defined, otherwise the current map boundaries are taken.

"""

import pygmt

fig = pygmt.Figure()
fig.basemap(region=[0, 10, 0, 11], projection="X10c/10c", frame=True)

fig.hlines(1, label="line1")
fig.hlines([2, 3], pen="2p,dodgerblue4", label="line2")
fig.hlines([4, 5], xmin=2, xmax=8, pen="2p,red3", label="line3")
fig.hlines([6, 7], xmin=[1, 3], xmax=[8, 7], pen="3p,seagreen", label="line4")
fig.hlines(
[8, 9, 10],
xmin=[1.3, 3, 2],
xmax=[6.5, 7, 5],
pen=["4p,darkmagenta", "2p,gold,--", "3.5p,blue,."],
label=["line5", "line6", "line7"],
)

fig.legend()
fig.show()
1 change: 1 addition & 0 deletions pygmt/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ def _repr_html_(self):
grdcontour,
grdimage,
grdview,
hlines,
image,
inset,
legend,
Expand Down
1 change: 1 addition & 0 deletions pygmt/src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from pygmt.src.grdinfo import grdinfo
from pygmt.src.grdtrack import grdtrack
from pygmt.src.grdview import grdview
from pygmt.src.hlines import hlines
from pygmt.src.image import image
from pygmt.src.info import info
from pygmt.src.inset import inset
Expand Down
164 changes: 164 additions & 0 deletions pygmt/src/hlines.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
"""
hlines - Plot horizontal lines.
"""
import numpy as np
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.helpers import (
build_arg_string,
data_kind,
fmt_docstring,
kwargs_to_strings,
use_alias,
)


@fmt_docstring
@use_alias(
B="frame",
C="cmap",
D="offset",
J="projection",
N="no_clip",
R="region",
U="timestamp",
V="verbose",
W="pen",
X="xshift",
Y="yshift",
Z="zvalue",
l="label",
p="perspective",
t="transparency",
michaelgrund marked this conversation as resolved.
Show resolved Hide resolved
)
@kwargs_to_strings(R="sequence", p="sequence")
def hlines(self, y=None, xmin=None, xmax=None, **kwargs):
"""
Plot one or a collection of horizontal lines.

Takes a single y value or a list of individual y values and optionally
lower and upper x value limits as input.

Must provide *y*.

If y values are given without x limits then the current map boundaries are
used as lower and upper limits. If only a single set of x limits is given
then all lines will have the same length, otherwise give x limits for each
individual line. If only a single label is given then all lines are grouped
under this label in the legend (if shown). If each line should appear as a
single entry in the legend, give corresponding labels for all lines
(same for **pen**).

Parameters
seisman marked this conversation as resolved.
Show resolved Hide resolved
----------
y : float or 1d array
seisman marked this conversation as resolved.
Show resolved Hide resolved
The y coordinates or an array of y coordinates of the
horizontal lines to plot.
{J}
{R}
{B}
{CPT}
offset : str
``dx/dy``.
Offset the line locations by the given amounts
*dx/dy* [Default is no offset]. If *dy* is not given it is set
equal to *dx*.
no_clip : bool or str
``'[c|r]'``.
Do NOT clip lines that fall outside map border [Default plots
lines whose coordinates are strictly inside the map border only].
The option does not apply to lines which are always
clipped to the map region. For periodic (360-longitude) maps we
must plot all lines twice in case they are clipped by the
repeating boundary. ``no_clip=True`` will turn off clipping and not
plot repeating lines. Use ``no_clip="r"`` to turn off clipping
but retain the plotting of such repeating lines, or use
``no_clip="c"`` to retain clipping but turn off plotting of
repeating lines.
{W}
{U}
{V}
{XY}
zvalue : str or float
``value``.
Instead of specifying a line color via **pen**, give it a *value*
via **zvalue** and a color lookup table via **cmap**. Requires
appending **+z** to **pen** (e.g. ``pen = "5p,+z"``,
``zvalue = 0.8``, ``cmap = "viridis"``).
label : str
Add a legend entry for the line being plotted.
{p}
{t}
*transparency* can also be a 1d array to set varying transparency
for lines.
"""

kwargs = self._preprocess(**kwargs)

list_length = len(np.atleast_1d(y))

# prepare x vals
if xmin is None and xmax is None:
# get limits from current map boundings if not given via xmin, xmax
with Session() as lib:
mapbnds = lib.extract_region()
x = np.array([[mapbnds[0]], [mapbnds[1]]])
x = np.repeat(x, list_length, axis=1)
elif xmin is None or xmax is None:
raise GMTInvalidInput(
"Must provide both, xmin and xmax if limits are not set automatically."
)

else:
# if only a single xmin and xmax without [], repeat to fit size of y
if isinstance(xmin, (int, float)):
x = np.array([[xmin], [xmax]])
x = np.repeat(x, list_length, axis=1)
else:
if len(xmin) != len(xmax):
GMTInvalidInput("Must provide same length for xmin and xmax.")
else:
x = np.array([xmin, xmax])

# prepare labels
if "l" in kwargs:
# if several lines belong to the same label, first take the label,
# then set all to None and reset the first entry to the given label
if not isinstance(kwargs["l"], list):
label2use = kwargs["l"]
kwargs["l"] = np.repeat(None, list_length)
kwargs["l"][0] = label2use
else:
kwargs["l"] = np.repeat(None, list_length)

# prepare pens
if "W" in kwargs:
# select pen, no series
if not isinstance(kwargs["W"], list):
pen2use = kwargs["W"]
kwargs["W"] = np.repeat(pen2use, list_length)
else: # use as default if no pen is given (neither single nor series)
kwargs["W"] = np.repeat("1p,black", list_length)

# loop over entries
kwargs_copy = kwargs.copy()

for index in range(list_length):
y2plt = [np.atleast_1d(y)[index], np.atleast_1d(y)[index]]
x2plt = [np.atleast_1d(x)[0][index], np.atleast_1d(x)[1][index]]
kind = data_kind(None, x2plt, y2plt)

with Session() as lib:
if kind == "vectors":
file_context = lib.virtualfile_from_vectors(
np.atleast_1d(x2plt), np.atleast_1d(y2plt)
)
else:
raise GMTInvalidInput("Unrecognized data type.")

kwargs["l"] = kwargs_copy["l"][index]
kwargs["W"] = kwargs_copy["W"][index]

with file_context as fname:
arg_str = " ".join([fname, build_arg_string(kwargs)])
lib.call_module("plot", arg_str)
73 changes: 73 additions & 0 deletions pygmt/tests/test_hlines.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""
Tests for hline.
"""
from pygmt import Figure
from pygmt.helpers.testing import check_figures_equal


@check_figures_equal()
def test_hlines_value_sets():
"""
Passing sets of y, xmin and xmax.
"""

fig_ref, fig_test = Figure(), Figure()

fig_ref.hlines(
region=[0, 10, 0, 20],
projection="X10c/10c",
frame=True,
y=[5.5, 10, 6, 11],
xmin=[3.1, 6, 0, 1],
xmax=[5.5, 7.8, 10, 9],
label="test2",
pen="4p,green",
)

fig_test.hlines(
region="0/10/0/20",
projection="X10c/10c",
frame=True,
y=[5.5, 10, 6, 11],
xmin=[3.1, 6, 0, 1],
xmax=[5.5, 7.8, 10, 9],
label="test2",
pen="4p,green",
)

return fig_ref, fig_test


@check_figures_equal()
def test_hlines_zvalue():
"""
Passing in color via zvalue.
"""

fig_ref, fig_test = Figure(), Figure()

fig_ref.hlines(
region=[0, 10, 0, 20],
projection="X10c/10c",
frame=True,
y=[9.9],
xmin=2,
xmax=6,
pen="5p,+z",
zvalue="0.5",
cmap="magma",
)

fig_test.hlines(
region="0/10/0/20",
projection="X10c/10c",
frame=True,
y=[9.9],
xmin=2,
xmax=6,
pen="5p,+z",
zvalue="0.5",
cmap="magma",
)

return fig_ref, fig_test