11import math
22from itertools import product
3+ from collections import Iterable
34import warnings
45import numpy as np
56import scipy as sp
@@ -78,18 +79,16 @@ def plot_text(pos, text=None, ax=None, color=None, **kwargs):
7879 return [handle ]
7980
8081
81- def plot_point (
82- pos , marker = "bs" , label = None , text = None , ax = None , textargs = None , ** kwargs
83- ):
82+ def plot_point (pos , marker = "bs" , text = None , ax = None , textargs = None , ** kwargs ):
8483 """
8584 Plot a point using matplotlib
8685
8786 :param pos: position of marker
8887 :type pos: array_like(2), ndarray(2,n), list of 2-tuples
8988 :param marker: matplotlub marker style, defaults to 'bs'
9089 :type marker: str or list of str, optional
91- :param label : text label, defaults to None
92- :type label : str, optional
90+ :param text : text label, defaults to None
91+ :type text : str, optional
9392 :param ax: axes to plot in, defaults to ``gca()``
9493 :type ax: Axis, optional
9594 :return: the matplotlib object
@@ -108,10 +107,10 @@ def plot_point(
108107
109108 - Multiple points can be marked if ``pos`` is a 2xn array or a list of
110109 coordinate pairs. In this case:
111- - all points have the same label
112- - label can include the format string {} which is susbstituted for the
110+ - all points have the same ``text`` label
111+ - ``text`` can include the format string {} which is susbstituted for the
113112 point index, starting at zero
114- - label can be a tuple containing a format string followed by vectors
113+ - ``text`` can be a tuple containing a format string followed by vectors
115114 of shape(n). For example::
116115
117116 ``("#{0} a={1:.1f}, b={2:.1f}", a, b)``
@@ -135,9 +134,6 @@ def plot_point(
135134 columns of ``p`` and label them all with successive elements of ``z``.
136135 """
137136
138- if text is not None :
139- raise DeprecationWarning ("use label not text" )
140-
141137 if isinstance (pos , np .ndarray ):
142138 if pos .ndim == 1 :
143139 x = pos [0 ]
@@ -177,22 +173,22 @@ def plot_point(
177173 handles .append (plt .plot (x , y , m , ** kwargs ))
178174 else :
179175 handles .append (plt .plot (x , y , marker , ** kwargs ))
180- if label is not None :
176+ if text is not None :
181177 try :
182178 xy = zip (x , y )
183179 except TypeError :
184180 xy = [(x , y )]
185- if isinstance (label , str ):
181+ if isinstance (text , str ):
186182 # simple string, but might have format chars
187183 for i , (x , y ) in enumerate (xy ):
188- handles .append (plt .text (x , y , " " + label .format (i ), ** textopts ))
189- elif isinstance (label , (tuple , list )):
184+ handles .append (plt .text (x , y , " " + text .format (i ), ** textopts ))
185+ elif isinstance (text , (tuple , list )):
190186 for i , (x , y ) in enumerate (xy ):
191187 handles .append (
192188 plt .text (
193189 x ,
194190 y ,
195- " " + label [0 ].format (i , * [d [i ] for d in label [1 :]]),
191+ " " + text [0 ].format (i , * [d [i ] for d in text [1 :]]),
196192 ** textopts
197193 )
198194 )
@@ -251,10 +247,10 @@ def plot_homline(lines, *args, ax=None, xlim=None, ylim=None, **kwargs):
251247
252248def plot_box (
253249 * fmt ,
254- bl = None ,
255- tl = None ,
256- br = None ,
257- tr = None ,
250+ lb = None ,
251+ lt = None ,
252+ rb = None ,
253+ rt = None ,
258254 wh = None ,
259255 centre = None ,
260256 l = None ,
@@ -265,6 +261,7 @@ def plot_box(
265261 h = None ,
266262 ax = None ,
267263 bbox = None ,
264+ ltrb = None ,
268265 filled = False ,
269266 ** kwargs
270267):
@@ -277,10 +274,10 @@ def plot_box(
277274 :type tl: [array_like(2), optional
278275 :param br: bottom-right corner, defaults to None
279276 :type br: array_like(2), optional
280- :param tr: top -ight corner, defaults to None
277+ :param tr: top-right corner, defaults to None
281278 :type tr: array_like(2), optional
282- :param wh: width and height, defaults to None
283- :type wh: array_like(2), optional
279+ :param wh: width and height, if both are the same provide scalar, defaults to None
280+ :type wh: scalar, array_like(2), optional
284281 :param centre: centre of box, defaults to None
285282 :type centre: array_like(2), optional
286283 :param l: left side of box, minimum x, defaults to None
@@ -313,35 +310,49 @@ def plot_box(
313310 The box can be specified in many ways:
314311
315312 - bounding box which is a 2x2 matrix [xmin, xmax; ymin, ymax]
313+ - bounding box [xmin, xmax, ymin, ymax]
314+ - alternative box [xmin, ymin, xmax, ymax]
316315 - centre and width+height
317316 - bottom-left and top-right corners
318317 - bottom-left corner and width+height
319318 - top-right corner and width+height
320319 - top-left corner and width+height
321320
321+ For plots where the y-axis is inverted (eg. for images) then top is the
322+ smaller vertical coordinate.
323+
322324 Example:
323325
324326 .. runblock:: pycon
325327
326328 >>> from spatialmath.base import plotvol2, plot_box
327329 >>> plotvol2(5)
328- >>> plot_box('r', centre=(2,3), wh=(1,1))
330+ >>> plot_box('r', centre=(2,3), wh=1) # w=h=1
329331 >>> plot_box(tl=(1,1), br=(0,2), filled=True, color='b')
330332 """
331333
332334 if bbox is not None :
333- l , r , b , t = bbox
335+ if isinstance (bbox , ndarray ) and bbox .ndims > 1 :
336+ # case of [l r; t b]
337+ bbox = bbox .ravel ()
338+ l , r , t , b = bbox
339+ elif ltrb is not None :
340+ l , t , r , b = ltrb
334341 else :
335- if tl is not None :
336- l , t = tl
337- if tr is not None :
338- r , t = tr
339- if bl is not None :
340- l , b = bl
341- if br is not None :
342- r , b = br
342+ if lt is not None :
343+ l , t = lt
344+ if rt is not None :
345+ r , t = rt
346+ if lb is not None :
347+ l , b = lb
348+ if rb is not None :
349+ r , b = rb
343350 if wh is not None :
344- w , h = wh
351+ if isinstance (wh , Iterable ):
352+ w , h = wh
353+ else :
354+ w = wh
355+ h = wh
345356 if centre is not None :
346357 cx , cy = centre
347358 if l is None :
@@ -356,17 +367,26 @@ def plot_box(
356367 pass
357368 if b is None :
358369 try :
359- b = t - h
370+ t = b + h
360371 except :
361372 pass
362373 if b is None :
363374 try :
364- b = cy + h / 2
375+ t = cy - h / 2
365376 except :
366377 pass
367378
368379 ax = axes_logic (ax , 2 )
369380
381+ if ax .yaxis_inverted ():
382+ # if y-axis is flipped, switch top and bottom
383+ t , b = b , t
384+
385+ if l >= r :
386+ raise ValueError ("left must be less than right" )
387+ if b >= t :
388+ raise ValueError ("bottom must be less than top" )
389+
370390 if filled :
371391 if w is None :
372392 try :
@@ -401,9 +421,9 @@ def plot_box(
401421 t = cy + h / 2
402422 except :
403423 pass
404- r = plt .plot ([l , l , r , r , l ], [b , t , t , b , b ], * fmt , ** kwargs )
424+ r = plt .plot ([l , l , r , r , l ], [b , t , t , b , b ], * fmt , ** kwargs )[ 0 ]
405425
406- return [ r ]
426+ return r
407427
408428
409429def plot_poly (vertices , * fmt , close = False , ** kwargs ):
@@ -451,7 +471,7 @@ def circle(centre=(0, 0), radius=1, resolution=50):
451471
452472
453473def plot_circle (
454- radius , * fmt , centre = (0 , 0 ), resolution = 50 , ax = None , filled = False , ** kwargs
474+ radius , centre = (0 , 0 ), * fmt , resolution = 50 , ax = None , filled = False , ** kwargs
455475):
456476 """
457477 Plot a circle using matplotlib
@@ -633,9 +653,9 @@ def sphere(radius=1, centre=(0, 0, 0), resolution=50):
633653
634654 Phi , Theta = np .meshgrid (phi_range , theta_range )
635655
636- x = radius * np .sin (Theta ) * np .cos (Phi )
637- y = radius * np .sin (Theta ) * np .sin (Phi )
638- z = radius * np .cos (Theta )
656+ x = radius * np .sin (Theta ) * np .cos (Phi ) + centre [ 0 ]
657+ y = radius * np .sin (Theta ) * np .sin (Phi ) + centre [ 1 ]
658+ z = radius * np .cos (Theta ) + centre [ 2 ]
639659
640660 return (x , y , z )
641661
@@ -727,7 +747,7 @@ def ellipsoid(
727747 # process the probability
728748 from scipy .stats .distributions import chi2
729749
730- s = math .sqrt (chi2 .ppf (confidence , df = 2 )) * scale
750+ s = math .sqrt (chi2 .ppf (confidence , df = 3 )) * scale
731751 else :
732752 s = scale
733753
@@ -1164,6 +1184,7 @@ def plotvol2(dim, ax=None, equal=True, grid=False, labels=True):
11641184 ax .set_aspect ("equal" )
11651185 if grid :
11661186 ax .grid (True )
1187+ ax .set_axisbelow (True )
11671188
11681189 # signal to related functions that plotvol set the axis limits
11691190 ax ._plotvol = True
0 commit comments