; docformat = 'rst' ;+ ; Plot an ellipse ; ; Wrapper on plot or oplot ; :Params: ; a : in, required ; Semimajor/minor x-axis ; b : in, required ; Semimajor/minor y-axis ; xc : in, optional, default=0 ; x-co-ordinate of centre of ellipse ; yc : in, optional, default=0 ; y-co-ordinate of centre of ellipse ; :Keywords: ; ang : in, optional ; Positional angle (degrees anticlockwise) ; rho : in, optional ; Correlation between x and y, with a and b now interpreted as ; standard deviation in x and y, to give <n_sigma>-sigma contours ; ; Equivalently, plot an ellipse within a rectangle bounded by xc ; +/- a and yc +/- b, where the ellipse touches the rectangle at ; +/- (xc + rho * a, yc + b) and +/- (xc + a, yc + rho * b) ; n_sigma : in, optional, default=1 ; With rho, plot <n_sigma>-sigma contour(s) (equivalent to ; multiplier on a and b). Can be an array of values ; overplot : in, optional ; Set /overplot to overplot (uses oplot rather than plot) ; plotfile : in, optional ; See ajs_plot_start ; show_plot : in, optional ; See ajs_plot_start ; open : in, optional ; See ajs_plot_start ; close : in, optional ; See ajs_plot_start ; _REF_EXTRA ; Keywords for plot/oplot ; :Examples: ; ajs_ellipse_plot, 1, 1 ; ; ajs_ellipse_plot, 2, 3, 10, 20 ; ; ajs_ellipse_plot, 4, 1, ang=30 ; ; ajs_ellipse_plot, 1, 1, rho=0.8, /overplot ; ; ajs_ellipse_plot, 3, 1, rho=0.5, n_sigma=2 ; ; ajs_ellipse_plot, 3, 1, rho=-0.5, n_sigma=[1,3,2] ; :History: ; 28 Mar 2008 Written, Anthony Smith ;- PRO ajs_ellipse_plot, a, b, xc, yc, ang=ang, rho=rho, overplot=overplot, $ n_sigma=n_sigma, plotfile=plotfile, $ show_plot=show_plot, open=open, close=close, _REF_EXTRA=e compile_opt idl2 debug = ajs_debug() IF debug GE 2 THEN BEGIN message, 'Plotting ellipse', /inf message, ajs_kw_string(a=a, b=b, xc=xc, xy=xy, ang=ang, rho=rho, $ overplot=overplot, n_sigma=n_sigma, $ plotfile=plotfile, show_plot=show_plot, $ open=open, close=close), /inf ENDIF ;; Setup plot eps = keyword_set(open) OR keyword_set(show_plot) ajs_plot_start, plotfile=plotfile, eps=eps IF NOT keyword_set(close) AND n_elements(a) GT 0 THEN BEGIN ;; Plot <n_sigma>-sigma contours? IF n_elements(n_sigma) EQ 0 THEN BEGIN ;; Change names so input arrays do not get altered c = a d = b ENDIF ELSE IF n_elements(n_sigma) EQ 1 THEN BEGIN c = a * n_sigma d = b * n_sigma ENDIF ELSE BEGIN ;; Loop over different values of n_sigma and then return n_sigma_sorted = n_sigma[reverse(sort(n_sigma))] ;; Optional overplot for first (largest) contour IF n_elements(plotfile) GT 0 OR keyword_set(show_plot) THEN $ open_tmp = 1 $ ELSE $ open_tmp = keyword_set(open) ajs_ellipse_plot, a, b, xc, yc, ang=ang, rho=rho, $ overplot=overplot, $ n_sigma=n_sigma_sorted[0], plotfile=plotfile, $ open=open_tmp, show_plot=show_plot, _STRICT_EXTRA=e ;; Loop over the rest FOR i = 1, n_elements(n_sigma) - 1 DO BEGIN ajs_ellipse_plot, a, b, xc, yc, ang=ang, rho=rho, /overplot, $ n_sigma=n_sigma_sorted[i], open=open_tmp, $ _STRICT_EXTRA=e ENDFOR IF n_elements(plotfile) GT 0 AND NOT keyword_set(open) THEN $ ajs_ellipse_plot, plotfile=plotfile, /close, show_plot=show_plot ;; Done return ENDELSE ;; Make a circle theta = ajs_linspace(0, 360, 181) / !RADEG ; Radians x = cos(theta) y = sin(theta) ;; Bounded by a rectangle? IF n_elements(rho) GT 0 THEN BEGIN ;; Centred on origin, equation for bivariate Gaussian gives ;; 1-sigma contour as (ellipse) ;; 1 = (1 / (1 - rho^2)) * [ x^2 / sigma_x^2 + y^2 / sigma_y^2 ;; - 2 rho x y / (sigma_x sigma_y) ] ;; Quadratic function => semimajor/minor axes given by eigenvalues ;; 1 = e_1 X^2 + e_2 Y^2 ;; where ellipse is given by e_1 = 1 / c^2 ;; e_2 = 1 / d^2 ;; E-vals of symm. matrix of above fn, with c = sigma_x, d = sigma_y evals = eigenql([[1. / (c ^ 2. * (1. - rho ^ 2.)), $ - rho / (c * d * (1. - rho ^ 2.))], $ [- rho / (c * d * (1. - rho ^ 2.)), $ 1. / (d ^ 2. * (1. - rho ^ 2.))]], $ eigenvectors=evecs, /double) ;; Axes of unrotated ellipse (to be rotated later on) c = 1. / sqrt(evals[0]) d = 1. / sqrt(evals[1]) ;; Matrix of eigenvectors will be the rotation matrix => find angle ang = atan(evecs[0, 1] / evecs[0, 0]) * !RADEG ;; Eigenvalues are in descending order, so may need to reverse rot. ;; (Seems to work, not sure why!) IF rho GT 0 THEN $ ang = -abs(ang) $ ELSE $ ang = abs(ang) ENDIF ;; Change its size x = x * c y = y * d ;; Rotate it IF n_elements(ang) GT 0 THEN BEGIN x0 = x y0 = y cosang = cos(ang / !RADEG) sinang = sin(ang / !RADEG) x = x0 * cosang - y0 * sinang y = x0 * sinang + y0 * cosang ENDIF ;; Shift it IF n_elements(xc) GT 0 THEN $ x = x + xc IF n_elements(yc) GT 0 THEN $ y = y + yc ;; Plot it IF keyword_set(overplot) THEN $ oplot, x, y, _EXTRA=e $ ELSE $ plot, x, y, _STRICT_EXTRA=e ENDIF ajs_plot_stop, plotfile=plotfile, show_plot=show_plot, open=open, close=close END