-
Notifications
You must be signed in to change notification settings - Fork 214
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
base: main
Are you sure you want to change the base?
Changes from all commits
7ed3b49
096b9de
92fa9c0
975b305
f25a89c
3cee081
a0c29fc
51dcb6a
4fdc984
154d05e
ddd04b4
d0bc35c
450d8de
f75fbe1
a375a77
71113dd
1438d43
e3a564e
d6a8fa5
ff13180
1881e95
7222e9b
65eb85d
2353587
49008ed
457bf72
f2c84a7
50dccf9
e7726c0
60d6e55
46f8702
5648778
d553e28
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
""" | ||
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"], | ||
transparency=50, | ||
) | ||
|
||
fig.legend() | ||
fig.show() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -423,6 +423,7 @@ def _repr_html_(self): | |
grdimage, | ||
grdview, | ||
histogram, | ||
hlines, | ||
image, | ||
inset, | ||
legend, | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,146 @@ | ||||||||||||||||||
""" | ||||||||||||||||||
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( | ||||||||||||||||||
N="no_clip", | ||||||||||||||||||
V="verbose", | ||||||||||||||||||
W="pen", | ||||||||||||||||||
l="label", | ||||||||||||||||||
p="perspective", | ||||||||||||||||||
t="transparency", | ||||||||||||||||||
) | ||||||||||||||||||
@kwargs_to_strings(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 | ||||||||||||||||||
---------- | ||||||||||||||||||
y : float or 1d array | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||
The y coordinates or an array of y coordinates of the | ||||||||||||||||||
horizontal lines to plot. | ||||||||||||||||||
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} | ||||||||||||||||||
{V} | ||||||||||||||||||
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) # pylint: disable=protected-access | ||||||||||||||||||
|
||||||||||||||||||
y = np.atleast_1d(y) | ||||||||||||||||||
list_length = len(y) | ||||||||||||||||||
|
||||||||||||||||||
# prepare x values | ||||||||||||||||||
def prep_data(xmin, xmax, list_length): | ||||||||||||||||||
|
||||||||||||||||||
if xmin is None and xmax is None: | ||||||||||||||||||
with Session() as lib: | ||||||||||||||||||
# get limits from current map boundings if not given | ||||||||||||||||||
# via xmin, xmax | ||||||||||||||||||
x = np.array([[lib.extract_region()[0]], [lib.extract_region()[1]]]) | ||||||||||||||||||
x = np.repeat(x, list_length, axis=1) | ||||||||||||||||||
Comment on lines
+76
to
+80
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the
Suggested change
|
||||||||||||||||||
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]) | ||||||||||||||||||
|
||||||||||||||||||
return np.atleast_1d(x) | ||||||||||||||||||
|
||||||||||||||||||
def prep_style(kwargs, list_length): | ||||||||||||||||||
|
||||||||||||||||||
# prepare labels | ||||||||||||||||||
if "l" in kwargs: | ||||||||||||||||||
# if several lines belong to the same label, first set all to None | ||||||||||||||||||
# then replace first entry by the label given via "l" | ||||||||||||||||||
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): | ||||||||||||||||||
kwargs["W"] = np.repeat(kwargs["W"], list_length) | ||||||||||||||||||
else: # use as default if no pen is given (neither single nor series) | ||||||||||||||||||
kwargs["W"] = np.repeat("1p,black", list_length) | ||||||||||||||||||
|
||||||||||||||||||
return kwargs | ||||||||||||||||||
|
||||||||||||||||||
# loop over entries | ||||||||||||||||||
x = prep_data(xmin, xmax, list_length) | ||||||||||||||||||
kwargs = prep_style(kwargs, list_length) | ||||||||||||||||||
kwargs_copy = kwargs.copy() | ||||||||||||||||||
|
||||||||||||||||||
for index in range(list_length): | ||||||||||||||||||
|
||||||||||||||||||
with Session() as lib: | ||||||||||||||||||
if ( | ||||||||||||||||||
data_kind(None, [x[0][index], x[1][index]], [y[index], y[index]]) | ||||||||||||||||||
== "vectors" | ||||||||||||||||||
): | ||||||||||||||||||
file_context = lib.virtualfile_from_vectors( | ||||||||||||||||||
np.atleast_1d([x[0][index], x[1][index]]), [y[index], y[index]] | ||||||||||||||||||
) | ||||||||||||||||||
else: | ||||||||||||||||||
raise GMTInvalidInput("Unrecognized data type.") | ||||||||||||||||||
|
||||||||||||||||||
kwargs["l"] = kwargs_copy["l"][index] | ||||||||||||||||||
kwargs["W"] = kwargs_copy["W"][index] | ||||||||||||||||||
|
||||||||||||||||||
with file_context as fname: | ||||||||||||||||||
lib.call_module("plot", " ".join([fname, build_arg_string(kwargs)])) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
""" | ||
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.basemap(region=[0, 10, 0, 20], projection="X10c/10c", frame=True) | ||
fig_ref.hlines( | ||
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.basemap(region="0/10/0/20", projection="X10c/10c", frame=True) | ||
fig_test.hlines( | ||
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 |
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.