comparison light_curve.py @ 0:2b1759ccaa8b draft default tip

planemo upload for repository https://github.com/esg-epfl-apc/tools-astro/tree/main/tools commit f28a8cb73a7f3053eac92166867a48b3d4af28fd
author astroteam
date Fri, 25 Apr 2025 21:48:27 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:2b1759ccaa8b
1 #!/usr/bin/env python
2 # coding: utf-8
3
4 #!/usr/bin/env python
5
6 # This script is generated with nb2galaxy
7
8 # flake8: noqa
9
10 import json
11 import os
12 import shutil
13
14 from oda_api.json import CustomJSONEncoder
15
16 fn = "data.tsv" # oda:POSIXPath
17 skiprows = 0 # http://odahub.io/ontology#Integer
18 sep = "whitespace" # http://odahub.io/ontology#String ; oda:allowed_value "comma", "tab", "space", "whitespace", "semicolon"
19 column = "T" # http://odahub.io/ontology#String
20 weight_col = "" # http://odahub.io/ontology#String
21 binning = "logarithmic" # http://odahub.io/ontology#String ; oda:allowed_value "linear","logarithmic"
22 minval = 0 # http://odahub.io/ontology#Float
23 maxval = 0 # http://odahub.io/ontology#Float
24 use_quantile_values = False # http://odahub.io/ontology#Boolean
25 nbins = 15 # http://odahub.io/ontology#Integer
26 xlabel = "time, s" # http://odahub.io/ontology#String
27 ylabel = "Ncounts" # http://odahub.io/ontology#String
28 plot_mode = "flux" # http://odahub.io/ontology#String ; oda:allowed_value "counts", "flux"
29
30 _galaxy_wd = os.getcwd()
31
32 with open("inputs.json", "r") as fd:
33 inp_dic = json.load(fd)
34 if "C_data_product_" in inp_dic.keys():
35 inp_pdic = inp_dic["C_data_product_"]
36 else:
37 inp_pdic = inp_dic
38 fn = str(inp_pdic["fn"])
39 skiprows = int(inp_pdic["skiprows"])
40 sep = str(inp_pdic["sep"])
41 column = str(inp_pdic["column"])
42 weight_col = str(inp_pdic["weight_col"])
43 binning = str(inp_pdic["binning"])
44 minval = float(inp_pdic["minval"])
45 maxval = float(inp_pdic["maxval"])
46 use_quantile_values = bool(inp_pdic["use_quantile_values"])
47 nbins = int(inp_pdic["nbins"])
48 xlabel = str(inp_pdic["xlabel"])
49 ylabel = str(inp_pdic["ylabel"])
50 plot_mode = str(inp_pdic["plot_mode"])
51
52 import matplotlib.pyplot as plt
53 import numpy as np
54 import pandas as pd
55
56 if plot_mode != "counts" and ylabel == "Ncounts":
57 ylabel = plot_mode # replace default value
58
59 assert minval >= 0 or not use_quantile_values
60 assert maxval >= 0 or not use_quantile_values
61 assert minval <= 1 or not use_quantile_values
62 assert maxval <= 1 or not use_quantile_values
63 assert minval < maxval or minval == 0 or maxval == 0
64
65 separators = {
66 "tab": "\t",
67 "comma": ",",
68 "semicolon": ";",
69 "whitespace": "\s+",
70 "space": " ",
71 }
72
73 df = None
74
75 if sep == "auto":
76 for name, s in separators.items():
77 try:
78 df = pd.read_csv(fn, sep=s, index_col=False, skiprows=skiprows)
79 if len(df.columns) > 2:
80 sep = s
81 print("Detected separator: ", name)
82 break
83 except Exception as e:
84 print("Separator ", s, " failed", e)
85 assert sep != "auto", "Failed to find valid separator"
86
87 if df is None:
88 df = pd.read_csv(fn, sep=separators[sep], index_col=False)
89
90 df.columns
91
92 def weighted_quantile(
93 values, quantiles, sample_weight=None, values_sorted=False, old_style=False
94 ):
95 """Very close to numpy.percentile, but supports weights.
96 NOTE: quantiles should be in [0, 1]!
97 :param values: numpy.array with data
98 :param quantiles: array-like with many quantiles needed
99 :param sample_weight: array-like of the same length as `array`
100 :param values_sorted: bool, if True, then will avoid sorting of initial array
101 :param old_style: if True, will correct output to be consistent with numpy.percentile.
102 :return: numpy.array with computed quantiles.
103 """
104 values = np.array(values)
105 quantiles = np.array(quantiles)
106 if sample_weight is None:
107 sample_weight = np.ones(len(values))
108 sample_weight = np.array(sample_weight)
109 assert np.all(quantiles >= 0) and np.all(
110 quantiles <= 1
111 ), "quantiles should be in [0, 1]"
112
113 if not values_sorted:
114 sorter = np.argsort(values)
115 values = values[sorter]
116 sample_weight = sample_weight[sorter]
117
118 weighted_quantiles = np.cumsum(sample_weight) - 0.5 * sample_weight
119 if old_style:
120 # To be convenient with np.percentile
121 weighted_quantiles -= weighted_quantiles[0]
122 weighted_quantiles /= weighted_quantiles[-1]
123 else:
124 weighted_quantiles /= np.sum(sample_weight)
125 return np.interp(quantiles, weighted_quantiles, values)
126
127 def read_data(df, colname, optional=False):
128 for i, c in enumerate(df.columns):
129 if colname == f"c{i+1}":
130 print(colname, c)
131 return df[c].values
132 elif colname == c:
133 print(colname, c)
134 return df[c].values
135
136 assert optional, colname + " column not found"
137 return None
138
139 delays = read_data(df, column)
140 weights = read_data(df, weight_col, optional=True)
141 if weights is None:
142 weights = np.ones_like(delays)
143
144 if binning != "linear":
145 min_positive_val = np.min(delays[delays > 0])
146 delays[delays <= 0] = (
147 min_positive_val # replace zero delays with minimal positive value
148 )
149
150 if use_quantile_values:
151 minval, maxval = weighted_quantile(
152 delays, [minval, maxval], sample_weight=weights
153 )
154 if minval == maxval:
155 print("ignoreing minval and maxval (empty range)")
156 minval = np.min(delays)
157 maxval = np.max(delays)
158 else:
159 if minval == 0:
160 minval = np.min(delays)
161 if maxval == 0:
162 maxval = np.max(delays)
163
164 if minval == maxval:
165 print("correcting minval and maxval (empty range)")
166 maxval = minval * 1.1 if minval > 0 else 1e-100
167
168 from numpy import log10
169
170 if binning == "linear":
171 bins = np.linspace(minval, maxval, nbins + 1)
172 else:
173 bins = np.logspace(log10(minval), log10(maxval), nbins + 1)
174 bins
175
176 if plot_mode == "flux" and binning == "logarithmic":
177 weights = weights / delays
178
179 plt.figure()
180 h = plt.hist(delays, weights=weights, bins=bins)
181
182 if binning == "logarithmic":
183 plt.xscale("log")
184 plt.yscale("log")
185 plt.xlabel(xlabel)
186 plt.ylabel(ylabel)
187 plt.savefig("Histogram.png", format="png", dpi=150)
188 hist_counts = h[0]
189 hist_bins = h[1]
190 hist_mins = hist_bins[:-1]
191 hist_maxs = hist_bins[1:]
192
193 from astropy.table import Table
194 from oda_api.data_products import ODAAstropyTable, PictureProduct
195
196 names = ("bins_min", "bins_max", "counts")
197 res = ODAAstropyTable(Table([hist_mins, hist_maxs, hist_counts], names=names))
198
199 plot = PictureProduct.from_file("Histogram.png")
200
201 histogram_data = res # http://odahub.io/ontology#ODAAstropyTable
202 histogram_picture = plot # http://odahub.io/ontology#ODAPictureProduct
203
204 # output gathering
205 _galaxy_meta_data = {}
206 _oda_outs = []
207 _oda_outs.append(
208 (
209 "out_light_curve_histogram_data",
210 "histogram_data_galaxy.output",
211 histogram_data,
212 )
213 )
214 _oda_outs.append(
215 (
216 "out_light_curve_histogram_picture",
217 "histogram_picture_galaxy.output",
218 histogram_picture,
219 )
220 )
221
222 for _outn, _outfn, _outv in _oda_outs:
223 _galaxy_outfile_name = os.path.join(_galaxy_wd, _outfn)
224 if isinstance(_outv, str) and os.path.isfile(_outv):
225 shutil.move(_outv, _galaxy_outfile_name)
226 _galaxy_meta_data[_outn] = {"ext": "_sniff_"}
227 elif getattr(_outv, "write_fits_file", None):
228 _outv.write_fits_file(_galaxy_outfile_name)
229 _galaxy_meta_data[_outn] = {"ext": "fits"}
230 elif getattr(_outv, "write_file", None):
231 _outv.write_file(_galaxy_outfile_name)
232 _galaxy_meta_data[_outn] = {"ext": "_sniff_"}
233 else:
234 with open(_galaxy_outfile_name, "w") as fd:
235 json.dump(_outv, fd, cls=CustomJSONEncoder)
236 _galaxy_meta_data[_outn] = {"ext": "json"}
237
238 with open(os.path.join(_galaxy_wd, "galaxy.json"), "w") as fd:
239 json.dump(_galaxy_meta_data, fd)
240 print("*** Job finished successfully ***")