Passed
Push — master ( 20ef60...3972dc )
by Giacomo
10:31
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 os
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
import numpy as np
0 ignored issues
show
introduced by
Unable to import 'numpy'
Loading history...
3
import pandas as pd
0 ignored issues
show
introduced by
Unable to import 'pandas'
Loading history...
4
5
from threeML.io.rich_display import display
0 ignored issues
show
introduced by
Unable to import 'threeML.io.rich_display'
Loading history...
6
from threeML.io.file_utils import sanitize_filename
0 ignored issues
show
introduced by
Unable to import 'threeML.io.file_utils'
Loading history...
7
8
from ..serialize import Serialization
9
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...
10
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...
11
12
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...
13
14
15
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...
16
17
    # Sanitize files in input (expand variables and so on)
18
    map_tree_file = sanitize_filename(map_tree_file)
19
20
    if os.path.splitext(map_tree_file)[-1] == '.root':
0 ignored issues
show
unused-code introduced by
Unnecessary "else" after "return"
Loading history...
21
22
        return MapTree.from_root_file(map_tree_file, roi)
23
24
    else:
25
26
        return MapTree.from_hdf5(map_tree_file, roi)
27
28
29
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...
30
31
    def __init__(self, analysis_bins, roi):
32
33
        self._analysis_bins = analysis_bins
34
        self._roi = roi
35
36
    @classmethod
37
    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...
38
39
        data_analysis_bins = from_hdf5_file(map_tree_file, roi)
40
41
        return cls(data_analysis_bins, roi)
42
43
    @classmethod
44
    def from_root_file(cls, map_tree_file, roi):
45
        """
46
        Create a MapTree object from a ROOT file and a ROI. Do not use this directly, use map_tree_factory instead.
47
48
        :param map_tree_file:
49
        :param roi:
50
        :return:
51
        """
52
53
        data_analysis_bins = from_root_file(map_tree_file, roi)
54
55
        return cls(data_analysis_bins, roi)
56
57
    def __iter__(self):
58
        """
59
        This allows to loop over the analysis bins as in:
60
61
        for analysis_bin in maptree:
62
63
            ... do something ...
64
65
        :return: analysis bin_name iterator
66
        """
67
68
        for analysis_bin in self._analysis_bins:
69
70
            yield analysis_bin
71
72
    def __getitem__(self, item):
73
        """
74
        This allows to access the analysis bins by name:
75
76
        first_analysis_bin = maptree["bin_name 0"]
77
78
        :param item: string for access by name
79
        :return: the analysis bin_name
80
        """
81
82
        try:
83
84
            return self._analysis_bins[item]
85
86
        except IndexError:
87
88
            raise IndexError("Analysis bin_name with index %i does not exist" % (item))
89
90
    def __len__(self):
91
92
        return len(self._analysis_bins)
93
94
    @property
95
    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...
96
97
        return self._analysis_bins.keys()
98
99
    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...
100
101
        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...
102
103
        df['Bin'] = self._analysis_bins.keys()
104
        df['Nside'] = [self._analysis_bins[bin_id].nside for bin_id in self._analysis_bins]
105
        df['Scheme'] = [self._analysis_bins[bin_id].scheme for bin_id in self._analysis_bins]
106
107
        # Compute observed counts, background counts, how many pixels we have in the ROI and
108
        # the sky area they cover
109
        n_bins = len(self._analysis_bins)
110
111
        obs_counts = np.zeros(n_bins)
112
        bkg_counts = np.zeros_like(obs_counts)
113
        n_pixels = np.zeros(n_bins, dtype=int)
114
        sky_area = np.zeros_like(obs_counts)
115
116
        size = 0
117
118
        for i, bin_id in enumerate(self._analysis_bins):
119
120
            analysis_bin = self._analysis_bins[bin_id]
121
122
            sparse_obs = analysis_bin.observation_map.as_partial()
123
            sparse_bkg = analysis_bin.background_map.as_partial()
124
125
            size += sparse_obs.nbytes
126
            size += sparse_bkg.nbytes
127
128
            obs_counts[i] = sparse_obs.sum()
129
            bkg_counts[i] = sparse_bkg.sum()
130
            n_pixels[i] = sparse_obs.shape[0]
131
            sky_area[i] = n_pixels[i] * analysis_bin.observation_map.pixel_area
132
133
        df['Obs counts'] = obs_counts
134
        df['Bkg counts'] = bkg_counts
135
        df['obs/bkg'] = obs_counts / bkg_counts
136
        df['Pixels in ROI'] = n_pixels
137
        df['Area (deg^2)'] = sky_area
138
139
        display(df)
140
141
        first_bin_id = self._analysis_bins.keys()[0]
142
        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...
143
            % self._analysis_bins[first_bin_id].n_transits)
144
        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...
145
146
    def write(self, filename):
147
        """
148
        Export the tree to a HDF5 file.
149
150
        NOTE: if an ROI has been applied, only the data within the ROI will be saved.
151
152
        :param filename: output filename. Use an extension .hd5 or .hdf5 to ensure proper handling by downstream
153
        software
154
        :return: None
155
        """
156
157
        # Make a dataframe with the ordered list of bin names
158
        # bin_names = map(lambda x:x.name, self._analysis_bins)
159
160
        # Create a dataframe with a multi-index, with the energy bin name as first level and the HEALPIX pixel ID
161
        # as the second level
162
        multi_index_keys = []
163
        dfs = []
164
        all_metas = []
165
166
        for bin_id in self._analysis_bins:
167
168
            analysis_bin = self._analysis_bins[bin_id]
169
170
            assert bin_id == analysis_bin.name, \
171
                'Bin name inconsistency: {} != {}'.format(bin_id, analysis_bin.name)
172
173
            multi_index_keys.append(analysis_bin.name)
174
175
            this_df, this_meta = analysis_bin.to_pandas()
176
177
            dfs.append(this_df)
178
            all_metas.append(pd.Series(this_meta))
179
180
        analysis_bins_df = pd.concat(dfs, axis=0, keys=multi_index_keys)
181
        meta_df = pd.concat(all_metas, axis=1, keys=multi_index_keys).T
182
183
        with Serialization(filename, mode='w') as serializer:
184
185
            serializer.store_pandas_object('/analysis_bins', analysis_bins_df)
186
            serializer.store_pandas_object('/analysis_bins_meta', meta_df)
187
188
            # Write the ROI
189
            if self._roi is not None:
190
191
                serializer.store_pandas_object('/ROI', pd.Series(), **self._roi.to_dict())
192
193
            else:
194
195
                serializer.store_pandas_object('/ROI', pd.Series())
196