isgri 0.5.1__py3-none-any.whl → 0.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- isgri/__version__.py +1 -1
- isgri/catalog/scwquery.py +42 -0
- isgri/cli/__init__.py +1 -0
- isgri/{cli.py → cli/main.py} +168 -224
- isgri/cli/query.py +172 -0
- {isgri-0.5.1.dist-info → isgri-0.6.0.dist-info}/METADATA +5 -25
- {isgri-0.5.1.dist-info → isgri-0.6.0.dist-info}/RECORD +10 -8
- isgri-0.6.0.dist-info/entry_points.txt +2 -0
- isgri-0.5.1.dist-info/entry_points.txt +0 -2
- {isgri-0.5.1.dist-info → isgri-0.6.0.dist-info}/WHEEL +0 -0
- {isgri-0.5.1.dist-info → isgri-0.6.0.dist-info}/licenses/LICENSE +0 -0
isgri/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.6.0"
|
isgri/catalog/scwquery.py
CHANGED
|
@@ -344,6 +344,48 @@ class ScwQuery:
|
|
|
344
344
|
combined_mask &= filt.mask
|
|
345
345
|
return self.catalog[combined_mask]
|
|
346
346
|
|
|
347
|
+
def write(
|
|
348
|
+
self, output_path: Union[str, Path], swid_only: Optional[str] = False, overwrite: Optional[bool] = False
|
|
349
|
+
):
|
|
350
|
+
"""Write filtered catalog to the file.
|
|
351
|
+
|
|
352
|
+
Parameters
|
|
353
|
+
----------
|
|
354
|
+
output_path : str or Path
|
|
355
|
+
Path to output file. Format auto-detected from extension:
|
|
356
|
+
- .txt: SWID list (one per line)
|
|
357
|
+
- .fits: FITS table
|
|
358
|
+
- .csv: CSV table
|
|
359
|
+
swid_only : bool, optional
|
|
360
|
+
If True, write only SWID list regardless of extension
|
|
361
|
+
overwrite : bool, optional
|
|
362
|
+
Whether to overwrite existing file, by default False
|
|
363
|
+
|
|
364
|
+
Raises
|
|
365
|
+
------
|
|
366
|
+
FileExistsError
|
|
367
|
+
If file exists and overwrite=False
|
|
368
|
+
|
|
369
|
+
Examples
|
|
370
|
+
--------
|
|
371
|
+
>>> query.time(tstart=3000).write("filtered_scws.fits", overwrite=True)
|
|
372
|
+
>>> query.quality(max_chi=2.0).write("good_scws.txt", swid_only=True)
|
|
373
|
+
>>> query.write("scws.csv")
|
|
374
|
+
>>> query.write("output", swid_only=True) # Force SWID list regardless of extension
|
|
375
|
+
"""
|
|
376
|
+
|
|
377
|
+
results = self.get()
|
|
378
|
+
if isinstance(output_path, str):
|
|
379
|
+
output_path = Path(output_path)
|
|
380
|
+
if output_path.exists() and not overwrite:
|
|
381
|
+
raise FileExistsError(f"Output file already exists: {output_path}")
|
|
382
|
+
if swid_only or output_path.suffix == ".txt":
|
|
383
|
+
with open(output_path, "w") as f:
|
|
384
|
+
for swid in results["SWID"]:
|
|
385
|
+
f.write(f"{swid}\n")
|
|
386
|
+
else:
|
|
387
|
+
results.write(output_path, overwrite=overwrite)
|
|
388
|
+
|
|
347
389
|
def count(self) -> int:
|
|
348
390
|
"""
|
|
349
391
|
Count SCWs matching current filters.
|
isgri/cli/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .main import main
|
isgri/{cli.py → cli/main.py}
RENAMED
|
@@ -1,224 +1,168 @@
|
|
|
1
|
-
import click
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@click.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
@main.command()
|
|
171
|
-
@click.option("--archive", type=click.Path(), help="INTEGRAL archive directory path")
|
|
172
|
-
@click.option("--catalog", type=click.Path(), help="Catalog FITS file path")
|
|
173
|
-
def config_set(archive, catalog):
|
|
174
|
-
"""
|
|
175
|
-
Set configuration values.
|
|
176
|
-
|
|
177
|
-
Set default paths for archive directory and/or catalog file.
|
|
178
|
-
Paths are expanded (~ becomes home directory) and resolved to absolute paths.
|
|
179
|
-
Warns if path doesn't exist but allows setting anyway.
|
|
180
|
-
|
|
181
|
-
Examples:
|
|
182
|
-
|
|
183
|
-
Set archive path:
|
|
184
|
-
|
|
185
|
-
isgri config-set --archive /anita/archivio/
|
|
186
|
-
|
|
187
|
-
Set catalog path:
|
|
188
|
-
|
|
189
|
-
isgri config-set --catalog ~/data/scw_catalog.fits
|
|
190
|
-
|
|
191
|
-
Set both at once:
|
|
192
|
-
|
|
193
|
-
isgri config-set --archive /anita/archivio/ --catalog ~/data/scw_catalog.fits
|
|
194
|
-
"""
|
|
195
|
-
if not archive and not catalog:
|
|
196
|
-
click.echo("Error: Specify at least one option (--archive or --catalog)", err=True)
|
|
197
|
-
raise click.Abort()
|
|
198
|
-
|
|
199
|
-
cfg = Config()
|
|
200
|
-
|
|
201
|
-
if archive:
|
|
202
|
-
archive_path = Path(archive).expanduser().resolve()
|
|
203
|
-
if not archive_path.exists():
|
|
204
|
-
click.echo(f"Warning: Archive path does not exist: {archive_path}", err=True)
|
|
205
|
-
if not click.confirm("Set anyway?"):
|
|
206
|
-
raise click.Abort()
|
|
207
|
-
cfg.set(archive_path=archive_path)
|
|
208
|
-
click.echo(f"✓ Archive path set to: {archive_path}")
|
|
209
|
-
|
|
210
|
-
if catalog:
|
|
211
|
-
catalog_path = Path(catalog).expanduser().resolve()
|
|
212
|
-
if not catalog_path.exists():
|
|
213
|
-
click.echo(f"Warning: Catalog file does not exist: {catalog_path}", err=True)
|
|
214
|
-
if not click.confirm("Set anyway?"):
|
|
215
|
-
raise click.Abort()
|
|
216
|
-
cfg.set(catalog_path=catalog_path)
|
|
217
|
-
click.echo(f"✓ Catalog path set to: {catalog_path}")
|
|
218
|
-
|
|
219
|
-
click.echo()
|
|
220
|
-
click.echo(f"Configuration saved to: {cfg.path}")
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if __name__ == "__main__":
|
|
224
|
-
main()
|
|
1
|
+
import click
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from ..catalog import ScwQuery
|
|
4
|
+
from ..__version__ import __version__
|
|
5
|
+
from ..config import Config
|
|
6
|
+
from .query import query_direct, query_interactive
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.group()
|
|
10
|
+
@click.version_option(version=__version__)
|
|
11
|
+
def main():
|
|
12
|
+
"""ISGRI - INTEGRAL/ISGRI data analysis toolkit."""
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@main.command()
|
|
17
|
+
@click.option("--catalog", type=click.Path(), help="Path to catalog FITS file. If not provided, uses config value.")
|
|
18
|
+
@click.option("--tstart", help="Start time (YYYY-MM-DD or IJD)")
|
|
19
|
+
@click.option("--tstop", help="Stop time (YYYY-MM-DD or IJD)")
|
|
20
|
+
@click.option("--ra", help="Right ascension (degrees or HH:MM:SS)")
|
|
21
|
+
@click.option("--dec", help="Declination (degrees or DD:MM:SS)")
|
|
22
|
+
@click.option("--radius", type=float, help="Angular separation (degrees)")
|
|
23
|
+
@click.option("--fov", type=click.Choice(["full", "any"]), default="any", help="Field of view mode")
|
|
24
|
+
@click.option("--max-chi", type=float, help="Maximum chi-squared value")
|
|
25
|
+
@click.option("--chi-type", type=click.Choice(["RAW", "CUT", "GTI"]), default="CUT", help="Type of chi-squared value")
|
|
26
|
+
@click.option("--revolution", help="Revolution number")
|
|
27
|
+
@click.option(
|
|
28
|
+
"--output", "-o", type=click.Path(), help="Output file (.fits or .csv or any if --list-swids or --count)"
|
|
29
|
+
)
|
|
30
|
+
@click.option("--list-swids", is_flag=True, help="Only output SWID list")
|
|
31
|
+
@click.option("--count", is_flag=True, help="Only show count")
|
|
32
|
+
def query(catalog, tstart, tstop, ra, dec, radius, fov, max_chi, chi_type, revolution, output, list_swids, count):
|
|
33
|
+
"""
|
|
34
|
+
Query INTEGRAL science window catalog.
|
|
35
|
+
|
|
36
|
+
If no catalog path is provided, uses the default from configuration.
|
|
37
|
+
Multiple filters can be combined.
|
|
38
|
+
|
|
39
|
+
Examples:
|
|
40
|
+
Query by time range (IJD):
|
|
41
|
+
|
|
42
|
+
isgri query --tstart 3000 --tstop 3100
|
|
43
|
+
|
|
44
|
+
Query by time range (ISO date):
|
|
45
|
+
|
|
46
|
+
isgri query --tstart 2010-01-01 --tstop 2010-12-31
|
|
47
|
+
|
|
48
|
+
Query by sky position:
|
|
49
|
+
|
|
50
|
+
isgri query --ra 83.63 --dec 22.01 --fov full
|
|
51
|
+
isgri query --ra 83.63 --dec 22.01 --radius 5.0
|
|
52
|
+
|
|
53
|
+
Query with quality cut:
|
|
54
|
+
|
|
55
|
+
isgri query --max-chi 2.0 --chi-type CUT
|
|
56
|
+
|
|
57
|
+
Save results to file:
|
|
58
|
+
|
|
59
|
+
isgri query --tstart 3000 --tstop 3100 --output results.fits
|
|
60
|
+
|
|
61
|
+
Get only SWID list:
|
|
62
|
+
|
|
63
|
+
isgri query --tstart 3000 --tstop 3100 --list-swids
|
|
64
|
+
|
|
65
|
+
Count matching science windows:
|
|
66
|
+
|
|
67
|
+
isgri query --ra 83.63 --dec 22.01 --count
|
|
68
|
+
"""
|
|
69
|
+
if catalog is None:
|
|
70
|
+
cfg = Config()
|
|
71
|
+
catalog = cfg.catalog_path
|
|
72
|
+
|
|
73
|
+
if not catalog:
|
|
74
|
+
click.echo("Error: No catalog configured", err=True)
|
|
75
|
+
raise click.Abort()
|
|
76
|
+
|
|
77
|
+
if any(param is not None for param in [tstart, tstop, ra, dec, radius, max_chi, revolution]):
|
|
78
|
+
query_direct(
|
|
79
|
+
catalog, tstart, tstop, ra, dec, radius, fov, max_chi, chi_type, revolution, output, list_swids, count
|
|
80
|
+
)
|
|
81
|
+
else:
|
|
82
|
+
query_interactive(catalog)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@main.command()
|
|
86
|
+
def config():
|
|
87
|
+
"""
|
|
88
|
+
Show current configuration.
|
|
89
|
+
|
|
90
|
+
Displays paths to config file, archive directory, and catalog file,
|
|
91
|
+
along with their existence status.
|
|
92
|
+
"""
|
|
93
|
+
cfg = Config()
|
|
94
|
+
|
|
95
|
+
click.echo(f"Config file: {cfg.path}")
|
|
96
|
+
click.echo(f" Exists: {cfg.path.exists()}")
|
|
97
|
+
click.echo()
|
|
98
|
+
|
|
99
|
+
archive = cfg.archive_path
|
|
100
|
+
click.echo(f"Archive path: {archive if archive else '(not set)'}")
|
|
101
|
+
if archive:
|
|
102
|
+
click.echo(f" Exists: {archive.exists()}")
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
catalog = cfg.catalog_path
|
|
106
|
+
click.echo(f"Catalog path: {catalog if catalog else '(not set)'}")
|
|
107
|
+
if catalog:
|
|
108
|
+
click.echo(f" Exists: {catalog.exists()}")
|
|
109
|
+
except FileNotFoundError as e:
|
|
110
|
+
click.echo(f"Catalog path: (configured but file not found)")
|
|
111
|
+
click.echo(f" Error: {e}")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@main.command()
|
|
115
|
+
@click.option("--archive", type=click.Path(), help="INTEGRAL archive directory path")
|
|
116
|
+
@click.option("--catalog", type=click.Path(), help="Catalog FITS file path")
|
|
117
|
+
def config_set(archive, catalog):
|
|
118
|
+
"""
|
|
119
|
+
Set configuration values.
|
|
120
|
+
|
|
121
|
+
Set default paths for archive directory and/or catalog file.
|
|
122
|
+
Paths are expanded (~ becomes home directory) and resolved to absolute paths.
|
|
123
|
+
Warns if path doesn't exist but allows setting anyway.
|
|
124
|
+
|
|
125
|
+
Examples:
|
|
126
|
+
|
|
127
|
+
Set archive path:
|
|
128
|
+
|
|
129
|
+
isgri config-set --archive /anita/archivio/
|
|
130
|
+
|
|
131
|
+
Set catalog path:
|
|
132
|
+
|
|
133
|
+
isgri config-set --catalog ~/data/scw_catalog.fits
|
|
134
|
+
|
|
135
|
+
Set both at once:
|
|
136
|
+
|
|
137
|
+
isgri config-set --archive /anita/archivio/ --catalog ~/data/scw_catalog.fits
|
|
138
|
+
"""
|
|
139
|
+
if not archive and not catalog:
|
|
140
|
+
click.echo("Error: Specify at least one option (--archive or --catalog)", err=True)
|
|
141
|
+
raise click.Abort()
|
|
142
|
+
|
|
143
|
+
cfg = Config()
|
|
144
|
+
|
|
145
|
+
if archive:
|
|
146
|
+
archive_path = Path(archive).expanduser().resolve()
|
|
147
|
+
if not archive_path.exists():
|
|
148
|
+
click.echo(f"Warning: Archive path does not exist: {archive_path}", err=True)
|
|
149
|
+
if not click.confirm("Set anyway?"):
|
|
150
|
+
raise click.Abort()
|
|
151
|
+
cfg.set(archive_path=archive_path)
|
|
152
|
+
click.echo(f"✓ Archive path set to: {archive_path}")
|
|
153
|
+
|
|
154
|
+
if catalog:
|
|
155
|
+
catalog_path = Path(catalog).expanduser().resolve()
|
|
156
|
+
if not catalog_path.exists():
|
|
157
|
+
click.echo(f"Warning: Catalog file does not exist: {catalog_path}", err=True)
|
|
158
|
+
if not click.confirm("Set anyway?"):
|
|
159
|
+
raise click.Abort()
|
|
160
|
+
cfg.set(catalog_path=catalog_path)
|
|
161
|
+
click.echo(f"✓ Catalog path set to: {catalog_path}")
|
|
162
|
+
|
|
163
|
+
click.echo()
|
|
164
|
+
click.echo(f"Configuration saved to: {cfg.path}")
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
if __name__ == "__main__":
|
|
168
|
+
main()
|
isgri/cli/query.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from ..catalog import ScwQuery
|
|
4
|
+
from ..config import Config
|
|
5
|
+
from ..__version__ import __version__
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def parse_time(time_str):
|
|
9
|
+
"""
|
|
10
|
+
Parse time string as IJD float or ISO date string.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
time_str : str or None
|
|
15
|
+
Time as "YYYY-MM-DD" or IJD number
|
|
16
|
+
|
|
17
|
+
Returns
|
|
18
|
+
-------
|
|
19
|
+
float or str or None
|
|
20
|
+
Parsed time value
|
|
21
|
+
"""
|
|
22
|
+
if time_str is None:
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
return float(time_str)
|
|
27
|
+
except ValueError:
|
|
28
|
+
return time_str
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def parse_coord(coord):
|
|
32
|
+
"""
|
|
33
|
+
Parse RA and Dec strings as float degrees or sexagesimal strings.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
coord : str or None
|
|
38
|
+
Coordinate as float degrees or sexagesimal string
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
float or str or None
|
|
42
|
+
Parsed coordinate value
|
|
43
|
+
"""
|
|
44
|
+
if coord is None:
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
return float(coord)
|
|
49
|
+
except ValueError:
|
|
50
|
+
return coord
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def query_direct(
|
|
54
|
+
catalog_path, tstart, tstop, ra, dec, radius, fov, max_chi, chi_type, revolution, output, list_swids, count
|
|
55
|
+
):
|
|
56
|
+
try:
|
|
57
|
+
q = ScwQuery(catalog_path)
|
|
58
|
+
initial_count = len(q.catalog)
|
|
59
|
+
# Parse times (handle both IJD and ISO)
|
|
60
|
+
tstart = parse_time(tstart)
|
|
61
|
+
tstop = parse_time(tstop)
|
|
62
|
+
|
|
63
|
+
# Apply filters
|
|
64
|
+
if tstart or tstop:
|
|
65
|
+
q = q.time(tstart=tstart, tstop=tstop)
|
|
66
|
+
|
|
67
|
+
if ra is not None and dec is not None:
|
|
68
|
+
ra = parse_coord(ra)
|
|
69
|
+
dec = parse_coord(dec)
|
|
70
|
+
if radius is not None:
|
|
71
|
+
q = q.position(ra=ra, dec=dec, radius=radius)
|
|
72
|
+
else:
|
|
73
|
+
q = q.position(ra=ra, dec=dec, fov_mode=fov)
|
|
74
|
+
|
|
75
|
+
if max_chi is not None:
|
|
76
|
+
q = q.quality(max_chi=max_chi, chi_type=chi_type)
|
|
77
|
+
|
|
78
|
+
if revolution:
|
|
79
|
+
q = q.revolution(revolution)
|
|
80
|
+
|
|
81
|
+
results = q.get()
|
|
82
|
+
|
|
83
|
+
if count:
|
|
84
|
+
click.echo(len(results))
|
|
85
|
+
|
|
86
|
+
elif list_swids:
|
|
87
|
+
for swid in results["SWID"]:
|
|
88
|
+
click.echo(swid)
|
|
89
|
+
|
|
90
|
+
elif output:
|
|
91
|
+
if output.endswith(".csv"):
|
|
92
|
+
results.write(output, format="ascii.csv", overwrite=True)
|
|
93
|
+
else:
|
|
94
|
+
results.write(output, format="fits", overwrite=True)
|
|
95
|
+
click.echo(f"Saved {len(results)} SCWs to {output}")
|
|
96
|
+
|
|
97
|
+
else:
|
|
98
|
+
click.echo(f"Found {len(results)}/{initial_count} SCWs")
|
|
99
|
+
if len(results) > 0:
|
|
100
|
+
display_cols = ["SWID", "TSTART", "TSTOP", "RA_SCX", "DEC_SCX"]
|
|
101
|
+
chi_col = f"{chi_type}_CHI" if chi_type != "RAW" else "CHI"
|
|
102
|
+
if chi_col in results.colnames:
|
|
103
|
+
display_cols.append(chi_col)
|
|
104
|
+
click.echo(results[display_cols][:10])
|
|
105
|
+
if len(results) > 10:
|
|
106
|
+
click.echo(f"... and {len(results) - 10} more")
|
|
107
|
+
|
|
108
|
+
except Exception as e:
|
|
109
|
+
click.echo(f"Error: {e}", err=True)
|
|
110
|
+
raise click.Abort()
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def query_interactive(catalog_path):
|
|
114
|
+
"""Run interactive query session."""
|
|
115
|
+
click.echo("=== Interactive Query Mode ===\n")
|
|
116
|
+
|
|
117
|
+
q = ScwQuery(catalog_path)
|
|
118
|
+
click.echo(f"Loaded {len(q.catalog)} SCWs")
|
|
119
|
+
click.echo("Type 'help' for commands\n")
|
|
120
|
+
|
|
121
|
+
while True:
|
|
122
|
+
try:
|
|
123
|
+
cmd = click.prompt("query>", default="").strip().lower()
|
|
124
|
+
|
|
125
|
+
if cmd in ("exit", "quit", "q"):
|
|
126
|
+
break
|
|
127
|
+
elif cmd == "help":
|
|
128
|
+
click.echo("Commands: time, pos, quality, show, reset, save, exit")
|
|
129
|
+
elif cmd == "time":
|
|
130
|
+
tstart = click.prompt("Start", default="", show_default=False)
|
|
131
|
+
tstop = click.prompt("Stop", default="", show_default=False)
|
|
132
|
+
tstart = parse_time(tstart) if tstart else None
|
|
133
|
+
tstop = parse_time(tstop) if tstop else None
|
|
134
|
+
q = q.time(tstart=tstart or None, tstop=tstop or None)
|
|
135
|
+
click.echo(f"→ {q.count()} SCWs")
|
|
136
|
+
elif cmd == "pos":
|
|
137
|
+
ra = click.prompt("RA")
|
|
138
|
+
dec = click.prompt("Dec")
|
|
139
|
+
mode = click.prompt("Mode", type=click.Choice(["fov", "radius"]), default="fov")
|
|
140
|
+
if mode == "radius":
|
|
141
|
+
radius = click.prompt("Radius (deg)", type=float, default=10.0)
|
|
142
|
+
q = q.position(ra=parse_coord(ra), dec=parse_coord(dec), radius=radius)
|
|
143
|
+
else:
|
|
144
|
+
fov_mode = click.prompt("FOV mode", type=click.Choice(["full", "any"]), default="any")
|
|
145
|
+
q = q.position(ra=parse_coord(ra), dec=parse_coord(dec), fov_mode=fov_mode)
|
|
146
|
+
click.echo(f"→ {q.count()} SCWs")
|
|
147
|
+
|
|
148
|
+
elif cmd == "quality":
|
|
149
|
+
max_chi = click.prompt("Max chi-squared", type=float)
|
|
150
|
+
chi_type = click.prompt("Chi type", type=click.Choice(["RAW", "CUT", "GTI"]), default="CUT")
|
|
151
|
+
q = q.quality(max_chi=max_chi, chi_type=chi_type)
|
|
152
|
+
click.echo(f"→ {q.count()} SCWs")
|
|
153
|
+
|
|
154
|
+
elif cmd == "show":
|
|
155
|
+
results = q.get()
|
|
156
|
+
click.echo(f"\n{len(results)} SCWs:")
|
|
157
|
+
click.echo(results[["SWID", "TSTART", "TSTOP"]])
|
|
158
|
+
elif cmd == "reset":
|
|
159
|
+
q = q.reset()
|
|
160
|
+
click.echo(f"→ {len(q.catalog)} SCWs")
|
|
161
|
+
elif cmd == "save":
|
|
162
|
+
only_scws = click.confirm("Save only SWID list?", default=False)
|
|
163
|
+
path = click.prompt("File")
|
|
164
|
+
q.write(path, overwrite=True, swid_only=only_scws)
|
|
165
|
+
click.echo(f"✓ Saved")
|
|
166
|
+
else:
|
|
167
|
+
click.echo(f"Unknown: {cmd}")
|
|
168
|
+
|
|
169
|
+
except KeyboardInterrupt:
|
|
170
|
+
click.echo("\nUse 'exit' to quit")
|
|
171
|
+
except Exception as e:
|
|
172
|
+
click.echo(f"Error: {e}", err=True)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: isgri
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Python package for INTEGRAL IBIS/ISGRI lightcurve analysis
|
|
5
5
|
Author: Dominik Patryk Pacholski
|
|
6
6
|
License: MIT
|
|
@@ -55,6 +55,9 @@ pip install isgri
|
|
|
55
55
|
# Configure default paths (once)
|
|
56
56
|
isgri config-set --catalog ~/data/scw_catalog.fits
|
|
57
57
|
|
|
58
|
+
# Interactive method
|
|
59
|
+
isgri query
|
|
60
|
+
|
|
58
61
|
# Query by time range
|
|
59
62
|
isgri query --tstart 2010-01-01 --tstop 2010-12-31
|
|
60
63
|
|
|
@@ -138,27 +141,4 @@ Local config file `isgri_config.toml` in current directory overrides global conf
|
|
|
138
141
|
- **CLI Reference**: Run `isgri --help` or `isgri <command> --help`
|
|
139
142
|
- **Catalog Tutorial**: [scwquery_walkthrough.ipynb](https://github.com/dominp/isgri/blob/main/demo/scwquery_walkthrough.ipynb)
|
|
140
143
|
- **Light Curve Tutorial**: [lightcurve_walkthrough.ipynb](https://github.com/dominp/isgri/blob/main/demo/lightcurve_walkthrough.ipynb)
|
|
141
|
-
- **API Reference**: Use `help()` in Python or see docstrings
|
|
142
|
-
|
|
143
|
-
## Project Structure
|
|
144
|
-
|
|
145
|
-
```
|
|
146
|
-
isgri/
|
|
147
|
-
├── catalog/ # SCW catalog query tools
|
|
148
|
-
│ ├── scwquery.py # Main query interface
|
|
149
|
-
│ └── wcs.py # Coordinate transformations
|
|
150
|
-
├── utils/ # Light curve analysis utilities
|
|
151
|
-
│ ├── lightcurve.py # Light curve class
|
|
152
|
-
│ ├── quality.py # Quality metrics
|
|
153
|
-
│ ├── pif.py # PIF tools
|
|
154
|
-
│ ├── file_loaders.py
|
|
155
|
-
│ └── time_conversion.py
|
|
156
|
-
├── config.py # Configuration management
|
|
157
|
-
└── cli.py # Command line interface
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
## Requirements
|
|
161
|
-
|
|
162
|
-
- Python ≥ 3.10
|
|
163
|
-
- astropy
|
|
164
|
-
- numpy
|
|
144
|
+
- **API Reference**: Use `help()` in Python or see docstrings
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
isgri/__init__.py,sha256=V2hnOxXKcjMiusdGP8sOAR4QsBlWHQ0pZZMN2Cean6o,38
|
|
2
|
-
isgri/__version__.py,sha256=
|
|
3
|
-
isgri/cli.py,sha256=ESrhtFCo-VEYuC3y4CL9Hv2Mdr6MVESCkRZ0N6kLgKs,7211
|
|
2
|
+
isgri/__version__.py,sha256=DS49q_bFynltwBtgneHYeVXTHLg5bjAOFWvTkv-jYmY,21
|
|
4
3
|
isgri/config.py,sha256=i1ibczZsmgqELv4ik2h2nWLnHyl68_5KGsz5Ec8Uf4E,4365
|
|
5
4
|
isgri/catalog/__init__.py,sha256=CT9Zd1WISpv7kowf3bqagKewZ8SjLr1rZzVSFkwEj3o,58
|
|
6
5
|
isgri/catalog/builder.py,sha256=Ure_erpyApjSiAmIvhJahuf6c11VNXBn5R6-nQzsDw4,3488
|
|
7
|
-
isgri/catalog/scwquery.py,sha256=
|
|
6
|
+
isgri/catalog/scwquery.py,sha256=HobS4Im1GF28ZFYWrdXjUbCGJahBE3aS23bkGkYPjGc,19233
|
|
8
7
|
isgri/catalog/wcs.py,sha256=mD6bZxiBxKYpuYCl8f2tSCc8uuWFzMRL2jf5SuFAhfg,5562
|
|
8
|
+
isgri/cli/__init__.py,sha256=-bBNFYOq80A2Egtpo5V5zWJtYOxQfRZFQ_feve5lkFU,23
|
|
9
|
+
isgri/cli/main.py,sha256=pOwTbJ7nuOC48cdVm-e84GGjlOFic1ZMEvU2e3yKP4k,5613
|
|
10
|
+
isgri/cli/query.py,sha256=s_9p09nct4KnU3RVWW1BytLIY4cuY0SlGIobaCf_VMs,5772
|
|
9
11
|
isgri/utils/__init__.py,sha256=H83Al7urc6LNW5KUzUBRdtRBUTahiZmkehKFiK90RrU,183
|
|
10
12
|
isgri/utils/file_loaders.py,sha256=g-LUfYw35hPePlFeicymaL-NbZXzZWfNmM127XJjCKY,12497
|
|
11
13
|
isgri/utils/lightcurve.py,sha256=Pjys-eIyKShDKHqFpGa9SZ0Dzz7LiLIwBpUkp_6s41g,14133
|
|
12
14
|
isgri/utils/pif.py,sha256=LixlkShy1j_ymfdJLyCV8zl0EeHgfVDVjddSex18GLQ,8648
|
|
13
15
|
isgri/utils/quality.py,sha256=Na-sNEX1E4xWQJx0FYe9vbOAgPrTcLohHeUAnmlKYSw,13348
|
|
14
16
|
isgri/utils/time_conversion.py,sha256=MNPVjrsrmwRDbCWmqdWN0xRs8PtHkFGli-H2cYwF9Ns,5204
|
|
15
|
-
isgri-0.
|
|
16
|
-
isgri-0.
|
|
17
|
-
isgri-0.
|
|
18
|
-
isgri-0.
|
|
19
|
-
isgri-0.
|
|
17
|
+
isgri-0.6.0.dist-info/METADATA,sha256=OqyGmCzgW4fH3E__TwlEa-txR5wHlwtBWxme0miwwRc,3417
|
|
18
|
+
isgri-0.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
19
|
+
isgri-0.6.0.dist-info/entry_points.txt,sha256=aM2K4RGihbwsj9crjPG-BvWhErcdtZt3tJqT6AaOojU,46
|
|
20
|
+
isgri-0.6.0.dist-info/licenses/LICENSE,sha256=Q8oxmHR1cSnEXSHCjY3qeXMtupZI_1ZQZ1MBt4oeANE,1102
|
|
21
|
+
isgri-0.6.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|