66from collections .abc import Sequence
77from typing import Literal
88
9+ from pygmt ._typing import AnchorCode
910from pygmt .alias import Alias , AliasSystem
1011from pygmt .clib import Session
12+ from pygmt .exceptions import GMTInvalidInput
1113from pygmt .helpers import (
1214 build_arg_list ,
1315 deprecate_parameter ,
1416 fmt_docstring ,
1517 kwargs_to_strings ,
1618 use_alias ,
1719)
18- from pygmt .params import Box
20+ from pygmt .params import Box , Position
21+ from pygmt .src ._common import _parse_position
1922
2023__doctest_skip__ = ["inset" ]
2124
2225
2326@fmt_docstring
2427@deprecate_parameter ("margin" , "clearance" , "v0.18.0" , remove_version = "v0.20.0" )
28+ @use_alias (C = "clearance" )
29+ @kwargs_to_strings (C = "sequence" )
2530@contextlib .contextmanager
26- @use_alias (D = "position" , C = "clearance" )
27- @kwargs_to_strings (D = "sequence" , C = "sequence" )
2831def inset (
2932 self ,
30- projection : str | None = None ,
31- region : Sequence [float | str ] | str | None = None ,
33+ position : Position | Sequence [float | str ] | AnchorCode | None = None ,
34+ width : float | str | None = None ,
35+ height : float | str | None = None ,
3236 box : Box | bool = False ,
3337 no_clip : bool = False ,
38+ projection : str | None = None ,
39+ region : Sequence [float | str ] | str | None = None ,
3440 verbose : Literal ["quiet" , "error" , "warning" , "timing" , "info" , "compat" , "debug" ]
3541 | bool = False ,
3642 ** kwargs ,
3743):
3844 r"""
3945 Manage figure inset setup and completion.
4046
41- This method sets the position, frame, and margins for a smaller figure
42- inside of the larger figure. Plotting methods that are called within the
47+
48+ This method carves out a sub-region of the current plot canvas and restrict further
49+ plotting to that section of the canvas. Plotting methods that are called within the
4350 context manager are added to the inset figure.
4451
4552 Full GMT docs at :gmt-docs:`inset.html`.
4653
4754 $aliases
55+ - D = position, **+w**: width/height
4856 - F = box
4957 - J = projection
5058 - N = no_clip
@@ -53,45 +61,21 @@ def inset(
5361
5462 Parameters
5563 ----------
56- position : str or list
57- *xmin/xmax/ymin/ymax*\ [**+r**][**+u**\ *unit*]] \
58- | [**g**\|\ **j**\|\ **J**\|\ **n**\|\ **x**]\ *refpoint*\
59- **+w**\ *width*\ [/*height*][**+j**\ *justify*]\
60- [**+o**\ *dx*\ [/*dy*]].
61-
62- *This is the only required parameter.*
63- Define the map inset rectangle on the map. Specify the rectangle
64- in one of three ways:
65-
66- Append **g**\ *lon*/*lat* for map (user) coordinates,
67- **j**\ *code* or **J**\ *code* for setting the *refpoint* via a
68- :doc:`2-character justification code </techref/justification_codes>`
69- that refers to the (invisible)
70- projected map bounding box, **n**\ *xn*/*yn* for normalized (0-1)
71- bounding box coordinates, or **x**\ *x*/*y* for plot
72- coordinates (inches, centimeters, points, append unit).
73- All but **x** requires both ``region`` and ``projection`` to be
74- specified. You can offset the reference point via
75- **+o**\ *dx*/*dy* in the direction implied by *code* or
76- **+j**\ *justify*.
77-
78- Alternatively, give *west/east/south/north* of geographic
79- rectangle bounded by parallels and meridians; append **+r** if the
80- coordinates instead are the lower left and upper right corners of
81- the desired rectangle. (Or, give *xmin/xmax/ymin/ymax* of bounding
82- rectangle in projected coordinates and optionally
83- append **+u**\ *unit* [Default coordinate unit is meters (**e**)].
84-
85- Append **+w**\ *width*\ [/*height*] of bounding rectangle or box
86- in plot coordinates (inches, centimeters, etc.). By default, the
87- anchor point on the scale is assumed to be the bottom left corner
88- (**BL**), but this can be changed by appending **+j** followed by a
89- :doc:`2-character justification code </techref/justification_codes>`
90- *justify*.
91- **Note**: If **j** is used then *justify* defaults to the same
92- as *refpoint*, if **J** is used then *justify* defaults to the
93- mirror opposite of *refpoint*. Specify inset box attributes via
94- the ``box`` parameter [Default is outline only].
64+ position
65+ Position of the inset on the plot. It can be specified in multiple ways:
66+
67+ - A :class:`pygmt.params.Position` object to fully control the reference point,
68+ anchor point, and offset.
69+ - A sequence of two values representing the x and y coordinates in plot
70+ coordinates, e.g., ``(1, 2)`` or ``("1c", "2c")``.
71+ - A :doc:`2-character justification code </techref/justification_codes>` for a
72+ position inside the plot, e.g., ``"TL"`` for Top Left corner inside the plot.
73+
74+ If not specified, defaults to the bottom-left corner of the plot.
75+ width
76+ height
77+ Width and height of the inset. Width must be specified and height is set to be
78+ equal to width if not specified.
9579 box
9680 Draw a background box behind the inset. If set to ``True``, a simple rectangular
9781 box is drawn using :gmt-term:`MAP_FRAME_PEN`. To customize the box appearance,
@@ -109,37 +93,56 @@ def inset(
10993 no_clip
11094 Do **not** clip features extruding outside the inset frame boundaries [Default
11195 is ``False``].
112- $region
96+
11397 $projection
98+ $region
11499 $verbose
115100
116101 Examples
117102 --------
118103 >>> import pygmt
119104 >>> from pygmt.params import Box, Position
120105 >>>
121- >>> # Create the larger figure
122106 >>> fig = pygmt.Figure()
123107 >>> fig.coast(region="MG+r2", water="lightblue", shorelines="thin")
124- >>> # Use a "with" statement to initialize the inset context manager
108+ >>> # Use a "with" statement to initialize the inset context manager.
125109 >>> # Setting the position to Top Left and a width of 3.5 centimeters
126- >>> with fig.inset(position="jTL+w3.5c+o0.2c", clearance=0, box=Box(pen="green")):
127- ... # Map elements under the "with" statement are plotted in the inset
110+ >>> with fig.inset(
111+ ... position=Position("TL", offset=0.2),
112+ ... width="3.5c",
113+ ... clearance=0,
114+ ... box=Box(pen="green"),
115+ ... ): # Map elements under the "with" statement are plotted in the inset
128116 ... fig.coast(
129117 ... region="g",
130118 ... projection="G47/-20/?",
131119 ... land="gray",
132120 ... water="white",
133121 ... dcw="MG+gred",
134122 ... )
135- ...
136123 >>> # Map elements outside the "with" statement are plotted in the main figure
137124 >>> fig.logo(position=Position("BR", offset=0.2), width="3c")
138125 >>> fig.show()
139126 """
140127 self ._activate_figure ()
141128
129+ position = _parse_position (
130+ position ,
131+ kwdict = {"width" : width , "height" : height },
132+ default = Position ((0 , 0 ), cstype = "plotcoords" ), # Default to (0,0) in plotcoords
133+ )
134+
135+ # width is mandatory.
136+ if width is None and not isinstance (position , str ):
137+ msg = "Parameter 'width' must be specified."
138+ raise GMTInvalidInput (msg )
139+
142140 aliasdict = AliasSystem (
141+ D = [
142+ Alias (position , name = "position" ),
143+ Alias (width , name = "width" , prefix = "+w" ), # +wwidth/height
144+ Alias (height , name = "height" , prefix = "/" ),
145+ ],
143146 F = Alias (box , name = "box" ),
144147 N = Alias (no_clip , name = "no_clip" ),
145148 ).add_common (
0 commit comments