@@ -248,68 +248,99 @@ def plot_sphere(centre=(0,0,0), radius=1, npoints=50, ax=None, wireframe=False,
248248 ax .plot_surface (x , y , z , ** kwargs )
249249
250250
251- def ellipse (E , centre = (0 ,0 ,0 ), confidence = None , npoints = 40 , inverse = False ):
251+ def ellipse (E , centre = (0 ,0 ), scale = 1 , confidence = None , npoints = 40 , inverted = False ):
252+ """[summary]
253+
254+ :param E: ellipse defined by :math:`x^T \mat{E} x = 1`
255+ :type E: ndarray(2,2)
256+ :param centre: ellipse centre, defaults to (0,0,0)
257+ :type centre: tuple, optional
258+ :param scale:
259+ :type scale:
260+ :param confidence: if E is an inverse covariance matrix plot an ellipse
261+ for this confidence interval in the range [0,1], defaults to None
262+ :type confidence: float, optional
263+ :param npoints: number of points on circumferance, defaults to 40
264+ :type npoints: int, optional
265+ :param inverted: if :math:`\mat{E}^{-1}` is provided, defaults to False
266+ :type inverted: bool, optional
267+ :raises ValueError: [description]
268+ :return: x and y coordinates
269+ :rtype: tuple of ndarray(1)
270+
271+ .. note:: In some problems we compute :math:`\mat{E}^{-1}` so to avoid
272+ inverting ``E`` twice to compute the ellipse, we flag that the inverse
273+ is provided using ``inverted``. For example:
274+
275+ - for robot manipulability
276+ :math:`\n u (\mat{J} \mat{J}^T)^{-1} \n u` i
277+ - a covariance matrix
278+ :math:`(x - \mu)^T \mat{P}^{-1} (x - \mu)`
279+ """
252280 if E .shape != (2 ,2 ):
253281 raise ValueError ('ellipse is defined by a 2x2 matrix' )
254282
255- if inverse :
256- E = np .linalg .inv (E )
257-
258283 if confidence :
259284 # process the probability
260- s = sqrt (chi2inv (confidence , 2 ))
285+ s = sqrt (chi2inv (confidence , 2 )) * scale
261286 else :
262- s = 1
287+ s = scale
263288
264289 x , y = circle () # unit circle
265- e = sp .linalg .sqrtm (E ) @ np .array ([x , y ])
290+
291+ if not inverted :
292+ E = np .linalg .inv (E )
293+
294+ e = s * sp .linalg .sqrtm (E ) @ np .array ([x , y ]) + np .c_ [centre ]
266295 return e [0 ,:], e [1 ,:]
267296
268- def plot_ellipse (E , centre = (0 ,0 ), confidence = None , npoints = 40 , inverse = False , filled = None , ** kwargs ):
297+ def plot_ellipse (E , centre = (0 ,0 ), scale = 1 , confidence = None , npoints = 40 , inverted = False , ax = None , filled = None , ** kwargs ):
269298
270299 # allow for centre[2] to plot ellipse in a plane in a 3D plot
271300
272- x , y = ellipse (E , centre , confidence , npoints , inverse )
301+ x , y = ellipse (E , centre , scale , confidence , npoints , inverted )
273302 ax = _axes_logic (ax , 2 )
274303 if filled :
275304 patch = plt .Polygon (x , y , ** kwargs )
276305 ax .add_patch (patch )
277306 else :
278307 plt .plot (x , y , ** kwargs )
279308
280- def ellipsoid (E , centre = (0 ,0 ,0 ), confidence = None , npoints = 40 , inverse = False ):
309+ def ellipsoid (E , centre = (0 ,0 ,0 ), scale = 1 , confidence = None , npoints = 40 , inverted = False ):
281310
282311 if E .shape != (3 ,3 ):
283312 raise ValueError ('ellipsoid is defined by a 3x3 matrix' )
284313
285- if inverse :
286- E = np .linalg .inv (E )
287-
288314 if confidence :
289315 # process the probability
290316 from scipy .stats .distributions import chi2
291- s = math .sqrt (chi2 .ppf (s , df = 2 ))
317+ s = math .sqrt (chi2 .ppf (s , df = 2 )) * scale
292318 else :
293- s = 1
319+ s = scale
320+
321+ if not inverted :
322+ E = np .linalg .inv (E )
294323
295324 x , y , z = sphere () # unit sphere
296- e = sp .linalg .sqrtm (E ) @ np .array ([x .flatten (), y .flatten (), z .flatten ()])
325+ e = s * sp .linalg .sqrtm (E ) @ np .array ([x .flatten (), y .flatten (), z .flatten ()]) + np . c_ [ centre ]. T
297326 return e [0 ,:].reshape (x .shape ), e [1 ,:].reshape (x .shape ), e [2 ,:].reshape (x .shape )
298327
299- def plot_ellipsoid (E , centre = (0 ,0 ,0 ), confidence = None , npoints = 40 , inverse = False , ax = None , wireframe = False , stride = 1 , ** kwargs ):
328+ def plot_ellipsoid (E , centre = (0 ,0 ,0 ), scale = 1 , confidence = None , npoints = 40 , inverted = False , ax = None , wireframe = False , stride = 1 , ** kwargs ):
300329 """
301330 Draw an ellipsoid
302331
303332 :param E: ellipsoid
304333 :type E: ndarray(3,3)
305334 :param centre: [description], defaults to (0,0,0)
306335 :type centre: tuple, optional
336+ :param scale:
337+ :type scale:
307338 :param confidence: confidence interval, range 0 to 1
308339 :type confidence: float
309340 :param npoints: [description], defaults to 40
310341 :type npoints: int, optional
311- :param inverse : [description], defaults to False
312- :type inverse : bool, optional
342+ :param inverted : [description], defaults to False
343+ :type inverted : bool, optional
313344 :param ax: [description], defaults to None
314345 :type ax: [type], optional
315346 :param wireframe: [description], defaults to False
@@ -334,7 +365,7 @@ def plot_ellipsoid(E, centre=(0,0,0), confidence=None, npoints=40, inverse=False
334365 - If a confidence interval is given then ``E`` is interpretted as a covariance
335366 matrix and the ellipse size is computed using an inverse chi-squared function.
336367 """
337- x , y , z = ellipsoid (E , centre , confidence , npoints , inverse )
368+ x , y , z = ellipsoid (E , centre , scale , confidence , npoints , inverted )
338369 ax = _axes_logic (ax , 3 )
339370 if wireframe :
340371 return ax .plot_wireframe (x , y , z , rstride = stride , cstride = stride , ** kwargs )
0 commit comments