Skip to content
Open
Changes from all commits
Commits
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
95 changes: 72 additions & 23 deletions spatialmath/base/graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,8 @@ def plot_homline(
return handles

def plot_box(
*fmt: Optional[str],
fmt: str | None = None,
*,
lbrt: Optional[ArrayLike4] = None,
lrbt: Optional[ArrayLike4] = None,
lbwh: Optional[ArrayLike4] = None,
Expand All @@ -339,6 +340,7 @@ def plot_box(
rt: Optional[ArrayLike2] = None,
wh: Optional[ArrayLike2] = None,
centre: Optional[ArrayLike2] = None,
center: Optional[ArrayLike2] = None,
w: Optional[float] = None,
h: Optional[float] = None,
ax: Optional[plt.Axes] = None,
Expand All @@ -358,39 +360,79 @@ def plot_box(
:type rt: array_like(2), optional
:param wh: width and height, if both are the same provide scalar, defaults to None
:type wh: scalar, array_like(2), optional
:param centre: centre of box, defaults to None
:param centre: centre of box, defaults to None (alias: ``center``)
:type centre: array_like(2), optional
:param w: width of box, defaults to None
:type w: float, optional
:param h: height of box, defaults to None
:type h: float, optional
;param lbrt: left-bottom, right-top corners, defaults to None
:type lbrt: array_like(4), optional
:param lrbt: left-right, bottom-top corners, defaults to None
:type lrbt: array_like(4), optional
:param lbwh: left-bottom corner, width and height, defaults to None
:type lbwh: array_like(4), optional
:param ltrb: left-top, right-bottom corners, defaults to None
:type ltrb: array_like(4), optional
:param ax: the axes to draw on, defaults to ``gca()``
:type ax: Axis, optional
:param bbox: bounding box matrix, defaults to None
:type bbox: array_like(4), optional
:param color: box outline color
:param filled: fill the box, defaults to False (alias for Matplotlib ``fill``)
:type filled: bool
:param thickness: line thickness (alias for Matplotlib ``linewidth``)
:type thickness: float, optional
:param kwargs: additional arguments passed to ``pyplot.Rectangle()``

:return: the matplotlib object
:rtype: Patch.Rectangle instance

Appearance is controlled by Matplotlib properties passed as keyword arguments, for example:

:param color: box outline and fill color
:type color: array_like(3) or str
:param fillcolor: box fill color
:param edgecolor: box outline colour (alias: ``ec``)
:type edgecolor: array_like(3) or str
:param fillcolor: box fill colour
:type fillcolor: array_like(3) or str
:param filled: fill the box, defaults to False
:type filled: bool
:param alpha: transparency, defaults to 1
:type alpha: float, optional
:param thickness: line thickness, defaults to None
:type thickness: float, optional
:return: the matplotlib object
:rtype: Patch.Rectangle instance
:param linestyle: box outline line style (alias: ``ls``)
:type linestyle: str, optional
:param linewidth: box outline line thickness (alias: ``lw``)
:type linewidth: float, optional

Additionally, the line style and color can be conveniently set using the pyplot
convention where the first argument is a ``fmt`` string, for example ``"r--"``
for dashed red. The allowable color letters are ``"rgbcmyk"`` and the line style
characters are ``"-", "--", "-.", ":"``.

The box can be specified in many ways. Two corners:

The box can be specified in many ways:
- `lb` = left-bottom corner
- `lt` = left-top corner
- `rb` = right-bottom corner
- `rt` = right-top corner

- bounding box [xmin, xmax, ymin, ymax]
- alternative box [xmin, ymin, xmax, ymax]
- centre and width+height
- left-bottom and right-top corners
- left-bottom corner and width+height
- right-top corner and width+height
- left-top corner and width+height
Alternatively, one corner or `centre` plus the dimensons:

- `wh` = [width, height]
- `w` = width
- `h` = height

Alternatively, the box can be specified by a number of 4-vectors, various
conventions are in use across different packages, so we support them all:

- `lbrt` = [umin, vmin, umax, vmax]
- `lrbt` = [umin, umax, vmin, vmax]
- `lbwh` = [umin, vmin, w, h]
- `bbox` same as `lbwh`
- `ltrb` = [umin, vmin, umax, vmax]`

For plots where the y-axis is inverted (eg. for images) then top is the
smaller vertical coordinate.
smaller vertical coordinate (highest in the window).

Example::

Expand Down Expand Up @@ -440,6 +482,8 @@ def plot_box(
elif w is not None and h is not None:
# we have width & height, one corner is enough

if centre is None:
centre = center
if centre is not None:
lb = (centre[0] - w / 2, centre[1] - h / 2)

Expand All @@ -464,7 +508,7 @@ def plot_box(
h = lt[1] - rb[1]

else:
raise ValueError("cant compute box")
raise ValueError("insufficient parameters to compute a box")

if w < 0:
raise ValueError("width must be positive")
Expand All @@ -479,9 +523,9 @@ def plot_box(
else:
ec = None
ls = ""
if len(fmt) > 0:
if fmt is not None:
colors = "rgbcmywk"
for f in fmt[0]:
for f in fmt:
if f in colors:
ec = f
else:
Expand All @@ -490,8 +534,13 @@ def plot_box(
ls = None

if "color" in kwargs:
ec = kwargs["color"]
del kwargs["color"]
ec = kwargs.pop("color")
if "edgecolor" in kwargs:
ec = kwargs.pop("edgecolor")
if "linestyle" in kwargs:
ls = kwargs.pop("linestyle")
elif "ls" in kwargs:
ls = kwargs.pop("ls")
r = plt.Rectangle(
lb, w, h, clip_on=True, linestyle=ls, edgecolor=ec, fill=False, **kwargs
)
Expand Down Expand Up @@ -558,7 +607,7 @@ def plot_arrow(
ax = plotvol2(5)
ax.grid()
plot_arrow(
(-2, -2), (2, 4), label="$\mathit{p}_3$", color="r", width=0.1
(-2, -2), (2, 4), label=r"$\mathit{p}_3$", color="r", width=0.1
)
plt.show(block=True)

Expand Down
Loading