Passed
Push — master ( 3853ea...f123dc )
by J. Michael
01:05
created

polarpy.polarlike.PolarLike.bin_widths()   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nop 1
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
import collections
0 ignored issues
show
Coding Style introduced by
This module should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
2
from contextlib import contextmanager
3
import matplotlib.pyplot as plt
0 ignored issues
show
introduced by
Unable to import 'matplotlib.pyplot'
Loading history...
4
import numpy as np
0 ignored issues
show
introduced by
Unable to import 'numpy'
Loading history...
5
6
from astromodels import Parameter, Uniform_prior
0 ignored issues
show
introduced by
Unable to import 'astromodels'
Loading history...
7
from threeML import PluginPrototype
0 ignored issues
show
introduced by
Unable to import 'threeML'
Loading history...
8
from threeML.io.plotting.step_plot import step_plot
0 ignored issues
show
introduced by
Unable to import 'threeML.io.plotting.step_plot'
Loading history...
9
from threeML.utils.binner import Rebinner
0 ignored issues
show
introduced by
Unable to import 'threeML.utils.binner'
Loading history...
10
from threeML.utils.polarization.binned_polarization import BinnedModulationCurve
0 ignored issues
show
introduced by
Unable to import 'threeML.utils.polarization.binned_polarization'
Loading history...
11
from threeML.utils.statistics.likelihood_functions import poisson_observed_poisson_background, \
0 ignored issues
show
introduced by
Unable to import 'threeML.utils.statistics.likelihood_functions'
Loading history...
12
    poisson_observed_gaussian_background
13
14
from polarpy.modulation_curve_file import ModulationCurveFile
15
from polarpy.polar_response import PolarResponse
16
17
18
class PolarLike(PluginPrototype):
0 ignored issues
show
best-practice introduced by
Too many instance attributes (21/7)
Loading history...
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
19
    """
20
    Preliminary POLAR polarization plugin
21
    """
22
23
    def __init__(self, name, observation, background, response, interval_number=None, verbose=False):
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (101/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
best-practice introduced by
Too many arguments (7/5)
Loading history...
24
        """
25
26
27
28
        :param interval_number:
29
        :param name:
30
        :param observation:
31
        :param background:
32
        :param response:
33
34
        :param verbose:
35
36
        """
37
38
        # if we pass a string, there may be multiple time intervals
39
        # saved so we must specify a time interval
40
41
        if isinstance(observation, str):
42
            assert interval_number is not None, 'must specify an interval number'
43
44
            # this is a file
45
            read_file = ModulationCurveFile.read(observation)
46
47
            # create the bmc
48
            observation = read_file.to_binned_modulation_curve(interval=interval_number)
49
50
        # the same applies for the background
51
        if isinstance(background, str):
52
            assert interval_number is not None, 'must specify an interval number'
53
54
            # this is a file
55
            read_file = ModulationCurveFile.read(background)
56
57
            background = read_file.to_binned_modulation_curve(interval=interval_number)
58
59
        assert isinstance(observation, BinnedModulationCurve), 'The observation must be a BinnedModulationCurve'
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (112/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
60
        assert isinstance(background, BinnedModulationCurve), 'The observation must be a BinnedModulationCurve'
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (111/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
61
62
        # attach the required variables
63
64
        self._observation = observation
65
        self._background = background
66
67
        self._observed_counts = observation.counts
68
        self._background_counts = background.counts
69
        self._background_count_errors = background.count_errors
70
        self._scale = observation.exposure / background.exposure
71
        self._exposure = observation.exposure
72
        self._background_exposure = background.exposure
73
74
        self._likelihood_model = None
75
        self._rebinner = None
76
        
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
77
        # now do some double checks
78
79
        assert len(self._observed_counts) == len(self._background_counts)
80
81
        self._n_synthetic_datasets = 0
82
83
        # set up the effective area correction
84
85
        self._nuisance_parameter = Parameter(
86
            "cons_%s" % name,
87
            1.0,
88
            min_value=0.8,
89
            max_value=1.2,
90
            delta=0.05,
91
            free=False,
92
            desc="Effective area correction for %s" % name)
93
94
        nuisance_parameters = collections.OrderedDict()
95
        nuisance_parameters[self._nuisance_parameter.name] = self._nuisance_parameter
96
97
        # pass to the plugin proto
98
99
        super(PolarLike, self).__init__(name, nuisance_parameters)
100
101
102
        # The following vectors are the ones that will be really used for the computation. At the beginning they just
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (117/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
103
        # point to the original ones, but if a rebinner is used and/or a mask is created through set_active_measurements,
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (121/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
104
        # they will contain the rebinned and/or masked versions
105
106
        self._current_observed_counts = self._observed_counts
107
        self._current_background_counts = self._background_counts
108
        self._current_background_count_errors = self._background_count_errors
109
110
111
        self._verbose = verbose
112
113
        # we can either attach or build a response
114
115
        assert isinstance(response, str) or isinstance(
0 ignored issues
show
Unused Code introduced by
Consider merging these isinstance calls to isinstance(response, (PolarResponse, str))
Loading history...
116
            response, PolarResponse), 'The response must be a file name or a PolarResponse'
117
118
        if isinstance(response, PolarResponse):
119
120
            self._response = response
121
122
        else:
123
124
            self._response = PolarResponse(response)
125
126
        # attach the interpolators to the
127
128
        self._all_interp = self._response.interpolators
129
130
        # we also make sure the lengths match up here
131
        assert self._response.n_scattering_bins == len(
132
            self._observation.counts), 'observation counts shape does not agree with response shape'
133
134
    def use_effective_area_correction(self, lower=0.5, upper=1.5):
135
        """
136
        Use an area constant to correct for response issues
137
138
        :param lower:
139
        :param upper:
140
        :return:
141
        """
142
143
        self._nuisance_parameter.free = True
144
        self._nuisance_parameter.bounds = (lower, upper)
145
        self._nuisance_parameter.prior = Uniform_prior(lower_bound=lower, upper_bound=upper)
146
        if self._verbose:
147
            print('Using effective area correction')
148
149
    def fix_effective_area_correction(self, value=1):
150
        """
151
152
        fix the effective area correction to a particular values
153
154
        :param value:
155
        :return:
156
        """
157
158
        # allow the value to be outside the bounds
159
        if self._nuisance_parameter.max_value < value:
160
161
            self._nuisance_parameter.max_value = value + 0.1
162
163
        elif self._nuisance_parameter.min_value > value:
164
165
            self._nuisance_parameter.min_value = value = 0.1
166
167
        self._nuisance_parameter.fix = True
168
        self._nuisance_parameter.value = value
169
170
        if self._verbose:
171
            print('Fixing effective area correction')
172
173
    @property
174
    def effective_area_correction(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
175
176
        return self._nuisance_parameter
177
178
    def get_simulated_dataset(self, new_name=None, **kwargs):
0 ignored issues
show
Unused Code introduced by
The argument kwargs seems to be unused.
Loading history...
179
        """
180
        Returns another Binned instance where data have been obtained by randomizing the current expectation from the
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (117/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
181
        model, as well as from the background (depending on the respective noise models)
182
183
        :return: an BinnedSpectrum or child instance
184
        """
185
186
        assert self._likelihood_model is not None, "You need to set up a model before randomizing"
187
188
        # Keep track of how many syntethic datasets we have generated
189
190
        self._n_synthetic_datasets += 1
191
192
        # Generate a name for the new dataset if needed
193
        if new_name is None:
194
            new_name = "%s_sim_%i" % (self.name, self._n_synthetic_datasets)
195
196
        # Generate randomized data depending on the different noise models
197
198
        # We remove the mask temporarily because we need the various elements for all channels. We will restore it
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (114/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
199
        # at the end
200
201
        # Get the source model for all channels (that's why we don't use the .folded_model property)
202
203
        
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
204
        # We remove the mask temporarily because we need the various elements for all channels. We will restore it
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (114/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
205
        # at the end
206
207
        original_rebinner = self._rebinner
208
209
        with self._without_rebinner():
210
211
            # Get the source model for all channels (that's why we don't use the .folded_model property)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (104/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
212
213
        
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
214
            source_model_counts = self._get_model_counts()
215
216
            if self._background.is_poisson:
217
                _, background_model_counts = poisson_observed_poisson_background(
218
                            self._current_observed_counts, self._current_background_counts, self._scale, source_model_counts)
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 8 spaces).
Loading history...
Coding Style introduced by
This line is too long as per the coding-style (125/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
219
            else:
220
221
                _, background_model_counts = poisson_observed_gaussian_background(
222
                            self._current_observed_counts, self._current_background_counts, self._current_background_count_errors, source_model_counts)
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 8 spaces).
Loading history...
Coding Style introduced by
This line is too long as per the coding-style (151/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
223
224
            # Now randomize the expectations
225
226
            # Randomize expectations for the source
227
228
            randomized_source_counts = np.random.poisson(source_model_counts + background_model_counts)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (103/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
229
230
            randomized_background_counts = np.random.poisson(background_model_counts)
231
232
            new_observation = self._observation.clone(new_counts=randomized_source_counts)
233
234
            new_background = self._background.clone(new_counts=randomized_background_counts)
235
236
            new_plugin = PolarLike(
237
                name=new_name,
238
                observation=new_observation,
239
                background=new_background,
240
                response=self._response,
241
                verbose=False,
242
            )
243
244
            # Apply the same selections as the current data set
245
            if original_rebinner is not None:
246
247
                # Apply rebinning, which also applies the mask
248
                new_plugin._apply_rebinner(original_rebinner)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _apply_rebinner was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
249
250
            
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
251
            return new_plugin
252
253
    def set_model(self, likelihood_model_instance):
254
        """
255
        Set the model to be used in the joint minimization. Must be a LikelihoodModel instance.
256
        :param likelihood_model_instance: instance of Model
257
        :type likelihood_model_instance: astromodels.Model
258
        """
259
260
        if likelihood_model_instance is None:
261
            return
262
263
        # if self._source_name is not None:
264
265
        #     # Make sure that the source is in the model
266
        #     assert self._source_name in likelihood_model_instance.sources, \
267
        #                                         "This XYLike plugin refers to the source %s, " \
268
        #                                         "but that source is not in the likelihood model" % (self._source_name)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (120/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
269
270
        for k, v in likelihood_model_instance.free_parameters.items():
0 ignored issues
show
Coding Style Naming introduced by
The name v does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
271
272
            if 'polarization.degree' in k:
273
                self._pol_degree = v
0 ignored issues
show
Coding Style introduced by
The attribute _pol_degree was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
274
275
            if 'polarization.angle' in k:
276
                self._pol_angle = v
0 ignored issues
show
Coding Style introduced by
The attribute _pol_angle was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
277
278
        # now we need to get the intergal flux
279
280
        _, integral = self._get_diff_flux_and_integral(likelihood_model_instance)
281
282
        self._integral_flux = integral
0 ignored issues
show
Coding Style introduced by
The attribute _integral_flux was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
283
284
        self._likelihood_model = likelihood_model_instance
285
286
    def _get_diff_flux_and_integral(self, likelihood_model):
287
288
        n_point_sources = likelihood_model.get_number_of_point_sources()
289
290
        # Make a function which will stack all point sources (OGIP do not support spatial dimension)
291
292
        def differential_flux(scattering_edges):
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
293
            fluxes = likelihood_model.get_point_source_fluxes(0, scattering_edges, tag=self._tag)
294
295
            # If we have only one point source, this will never be executed
296
            for i in range(1, n_point_sources):
297
                fluxes += likelihood_model.get_point_source_fluxes(i, scattering_edges, tag=self._tag)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (102/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
298
299
            return fluxes
300
301
        # The following integrates the diffFlux function using Simpson's rule
302
        # This assume that the intervals e1,e2 are all small, which is guaranteed
303
        # for any reasonable response matrix, given that e1 and e2 are Monte-Carlo
304
        # scattering_edges. It also assumes that the function is smooth in the interval
305
        # e1 - e2 and twice-differentiable, again reasonable on small intervals for
306
        # decent models. It might fail for models with too sharp features, smaller
307
        # than the size of the monte carlo interval.
308
309
        def integral(e1, e2):
0 ignored issues
show
Coding Style Naming introduced by
The name e1 does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style Naming introduced by
The name e2 does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
310
            # Simpson's rule
311
312
            return (e2 - e1) / 6.0 * (differential_flux(e1) + 4 * differential_flux(
313
                (e1 + e2) / 2.0) + differential_flux(e2))
314
315
        return differential_flux, integral
316
317
    def _get_model_rate(self):
318
319
        # first we need to get the integrated expectation from the spectrum
320
321
        intergal_spectrum = np.array(
322
            [self._integral_flux(emin, emax) for emin, emax in zip(self._response.ene_lo, self._response.ene_hi)])
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (114/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
323
324
        # we evaluate at the center of the bin. the bin widths are already included
325
        eval_points = np.array(
326
            [[ene, self._pol_angle.value, self._pol_degree.value] for ene in self._response.energy_mid])
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (104/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
327
328
        expectation = []
329
330
        # create the model counts by summing over energy
331
332
        for i, interpolator in enumerate(self._all_interp):
0 ignored issues
show
Unused Code introduced by
The variable i seems to be unused.
Loading history...
333
            rate = np.dot(interpolator(eval_points), intergal_spectrum)
334
335
            expectation.append(rate)
336
337
        return np.array(expectation)
338
339
    def _get_model_counts(self):
340
341
342
        if self._rebinner is None:
343
            model_rate = self._get_model_rate()
344
345
        else:
346
347
            model_rate, = self._rebinner.rebin(self._get_model_rate())
348
349
        
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
350
        return self._nuisance_parameter.value * self._exposure * model_rate
351
352
    def get_log_like(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
353
354
        model_counts = self._get_model_counts()
355
356
        if self._background.is_poisson:
357
358
            loglike, bkg_model = poisson_observed_poisson_background(        self._current_observed_counts, self._current_background_counts,
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (140/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Coding Style introduced by
No space allowed after bracket
Loading history...
Unused Code introduced by
The variable bkg_model seems to be unused.
Loading history...
359
                                                                     self._scale, model_counts)
0 ignored issues
show
Coding Style introduced by
Wrong continued indentation (add 8 spaces).
Loading history...
360
361
        else:
362
363
            loglike, bkg_model = poisson_observed_gaussian_background(        self._current_observed_counts, self._current_background_counts,
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (141/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Coding Style introduced by
No space allowed after bracket
Loading history...
364
                                                                      self._current_background_count_errors, model_counts)
0 ignored issues
show
Coding Style introduced by
Wrong continued indentation (add 8 spaces).
Loading history...
Coding Style introduced by
This line is too long as per the coding-style (122/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
365
366
        return np.sum(loglike)
367
368
    def inner_fit(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
369
370
        return self.get_log_like()
371
372
    def writeto(self, file_name):
373
        """
374
        Write the data to HDF5 modulation curve files. Both background and observation
375
        files are created
376
        :param file_name: the file name header. The .h5 extension is added automatically
377
        """
378
        # first create a file container
379
        observation_file = ModulationCurveFile.from_binned_modulation_curve(self._observation)
380
381
        background_file = ModulationCurveFile.from_binned_modulation_curve(self._background)
382
383
        observation_file.writeto("%s.h5" % file_name)
384
385
        background_file.writeto("%s_bak.h5" % file_name)
386
387
388
389
    @property
390
    def scattering_boundaries(self):
391
        """
392
        Energy boundaries of channels currently in use (rebinned, if a rebinner is active)
393
394
        :return: (sa_min, sa_max)
395
        """
396
397
        scattering_edges = np.array(self._observation.edges)
398
399
        sa_min, sa_max = scattering_edges[:-1], scattering_edges[1:]
400
401
        if self._rebinner is not None:
402
            # Get the rebinned chans. NOTE: these are already masked
403
404
            sa_min, sa_max = self._rebinner.get_new_start_and_stop(sa_min, sa_max)
405
406
 
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
407
        return sa_min, sa_max
408
409
    @property
410
    def bin_widths(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
411
412
        sa_min, sa_max = self.scattering_boundaries
413
414
        return sa_max - sa_min
415
416
        
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
417
    def display(self, ax=None, show_data=True, show_model=True, show_total=False, model_kwargs={}, data_kwargs={}):
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (115/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Bug Best Practice introduced by
The default value {} might cause unintended side-effects.

Objects as default values are only created once in Python and not on each invocation of the function. If the default object is modified, this modification is carried over to the next invocation of the method.

# Bad:
# If array_param is modified inside the function, the next invocation will
# receive the modified object.
def some_function(array_param=[]):
    # ...

# Better: Create an array on each invocation
def some_function(array_param=None):
    array_param = array_param or []
    # ...
Loading history...
Coding Style Naming introduced by
The name ax does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
best-practice introduced by
Too many arguments (7/5)
Loading history...
Comprehensibility introduced by
This function exceeds the maximum number of variables (17/15).
Loading history...
418
        """
419
420
        :param ax:
421
        :param show_data:
422
        :param show_model:
423
        :param show_total:
424
        :param model_kwargs:
425
        :param data_kwargs:
426
        :return:
427
        """
428
429
        sa_min, sa_max = self.scattering_boundaries
430
        
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
431
        if show_total:
432
            show_model = False
433
            show_data = False
434
435
        if ax is None:
436
437
            fig, ax = plt.subplots()
438
439
        else:
440
441
            fig = ax.get_figure()
442
443
        if show_total:
444
445
            total_rate = self._current_observed_counts / self._exposure / self.bin_widths
446
            bkg_rate = self._current_background_counts / self._background_exposure /self.bin_widths
447
448
            total_errors = np.sqrt(total_rate)
449
450
            if self._background.is_poisson:
451
452
                bkg_errors = np.sqrt(bkg_rate)
453
454
            else:
455
456
                bkg_errors = self._current_background_count_errors / self.bin_widths
457
458
            ax.hlines(
459
                total_rate,
460
                sa_min,
461
                sa_max,
462
                color='#7D0505',
463
                **data_kwargs)
464
            ax.vlines(
465
                np.mean([self.scattering_boundaries],axis=1),
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
Loading history...
466
                total_rate - total_errors,
467
                total_rate + total_errors,
468
                color='#7D0505',
469
                **data_kwargs)
470
471
            ax.hlines(
472
                bkg_rate,
473
                sa_min,
474
                sa_max,
475
                color='#0D5BAE',
476
                **data_kwargs)
477
            ax.vlines(
478
                np.mean([self.scattering_boundaries],axis=1),
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
Loading history...
479
                bkg_rate - bkg_errors,
480
                bkg_rate + bkg_errors,
481
                color='#0D5BAE',
482
                **data_kwargs)
483
484
        if show_data:
485
486
            net_rate = (        self._observed_counts / self._exposure) - self._background_counts / self._background_exposure
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (125/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Coding Style introduced by
No space allowed after bracket
Loading history...
487
488
            if self._background.is_poisson:
489
490
                errors = np.sqrt((        self._observed_counts / self._exposure) +
0 ignored issues
show
Coding Style introduced by
No space allowed after bracket
Loading history...
491
                                 (self._background_counts / self._background_exposure))
492
493
            else:
494
495
                errors = np.sqrt((        self._observed_counts / self._exposure) +
0 ignored issues
show
Coding Style introduced by
No space allowed after bracket
Loading history...
496
                                 (self._background.count_errors / self._background_exposure)**2)
497
498
            ax.hlines(net_rate/self.bin_widths, self._response.scattering_bins_lo, self._response.scattering_bins_hi, **data_kwargs)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (132/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
499
            ax.vlines(self._response.scattering_bins, (net_rate - errors)/self.bin_widths, (net_rate + errors)/self.bin_widths, **data_kwargs)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (142/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
500
501
        if show_model:
502
            step_plot(
503
                ax=ax,
504
                xbins=np.vstack([self._response.scattering_bins_lo, self._response.scattering_bins_hi]).T,
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (106/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
505
                y=self._get_model_counts() / self._exposure /self.bin_widths,
506
                **model_kwargs)
507
508
        ax.set_xlabel('Scattering Angle')
509
        ax.set_ylabel('Net Rate (cnt/s/bin)')
510
511
        return fig
512
513
    @property
514
    def observation(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
515
        return self._observation
516
517
    @property
518
    def background(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
519
        return self._background
520
521
    @contextmanager
522
    def _without_rebinner(self):
523
524
        # Store rebinner for later use
525
526
        rebinner = self._rebinner
527
528
        # Clean mask and rebinning
529
530
        self.remove_rebinning()
531
        
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
532
533
        # Execute whathever
534
535
        yield
536
537
        # Restore mask and rebinner (if any)
538
539
540
541
        if rebinner is not None:
542
543
            # There was a rebinner, use it. Note that the rebinner applies the mask by itself
544
545
            self._apply_rebinner(rebinner)
546
547
548
549
550
            
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
551
    def rebin_on_background(self, min_number_of_counts):
552
        """
553
        Rebin the spectrum guaranteeing the provided minimum number of counts in each background bin. This is usually
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (117/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
554
        required for spectra with very few background counts to make the Poisson profile likelihood meaningful.
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (111/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
555
        Of course this is not relevant if you treat the background as ideal, nor if the background spectrum has
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (111/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
556
        Gaussian errors.
557
558
        The observed spectrum will be rebinned in the same fashion as the background spectrum.
559
560
        To neutralize this completely, use "remove_rebinning"
561
562
        :param min_number_of_counts: the minimum number of counts in each bin
563
        :return: none
564
        """
565
566
        # NOTE: the rebinner takes care of the mask already
567
568
        assert self._background is not None, "This data has no background, cannot rebin on background!"
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (103/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
569
570
        rebinner = Rebinner(self._background_counts, min_number_of_counts, mask = None)
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
Loading history...
571
572
        self._apply_rebinner(rebinner)
573
574
    def rebin_on_source(self, min_number_of_counts):
575
        """
576
        Rebin the spectrum guaranteeing the provided minimum number of counts in each source bin.
577
578
        To neutralize this completely, use "remove_rebinning"
579
580
        :param min_number_of_counts: the minimum number of counts in each bin
581
        :return: none
582
        """
583
584
        # NOTE: the rebinner takes care of the mask already
585
586
587
588
        rebinner = Rebinner(self._observed_counts, min_number_of_counts, self._mask)
589
590
        self._apply_rebinner(rebinner)
591
592
    def _apply_rebinner(self, rebinner):
593
594
        self._rebinner = rebinner
595
596
        # Apply the rebinning to everything.
597
        # NOTE: the output of the .rebin method are the vectors with the mask *already applied*
598
599
        self._current_observed_counts, = self._rebinner.rebin(self._observed_counts)
600
601
        if self._background is not None:
602
603
            self._current_background_counts, = self._rebinner.rebin(self._background_counts)
604
605
            if self._background_count_errors is not None:
606
                # NOTE: the output of the .rebin method are the vectors with the mask *already applied*
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (103/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
607
608
                self._current_background_count_errors, = self._rebinner.rebin_errors(self._background_count_errors)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (115/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
609
610
        if self._verbose:
611
            print("Now using %s bins" % self._rebinner.n_bins)
612
613
    def remove_rebinning(self):
614
        """
615
        Remove the rebinning scheme set with rebin_on_background.
616
617
        :return:
618
        """
619
620
        self._rebinner = None
621
622
        self._current_observed_counts = self._observed_counts
623
        self._current_background_counts = self._background_counts
624
        self._current_background_count_errors = self._background_count_errors
625