PyThea 0.9.1__tar.gz → 0.11.0__tar.gz
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.
- {PyThea-0.9.1 → pythea-0.11.0}/CHANGELOG.md +33 -0
- {PyThea-0.9.1/PyThea.egg-info → pythea-0.11.0}/PKG-INFO +5 -3
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/PyThea_app.py +103 -53
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/_version.py +2 -2
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/callbacks.py +2 -1
- pythea-0.11.0/PyThea/data/sample_data.py +35 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/geometrical_models.py +12 -6
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/modules.py +25 -11
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/pythea_cli.py +21 -2
- pythea-0.11.0/PyThea/sunpy_dev/extern/sunkit_instruments/aia/utils.py +14 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/sunpy_dev/map/maputils.py +18 -11
- pythea-0.11.0/PyThea/test/Pythea_test.py +24 -0
- pythea-0.11.0/PyThea/test/__init__.py +0 -0
- pythea-0.11.0/PyThea/test/figure_hashes.json +6 -0
- pythea-0.11.0/PyThea/test/test_figures.py +169 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/test/test_imports.py +4 -1
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/test/test_utils.py +47 -3
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/utils.py +57 -12
- {PyThea-0.9.1 → pythea-0.11.0/PyThea.egg-info}/PKG-INFO +5 -3
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea.egg-info/SOURCES.txt +4 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea.egg-info/requires.txt +4 -2
- {PyThea-0.9.1 → pythea-0.11.0}/environment.yml +4 -2
- {PyThea-0.9.1 → pythea-0.11.0}/requirements.txt +4 -2
- PyThea-0.9.1/PyThea/data/sample_data.py +0 -15
- PyThea-0.9.1/PyThea/test/Pythea_test.py +0 -8
- {PyThea-0.9.1 → pythea-0.11.0}/LICENSE.md +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/MANIFEST.in +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/__init__.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/config/__init__.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/config/app_styles.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/config/config_sliders.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/config/selected_bodies.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/config/selected_imagers.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/data/__init__.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/extensions/LICENSE_gcs_python.md +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/extensions/__init__.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/extensions/buttons.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/sunpy_dev/__init__.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/sunpy_dev/extern/__init__.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/sunpy_dev/extern/sunkit_instruments/__init__.py +0 -0
- {PyThea-0.9.1/PyThea/sunpy_dev/extern/sunkit_instruments/lasco → pythea-0.11.0/PyThea/sunpy_dev/extern/sunkit_instruments/aia}/__init__.py +0 -0
- {PyThea-0.9.1/PyThea/sunpy_dev/extern/sunkit_instruments/stereo → pythea-0.11.0/PyThea/sunpy_dev/extern/sunkit_instruments/lasco}/__init__.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/sunpy_dev/extern/sunkit_instruments/lasco/utils.py +0 -0
- {PyThea-0.9.1/PyThea/sunpy_dev/map → pythea-0.11.0/PyThea/sunpy_dev/extern/sunkit_instruments/stereo}/__init__.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/sunpy_dev/extern/sunkit_instruments/stereo/utils.py +0 -0
- {PyThea-0.9.1/PyThea/test → pythea-0.11.0/PyThea/sunpy_dev/map}/__init__.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/test/conftest.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/test/test_geometrical_models.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/test/test_remote_clients.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea/version.py +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea.egg-info/.DS_Store +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea.egg-info/dependency_links.txt +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea.egg-info/entry_points.txt +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea.egg-info/not-zip-safe +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/PyThea.egg-info/top_level.txt +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/README.md +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/README_pypi.md +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/pyproject.toml +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/setup.cfg +0 -0
- {PyThea-0.9.1 → pythea-0.11.0}/setup.py +0 -0
|
@@ -1,3 +1,36 @@
|
|
|
1
|
+
# v0.11.0 (17-April-2024)
|
|
2
|
+
|
|
3
|
+
## Features
|
|
4
|
+
- Adds tests for ellipsoid location on AIA and STEREO COR images.
|
|
5
|
+
- Adds test_load_fitting_json_file to check the fitting file load and save.
|
|
6
|
+
- Improve PyThea tests on cli.
|
|
7
|
+
|
|
8
|
+
## Major Changes
|
|
9
|
+
- Change the inputs for download_fits from string dates to timerange.
|
|
10
|
+
|
|
11
|
+
# v0.10.0 (17-April-2024)
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
- Option added to choose the step for Running Difference or the background image for the Base Difference image processing.
|
|
15
|
+
- Fetures added in the app to plot limb or meridians from different observers and grid.
|
|
16
|
+
- Feture added in the app for manual change of the images colorbar limits.
|
|
17
|
+
- Feture added in the app to use median filter images processing.
|
|
18
|
+
- Tests added: A test to verify the existence of Pythea's database directory
|
|
19
|
+
|
|
20
|
+
## Major Changes
|
|
21
|
+
- Updates sunpy dependencies to sunpy 5.1.2
|
|
22
|
+
|
|
23
|
+
## Minor Changes
|
|
24
|
+
- Improvements on the pipeline of image download and processing in the app.
|
|
25
|
+
- Improvements and simplifications on the figures production in the app.
|
|
26
|
+
- Values of the colormap limits in the app are stored and are reused when changing the imager.
|
|
27
|
+
|
|
28
|
+
## Bug Fixes
|
|
29
|
+
- Fixes a bug with test_database_dir_exists.
|
|
30
|
+
- Fixes a bug when corrupted fits files loaded and imager load skipped.
|
|
31
|
+
- Fixes a bug with AIA visuallization from missing date_average.
|
|
32
|
+
- Fixes a bug with supplementary imaging selection.
|
|
33
|
+
|
|
1
34
|
# v0.9.1 (5-March-2024)
|
|
2
35
|
|
|
3
36
|
## Features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PyThea
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: PyThea: A software package to reconstruct the 3D structure of CMEs and shock waves
|
|
5
5
|
Home-page: https://github.com/AthKouloumvakos/PyThea
|
|
6
6
|
Author: Athanasios Kouloumvakos
|
|
@@ -26,9 +26,10 @@ Requires-Dist: scipy
|
|
|
26
26
|
Requires-Dist: aiapy
|
|
27
27
|
Requires-Dist: astropy
|
|
28
28
|
Requires-Dist: astroquery
|
|
29
|
+
Requires-Dist: jplephem
|
|
29
30
|
Requires-Dist: numexpr
|
|
30
|
-
Requires-Dist: sunpy==
|
|
31
|
-
Requires-Dist: parfive==1.
|
|
31
|
+
Requires-Dist: sunpy==5.1.2
|
|
32
|
+
Requires-Dist: parfive==2.1.0
|
|
32
33
|
Requires-Dist: pooch
|
|
33
34
|
Requires-Dist: matplotlib
|
|
34
35
|
Requires-Dist: seaborn
|
|
@@ -42,6 +43,7 @@ Requires-Dist: tqdm
|
|
|
42
43
|
Requires-Dist: pyvista
|
|
43
44
|
Requires-Dist: pytest-astropy
|
|
44
45
|
Requires-Dist: pytest-sugar
|
|
46
|
+
Requires-Dist: pytest-mpl
|
|
45
47
|
|
|
46
48
|
# PyThea: A software package to reconstruct the 3D structure of CMEs and shock waves
|
|
47
49
|
|
|
@@ -18,23 +18,27 @@
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
import datetime
|
|
22
|
+
from copy import copy
|
|
23
|
+
|
|
21
24
|
import astropy.units as u
|
|
22
25
|
import numpy as np
|
|
23
26
|
import stqdm # See also https://github.com/tqdm/tqdm
|
|
24
27
|
import streamlit as st
|
|
25
28
|
from astropy.coordinates import Distance, SkyCoord, SphericalRepresentation
|
|
26
29
|
from sunpy.coordinates import frames
|
|
30
|
+
from sunpy.net import attrs as a
|
|
27
31
|
|
|
28
32
|
from PyThea.callbacks import load_or_delete_fittings
|
|
29
33
|
from PyThea.config import (app_styles, config_sliders, selected_bodies,
|
|
30
34
|
selected_imagers)
|
|
31
35
|
from PyThea.geometrical_models import ellipsoid, gcs, spheroid
|
|
32
|
-
from PyThea.modules import (date_and_event_selection,
|
|
36
|
+
from PyThea.modules import (date_and_event_selection, figure_streamlit,
|
|
37
|
+
final_parameters_gmodel,
|
|
33
38
|
fitting_and_slider_options_container,
|
|
34
|
-
fitting_sliders
|
|
35
|
-
from PyThea.sunpy_dev.map.maputils import get_closest
|
|
36
|
-
from PyThea.utils import (download_fits,
|
|
37
|
-
plot_bodies, plot_fitting_model,
|
|
39
|
+
fitting_sliders)
|
|
40
|
+
from PyThea.sunpy_dev.map.maputils import get_closest, maps_clims
|
|
41
|
+
from PyThea.utils import (download_fits, model_fittings, plot_fitting_model,
|
|
38
42
|
single_imager_maps_process)
|
|
39
43
|
from PyThea.version import version
|
|
40
44
|
|
|
@@ -185,24 +189,58 @@ def run():
|
|
|
185
189
|
if 'imagers_list_' not in st.session_state:
|
|
186
190
|
# imagers_list_ is used later when we download or filter the images
|
|
187
191
|
st.session_state['imagers_list_'] = []
|
|
188
|
-
image_mode = procoption_container.selectbox('Map
|
|
192
|
+
image_mode = procoption_container.selectbox('Map Sequence Processing',
|
|
189
193
|
options=['Running Diff.', 'Base Diff.', 'Plain'], key='image_mode',
|
|
190
|
-
on_change=delete_from_state,
|
|
194
|
+
on_change=delete_from_state,
|
|
195
|
+
kwargs={'vars': ['map', 'imagers_list_', 'clim', 'clim_manual_low', 'clim_manual_high']})
|
|
196
|
+
if image_mode in ['Running Diff.', 'Base Diff.']:
|
|
197
|
+
diff_value = procoption_container.number_input('Select Step/Image for Running/Base Diff.', 1, 5, key='diff_value',
|
|
198
|
+
on_change=delete_from_state,
|
|
199
|
+
kwargs={'vars': ['map', 'imagers_list_', 'clim', 'clim_manual_low', 'clim_manual_high']})
|
|
200
|
+
else:
|
|
201
|
+
diff_value = None
|
|
202
|
+
|
|
203
|
+
procoption_container.number_input('Median Filter', 1, 6, 1, 1, key='images_median_filter')
|
|
191
204
|
|
|
192
205
|
with st.sidebar.expander('Plot/View Options'):
|
|
193
206
|
plotviewopt_container = st.container()
|
|
194
|
-
|
|
207
|
+
plotviewopt_container.checkbox('Clip plot on image limits', value=True, key='clip_model')
|
|
195
208
|
plt_supp_imagers = plotviewopt_container.checkbox('Supplementary Imaging', value=False)
|
|
196
|
-
|
|
197
|
-
if star_field:
|
|
198
|
-
|
|
199
|
-
|
|
209
|
+
plotviewopt_container.checkbox('View Bodies or s/c', key='star_field')
|
|
210
|
+
if st.session_state.star_field:
|
|
211
|
+
plotviewopt_container.multiselect('Select Bodies', options=selected_bodies.bodies_dict.keys(),
|
|
212
|
+
default=['Mercury', 'Venus', 'Jupiter'],
|
|
213
|
+
key='bodies_list')
|
|
214
|
+
plotviewopt_container.checkbox('View Limb and Meridians', key='plot_solar_reference_lines_')
|
|
215
|
+
if st.session_state.plot_solar_reference_lines_:
|
|
216
|
+
markdown = '''
|
|
217
|
+
**Limb**: plots the solar limb as observed # noqa
|
|
218
|
+
for the selected observers. # noqa
|
|
219
|
+
**Central Meridian**: plots the central meridian # noqa
|
|
220
|
+
observed for the selected observers. # noqa
|
|
221
|
+
**CR Meridan+Equator**: plots the primary meridian # noqa
|
|
222
|
+
and equator of Carrington coordinate system. # noqa
|
|
223
|
+
'''.strip()
|
|
224
|
+
plotviewopt_container.selectbox('Select plot option',
|
|
225
|
+
options=['Limb from Obs.', 'Central Meridian from Obs.', 'Carr. Prime Meridian+Solar Equator',
|
|
226
|
+
'Stonyhurst Grid', 'Carrington Grid'],
|
|
227
|
+
help=markdown,
|
|
228
|
+
key='plot_solar_reference_lines_mode')
|
|
229
|
+
disabled = False if st.session_state.plot_solar_reference_lines_mode in ['Limb from Obs.', 'Central Meridian from Obs.'] else True
|
|
230
|
+
plotviewopt_container.multiselect('Select Bodies',
|
|
231
|
+
label_visibility='collapsed',
|
|
232
|
+
options=selected_bodies.bodies_dict.keys(),
|
|
233
|
+
default=['Earth'], disabled=disabled,
|
|
234
|
+
key='plot_solar_reference_lines_bodies_list')
|
|
200
235
|
|
|
201
236
|
#############################################################
|
|
202
237
|
# Download and Process the Images
|
|
203
238
|
# This part runs only if the map_ doesn't exits or the session_state.map_ does not contain all the imagers requested
|
|
204
239
|
imager_added = list(set(imagers_list) - set(st.session_state['imagers_list_']))
|
|
205
240
|
imager_removed = list(set(st.session_state['imagers_list_']) - set(imagers_list))
|
|
241
|
+
if 'map_colormap_limits' not in st.session_state:
|
|
242
|
+
st.session_state['map_colormap_limits'] = {}
|
|
243
|
+
|
|
206
244
|
if 'map_' not in st.session_state or imager_added != []:
|
|
207
245
|
st.session_state.map_ = {} if 'map_' not in st.session_state else st.session_state.map_
|
|
208
246
|
st.session_state.map = {} if 'map' not in st.session_state else st.session_state.map
|
|
@@ -211,22 +249,28 @@ def run():
|
|
|
211
249
|
for imager in progress_bar:
|
|
212
250
|
progress_bar.desc = f'Downloaded {imager} images from VSO'
|
|
213
251
|
if imager not in st.session_state.map_:
|
|
214
|
-
|
|
215
|
-
|
|
252
|
+
timerange = a.Time(st.session_state.date_process + datetime.timedelta(hours=imaging_time_range[0]),
|
|
253
|
+
st.session_state.date_process + datetime.timedelta(hours=imaging_time_range[1]))
|
|
254
|
+
st.session_state.map_[imager] = download_fits(timerange, imager)
|
|
255
|
+
st.session_state.map_[imager] = single_imager_maps_process(st.session_state.map_[imager],
|
|
256
|
+
**selected_imagers.imager_dict[imager][1],
|
|
257
|
+
skip='sequence_processing')
|
|
216
258
|
processed_images = single_imager_maps_process(st.session_state.map_[imager],
|
|
259
|
+
skip=['filter', 'prepare'],
|
|
217
260
|
image_mode=image_mode,
|
|
218
|
-
|
|
261
|
+
diff_num=diff_value)
|
|
219
262
|
if processed_images != []:
|
|
220
263
|
st.session_state.map[imager] = processed_images
|
|
264
|
+
st.session_state.map_colormap_limits[imager] = maps_clims(st.session_state.map[imager])
|
|
221
265
|
else:
|
|
222
266
|
st.session_state.imagers_list_.remove(imager)
|
|
267
|
+
st.session_state.map_colormap_limits.pop(imager, None)
|
|
268
|
+
|
|
223
269
|
if imager_removed != []:
|
|
224
270
|
st.session_state['imagers_list_'] = imagers_list
|
|
225
271
|
for imager in imager_removed:
|
|
226
272
|
st.session_state.map_.pop(imager, None)
|
|
227
273
|
|
|
228
|
-
maps_clims(st, st.session_state.imagers_list_)
|
|
229
|
-
|
|
230
274
|
if not st.session_state.imagers_list_:
|
|
231
275
|
st.error('No images have been downloaded or processed.') # TODO: Explain better
|
|
232
276
|
st.stop()
|
|
@@ -236,7 +280,8 @@ def run():
|
|
|
236
280
|
st.markdown('### Multi-viewpoint imaging')
|
|
237
281
|
col1, col2 = st.columns((1, 3))
|
|
238
282
|
imager_select = col1.selectbox('Select an imager',
|
|
239
|
-
options=st.session_state.imagers_list_
|
|
283
|
+
options=st.session_state.imagers_list_,
|
|
284
|
+
on_change=delete_from_state, kwargs={'vars': ['clim', 'clim_manual_low', 'clim_manual_high']})
|
|
240
285
|
|
|
241
286
|
maps_date = [getattr(maps, 'date_average', None) or getattr(maps, 'date', None) for maps in st.session_state.map[imager_select]]
|
|
242
287
|
if len(maps_date) > 1:
|
|
@@ -248,14 +293,26 @@ def run():
|
|
|
248
293
|
|
|
249
294
|
running_map = st.session_state.map[imager_select][maps_date.index(running_map_date)]
|
|
250
295
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
296
|
+
manual_clim = plotviewopt_container.checkbox('Provide clims values', on_change=delete_from_state, kwargs={'vars': ['clim']})
|
|
297
|
+
if manual_clim:
|
|
298
|
+
col1, col2 = plotviewopt_container.columns(2)
|
|
299
|
+
if 'clim_manual_low' not in st.session_state:
|
|
300
|
+
st.session_state.clim_manual_low = st.session_state.map_colormap_limits[imager_select][0]
|
|
301
|
+
qmin = col1.number_input('Low clim value', label_visibility='collapsed', key='clim_manual_low')
|
|
302
|
+
if 'clim_manual_high' not in st.session_state:
|
|
303
|
+
st.session_state.clim_manual_high = st.session_state.map_colormap_limits[imager_select][1]
|
|
304
|
+
qmax = col2.number_input('High clim value', label_visibility='collapsed', key='clim_manual_high')
|
|
305
|
+
st.session_state.map_colormap_limits[imager_select] = [qmin, qmax]
|
|
306
|
+
else:
|
|
307
|
+
qmin = st.session_state.map_colormap_limits[imager_select][0]
|
|
308
|
+
qmax = st.session_state.map_colormap_limits[imager_select][1]
|
|
309
|
+
cmmin, cpmax = config_sliders.slider_image_pmclims[image_mode]
|
|
310
|
+
if 'clim' not in st.session_state:
|
|
311
|
+
st.session_state.clim = [float(qmin), float(qmax)]
|
|
312
|
+
st.session_state.map_colormap_limits[imager_select] = \
|
|
313
|
+
plotviewopt_container.slider('Images colorbar limits:',
|
|
314
|
+
min_value=float(cmmin), max_value=float(cpmax),
|
|
315
|
+
key='clim')
|
|
259
316
|
|
|
260
317
|
#############################################################
|
|
261
318
|
# Finalize the geometrical model
|
|
@@ -290,35 +347,28 @@ def run():
|
|
|
290
347
|
|
|
291
348
|
#############################################################
|
|
292
349
|
# Plot main and supplement figure images
|
|
293
|
-
fig, axis =
|
|
294
|
-
if st.session_state.plot_mesh_mode == 'Skeleton':
|
|
295
|
-
model.plot(axis, mode='Skeleton')
|
|
296
|
-
elif st.session_state.plot_mesh_mode == 'Full':
|
|
297
|
-
model.plot(axis, mode='Skeleton')
|
|
298
|
-
model.plot(axis, mode='Full')
|
|
299
|
-
elif st.session_state.plot_mesh_mode == 'Surface':
|
|
300
|
-
model.plot(axis, only_surface=True)
|
|
301
|
-
|
|
302
|
-
if star_field:
|
|
303
|
-
plot_bodies(axis, bodies_list, running_map)
|
|
304
|
-
axis.legend()
|
|
350
|
+
fig, axis = figure_streamlit(st, running_map, image_mode, imager_select, model)
|
|
305
351
|
st.pyplot(fig)
|
|
306
352
|
|
|
307
|
-
if plt_supp_imagers
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
353
|
+
if plt_supp_imagers:
|
|
354
|
+
if len(st.session_state.imagers_list_) < 3:
|
|
355
|
+
other_element = [element for element in st.session_state.imagers_list_ if element != imager_select][0]
|
|
356
|
+
fig, axis = figure_streamlit(st, get_closest(st.session_state.map[other_element], running_map_date), image_mode, other_element, model)
|
|
357
|
+
st.pyplot(fig)
|
|
358
|
+
else:
|
|
359
|
+
supl_imagers_list = copy(st.session_state.imagers_list_)
|
|
360
|
+
supl_imagers_list.remove(imager_select)
|
|
361
|
+
supl_imagers = st.select_slider('Select supplement imagers',
|
|
362
|
+
options=supl_imagers_list,
|
|
363
|
+
value=(supl_imagers_list[0],
|
|
364
|
+
supl_imagers_list[-1]),
|
|
365
|
+
key='supl_imagers')
|
|
366
|
+
col1, col2 = st.columns(2)
|
|
367
|
+
fig, axis = figure_streamlit(st, get_closest(st.session_state.map[supl_imagers[0]], running_map_date), image_mode, supl_imagers[0], model)
|
|
368
|
+
col1.pyplot(fig)
|
|
369
|
+
fig, axis = figure_streamlit(st, get_closest(st.session_state.map[supl_imagers[1]], running_map_date), image_mode, supl_imagers[1], model)
|
|
370
|
+
model.plot(axis, mode='Skeleton')
|
|
371
|
+
col2.pyplot(fig)
|
|
322
372
|
|
|
323
373
|
#############################################################
|
|
324
374
|
# Store the fitting
|
|
@@ -39,7 +39,8 @@ def change_long_lat_sliders(st):
|
|
|
39
39
|
if st.session_state.coord_system == 'HGS':
|
|
40
40
|
center_ = st.session_state.center.transform_to(frames.HeliographicStonyhurst)
|
|
41
41
|
elif st.session_state.coord_system == 'HGC':
|
|
42
|
-
center_ = st.session_state.center.transform_to(frames.HeliographicCarrington
|
|
42
|
+
center_ = st.session_state.center.transform_to(frames.HeliographicCarrington(observer='Earth',
|
|
43
|
+
obstime=st.session_state.center.obstime))
|
|
43
44
|
st.session_state.longit = float(center_.lon.to_value(u.degree))
|
|
44
45
|
st.session_state.latitu = float(center_.lat.to_value(u.degree))
|
|
45
46
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import pooch
|
|
5
|
+
|
|
6
|
+
database_dir = os.path.join(Path.home(), 'PyThea')
|
|
7
|
+
github_main_url = 'https://github.com/AthKouloumvakos/PyThea-sample-data'
|
|
8
|
+
|
|
9
|
+
aia_sample_data = pooch.create(
|
|
10
|
+
path=os.path.join(database_dir, 'sample_data'), # The cache folder
|
|
11
|
+
base_url=f'{github_main_url}/raw/main/data/', # The remote data url on Github
|
|
12
|
+
registry={
|
|
13
|
+
'aia_lev1_1600a_2012_06_06t04_07_29_12z_image_lev1.fits': 'sha256:7e88d8a277ad3dd111c1bcff3c3936d6d5ef5186e05b4bfa7749ee43c05577d5',
|
|
14
|
+
'aia_lev1_1600a_2016_05_09t11_35_51_12z_image_lev1.fits': 'sha256:1c3bb938e9bfb3178cecead1319a92fa661eb70469715a441a849a98039f0b61'
|
|
15
|
+
},
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
stereo_sample_data = pooch.create(
|
|
19
|
+
path=os.path.join(database_dir, 'sample_data'), # The cache folder
|
|
20
|
+
base_url=f'{github_main_url}/raw/main/data/', # The remote data url on Github
|
|
21
|
+
registry={
|
|
22
|
+
'20120622_235400_d4c2a.fts': 'sha256:940680fe8bea754c9859170585d8299b9b049b631155435a31ecacf5b702d9cf',
|
|
23
|
+
'20140221_235400_d4c2b.fts': 'sha256:13638dedeb2e510c9e2ef11d46b372acb16f9b9645ca1cabf4d0ef8444353adc',
|
|
24
|
+
'20070503_102018_s4c1a.fts': 'sha256:55cf6e3741833a82e41b46e2345bf85a0e5580a2832900eccc41f235d36fc31e',
|
|
25
|
+
'20070503_102018_s4c1b.fts': 'sha256:ca8f4aabaeb7e4bc6f4e5d4819057ddfe3f9f621716224d11acc80d701e3beb8'
|
|
26
|
+
},
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
json_fitting_file_sample_data = pooch.create(
|
|
30
|
+
path=os.path.join(database_dir, 'sample_data'), # The cache folder
|
|
31
|
+
base_url=f'{github_main_url}/raw/main/data/', # The remote data url on Github
|
|
32
|
+
registry={
|
|
33
|
+
'FLX1p0D20211028T153500MEllipsoid.json': 'sha256:700687ed982317400ec409390571747694237de9688a2816baa7b1770b75c9b1',
|
|
34
|
+
},
|
|
35
|
+
)
|
|
@@ -283,7 +283,8 @@ class spheroid:
|
|
|
283
283
|
"""
|
|
284
284
|
Returns the spheroid parameters as `~pandas.DataFrame`.
|
|
285
285
|
"""
|
|
286
|
-
center_ = self.center.transform_to(frames.HeliographicCarrington
|
|
286
|
+
center_ = self.center.transform_to(frames.HeliographicCarrington(observer='Earth',
|
|
287
|
+
obstime=self.center.obstime))
|
|
287
288
|
data_dict = {
|
|
288
289
|
'hgln': self.center.lon.to_value(u.degree),
|
|
289
290
|
'hglt': self.center.lat.to_value(u.degree),
|
|
@@ -303,7 +304,8 @@ class spheroid:
|
|
|
303
304
|
'''
|
|
304
305
|
Returns the Spheroid object and parameters in a printable sting array.
|
|
305
306
|
'''
|
|
306
|
-
center_ = self.center.transform_to(frames.HeliographicCarrington
|
|
307
|
+
center_ = self.center.transform_to(frames.HeliographicCarrington(observer='Earth',
|
|
308
|
+
obstime=self.center.obstime))
|
|
307
309
|
output = '<Spheroid object \n'
|
|
308
310
|
output += 'HGLN = %3.2f degrees \n'%self.center.lon.to_value(u.degree)
|
|
309
311
|
output += 'HGLT = %3.2f degrees \n'%self.center.lat.to_value(u.degree)
|
|
@@ -402,7 +404,8 @@ class ellipsoid(spheroid):
|
|
|
402
404
|
"""
|
|
403
405
|
Returns the ellipsoid parameters as `~pandas.DataFrame`.
|
|
404
406
|
"""
|
|
405
|
-
center_ = self.center.transform_to(frames.HeliographicCarrington
|
|
407
|
+
center_ = self.center.transform_to(frames.HeliographicCarrington(observer='Earth',
|
|
408
|
+
obstime=self.center.obstime))
|
|
406
409
|
data_dict = {
|
|
407
410
|
'hgln': self.center.lon.to_value(u.degree),
|
|
408
411
|
'hglt': self.center.lat.to_value(u.degree),
|
|
@@ -469,7 +472,8 @@ class ellipsoid(spheroid):
|
|
|
469
472
|
'''
|
|
470
473
|
Returns the Ellipsoid object and parameters in a printable sting array.
|
|
471
474
|
'''
|
|
472
|
-
center_ = self.center.transform_to(frames.HeliographicCarrington
|
|
475
|
+
center_ = self.center.transform_to(frames.HeliographicCarrington(observer='Earth',
|
|
476
|
+
obstime=self.center.obstime))
|
|
473
477
|
output = '<Ellipsoid object \n'
|
|
474
478
|
output += 'HGLN = %3.2f degrees \n'%self.center.lon.to_value(u.degree)
|
|
475
479
|
output += 'HGLT = %3.2f degrees \n'%self.center.lat.to_value(u.degree)
|
|
@@ -669,7 +673,8 @@ class gcs():
|
|
|
669
673
|
"""
|
|
670
674
|
Returns the GCS parameters as `~pandas.DataFrame`.
|
|
671
675
|
"""
|
|
672
|
-
center_ = self.center.transform_to(frames.HeliographicCarrington
|
|
676
|
+
center_ = self.center.transform_to(frames.HeliographicCarrington(observer='Earth',
|
|
677
|
+
obstime=self.center.obstime))
|
|
673
678
|
data_dict = {
|
|
674
679
|
'hgln': self.center.lon.to_value(u.degree),
|
|
675
680
|
'hglt': self.center.lat.to_value(u.degree),
|
|
@@ -689,7 +694,8 @@ class gcs():
|
|
|
689
694
|
'''
|
|
690
695
|
Returns the GCS object and parameters in a printable sting array.
|
|
691
696
|
'''
|
|
692
|
-
center_ = self.center.transform_to(frames.HeliographicCarrington
|
|
697
|
+
center_ = self.center.transform_to(frames.HeliographicCarrington(observer='Earth',
|
|
698
|
+
obstime=self.center.obstime))
|
|
693
699
|
output = '<GCS object \n'
|
|
694
700
|
output += 'HGLN = %3.2f degrees \n'%self.center.lon.to_value(u.degree)
|
|
695
701
|
output += 'HGLT = %3.2f degrees \n'%self.center.lat.to_value(u.degree)
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
import datetime
|
|
22
22
|
|
|
23
23
|
import astropy.units as u
|
|
24
|
-
import numpy as np
|
|
25
24
|
|
|
26
25
|
from PyThea.callbacks import change_fitting_sliders, change_long_lat_sliders
|
|
27
26
|
from PyThea.config.config_sliders import sliders_dict as sd
|
|
28
27
|
from PyThea.geometrical_models import ellipsoid, gcs, spheroid
|
|
29
|
-
from PyThea.utils import get_hek_flare, model_fittings
|
|
28
|
+
from PyThea.utils import (get_hek_flare, make_figure, model_fittings,
|
|
29
|
+
plot_bodies, plot_solar_reference_lines)
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def date_and_event_selection(st):
|
|
@@ -184,13 +184,27 @@ def final_parameters_gmodel(st):
|
|
|
184
184
|
return rcenter, height, alpha, kappa, tilt
|
|
185
185
|
|
|
186
186
|
|
|
187
|
-
def
|
|
188
|
-
if 'map_clim' not in st.session_state:
|
|
189
|
-
st.session_state['map_clim'] = {}
|
|
187
|
+
def figure_streamlit(st, running_map, image_mode, imager, model):
|
|
190
188
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
189
|
+
fig, axis = make_figure(running_map, image_mode,
|
|
190
|
+
clim=st.session_state.map_colormap_limits[imager],
|
|
191
|
+
clip_model=st.session_state.clip_model,
|
|
192
|
+
median_filter=st.session_state.images_median_filter)
|
|
193
|
+
|
|
194
|
+
if st.session_state.plot_mesh_mode == 'Skeleton':
|
|
195
|
+
model.plot(axis, mode='Skeleton')
|
|
196
|
+
elif st.session_state.plot_mesh_mode == 'Full':
|
|
197
|
+
model.plot(axis, mode='Skeleton')
|
|
198
|
+
model.plot(axis, mode='Full')
|
|
199
|
+
elif st.session_state.plot_mesh_mode == 'Surface':
|
|
200
|
+
model.plot(axis, only_surface=True)
|
|
201
|
+
|
|
202
|
+
if st.session_state.star_field:
|
|
203
|
+
plot_bodies(axis, st.session_state.bodies_list, running_map)
|
|
204
|
+
axis.legend()
|
|
205
|
+
|
|
206
|
+
if st.session_state.plot_solar_reference_lines_:
|
|
207
|
+
plot_solar_reference_lines(axis, st.session_state.plot_solar_reference_lines_bodies_list,
|
|
208
|
+
running_map, mode=st.session_state.plot_solar_reference_lines_mode)
|
|
209
|
+
|
|
210
|
+
return fig, axis
|
|
@@ -99,9 +99,28 @@ def update():
|
|
|
99
99
|
|
|
100
100
|
|
|
101
101
|
@main.command('test')
|
|
102
|
-
|
|
102
|
+
@click.option('--mpl', is_flag=True, default=False, help='Run the test including figure tests.')
|
|
103
|
+
@click.option('--remote-data', is_flag=True, default=False, help='Run the test including figure tests.')
|
|
104
|
+
@click.option('--all', is_flag=True, default=False, help='Run the test including figure tests.')
|
|
105
|
+
def main_test(mpl, remote_data, all):
|
|
103
106
|
"""Test PyThea."""
|
|
104
|
-
|
|
107
|
+
|
|
108
|
+
test_directory = os.path.dirname(__file__)
|
|
109
|
+
|
|
110
|
+
print(f'Running a test of PyThea package located in: {test_directory}')
|
|
111
|
+
|
|
112
|
+
if mpl:
|
|
113
|
+
# Run a test of the package including figure tests
|
|
114
|
+
pytest.main(['-W', 'ignore', '--mpl', '--mpl-hash-library=figure_hashes.json', '--pyargs', f'{test_directory}'])
|
|
115
|
+
elif remote_data:
|
|
116
|
+
# Run a test of the package including remote-data tests
|
|
117
|
+
pytest.main(['-W', 'ignore', '--remote-data', '--pyargs', f'{test_directory}'])
|
|
118
|
+
elif all:
|
|
119
|
+
# Run a test of the package including remote-data tests
|
|
120
|
+
pytest.main(['-W', 'ignore', '--mpl', '--mpl-hash-library=figure_hashes.json', '--remote-data', '--pyargs', f'{test_directory}'])
|
|
121
|
+
else:
|
|
122
|
+
# Run a minimum test of the package (figure tests are always true and remote-data tests are skipped)
|
|
123
|
+
pytest.main(['-W', 'ignore', '--pyargs', f'{test_directory}'])
|
|
105
124
|
|
|
106
125
|
|
|
107
126
|
if __name__ == '__main__':
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from astropy.time import TimeDelta
|
|
2
|
+
from aiapy.calibrate import fix_observer_location, update_pointing
|
|
3
|
+
|
|
4
|
+
__all__ = ['prep_aia']
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def prep_aia(map_sequence):
|
|
8
|
+
map_sequence = [update_pointing(tmap) for tmap in map_sequence]
|
|
9
|
+
map_sequence = [fix_observer_location(tmap) for tmap in map_sequence]
|
|
10
|
+
|
|
11
|
+
for map_ in map_sequence:
|
|
12
|
+
map_.meta['DATE-AVG'] = (map_.date + TimeDelta(map_.meta['exptime']/2, format='sec')).value
|
|
13
|
+
|
|
14
|
+
return map_sequence
|
|
@@ -8,8 +8,8 @@ import warnings
|
|
|
8
8
|
import astropy.units as u
|
|
9
9
|
import numpy as np
|
|
10
10
|
import sunpy.map
|
|
11
|
-
from aiapy.calibrate import fix_observer_location, update_pointing
|
|
12
11
|
|
|
12
|
+
import PyThea.sunpy_dev.extern.sunkit_instruments.aia.utils # noqa
|
|
13
13
|
import PyThea.sunpy_dev.extern.sunkit_instruments.lasco.utils # noqa
|
|
14
14
|
import PyThea.sunpy_dev.extern.sunkit_instruments.stereo.utils # noqa
|
|
15
15
|
|
|
@@ -17,17 +17,17 @@ __all__ = ['maps_sequence_processing', 'get_closest', 'normalize_exposure',
|
|
|
17
17
|
'prepare_maps', 'difference_maps', 'mask_occulter']
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
def maps_sequence_processing(map_sequence,
|
|
20
|
+
def maps_sequence_processing(map_sequence, **kwargs):
|
|
21
21
|
"""
|
|
22
|
-
Returns a sequence of maps which is processed as running
|
|
22
|
+
Returns a sequence of maps which is processed as plain images, running or base difference images.
|
|
23
23
|
|
|
24
24
|
Parameters
|
|
25
25
|
----------
|
|
26
26
|
map_sequence : `~sunpy.map.GenericMap`
|
|
27
27
|
A list SunPy maps.
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
The type of sequence processing
|
|
29
|
+
image_mode : '~str'
|
|
30
|
+
The type of sequence processing: 'Running Diff.', 'Base Diff.', 'Plain'
|
|
31
31
|
|
|
32
32
|
Returns
|
|
33
33
|
-------
|
|
@@ -38,18 +38,21 @@ def maps_sequence_processing(map_sequence, seq_type='Plain'):
|
|
|
38
38
|
if len(map_sequence) == 0:
|
|
39
39
|
return []
|
|
40
40
|
|
|
41
|
+
seq_type = kwargs.get('image_mode', 'Plain')
|
|
42
|
+
diff_num = kwargs.get('diff_num', 1 if seq_type == 'Running Diff.' else 0 if seq_type == 'Base Diff.' else None)
|
|
43
|
+
|
|
41
44
|
normalized = True if True in [tmap.exposure_time == 1.0*u.second for tmap in map_sequence] else False
|
|
42
45
|
if not normalized:
|
|
43
46
|
warnings.warn('Warning [maps_sequence_processing]: The exposure time of the maps is not normalized.')
|
|
44
47
|
|
|
45
48
|
smap = []
|
|
46
49
|
if seq_type == 'Running Diff.':
|
|
47
|
-
for i in range(1, len(map_sequence)):
|
|
48
|
-
smap_diff = difference_maps(map_sequence[i], map_sequence[i-
|
|
50
|
+
for i in range(1+diff_num, len(map_sequence)):
|
|
51
|
+
smap_diff = difference_maps(map_sequence[i], map_sequence[i-diff_num])
|
|
49
52
|
smap.append(smap_diff)
|
|
50
53
|
if seq_type == 'Base Diff.':
|
|
51
54
|
for i in range(1, len(map_sequence)):
|
|
52
|
-
smap_diff = difference_maps(map_sequence[i], map_sequence[
|
|
55
|
+
smap_diff = difference_maps(map_sequence[i], map_sequence[diff_num])
|
|
53
56
|
smap.append(smap_diff)
|
|
54
57
|
if seq_type == 'Plain':
|
|
55
58
|
for i in range(0, len(map_sequence)):
|
|
@@ -151,6 +154,7 @@ def filter_maps(map_sequence, **kwargs):
|
|
|
151
154
|
sequence_final = sunpy.map.Map(map_sequence, sequence=True)
|
|
152
155
|
else:
|
|
153
156
|
sequence_final = []
|
|
157
|
+
|
|
154
158
|
return sequence_final
|
|
155
159
|
|
|
156
160
|
|
|
@@ -180,12 +184,11 @@ def prepare_maps(map_sequence, **kwargs):
|
|
|
180
184
|
return []
|
|
181
185
|
|
|
182
186
|
detector = map_sequence[0].detector
|
|
183
|
-
print(f'Preparing image sequence for {detector}.')
|
|
187
|
+
print(f'Preparing image sequence for {detector}. This could take a while...')
|
|
184
188
|
|
|
185
189
|
# Prepare the maps before anything else
|
|
186
190
|
if detector == 'AIA':
|
|
187
|
-
map_sequence =
|
|
188
|
-
map_sequence = [fix_observer_location(tmap) for tmap in map_sequence]
|
|
191
|
+
map_sequence = PyThea.sunpy_dev.extern.sunkit_instruments.aia.utils.prep_aia(map_sequence)
|
|
189
192
|
elif detector == 'COR1':
|
|
190
193
|
if 'polar' not in kwargs.keys():
|
|
191
194
|
map_sequence = PyThea.sunpy_dev.extern.sunkit_instruments.stereo.utils.cor_polariz(map_sequence)
|
|
@@ -286,3 +289,7 @@ def mask_occulter(smap, apply_mask=True, mask_value=0):
|
|
|
286
289
|
smap.data[mask_inner+mask_outer] = mask_value
|
|
287
290
|
return sunpy.map.Map(smap.data, smap.meta)
|
|
288
291
|
return mask_inner+mask_outer
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def maps_clims(images):
|
|
295
|
+
return [np.nanquantile(images[1].data, 0.20)-10, np.nanquantile(images[1].data, 0.80)+10]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A place for the more generic tests that do not fit in the other categories
|
|
3
|
+
|
|
4
|
+
Note
|
|
5
|
+
----
|
|
6
|
+
Before you start the test the PyThea pkg should be in the python path
|
|
7
|
+
export PYTHONPATH="${PYTHONPATH}:{top_level_dir_that_pythea_lives}/PyThea"
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_database_dir_exists():
|
|
15
|
+
"""
|
|
16
|
+
Tests that Pythea's database directory exists.
|
|
17
|
+
"""
|
|
18
|
+
# Skip the test if running in GitHub Actions
|
|
19
|
+
if os.environ.get('CI') == 'true':
|
|
20
|
+
print("Skipping test as it's running in GitHub Actions.")
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
database_dir = os.path.join(Path.home(), 'PyThea')
|
|
24
|
+
assert os.path.exists(database_dir), f"PyThea's database directory '{database_dir}' does not exist."
|
|
File without changes
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"PyThea.test.test_figures.test_ellipsoid_on_AIA_venus": "f1ff774b483a8c934c9353c552278c8823216fc7d9dad4ccc00c74be3f30c4c3",
|
|
3
|
+
"PyThea.test.test_figures.test_ellipsoid_on_AIA_mercury": "f6afda1c769a061b7ab1fc64c4e9c0f4658cdb97c3be83828ba5d98bf1bb182c",
|
|
4
|
+
"PyThea.test.test_figures.test_ellipsoid_on_STEREO_COR1_venus": "18a3af72e9da5b60e435f83ee3ef3f8cd0eb437eaef463329552ff56968f12ff",
|
|
5
|
+
"PyThea.test.test_figures.test_ellipsoid_on_STEREO_COR2_three_planets": "231d5635f57c4d66556674a83f6cbcef7dc94b51846e977c4c2dc3dc244096ac"
|
|
6
|
+
}
|