Commit b722b4775e153bd74a1e558dd10ccccff29c15fe
Committed by
Luigi Tibaldo
1 parent
a7dc2afa
Use gammalib optimizer in show_significance_distribution.py script
Showing
4 changed files
with
243 additions
and
130 deletions
cscripts/Makefile.am
| @@ -232,7 +232,8 @@ testdata = $(top_srcdir)/test/data/crab.xml \ | @@ -232,7 +232,8 @@ testdata = $(top_srcdir)/test/data/crab.xml \ | ||
| 232 | $(top_srcdir)/test/data/onoff_rmf.fits.gz \ | 232 | $(top_srcdir)/test/data/onoff_rmf.fits.gz \ |
| 233 | $(top_srcdir)/test/data/onoff_rmf1.fits.gz \ | 233 | $(top_srcdir)/test/data/onoff_rmf1.fits.gz \ |
| 234 | $(top_srcdir)/test/data/onoff_rmf2.fits.gz \ | 234 | $(top_srcdir)/test/data/onoff_rmf2.fits.gz \ |
| 235 | - $(top_srcdir)/test/data/model_crab_radialacceptance.xml | 235 | + $(top_srcdir)/test/data/model_crab_radialacceptance.xml \ |
| 236 | + $(top_srcdir)/test/data/sigdist_map.fits.gz | ||
| 236 | 237 | ||
| 237 | # Test data to be distributed in $(pyexecdir)/cscripts/tests/data/iactdata | 238 | # Test data to be distributed in $(pyexecdir)/cscripts/tests/data/iactdata |
| 238 | testiactdata = $(top_srcdir)/test/data/iactdata/hdu-index.fits.gz \ | 239 | testiactdata = $(top_srcdir)/test/data/iactdata/hdu-index.fits.gz \ |
examples/show_significance_distribution.py
| @@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
| 2 | # ========================================================================== | 2 | # ========================================================================== |
| 3 | # Shows the distribution of significances in a given significance map. | 3 | # Shows the distribution of significances in a given significance map. |
| 4 | # | 4 | # |
| 5 | -# Copyright (C) 2011-2017 Andreas Specovius | 5 | +# Copyright (C) 2018 Andreas Specovius |
| 6 | # | 6 | # |
| 7 | # This program is free software: you can redistribute it and/or modify | 7 | # This program is free software: you can redistribute it and/or modify |
| 8 | # it under the terms of the GNU General Public License as published by | 8 | # it under the terms of the GNU General Public License as published by |
| @@ -17,8 +17,35 @@ | @@ -17,8 +17,35 @@ | ||
| 17 | # You should have received a copy of the GNU General Public License | 17 | # You should have received a copy of the GNU General Public License |
| 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | # | 19 | # |
| 20 | +# -------------------------------------------------------------------------- | ||
| 21 | +# What do I need for plotting: | ||
| 22 | +# | ||
| 23 | +# - significance map itself [mappath] | ||
| 24 | +# Provided as a file path guiding to a GSkyMap in FITS format | ||
| 25 | +# No default | ||
| 26 | +# | ||
| 27 | +# - included regions (for shrinking data space i.e. for cutting certain edges | ||
| 28 | +# or at a certain radius) [includedreg] | ||
| 29 | +# Provided as a file path to a FITS WCS map or DS9 regions file | ||
| 30 | +# Default should be None, which means all is allowed | ||
| 31 | +# | ||
| 32 | +# - excluded regions [excludedreg] | ||
| 33 | +# Provided as a file path to a FITS WCS map or DS9 regions file | ||
| 34 | +# Default should be None, which means there are no excluded regions. In this | ||
| 35 | +# case no bkg will be plotted and fitted | ||
| 36 | +# | ||
| 37 | +# - binning parameters for the histogram: [nbins], [sign_min], [sign_max] | ||
| 38 | +# Provided as floats | ||
| 39 | +# Default should be -5 to 8 with 130 bins (131 edges) | ||
| 40 | +# | ||
| 41 | +# - title of the histogram [title] | ||
| 42 | +# Provided as string | ||
| 43 | +# Default should be an empty string | ||
| 44 | +# | ||
| 45 | +# - Path to plotted file [plotfile] | ||
| 20 | # ========================================================================== | 46 | # ========================================================================== |
| 21 | import sys | 47 | import sys |
| 48 | +import math | ||
| 22 | import gammalib | 49 | import gammalib |
| 23 | import cscripts | 50 | import cscripts |
| 24 | try: | 51 | try: |
| @@ -35,56 +62,99 @@ except ImportError: | @@ -35,56 +62,99 @@ except ImportError: | ||
| 35 | print('This script needs the "numpy" module') | 62 | print('This script needs the "numpy" module') |
| 36 | sys.exit() | 63 | sys.exit() |
| 37 | 64 | ||
| 38 | -try: | ||
| 39 | - import scipy.optimize as optimize | ||
| 40 | -except ImportError: | ||
| 41 | - print('This script needs the "scipy" module') | ||
| 42 | - sys.exit() | ||
| 43 | 65 | ||
| 44 | - | ||
| 45 | -# | ||
| 46 | -# | ||
| 47 | -# | ||
| 48 | -# What do I need for plotting: | ||
| 49 | -# | ||
| 50 | -#- significance map itself [mappath] | ||
| 51 | -# Provided as a file path guiding to a GSkyMap in FITS format | ||
| 52 | -# No default | ||
| 53 | -# | ||
| 54 | -#- included regions (for shrinking data space i.e. for cutting certain edges or at a certain radius) [includedreg] | ||
| 55 | -# Provided as a file path to a FITS WCS map or DS9 regions file | ||
| 56 | -# Default should be None, which means all is allowed | ||
| 57 | -# | ||
| 58 | -#- excluded regions [excludedreg] | ||
| 59 | -# Provided as a file path to a FITS WCS map or DS9 regions file | ||
| 60 | -# Default should be None, which means there are no excluded regions. In this case no bkg will be plotted and fitted | ||
| 61 | -# | ||
| 62 | -#- binning parameters for the histogram: [nbins], [sign_min], [sign_max] | ||
| 63 | -# Provided as floats | ||
| 64 | -# Default should be -5 to 8 with 130 bins (131 edges) | ||
| 65 | -# | ||
| 66 | -#- title of the histogram [title] | ||
| 67 | -# Provided as string | ||
| 68 | -# Default should be an empty string | ||
| 69 | -# | ||
| 70 | -#- Path to plotted file [plotfile] | ||
| 71 | -# | ||
| 72 | -# | 66 | +# ======================= # |
| 67 | +# Gaussian function class # | ||
| 68 | +# ======================= # | ||
| 69 | +class gaussian(gammalib.GPythonOptimizerFunction): | ||
| 70 | + | ||
| 71 | + # Constructor | ||
| 72 | + def __init__(self, x_vals, y_vals): | ||
| 73 | + | ||
| 74 | + # Call base class constructor | ||
| 75 | + gammalib.GPythonOptimizerFunction.__init__(self) | ||
| 76 | + | ||
| 77 | + # Set eval method | ||
| 78 | + self._set_eval(self.eval) | ||
| 79 | + | ||
| 80 | + # Set data | ||
| 81 | + self._x_vals = x_vals | ||
| 82 | + self._y_vals = y_vals | ||
| 83 | + | ||
| 84 | + # Methods | ||
| 85 | + def eval(self): | ||
| 86 | + """ | ||
| 87 | + Evaluate function | ||
| 88 | + """ | ||
| 89 | + # Recover parameters | ||
| 90 | + pars = self._pars() | ||
| 91 | + norm = pars[0].value() | ||
| 92 | + mean = pars[1].value() | ||
| 93 | + sigma = pars[2].value() | ||
| 94 | + | ||
| 95 | + # Evaluate function values | ||
| 96 | + y = [norm * math.exp(-0.5*(x-mean)**2/(sigma**2)) for x in self._x_vals] | ||
| 97 | + | ||
| 98 | + # Compute weights (1/sqrt(y)) | ||
| 99 | + weight = [1.0/val if val > 0.0 else 0.0 for val in self._y_vals] | ||
| 100 | + | ||
| 101 | + # Compute Chi Square | ||
| 102 | + value = 0.0 | ||
| 103 | + for i in range(len(self._x_vals)): | ||
| 104 | + arg = self._y_vals[i] - y[i] | ||
| 105 | + value += arg * arg * weight[i] | ||
| 106 | + | ||
| 107 | + # Evaluate gradient and curvature | ||
| 108 | + sigma2 = sigma * sigma | ||
| 109 | + sigma3 = sigma2 * sigma | ||
| 110 | + for i in range(len(self._x_vals)): | ||
| 111 | + | ||
| 112 | + # Evaluate function gradients | ||
| 113 | + dx = self._x_vals[i] - mean | ||
| 114 | + dnorm = y[i] / norm * pars[0].scale() | ||
| 115 | + dmean = y[i] * dx / sigma2 * pars[1].scale() | ||
| 116 | + dsigma = y[i] * dx**2 / sigma3 * pars[2].scale() | ||
| 117 | + | ||
| 118 | + # Setup gradient vector | ||
| 119 | + arg = (self._y_vals[i] - y[i]) * weight[i] | ||
| 120 | + self.gradient()[0] -= arg * dnorm | ||
| 121 | + self.gradient()[1] -= arg * dmean | ||
| 122 | + self.gradient()[2] -= arg * dsigma | ||
| 123 | + | ||
| 124 | + # Setup curvature matrix | ||
| 125 | + self.curvature()[0,0] += dnorm * dnorm * weight[i] | ||
| 126 | + self.curvature()[0,1] += dnorm * dmean * weight[i] | ||
| 127 | + self.curvature()[0,2] += dnorm * dsigma * weight[i] | ||
| 128 | + self.curvature()[1,0] += dmean * dnorm * weight[i] | ||
| 129 | + self.curvature()[1,1] += dmean * dmean * weight[i] | ||
| 130 | + self.curvature()[1,2] += dmean * dsigma * weight[i] | ||
| 131 | + self.curvature()[2,0] += dsigma * dnorm * weight[i] | ||
| 132 | + self.curvature()[2,1] += dsigma * dmean * weight[i] | ||
| 133 | + self.curvature()[2,2] += dsigma * dsigma * weight[i] | ||
| 134 | + | ||
| 135 | + # Set value | ||
| 136 | + self._set_value(value) | ||
| 137 | + | ||
| 138 | + # Return | ||
| 139 | + return | ||
| 73 | 140 | ||
| 74 | 141 | ||
| 75 | # ================ # | 142 | # ================ # |
| 76 | # Helper functions # | 143 | # Helper functions # |
| 77 | # ================ # | 144 | # ================ # |
| 78 | -def gaussian(x, norm, xmean, sigma): | ||
| 79 | - """ | ||
| 80 | - Compute function values for gaussian function. | ||
| 81 | - """ | ||
| 82 | - return norm*np.exp(-(x-xmean)**2/float(2*sigma**2)) | ||
| 83 | - | ||
| 84 | - | ||
| 85 | def skymap_to_numpy_ndarray(skymap): | 145 | def skymap_to_numpy_ndarray(skymap): |
| 86 | """ | 146 | """ |
| 87 | Return numpy.ndarray of pixel values of a skymap. | 147 | Return numpy.ndarray of pixel values of a skymap. |
| 148 | + | ||
| 149 | + Parameters | ||
| 150 | + ---------- | ||
| 151 | + skymap : `~gammalib.GSkyMap` | ||
| 152 | + Sky map. | ||
| 153 | + | ||
| 154 | + Returns | ||
| 155 | + ------- | ||
| 156 | + array : `~numpy.array` | ||
| 157 | + Numpy array | ||
| 88 | """ | 158 | """ |
| 89 | # Get map size | 159 | # Get map size |
| 90 | npix = skymap.npix() | 160 | npix = skymap.npix() |
| @@ -108,14 +178,19 @@ def read_regions(fpath, init_map): | @@ -108,14 +178,19 @@ def read_regions(fpath, init_map): | ||
| 108 | ---------- | 178 | ---------- |
| 109 | fpath : str | 179 | fpath : str |
| 110 | Path to regions file | 180 | Path to regions file |
| 111 | - init_map : GSkyMap | 181 | + init_map : `~gammalib.GSkyMap` |
| 112 | Sky map representing fov of interest. Used for initialisation of | 182 | Sky map representing fov of interest. Used for initialisation of |
| 113 | regions map. | 183 | regions map. |
| 184 | + | ||
| 185 | + Returns | ||
| 186 | + ------- | ||
| 187 | + map : `~gammalib.GSkyMap` | ||
| 188 | + Sky map. | ||
| 114 | """ | 189 | """ |
| 115 | 190 | ||
| 116 | # Create starter map for user fov filled with zeros | 191 | # Create starter map for user fov filled with zeros |
| 117 | - regions_map = init_map.copy() | ||
| 118 | - regions_map *= 0 | 192 | + regions_map = init_map.copy() |
| 193 | + regions_map *= 0.0 | ||
| 119 | 194 | ||
| 120 | # Take care about ds9 region files | 195 | # Take care about ds9 region files |
| 121 | if fpath.lower().endswith('.reg'): | 196 | if fpath.lower().endswith('.reg'): |
| @@ -132,8 +207,8 @@ def read_regions(fpath, init_map): | @@ -132,8 +207,8 @@ def read_regions(fpath, init_map): | ||
| 132 | # Add ds9 region map to global map | 207 | # Add ds9 region map to global map |
| 133 | regions_map += ds9_map.map() | 208 | regions_map += ds9_map.map() |
| 134 | 209 | ||
| 135 | - # Take care about fits wcs files | ||
| 136 | - elif fpath.lower().endswith('.fits'): | 210 | + # Take care about fits WCS files |
| 211 | + elif gammalib.GFilename(fpath).is_fits(): | ||
| 137 | 212 | ||
| 138 | # Read wcs regions map | 213 | # Read wcs regions map |
| 139 | wcs_regions = gammalib.GSkyMap(fpath) | 214 | wcs_regions = gammalib.GSkyMap(fpath) |
| @@ -142,18 +217,47 @@ def read_regions(fpath, init_map): | @@ -142,18 +217,47 @@ def read_regions(fpath, init_map): | ||
| 142 | regions_map += wcs_regions | 217 | regions_map += wcs_regions |
| 143 | 218 | ||
| 144 | else: | 219 | else: |
| 145 | - raise RuntimeError("Invalid regions file detected. Please provide " + | ||
| 146 | - "a valid ds9 or FITS WCS regions file.") | 220 | + raise RuntimeError('Invalid regions file detected. Please provide ' + |
| 221 | + 'a valid ds9 or FITS WCS regions file.') | ||
| 147 | 222 | ||
| 148 | # Return | 223 | # Return |
| 149 | return regions_map | 224 | return regions_map |
| 150 | 225 | ||
| 151 | 226 | ||
| 227 | +def linspace(minval, maxval, nbins): | ||
| 228 | + """ | ||
| 229 | + Return a linearly spaced array | ||
| 230 | + | ||
| 231 | + Parameters | ||
| 232 | + ---------- | ||
| 233 | + minval : float | ||
| 234 | + Minimum value | ||
| 235 | + maxval : float | ||
| 236 | + Maximum value | ||
| 237 | + nbins : int | ||
| 238 | + Number of bins | ||
| 239 | + | ||
| 240 | + Returns | ||
| 241 | + ------- | ||
| 242 | + bins : list of float | ||
| 243 | + Linearly spaced array | ||
| 244 | + """ | ||
| 245 | + # Compute bin width | ||
| 246 | + binwidth = (maxval - minval) / float(nbins-1) | ||
| 247 | + | ||
| 248 | + # Compute bins | ||
| 249 | + bins = [minval + binwidth*i for i in range(nbins)] | ||
| 250 | + | ||
| 251 | + # Return bins | ||
| 252 | + return bins | ||
| 253 | + | ||
| 254 | + | ||
| 152 | # ============================== # | 255 | # ============================== # |
| 153 | # Plot significance distribution # | 256 | # Plot significance distribution # |
| 154 | # ============================== # | 257 | # ============================== # |
| 155 | def plot_significance_distribution(mappath, nbins, sigma_min, sigma_max, | 258 | def plot_significance_distribution(mappath, nbins, sigma_min, sigma_max, |
| 156 | - includedreg, excludedreg, title): | 259 | + includedreg, excludedreg, title, |
| 260 | + plotfile): | ||
| 157 | """ | 261 | """ |
| 158 | Plot the significance distribution and return instance of pyplot | 262 | Plot the significance distribution and return instance of pyplot |
| 159 | figure and axis. | 263 | figure and axis. |
| @@ -174,57 +278,29 @@ def plot_significance_distribution(mappath, nbins, sigma_min, sigma_max, | @@ -174,57 +278,29 @@ def plot_significance_distribution(mappath, nbins, sigma_min, sigma_max, | ||
| 174 | Path to global excluded region file | 278 | Path to global excluded region file |
| 175 | title : str | 279 | title : str |
| 176 | Title of the plot | 280 | Title of the plot |
| 177 | - | ||
| 178 | - Figure and axis objects are returned. | 281 | + plotfile : str |
| 282 | + Name of file for plotting | ||
| 179 | """ | 283 | """ |
| 180 | 284 | ||
| 181 | # Read significance map | 285 | # Read significance map |
| 182 | - # ===================== | ||
| 183 | - | ||
| 184 | - # Read map | ||
| 185 | significance_map = gammalib.GSkyMap(mappath+'[SIGNIFICANCE]') | 286 | significance_map = gammalib.GSkyMap(mappath+'[SIGNIFICANCE]') |
| 186 | 287 | ||
| 187 | 288 | ||
| 188 | # Read included regions | 289 | # Read included regions |
| 189 | - # ===================== | ||
| 190 | - | ||
| 191 | - # Set availability to false | ||
| 192 | inclusion_available = False | 290 | inclusion_available = False |
| 193 | - | ||
| 194 | - # Read in case provided | ||
| 195 | if len(includedreg) > 0: | 291 | if len(includedreg) > 0: |
| 196 | - # Read regions map | ||
| 197 | - regions_map = read_regions(includedreg, init_map=significance_map) | ||
| 198 | - | ||
| 199 | - # Make numpy boolean mask | ||
| 200 | - mask_include = skymap_to_numpy_ndarray(regions_map).astype(bool) | ||
| 201 | - | ||
| 202 | - # Enable masked map | 292 | + regions_map = read_regions(includedreg, init_map=significance_map) |
| 293 | + mask_include = skymap_to_numpy_ndarray(regions_map).astype(bool) | ||
| 203 | inclusion_available = True | 294 | inclusion_available = True |
| 204 | 295 | ||
| 205 | - | ||
| 206 | # Read excluded regions | 296 | # Read excluded regions |
| 207 | - # ===================== | ||
| 208 | - | ||
| 209 | - # Set availability to false | ||
| 210 | src_exclusion_available = False | 297 | src_exclusion_available = False |
| 211 | - | ||
| 212 | - # Read in case provided | ||
| 213 | if len(excludedreg) > 0: | 298 | if len(excludedreg) > 0: |
| 214 | - # Read regions file | ||
| 215 | - regions_map = read_regions(excludedreg, init_map=significance_map) | ||
| 216 | - | ||
| 217 | - # Make numpy boolean mask | ||
| 218 | - mask_exclude = skymap_to_numpy_ndarray(regions_map).astype(bool) | ||
| 219 | - | ||
| 220 | - # Enable masked map | 299 | + regions_map = read_regions(excludedreg, init_map=significance_map) |
| 300 | + mask_exclude = skymap_to_numpy_ndarray(regions_map).astype(bool) | ||
| 221 | src_exclusion_available = True | 301 | src_exclusion_available = True |
| 222 | 302 | ||
| 223 | - | ||
| 224 | - # Convet maps to flat arrays and apply spatial cuts | ||
| 225 | - # ================================================= | ||
| 226 | - | ||
| 227 | - # significance data to flat array | 303 | + # Convert significance map to flat array |
| 228 | data = skymap_to_numpy_ndarray(significance_map) | 304 | data = skymap_to_numpy_ndarray(significance_map) |
| 229 | 305 | ||
| 230 | # Initialise dummy mask allowing all pixels | 306 | # Initialise dummy mask allowing all pixels |
| @@ -241,70 +317,93 @@ def plot_significance_distribution(mappath, nbins, sigma_min, sigma_max, | @@ -241,70 +317,93 @@ def plot_significance_distribution(mappath, nbins, sigma_min, sigma_max, | ||
| 241 | mask &= ~mask_exclude | 317 | mask &= ~mask_exclude |
| 242 | data_without_sources = data_without_sources[mask] | 318 | data_without_sources = data_without_sources[mask] |
| 243 | 319 | ||
| 244 | - | ||
| 245 | - # Compute bin edges to user parameters | ||
| 246 | - # ==================================== | ||
| 247 | - | ||
| 248 | # Compute bin edges, hence use nbins+1 | 320 | # Compute bin edges, hence use nbins+1 |
| 249 | - bin_edges = np.linspace(sigma_min, sigma_max, nbins+1) | ||
| 250 | - | ||
| 251 | - | ||
| 252 | - # Begin with plotting | ||
| 253 | - # =================== | 321 | + bin_edges = linspace(sigma_min, sigma_max, nbins+1) |
| 254 | 322 | ||
| 255 | # Create figure | 323 | # Create figure |
| 256 | fig = plt.figure() | 324 | fig = plt.figure() |
| 257 | ax = fig.gca() | 325 | ax = fig.gca() |
| 258 | 326 | ||
| 259 | - # Draw significance histogram for full fov | ||
| 260 | - y, _, _ = ax.hist(data, bins=bin_edges, histtype='step', color='k', label="significance") | 327 | + # Draw significance histogram for full FOV |
| 328 | + y, _, _ = ax.hist(data, bins=bin_edges, histtype='step', color='k', | ||
| 329 | + label='significance') | ||
| 261 | 330 | ||
| 262 | # Draw the default normal distribution. Scale to fit maximum of histogram | 331 | # Draw the default normal distribution. Scale to fit maximum of histogram |
| 263 | - ax.plot(bin_edges, gaussian(bin_edges, y.max(),0,1), 'b-') | 332 | + yvals = [y.max() * math.exp(-0.5*(x-0.0)**2/(1.0**2)) for x in bin_edges] |
| 333 | + ax.plot(bin_edges, yvals, 'b-') | ||
| 264 | msg = 'mean: $0$\nwidth: $1$' | 334 | msg = 'mean: $0$\nwidth: $1$' |
| 265 | - ax.text(0.98, 0.80, msg, ha='right', va='top', bbox=dict(edgecolor='blue', facecolor='white'), transform=ax.transAxes) | 335 | + ax.text(0.98, 0.80, msg, ha='right', va='top', |
| 336 | + bbox=dict(edgecolor='blue', facecolor='white'), | ||
| 337 | + transform=ax.transAxes) | ||
| 266 | 338 | ||
| 267 | - # If exclusion was provided also handle significanes with excluded src data | 339 | + # If exclusion was provided then also plot significances with excluded |
| 340 | + # source data | ||
| 268 | if src_exclusion_available: | 341 | if src_exclusion_available: |
| 269 | 342 | ||
| 270 | - # Draw histogram of significances for data without excluded sources | 343 | + # Draw histogram of significances for data with excluded sources |
| 271 | y, _, _ = ax.hist(data_without_sources, bins=bin_edges, histtype='step', | 344 | y, _, _ = ax.hist(data_without_sources, bins=bin_edges, histtype='step', |
| 272 | - color='k', alpha=0.5, label="significance without exclusions") | ||
| 273 | - | ||
| 274 | - # Fit a normal distribution to the binned masked significance data | ||
| 275 | - pars = [1.0, 0.0, 1.0] | ||
| 276 | - bin_centers = 0.5*(bin_edges[:-1] + bin_edges[1:]) | ||
| 277 | - | ||
| 278 | - pars_opt, pars_cov = optimize.curve_fit(gaussian, xdata=bin_centers, | ||
| 279 | - ydata=y, p0=pars) | ||
| 280 | - | ||
| 281 | - # Compute parameters fit errors | ||
| 282 | - pars_err = np.sqrt(np.diag(pars_cov)) | 345 | + color='k', alpha=0.5, |
| 346 | + label='significance without exclusions') | ||
| 347 | + | ||
| 348 | + # Set initial Gaussian parameters | ||
| 349 | + par1 = gammalib.GOptimizerPar('Norm', y.max()) | ||
| 350 | + par2 = gammalib.GOptimizerPar('Mean', 0.0) | ||
| 351 | + par3 = gammalib.GOptimizerPar('Sigma', 1.0) | ||
| 352 | + pars = gammalib.GOptimizerPars() | ||
| 353 | + pars.append(par1) | ||
| 354 | + pars.append(par2) | ||
| 355 | + pars.append(par3) | ||
| 356 | + | ||
| 357 | + # Set fit function | ||
| 358 | + x = [0.5*(bin_edges[i]+bin_edges[i+1]) for i in range(nbins)] | ||
| 359 | + fct = gaussian(x, y) | ||
| 360 | + | ||
| 361 | + # Optimize function and compute errors | ||
| 362 | + opt = gammalib.GOptimizerLM() | ||
| 363 | + opt.optimize(fct, pars) | ||
| 364 | + opt.errors(fct, pars) | ||
| 365 | + | ||
| 366 | + # Recover parameters and errors | ||
| 367 | + norm = pars[0].value() | ||
| 368 | + e_norm = pars[0].error() | ||
| 369 | + mean = pars[1].value() | ||
| 370 | + e_mean = pars[1].error() | ||
| 371 | + sigma = pars[2].value() | ||
| 372 | + e_sigma = pars[2].error() | ||
| 283 | 373 | ||
| 284 | # Log fit result | 374 | # Log fit result |
| 285 | - print('Fit of normal distribution to excluded source significance data ' +\ | 375 | + print('Fit of normal distribution to excluded source significance data '+ |
| 286 | 'results in: norm=%f+=%f xmean=%f+-%f sigma=%f+-%f' % | 376 | 'results in: norm=%f+=%f xmean=%f+-%f sigma=%f+-%f' % |
| 287 | - (pars_opt[0], pars_err[0], pars_opt[1], pars_err[1], pars_opt[2], pars_err[2]) | ||
| 288 | - ) | 377 | + (norm, e_norm, mean, e_mean, sigma, e_sigma)) |
| 289 | 378 | ||
| 290 | # Draw text box | 379 | # Draw text box |
| 291 | - msg = 'mean: $%.3f\pm%.3f$\nwidth: $%.3f\pm%.3f$' % (pars_opt[1], pars_err[1], pars_opt[2], pars_err[2]) | ||
| 292 | - ax.text(0.98, 0.95, msg, ha='right', va='top', bbox=dict(edgecolor='red', facecolor='white'), transform=ax.transAxes) | 380 | + msg = 'mean: $%.3f\pm%.3f$\nwidth: $%.3f\pm%.3f$' % \ |
| 381 | + (mean, e_mean, sigma, e_sigma) | ||
| 382 | + ax.text(0.98, 0.95, msg, ha='right', va='top', | ||
| 383 | + bbox=dict(edgecolor='red', facecolor='white'), | ||
| 384 | + transform=ax.transAxes) | ||
| 293 | 385 | ||
| 294 | - # Plot the normal (2) | ||
| 295 | - ax.plot(bin_edges, gaussian(bin_edges, *(pars_opt)), 'r-') | 386 | + # Plot the normal |
| 387 | + yvals = [norm * math.exp(-0.5*(x-mean)**2/(sigma**2)) for x in bin_edges] | ||
| 388 | + ax.plot(bin_edges, yvals, 'r-') | ||
| 296 | 389 | ||
| 297 | # Configure the plot | 390 | # Configure the plot |
| 298 | ax.set_ylim(0.5, ax.get_ylim()[1]*2.0) | 391 | ax.set_ylim(0.5, ax.get_ylim()[1]*2.0) |
| 299 | ax.set_xlim(sigma_min, sigma_max) | 392 | ax.set_xlim(sigma_min, sigma_max) |
| 300 | ax.set_title(title) | 393 | ax.set_title(title) |
| 301 | - ax.set_xlabel("Significance") | ||
| 302 | - ax.set_ylabel("Entries") | 394 | + ax.set_xlabel('Significance') |
| 395 | + ax.set_ylabel('Entries') | ||
| 303 | ax.grid() | 396 | ax.grid() |
| 304 | ax.set_yscale('log') | 397 | ax.set_yscale('log') |
| 305 | 398 | ||
| 399 | + # Show or save the plot | ||
| 400 | + if len(plotfile) > 0: | ||
| 401 | + plt.savefig(plotfile) | ||
| 402 | + else: | ||
| 403 | + plt.show() | ||
| 404 | + | ||
| 306 | # Return | 405 | # Return |
| 307 | - return fig, ax | 406 | + return |
| 308 | 407 | ||
| 309 | 408 | ||
| 310 | # ============================== # | 409 | # ============================== # |
| @@ -346,14 +445,9 @@ def show_significance_distribution(): | @@ -346,14 +445,9 @@ def show_significance_distribution(): | ||
| 346 | plotfile = options[6]['value'] | 445 | plotfile = options[6]['value'] |
| 347 | 446 | ||
| 348 | # Plot significance distribution histogram | 447 | # Plot significance distribution histogram |
| 349 | - fig, ax = plot_significance_distribution(args[0], nbins, sigma_min, sigma_max, | ||
| 350 | - includedreg, excludedreg, title) | ||
| 351 | - | ||
| 352 | - # Show or save the plot | ||
| 353 | - if len(plotfile) > 0: | ||
| 354 | - plt.savefig(plotfile) | ||
| 355 | - else: | ||
| 356 | - plt.show() | 448 | + plot_significance_distribution(args[0], nbins, sigma_min, sigma_max, |
| 449 | + includedreg, excludedreg, title, | ||
| 450 | + plotfile) | ||
| 357 | 451 | ||
| 358 | # Return | 452 | # Return |
| 359 | return | 453 | return |
test/data/sigdist_map.fits.gz
0 → 100644
No preview for this file type
test/test_examples.py.in
| @@ -123,6 +123,8 @@ class Test(gammalib.GPythonTestSuite): | @@ -123,6 +123,8 @@ class Test(gammalib.GPythonTestSuite): | ||
| 123 | 'Test show_obs.py') | 123 | 'Test show_obs.py') |
| 124 | self.append(self.test_show_pointings, | 124 | self.append(self.test_show_pointings, |
| 125 | 'Test show_pointings.py') | 125 | 'Test show_pointings.py') |
| 126 | + self.append(self.test_show_significance_distribution, | ||
| 127 | + 'Test show_significance_distribution.py') | ||
| 126 | 128 | ||
| 127 | # Return | 129 | # Return |
| 128 | return | 130 | return |
| @@ -526,6 +528,22 @@ class Test(gammalib.GPythonTestSuite): | @@ -526,6 +528,22 @@ class Test(gammalib.GPythonTestSuite): | ||
| 526 | # Return | 528 | # Return |
| 527 | return | 529 | return |
| 528 | 530 | ||
| 531 | + # Test show_significance_distribution | ||
| 532 | + def test_show_significance_distribution(self): | ||
| 533 | + """ | ||
| 534 | + Test show_significance_distribution | ||
| 535 | + """ | ||
| 536 | + # Set arguments | ||
| 537 | + args = '-p example_show_significance_distribution.eps '+ \ | ||
| 538 | + '%s/sigdist_map.fits --exclude %s/sigdist_map.fits[EXCLUSION]' % \ | ||
| 539 | + (self._datadir, self._datadir) | ||
| 540 | + | ||
| 541 | + # Execute script | ||
| 542 | + self._execute_python('show_significance_distribution', args=args) | ||
| 543 | + | ||
| 544 | + # Return | ||
| 545 | + return | ||
| 546 | + | ||
| 529 | 547 | ||
| 530 | # ======================== # | 548 | # ======================== # |
| 531 | # Main routine entry point # | 549 | # Main routine entry point # |