1
1
import math
2
2
from itertools import product
3
+ from collections import Iterable
3
4
import warnings
4
5
import numpy as np
5
6
import scipy as sp
@@ -78,18 +79,16 @@ def plot_text(pos, text=None, ax=None, color=None, **kwargs):
78
79
return [handle ]
79
80
80
81
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 ):
84
83
"""
85
84
Plot a point using matplotlib
86
85
87
86
:param pos: position of marker
88
87
:type pos: array_like(2), ndarray(2,n), list of 2-tuples
89
88
:param marker: matplotlub marker style, defaults to 'bs'
90
89
: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
93
92
:param ax: axes to plot in, defaults to ``gca()``
94
93
:type ax: Axis, optional
95
94
:return: the matplotlib object
@@ -108,10 +107,10 @@ def plot_point(
108
107
109
108
- Multiple points can be marked if ``pos`` is a 2xn array or a list of
110
109
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
113
112
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
115
114
of shape(n). For example::
116
115
117
116
``("#{0} a={1:.1f}, b={2:.1f}", a, b)``
@@ -135,9 +134,6 @@ def plot_point(
135
134
columns of ``p`` and label them all with successive elements of ``z``.
136
135
"""
137
136
138
- if text is not None :
139
- raise DeprecationWarning ("use label not text" )
140
-
141
137
if isinstance (pos , np .ndarray ):
142
138
if pos .ndim == 1 :
143
139
x = pos [0 ]
@@ -177,22 +173,22 @@ def plot_point(
177
173
handles .append (plt .plot (x , y , m , ** kwargs ))
178
174
else :
179
175
handles .append (plt .plot (x , y , marker , ** kwargs ))
180
- if label is not None :
176
+ if text is not None :
181
177
try :
182
178
xy = zip (x , y )
183
179
except TypeError :
184
180
xy = [(x , y )]
185
- if isinstance (label , str ):
181
+ if isinstance (text , str ):
186
182
# simple string, but might have format chars
187
183
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 )):
190
186
for i , (x , y ) in enumerate (xy ):
191
187
handles .append (
192
188
plt .text (
193
189
x ,
194
190
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 :]]),
196
192
** textopts
197
193
)
198
194
)
@@ -251,10 +247,10 @@ def plot_homline(lines, *args, ax=None, xlim=None, ylim=None, **kwargs):
251
247
252
248
def plot_box (
253
249
* 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 ,
258
254
wh = None ,
259
255
centre = None ,
260
256
l = None ,
@@ -265,6 +261,7 @@ def plot_box(
265
261
h = None ,
266
262
ax = None ,
267
263
bbox = None ,
264
+ ltrb = None ,
268
265
filled = False ,
269
266
** kwargs
270
267
):
@@ -277,10 +274,10 @@ def plot_box(
277
274
:type tl: [array_like(2), optional
278
275
:param br: bottom-right corner, defaults to None
279
276
:type br: array_like(2), optional
280
- :param tr: top -ight corner, defaults to None
277
+ :param tr: top-right corner, defaults to None
281
278
: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
284
281
:param centre: centre of box, defaults to None
285
282
:type centre: array_like(2), optional
286
283
:param l: left side of box, minimum x, defaults to None
@@ -313,35 +310,49 @@ def plot_box(
313
310
The box can be specified in many ways:
314
311
315
312
- 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]
316
315
- centre and width+height
317
316
- bottom-left and top-right corners
318
317
- bottom-left corner and width+height
319
318
- top-right corner and width+height
320
319
- top-left corner and width+height
321
320
321
+ For plots where the y-axis is inverted (eg. for images) then top is the
322
+ smaller vertical coordinate.
323
+
322
324
Example:
323
325
324
326
.. runblock:: pycon
325
327
326
328
>>> from spatialmath.base import plotvol2, plot_box
327
329
>>> plotvol2(5)
328
- >>> plot_box('r', centre=(2,3), wh=(1,1))
330
+ >>> plot_box('r', centre=(2,3), wh=1) # w=h=1
329
331
>>> plot_box(tl=(1,1), br=(0,2), filled=True, color='b')
330
332
"""
331
333
332
334
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
334
341
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
343
350
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
345
356
if centre is not None :
346
357
cx , cy = centre
347
358
if l is None :
@@ -356,17 +367,26 @@ def plot_box(
356
367
pass
357
368
if b is None :
358
369
try :
359
- b = t - h
370
+ t = b + h
360
371
except :
361
372
pass
362
373
if b is None :
363
374
try :
364
- b = cy + h / 2
375
+ t = cy - h / 2
365
376
except :
366
377
pass
367
378
368
379
ax = axes_logic (ax , 2 )
369
380
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
+
370
390
if filled :
371
391
if w is None :
372
392
try :
@@ -401,9 +421,9 @@ def plot_box(
401
421
t = cy + h / 2
402
422
except :
403
423
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 ]
405
425
406
- return [ r ]
426
+ return r
407
427
408
428
409
429
def plot_poly (vertices , * fmt , close = False , ** kwargs ):
@@ -451,7 +471,7 @@ def circle(centre=(0, 0), radius=1, resolution=50):
451
471
452
472
453
473
def 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
455
475
):
456
476
"""
457
477
Plot a circle using matplotlib
@@ -633,9 +653,9 @@ def sphere(radius=1, centre=(0, 0, 0), resolution=50):
633
653
634
654
Phi , Theta = np .meshgrid (phi_range , theta_range )
635
655
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 ]
639
659
640
660
return (x , y , z )
641
661
@@ -727,7 +747,7 @@ def ellipsoid(
727
747
# process the probability
728
748
from scipy .stats .distributions import chi2
729
749
730
- s = math .sqrt (chi2 .ppf (confidence , df = 2 )) * scale
750
+ s = math .sqrt (chi2 .ppf (confidence , df = 3 )) * scale
731
751
else :
732
752
s = scale
733
753
@@ -1164,6 +1184,7 @@ def plotvol2(dim, ax=None, equal=True, grid=False, labels=True):
1164
1184
ax .set_aspect ("equal" )
1165
1185
if grid :
1166
1186
ax .grid (True )
1187
+ ax .set_axisbelow (True )
1167
1188
1168
1189
# signal to related functions that plotvol set the axis limits
1169
1190
ax ._plotvol = True
0 commit comments