Skip to content

Commit 862dbb6

Browse files
committed
Add the Axes, Axis, Frame classes for the frame parameter
1 parent dc6fd38 commit 862dbb6

File tree

3 files changed

+170
-0
lines changed

3 files changed

+170
-0
lines changed

pygmt/params/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
"""
44

55
from pygmt.params.box import Box
6+
from pygmt.params.frame import Axes, Axis, Frame
67
from pygmt.params.pattern import Pattern

pygmt/params/frame.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
"""
2+
The Axes, Axis, and Frame classes for specifying the frame.
3+
"""
4+
5+
import dataclasses
6+
from typing import Any, Literal
7+
8+
from pygmt.alias import Alias
9+
from pygmt.params.base import BaseParam
10+
11+
12+
@dataclasses.dataclass(repr=False)
13+
class Axis(BaseParam):
14+
"""
15+
Class for setting up one axis of a plot.
16+
"""
17+
18+
#: Intervals for annotations and major tick spacing, minor tick spacing, and/or
19+
#: grid line spacing.
20+
interval: float | str
21+
22+
#: Plot slanted annotations (for Cartesian plots only), where *angle* is measured
23+
#: with respect to the horizontal and must be in the -90 <= *angle* <= 90 range.
24+
#: Default is normal (i.e., ``angle=90``) for y-axis and parallel (i.e.,
25+
#: ``angle=0``) for x-axis annotations. These defaults can be changed via
26+
#: :gmt-term:`MAP_ANNOT_ORTHO`.
27+
angle: float | None = None
28+
29+
#: Skip annotations that fall exactly at the ends of the axis. Choose from ``left``
30+
#: or ``right`` to skip only the lower or upper annotation, respectively, or
31+
#: ``True`` to skip both.
32+
skip_edge: Literal["left", "right"] | bool = False
33+
34+
#: Give fancy annotations with W|E|S|N suffixes encoding the sign (for geographic
35+
#: axes only).
36+
fancy: bool = False
37+
38+
#: Add a label to the axis (for Cartesian plots only). The label is placed parallel
39+
#: to the axis by default; use **hlabel** to force a horizontal label for y-axis,
40+
#: which is useful for very short labels.
41+
label: str | None = None
42+
hlabel: str | None = None
43+
44+
#: Add an alternate label for the right or upper axes. The label is placed parallel
45+
#: to the axis by default; use **alt_hlabel** to force a horizontal label for
46+
#: y-axis, which is useful for very short labels. [For Cartesian plots only].
47+
alt_label: str | None = None
48+
alt_hlabel: str | None = None
49+
50+
#: Add a leading text prefix for axis annotation (e.g., dollar sign for plots
51+
#: related to money) (for Cartesian plots only). For geographic maps the addition
52+
#: of degree symbols, etc. is automatic and controlled by
53+
#: :gmt-term:`FORMAT_GEO_MAP`.
54+
prefix: str | None = None
55+
56+
#: Append a unit to the annotations (for Cartesian plots only). For geographic maps
57+
#: the addition of degree symbols, etc. is automatic and controlled by
58+
#: :gmt-term:`FORMAT_GEO_MAP`.
59+
unit: str | None = None
60+
61+
@property
62+
def _aliases(self):
63+
return [
64+
Alias(self.interval, name="interval"),
65+
Alias(self.angle, name="angle", prefix="+a"),
66+
Alias(
67+
self.skip_edge,
68+
name="skip_edge",
69+
prefix="+e",
70+
mapping={True: True, "left": "l", "right": "r"},
71+
),
72+
Alias(self.fancy, name="fancy", prefix="+f"),
73+
Alias(self.label, name="label", prefix="+l"),
74+
Alias(self.hlabel, name="hlabel", prefix="+L"),
75+
Alias(self.alt_label, name="alt_label", prefix="+s"),
76+
Alias(self.alt_hlabel, name="alt_hlabel", prefix="+S"),
77+
Alias(self.unit, name="unit", prefix="+u"),
78+
]
79+
80+
81+
@dataclasses.dataclass(repr=False)
82+
class Axes(BaseParam):
83+
"""
84+
Class for specifying the frame of a plot.
85+
"""
86+
87+
#: Specify which axes to draw and their attributes.
88+
axes: str | None = None
89+
90+
#: Fill for the interior of the canvas [Default is no fill]. This also sets fill
91+
#: for the two back-walls in 3-D plots.
92+
fill: str | None = None
93+
94+
#: The title string centered above the plot frame [Default is no title].
95+
title: str | None = None
96+
97+
#: The subtitle string beneath the title [Default is no subtitle]. This requires
98+
#: ``title`` to be set.
99+
subtitle: str | None = None
100+
101+
@property
102+
def _aliases(self):
103+
return [
104+
Alias(self.axes, name="axes"),
105+
Alias(self.fill, name="fill", prefix="+g"),
106+
Alias(self.title, name="title", prefix="+t"),
107+
Alias(self.subtitle, name="subtitle", prefix="+s"),
108+
]
109+
110+
111+
@dataclasses.dataclass(repr=False)
112+
class Frame(BaseParam):
113+
"""
114+
Class for setting up the frame of a plot.
115+
"""
116+
117+
axes: Any = None
118+
xaxis: Any = None
119+
yaxis: Any = None
120+
zaxis: Any = None
121+
122+
@property
123+
def _aliases(self):
124+
return [
125+
Alias(self.axes),
126+
Alias(self.xaxis, prefix="x"),
127+
Alias(self.yaxis, prefix="y"),
128+
Alias(self.zaxis, prefix="z"),
129+
]
130+
131+
def __iter__(self):
132+
"""
133+
Iterate over the aliases of the class.
134+
135+
Yields
136+
------
137+
The value of each alias in the class. None are excluded.
138+
"""
139+
yield from (alias._value for alias in self._aliases if alias._value is not None)

pygmt/tests/test_params_frame.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""
2+
Test the Frame/Axes/Axis classes.
3+
"""
4+
5+
from pygmt.params import Axes, Axis
6+
7+
8+
def test_params_axis():
9+
"""
10+
Test the Axis class.
11+
"""
12+
assert str(Axis(interval="a1f0.5")) == "a1f0.5"
13+
assert str(Axis(interval="a1f0.5", angle=30)) == "a1f0.5+a30"
14+
assert str(Axis(interval="a1f0.5", angle=30, skip_edge="left")) == "a1f0.5+a30+el"
15+
assert str(Axis(interval="a1f0.5", fancy=True)) == "a1f0.5+f"
16+
assert str(Axis(interval="a1f0.5", label="My Label")) == "a1f0.5+lMy Label"
17+
assert str(Axis(interval="a1f0.5", hlabel="My HLabel")) == "a1f0.5+LMy HLabel"
18+
assert str(Axis(interval="a1f0.5", alt_label="Alt Label")) == "a1f0.5+sAlt Label"
19+
assert str(Axis(interval="a1f0.5", alt_hlabel="Alt HLabel")) == "a1f0.5+SAlt HLabel"
20+
assert str(Axis(interval="a1f0.5", unit="km")) == "a1f0.5+ukm"
21+
22+
23+
def test_params_axes():
24+
"""
25+
Test the Axes class.
26+
"""
27+
assert (
28+
str(Axes("WSen", title="My Plot Title", fill="lightred"))
29+
== "WSen+glightred+tMy Plot Title"
30+
)

0 commit comments

Comments
 (0)