Passed
Pull Request — master (#4)
by
unknown
11:38
created

hawc_hal.maptree.map_tree.MapTree.write()   B

Complexity

Conditions 5

Size

Total Lines 50
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 20
dl 0
loc 50
rs 8.9332
c 0
b 0
f 0
cc 5
nop 2
1
import numpy as np
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...
introduced by
Unable to import 'numpy'
Loading history...
2
import pandas as pd
0 ignored issues
show
introduced by
Unable to import 'pandas'
Loading history...
3
import six
0 ignored issues
show
introduced by
third party import "import six" should be placed before "import numpy as np"
Loading history...
Unused Code introduced by
The import six seems to be unused.
Loading history...
4
import os
0 ignored issues
show
introduced by
standard import "import os" should be placed before "import six"
Loading history...
5
import collections
0 ignored issues
show
Unused Code introduced by
The import collections seems to be unused.
Loading history...
introduced by
standard import "import collections" should be placed before "import six"
Loading history...
6
7
from threeML.io.rich_display import display
0 ignored issues
show
introduced by
Unable to import 'threeML.io.rich_display'
Loading history...
8
from threeML.io.file_utils import sanitize_filename
0 ignored issues
show
introduced by
Unable to import 'threeML.io.file_utils'
Loading history...
9
10
from ..serialize import Serialization
11
from from_root_file import from_root_file
0 ignored issues
show
Coding Style introduced by
Relative import 'from_root_file', should be 'hawc_hal.maptree.from_root_file'
Loading history...
introduced by
first party import "from from_root_file import from_root_file" should be placed before "from ..serialize import Serialization"
Loading history...
12
from from_hdf5_file import from_hdf5_file
0 ignored issues
show
Coding Style introduced by
Relative import 'from_hdf5_file', should be 'hawc_hal.maptree.from_hdf5_file'
Loading history...
introduced by
first party import "from from_hdf5_file import from_hdf5_file" should be placed before "from ..serialize import Serialization"
Loading history...
13
14
import astropy.units as u
0 ignored issues
show
introduced by
Unable to import 'astropy.units'
Loading history...
introduced by
first party import "import astropy.units as u" should be placed before "from ..serialize import Serialization"
Loading history...
15
16
17
def map_tree_factory(map_tree_file, roi):
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...
18
19
    # Sanitize files in input (expand variables and so on)
20
    map_tree_file = sanitize_filename(map_tree_file)
21
22
    if os.path.splitext(map_tree_file)[-1] == '.root':
0 ignored issues
show
unused-code introduced by
Unnecessary "else" after "return"
Loading history...
23
24
        return MapTree.from_root_file(map_tree_file, roi)
25
26
    else:
27
28
        return MapTree.from_hdf5(map_tree_file, roi)
29
30
31
class MapTree(object):
0 ignored issues
show
Coding Style introduced by
This class 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...
32
33
    def __init__(self, analysis_bins, roi):
34
35
        self._analysis_bins = analysis_bins
36
        self._roi = roi
37
38
    @classmethod
39
    def from_hdf5(cls, map_tree_file, roi):
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...
40
41
        data_analysis_bins = from_hdf5_file(map_tree_file, roi)
42
43
        return cls(data_analysis_bins, roi)
44
45
    @classmethod
46
    def from_root_file(cls, map_tree_file, roi):
47
        """
48
        Create a MapTree object from a ROOT file and a ROI. Do not use this directly, use map_tree_factory instead.
49
50
        :param map_tree_file:
51
        :param roi:
52
        :return:
53
        """
54
55
        data_analysis_bins = from_root_file(map_tree_file, roi)
56
57
        return cls(data_analysis_bins, roi)
58
59
    def __iter__(self):
60
        """
61
        This allows to loop over the analysis bins as in:
62
63
        for analysis_bin in maptree:
64
65
            ... do something ...
66
67
        :return: analysis bin_name iterator
68
        """
69
70
        for analysis_bin in self._analysis_bins:
71
72
            yield analysis_bin
73
74
    def __getitem__(self, item):
75
        """
76
        This allows to access the analysis bins by name:
77
78
        first_analysis_bin = maptree["bin_name 0"]
79
80
        :param item: string for access by name
81
        :return: the analysis bin_name
82
        """
83
84
        try:
85
86
            return self._analysis_bins[item]
87
88
        except IndexError:
89
90
            raise IndexError("Analysis bin_name with index %i does not exist" % (item))
91
92
    def __len__(self):
93
94
        return len(self._analysis_bins)
95
96
    @property
97
    def analysis_bins_labels(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...
98
99
        return self._analysis_bins.keys()
100
101
    def display(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...
102
103
        df = pd.DataFrame()
0 ignored issues
show
Coding Style Naming introduced by
Variable name "df" doesn't conform to snake_case naming style ('(([a-z_][a-z0-9_]2,30)|(_[a-z0-9_]*)|(__[a-z][a-z0-9_]+__))$' pattern)

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...
104
105
        df['Bin'] = self._analysis_bins.keys()
106
        df['Nside'] = [self._analysis_bins[bin_id].nside for bin_id in self._analysis_bins]
107
        df['Scheme'] = [self._analysis_bins[bin_id].scheme for bin_id in self._analysis_bins]
108
109
        # Compute observed counts, background counts, how many pixels we have in the ROI and
110
        # the sky area they cover
111
        n_bins = len(self._analysis_bins)
112
113
        obs_counts = np.zeros(n_bins)
114
        bkg_counts = np.zeros_like(obs_counts)
115
        n_pixels = np.zeros(n_bins, dtype=int)
116
        sky_area = np.zeros_like(obs_counts)
117
118
        size = 0
119
120
        for i, bin_id in enumerate(self._analysis_bins):
121
122
            analysis_bin = self._analysis_bins[bin_id]
123
124
            sparse_obs = analysis_bin.observation_map.as_partial()
125
            sparse_bkg = analysis_bin.background_map.as_partial()
126
127
            size += sparse_obs.nbytes
128
            size += sparse_bkg.nbytes
129
130
            obs_counts[i] = sparse_obs.sum()
131
            bkg_counts[i] = sparse_bkg.sum()
132
            n_pixels[i] = sparse_obs.shape[0]
133
            sky_area[i] = n_pixels[i] * analysis_bin.observation_map.pixel_area
134
135
        df['Obs counts'] = obs_counts
136
        df['Bkg counts'] = bkg_counts
137
        df['obs/bkg'] = obs_counts / bkg_counts
138
        df['Pixels in ROI'] = n_pixels
139
        df['Area (deg^2)'] = sky_area
140
141
        display(df)
142
143
        first_bin_id = self._analysis_bins.keys()[0]
144
        print("This Map Tree contains %.3f transits in the first bin" \
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
145
            % self._analysis_bins[first_bin_id].n_transits)
146
        print("Total data size: %.2f Mb" % (size * u.byte).to(u.megabyte).value)
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
147
148
    def write(self, filename):
149
        """
150
        Export the tree to a HDF5 file.
151
152
        NOTE: if an ROI has been applied, only the data within the ROI will be saved.
153
154
        :param filename: output filename. Use an extension .hd5 or .hdf5 to ensure proper handling by downstream
155
        software
156
        :return: None
157
        """
158
159
        # Make a dataframe with the ordered list of bin names
160
        # bin_names = map(lambda x:x.name, self._analysis_bins)
161
162
        # Create a dataframe with a multi-index, with the energy bin name as first level and the HEALPIX pixel ID
163
        # as the second level
164
        multi_index_keys = []
165
        dfs = []
166
        all_metas = []
167
168
        for bin_id in self._analysis_bins:
169
170
            analysis_bin = self._analysis_bins[bin_id]
171
172
            assert bin_id == analysis_bin.name, \
173
                'Bin name inconsistency: {} != {}'.format(bin_id, analysis_bin.name)
174
175
            multi_index_keys.append(analysis_bin.name)
176
177
            this_df, this_meta = analysis_bin.to_pandas()
178
179
            dfs.append(this_df)
180
            all_metas.append(pd.Series(this_meta))
181
182
        analysis_bins_df = pd.concat(dfs, axis=0, keys=multi_index_keys)
183
        meta_df = pd.concat(all_metas, axis=1, keys=multi_index_keys).T
184
185
        with Serialization(filename, mode='w') as serializer:
186
187
            serializer.store_pandas_object('/analysis_bins', analysis_bins_df)
188
            serializer.store_pandas_object('/analysis_bins_meta', meta_df)
189
190
            # Write the ROI
191
            if self._roi is not None:
192
193
                serializer.store_pandas_object('/ROI', pd.Series(), **self._roi.to_dict())
194
195
            else:
196
197
                serializer.store_pandas_object('/ROI', pd.Series())
198