Skip to content

Instantly share code, notes, and snippets.

@jiffyclub
Created October 25, 2011 00:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jiffyclub/1310937 to your computer and use it in GitHub Desktop.
Save jiffyclub/1310937 to your computer and use it in GitHub Desktop.
Find modal sky on an array.
import numpy, pylab, scipy
from scipy import optimize
# Uses MEANCLIP from above
from meanclip import meanclip
def msky(inarray, do_plot=0, verbose=0, ptitle='', func=0):
"""
Find modal sky on an array.
First step is determination of median value and sigma.
Histogram of the data and fit parabola to the
logaritmic histogram. The coefficient of the parabola
are used to get mode and sigma of the sky on the
assumption that it is well fitted by a gaussian or
2nd-degree polynomial.
.. note:: MYSKY5 routine from ACS library.
:History:
* 11/25/2009 Created by PLL based on IDL routine by MS.
* 01/29/2010 PLL fixed broken where statement for histogram.
Parameters
----------
inarray: array_like
Input data.
do_plot: {0, 1}
Do plot?
verbose: {0, 1}
Print info to screen?
ptitle: string
Title of plot. Only used if `do_plot`=1.
func: {0, 1}
Function for fitting:
* 0: 2nd degree polynomial
* 1: Gaussian
Returns
-------
mmean: float
Mode of fitted function.
sigma: float
Sigma of fitted function.
"""
# Constants
func_name = 'MSKY'
nsig = 8.0
c1 = 2.5 # 2.8
c2 = 0.8 # 1.3
# Min/max of input array
arr_min = numpy.min(inarray)
arr_max = numpy.max(inarray)
# Get sigma
mmean, sigma = meanclip(inarray, clipsig=5.0, maxiter=10, verbose=verbose)
if sigma <= 0:
print ' '
print '%s: Weird distribution' % func_name
print '%-6s: %.6f' % ('MEAN', mmean)
print '%-6s: %.6f' % ('STDDEV', sigma)
print '%-6s: %.6f' % ('MIN', arr_min)
print '%-6s: %.6f' % ('MAX', arr_max)
return mmean, sigma
# Print info
if verbose:
print ' '
print '%s input array info' % func_name
print '%-6s: %.6f' % ('MIN', arr_min)
print '%-6s: %.6f' % ('MAX', arr_max)
# Flatten input array
arr_1d = inarray.reshape( inarray.size, )
# Define min and max for the histogram
x = nsig * sigma
mmean = numpy.median(arr_1d)
minhist = mmean - x
maxhist = mmean + x
ufi = inarray[ numpy.where((inarray > minhist) & (inarray < maxhist)) ]
# Calculate 25% and 75% percentile to get the interquartile range
# IRQ = pc75-pc25
# zenman, A. J. 1991.
sixd = numpy.argsort( ufi )
ndata = ufi.size
pc25 = ufi[ sixd[0.25*ndata] ]
pc75 = ufi[ sixd[0.75*ndata] ]
irq = pc75 - pc25
step = 2.0 * irq * ndata**(-1.0/3.0)
# Calculate number of bins to use
nbin = round(2*x / step - 1)
# Histogram
# http://www.scipy.org/Tentative_NumPy_Tutorial
yhist, hbin = numpy.histogram(arr_1d, range=(minhist,maxhist),bins=nbin)
xhist = 0.5 * ( hbin[1:] + hbin[:-1] )
# Define xmin and xmax for the 2-0rder fit
x1 = mmean - c1*sigma
x2 = mmean + c2*sigma
# Select the points beween x1 and x2 for the fit
w = numpy.where((xhist > x1) & (xhist < x2) & (yhist > 0))
count = len(w[0])
xwg = xhist[w]
nywg = yhist[w]
if count < 2:
print ' '
print '%s: Singular matrix' % func_name
print '%-6s: %.6f' % ('X[W]', xwg)
print '%-6s: %.6f' % ('NY[W]', nywg)
print '%-6s: %.6f' % ('MEDIAN', mmean)
return mmean, sigma
# Change to log scale
yhist = numpy.log10(yhist)
iyh = numpy.where( ~numpy.isinf(yhist) )
xhist = xhist[iyh]
yhist = yhist[iyh]
nywg = numpy.log10(nywg)
# Calculate the fit coefficients
ymax = nywg.max()
# Gaussian
# http://www.scipy.org/Cookbook/FittingData
if func == 1:
if verbose: print '%s: Fitting gaussian' % func_name
# Initial guess
ysum = numpy.sum(nywg)
mmean = numpy.sum(xwg * nywg) / ysum
sigma = numpy.sqrt(numpy.abs(numpy.sum((xwg-mmean)**2*nywg)/ysum))
params = (ymax, mmean, sigma)
# Error function to minimize
errorfunction = lambda p: scipy.ravel(gaussian(*p)(xhist) - yhist)
# Linear least square fitting
a_opt, a_success = optimize.leastsq(errorfunction, params)
ymax = a_opt[0]
mmean = a_opt[1]
sigma = a_opt[2]
# Fit to entire range
yall = ymax * numpy.exp(-(xhist-mmean)**2/(2.0*sigma**2))
# 2nd degree polynomial
else:
if verbose: print '%s: Fitting 2nd deg polynomial' % func_name
# Polynomial
a_opt = numpy.polyfit(xwg, nywg, 2)
mmean = -0.5*a_opt[1]/a_opt[0]
sigma = numpy.sqrt(-0.5 / ( a_opt[0]*numpy.log(10) ) )
# Fit to entire range
yall = a_opt[0]*xhist**2 + a_opt[1]*xhist + a_opt[2]
# Print results
if verbose:
print ' '
print '%s: Results' % func_name
print '%-6s: %.6f' % ('MODE', mmean)
print '%-6s: %.6f' % ('SIGMA', sigma)
print ' '
plot_y1 = 0
plot_y2 = ymax + 0.1
# Plot results
if do_plot:
pylab.clf()
# Data points
pylab.plot(xhist, yhist, 'ko')
# Mark fitted region
pylab.plot(xwg, nywg, 'bo', hold=1)
# Draw fitted function
pylab.plot(xhist, yall, 'r--', hold=1)
pylab.axvline(x=mmean, color='r')
# Plot xmin xmax for the fit
pylab.axvline(x=x1, ymin=0, ymax=0.1, color='b')
pylab.axvline(x=x2, ymin=0, ymax=0.1, color='b')
# Axis limits and labels
pylab.axis([minhist, maxhist, plot_y1, plot_y2])
pylab.xlabel('Pix value')
pylab.ylabel('Log num of pix')
pylab.title(ptitle)
#pylab.show()
# Pause for visual examination of plot
x_user = raw_input('ENTER ANY CHAR TO CONTINUE: ')
return mmean, sigma
def gaussian(height, center_x, width_x):
"""
Returns a gaussian function with the given parameters.
This is used for least square fitting optimization.
.. note:: This is used by `msky`.
Parameters
----------
height: float
Peak amplitude.
center_x: float
Peak location.
width_x: float
Sigma of gaussian curve.
Returns
-------
x: lambda function
Function used for optimization.
"""
return lambda x: height * numpy.exp(-(center_x-x)**2/(2.0*width_x**2))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment