Skip to content

Commit 5cf6565

Browse files
committed
Improve handling of the "format string" arg.
Provide a US-spelling version of the 'centre' option, either 'center' or 'centre' will work. Prevent multiple Matplotlib arguments of the same name being passed to `plt.Rectangle`, as happens from `plot_labelbox`. Improve function docstring. Minor fix in docstring for `plot_arrow`, tex string should be raw. This upsets Sphinx when any other package imports spatialmath.
1 parent 92f6199 commit 5cf6565

1 file changed

Lines changed: 72 additions & 23 deletions

File tree

spatialmath/base/graphics.py

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,8 @@ def plot_homline(
327327
return handles
328328

329329
def plot_box(
330-
*fmt: Optional[str],
330+
fmt: str | None = None,
331+
*,
331332
lbrt: Optional[ArrayLike4] = None,
332333
lrbt: Optional[ArrayLike4] = None,
333334
lbwh: Optional[ArrayLike4] = None,
@@ -339,6 +340,7 @@ def plot_box(
339340
rt: Optional[ArrayLike2] = None,
340341
wh: Optional[ArrayLike2] = None,
341342
centre: Optional[ArrayLike2] = None,
343+
center: Optional[ArrayLike2] = None,
342344
w: Optional[float] = None,
343345
h: Optional[float] = None,
344346
ax: Optional[plt.Axes] = None,
@@ -358,39 +360,79 @@ def plot_box(
358360
:type rt: array_like(2), optional
359361
:param wh: width and height, if both are the same provide scalar, defaults to None
360362
:type wh: scalar, array_like(2), optional
361-
:param centre: centre of box, defaults to None
363+
:param centre: centre of box, defaults to None (alias: ``center``)
362364
:type centre: array_like(2), optional
363365
:param w: width of box, defaults to None
364366
:type w: float, optional
365367
:param h: height of box, defaults to None
366368
:type h: float, optional
369+
;param lbrt: left-bottom, right-top corners, defaults to None
370+
:type lbrt: array_like(4), optional
371+
:param lrbt: left-right, bottom-top corners, defaults to None
372+
:type lrbt: array_like(4), optional
373+
:param lbwh: left-bottom corner, width and height, defaults to None
374+
:type lbwh: array_like(4), optional
375+
:param ltrb: left-top, right-bottom corners, defaults to None
376+
:type ltrb: array_like(4), optional
367377
:param ax: the axes to draw on, defaults to ``gca()``
368378
:type ax: Axis, optional
369379
:param bbox: bounding box matrix, defaults to None
370380
:type bbox: array_like(4), optional
371-
:param color: box outline color
381+
:param filled: fill the box, defaults to False (alias for Matplotlib ``fill``)
382+
:type filled: bool
383+
:param thickness: line thickness (alias for Matplotlib ``linewidth``)
384+
:type thickness: float, optional
385+
:param kwargs: additional arguments passed to ``pyplot.Rectangle()``
386+
387+
:return: the matplotlib object
388+
:rtype: Patch.Rectangle instance
389+
390+
Appearance is controlled by Matplotlib properties passed as keyword arguments, for example:
391+
392+
:param color: box outline and fill color
372393
:type color: array_like(3) or str
373-
:param fillcolor: box fill color
394+
:param edgecolor: box outline colour (alias: ``ec``)
395+
:type edgecolor: array_like(3) or str
396+
:param fillcolor: box fill colour
374397
:type fillcolor: array_like(3) or str
398+
:param filled: fill the box, defaults to False
399+
:type filled: bool
375400
:param alpha: transparency, defaults to 1
376401
:type alpha: float, optional
377-
:param thickness: line thickness, defaults to None
378-
:type thickness: float, optional
379-
:return: the matplotlib object
380-
:rtype: Patch.Rectangle instance
402+
:param linestyle: box outline line style (alias: ``ls``)
403+
:type linestyle: str, optional
404+
:param linewidth: box outline line thickness (alias: ``lw``)
405+
:type linewidth: float, optional
406+
407+
Additionally, the line style and color can be conveniently set using the pyplot
408+
convention where the first argument is a ``fmt`` string, for example ``"r--"``
409+
for dashed red. The allowable color letters are ``"rgbcmyk"`` and the line style
410+
characters are ``"-", "--", "-.", ":"``.
411+
412+
The box can be specified in many ways. Two corners:
381413
382-
The box can be specified in many ways:
414+
- `lb` = left-bottom corner
415+
- `lt` = left-top corner
416+
- `rb` = right-bottom corner
417+
- `rt` = right-top corner
383418
384-
- bounding box [xmin, xmax, ymin, ymax]
385-
- alternative box [xmin, ymin, xmax, ymax]
386-
- centre and width+height
387-
- left-bottom and right-top corners
388-
- left-bottom corner and width+height
389-
- right-top corner and width+height
390-
- left-top corner and width+height
419+
Alternatively, one corner or `centre` plus the dimensons:
420+
421+
- `wh` = [width, height]
422+
- `w` = width
423+
- `h` = height
424+
425+
Alternatively, the box can be specified by a number of 4-vectors, various
426+
conventions are in use across different packages, so we support them all:
427+
428+
- `lbrt` = [umin, vmin, umax, vmax]
429+
- `lrbt` = [umin, umax, vmin, vmax]
430+
- `lbwh` = [umin, vmin, w, h]
431+
- `bbox` same as `lbwh`
432+
- `ltrb` = [umin, vmin, umax, vmax]`
391433
392434
For plots where the y-axis is inverted (eg. for images) then top is the
393-
smaller vertical coordinate.
435+
smaller vertical coordinate (highest in the window).
394436
395437
Example::
396438
@@ -440,6 +482,8 @@ def plot_box(
440482
elif w is not None and h is not None:
441483
# we have width & height, one corner is enough
442484

485+
if centre is None:
486+
centre = center
443487
if centre is not None:
444488
lb = (centre[0] - w / 2, centre[1] - h / 2)
445489

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

466510
else:
467-
raise ValueError("cant compute box")
511+
raise ValueError("insufficient parameters to compute a box")
468512

469513
if w < 0:
470514
raise ValueError("width must be positive")
@@ -479,9 +523,9 @@ def plot_box(
479523
else:
480524
ec = None
481525
ls = ""
482-
if len(fmt) > 0:
526+
if fmt is not None:
483527
colors = "rgbcmywk"
484-
for f in fmt[0]:
528+
for f in fmt:
485529
if f in colors:
486530
ec = f
487531
else:
@@ -490,8 +534,13 @@ def plot_box(
490534
ls = None
491535

492536
if "color" in kwargs:
493-
ec = kwargs["color"]
494-
del kwargs["color"]
537+
ec = kwargs.pop("color")
538+
if "edgecolor" in kwargs:
539+
ec = kwargs.pop("edgecolor")
540+
if "linestyle" in kwargs:
541+
ls = kwargs.pop("linestyle")
542+
elif "ls" in kwargs:
543+
ls = kwargs.pop("ls")
495544
r = plt.Rectangle(
496545
lb, w, h, clip_on=True, linestyle=ls, edgecolor=ec, fill=False, **kwargs
497546
)
@@ -558,7 +607,7 @@ def plot_arrow(
558607
ax = plotvol2(5)
559608
ax.grid()
560609
plot_arrow(
561-
(-2, -2), (2, 4), label="$\mathit{p}_3$", color="r", width=0.1
610+
(-2, -2), (2, 4), label=r"$\mathit{p}_3$", color="r", width=0.1
562611
)
563612
plt.show(block=True)
564613

0 commit comments

Comments
 (0)