This notebook demonstrates the observations made by key instruments,e.g., SolO/EUI, Hinode/EIS, SolO/SPICE, and IRIS during the DKIST-SolO cooridinated observation campaign in Oct. 2022. This campagin would not be possible without the support from both DKIST and Solar Orbiter teams, including using the director discretionary time of DKIST. Many thanks to K. Barczynski, T. Schad, M. Janiver, C. Nelson, A. Tritschler, D. Müller, and other DKIST, Solar Orbiter, IRIS, and Hinode team members and planners to make it happen. A manuscript summaries the 2022 campaign is under preparation (Barczynski et al. in prep).
This study focuses on upflow regions at active region boundaries, which is beyond the FOVs of DKIST/VBI and ViSP. Additionally, DKIST/Cryo-NIRSP data is still under processing. Therefore, we choose not to present DKIST data in this notebook. The timeline and FOVs of the key observations analyzed in this study are presented in Figure 2.
Note: The internal hyperlink only works on GitHub Pages or nbviewer. Do not click when viewing the notebook on GitHub.
import sunpy
import sunpy.map
import numpy as np
import pandas as pd
import sunpy.net.attrs as a
from sunpy.net import Fido
import sunpy_soar
from astropy.time import Time
import astropy.units as u
from astropy.coordinates import SkyCoord
from astropy.visualization import ImageNormalize, AsinhStretch
from sunpy.coordinates import (propagate_with_solar_surface,
Helioprojective,
get_horizons_coord)
import requests
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import matplotlib.dates as mdates
from matplotlib import rc_context, rcParams
import matplotlib.patheffects as path_effects
import matplotlib.dates as mdates
import matplotlib.patches as patches
from sunraster.instr.spice import read_spice_l2_fits
from scipy.spatial import ConvexHull
from sjireader import read_iris_sji
from itertools import chain
/tmp/ipykernel_7923/2422070338.py:7: UserWarning: could not determine sunpy_soar package version; this indicates a broken installation import sunpy_soar
ms_style_dict = {'text.usetex': True, 'font.family': 'serif', 'axes.linewidth': 1.2,
'xtick.major.width': 1.2, 'xtick.major.size': 4,
'ytick.major.width': 1.2, 'ytick.major.size': 4,
'xtick.minor.width': 1.2, 'xtick.minor.size': 2,
'ytick.minor.width': 1.2, 'ytick.minor.size': 2,
'xtick.direction': 'in', 'ytick.direction': 'in',
'text.latex.preamble': r'\usepackage[T1]{fontenc}'
r'\usepackage{amsmath}' r'\usepackage{siunitx}'
r'\sisetup{detect-all=True}' r'\usepackage{fixltx2e}'}
rcParams.update(ms_style_dict)
eis_list_file = "../../src/EIS/eis_obs_list.xlsx"
eis_list_df = pd.read_excel(eis_list_file, sheet_name="Sheet1")
eis_list_df = eis_list_df.replace({'stud_acr': {'HH_Flare+AR_180x152H': 'HH_Flare', 'HPW021VEL260x512v2': 'HPW021VEL'}})
eis_list_df
| obs_start | obs_end | texp | stud_acr | repeat | fovx | fovy | cdelt1 | des | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 2022-10-19 18:26:00 | 2022-10-19 22:37:00 | 10 | HH_Flare | 48 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 1 | 2022-10-20 03:44:00 | 2022-10-20 04:47:00 | 60 | DHB_007_v2 | 1 | 248 | 512 | 4 | slow scan, long slit, large FOV, more lines |
| 2 | 2022-10-20 07:05:00 | 2022-10-20 11:05:00 | 10 | HH_Flare | 40 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 3 | 2022-10-20 18:54:00 | 2022-10-20 20:03:00 | 10 | HH_Flare | 13 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 4 | 2022-10-20 23:43:00 | 2022-10-21 02:12:00 | 60 | DHB_007_v2 | 2 | 248 | 512 | 4 | slow scan, long slit, large FOV, more lines |
| 5 | 2022-10-21 03:15:00 | 2022-10-21 05:12:00 | 10 | HH_Flare | 22 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 6 | 2022-10-21 06:12:00 | 2022-10-21 17:14:00 | 10 | HH_Flare | 124 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 7 | 2022-10-21 18:14:00 | 2022-10-21 22:41:00 | 10 | HH_Flare | 50 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 8 | 2022-10-22 06:30:00 | 2022-10-22 07:35:00 | 60 | DHB_007_v2 | 1 | 248 | 512 | 4 | slow scan, long slit, large FOV, more lines |
| 9 | 2022-10-22 08:08:00 | 2022-10-22 10:43:00 | 10 | HH_Flare | 25 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 10 | 2022-10-22 11:18:00 | 2022-10-22 17:48:00 | 10 | HH_Flare | 63 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 11 | 2022-10-22 18:34:00 | 2022-10-22 19:27:00 | 10 | HH_Flare | 10 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 12 | 2022-10-22 21:40:00 | 2022-10-23 00:20:00 | 60 | DHB_007_v2 | 2 | 248 | 512 | 4 | slow scan, long slit, large FOV, more lines |
| 13 | 2022-10-23 00:44:00 | 2022-10-23 04:39:00 | 10 | EL_DHB_01 | 48 | 50 | 152 | 2 | fast scan, small step size and FOV, more line... |
| 14 | 2022-10-23 07:05:00 | 2022-10-23 17:56:00 | 10 | HH_Flare | 94 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 15 | 2022-10-23 19:01:00 | 2022-10-23 19:49:00 | 10 | HH_Flare | 11 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 16 | 2022-10-23 20:38:00 | 2022-10-23 23:19:00 | 60 | DHB_007_v2 | 2 | 248 | 512 | 4 | slow scan, long slit, large FOV, more lines |
| 17 | 2022-10-23 23:50:00 | 2022-10-24 00:51:00 | 40 | HPW021VEL | 1 | 261 | 512 | 3 | slow scan, long slit, large FOV, more lines |
| 18 | 2022-10-24 01:15:00 | 2022-10-24 02:16:00 | 60 | Atlas_60 | 1 | 120 | 160 | 2 | slow scan, small stepsize and FOV, full CCDs, ... |
| 19 | 2022-10-24 02:49:00 | 2022-10-24 03:50:00 | 40 | HPW021VEL | 1 | 261 | 512 | 3 | slow scan, long slit, large FOV, more lines |
| 20 | 2022-10-24 08:00:00 | 2022-10-24 17:22:00 | 10 | HH_Flare | 85 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 21 | 2022-10-24 18:08:00 | 2022-10-24 22:17:00 | 10 | HH_Flare | 33 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 22 | 2022-10-25 00:23:00 | 2022-10-25 02:52:00 | 60 | DHB_007_v2 | 2 | 248 | 512 | 4 | slow scan, long slit, large FOV, more lines |
| 23 | 2022-10-25 13:01:00 | 2022-10-25 16:13:00 | 10 | HH_Flare | 36 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 24 | 2022-10-25 18:34:00 | 2022-10-25 19:27:00 | 10 | HH_Flare | 10 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 25 | 2022-10-25 20:11:00 | 2022-10-25 22:52:00 | 60 | DHB_007_v2 | 2 | 248 | 512 | 4 | slow scan, long slit, large FOV, more lines |
| 26 | 2022-10-25 23:24:00 | 2022-10-26 03:18:00 | 10 | EL_DHB_01 | 48 | 50 | 152 | 2 | fast scan, small step size and FOV, more line... |
| 27 | 2022-10-26 07:13:00 | 2022-10-26 09:55:00 | 60 | DHB_007_v2 | 60 | 248 | 512 | 4 | slow scan, long slit, large FOV, more lines |
| 28 | 2022-10-26 15:44:00 | 2022-10-26 16:53:00 | 10 | HH_Flare | 13 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 29 | 2022-10-26 19:09:00 | 2022-10-26 23:21:00 | 10 | HH_Flare | 33 | 180 | 152 | 6 | fast, sparse scan, minimal lines |
| 30 | 2022-10-27 10:59:00 | 2022-10-27 15:43:00 | 10 | EL_DHB_01 | 58 | 50 | 152 | 2 | fast scan, small step size and FOV, more line... |
| 31 | 2022-10-28 11:30:00 | 2022-10-28 12:31:00 | 40 | HPW021VEL | 1 | 261 | 512 | 3 | slow scan, long slit, large FOV, more lines |
| 32 | 2022-10-28 13:00:00 | 2022-10-28 14:02:00 | 60 | Atlas_60 | 1 | 120 | 160 | 2 | slow scan, small stepsize and FOV, full CCDs, ... |
def get_hri_list(date_begin='2022-10-18', date_end='2022-10-26'):
instrument = a.Instrument("EUI")
time = a.Time(date_begin, date_end)
level = a.Level(2)
product = a.soar.Product("eui-hrieuv174-image") | a.soar.Product("eui-hrieuvzer-image")
result = Fido.search(instrument & time & level & product)
hri_time_slots = []
for result_ in result:
time_start = Time(result_['Start time'])
time_end = Time(result_['End time'])
for ii in range(8):
time_interval = Time((Time(date_begin) + ii*u.day, Time(date_begin) + (ii+1)*u.day))
time_start_subset = time_start[(time_start > time_interval[0]) & (time_start < time_interval[1])]
time_end_subset = time_end[(time_end > time_interval[0]) & (time_end < time_interval[1])]
if len(time_start_subset) > 0:
hri_time_slots.append(Time((np.min(time_start_subset), np.max(time_end_subset))))
return result, hri_time_slots
hri_list, hri_time_slots = get_hri_list()
def get_fsi_list(date_begin='2022-10-18', date_end='2022-10-26'):
instrument = a.Instrument("EUI")
time = a.Time(date_begin, date_end)
level = a.Level(2)
product = a.soar.Product("eui-fsi174-image")
result = Fido.search(instrument & time & level & product)
return result
fsi_list = get_fsi_list()
def get_phi_list(date_begin='2022-10-18', date_end='2022-10-26'):
instrument = a.Instrument("PHI")
time = a.Time(date_begin, date_end)
level = a.Level(2)
product = a.soar.Product("phi-hrt-blos")
result = Fido.search(instrument & time & level & product)
return result
phi_list = get_phi_list()
def get_spice_list(date_begin='2022-10-18', date_end='2022-10-26'):
instrument = a.Instrument("SPICE")
time = a.Time(date_begin, date_end)
level = a.Level(2)
product = a.soar.Product("spice-n-ras")
result = Fido.search(instrument & time & level & product)[0]
long_raster_mask = Time(result['End time']) - Time(result['Start time']) > 1*u.hr
return result[long_raster_mask], result[~long_raster_mask]
spice_long_list, spice_short_list = get_spice_list()
def get_iris_observe_ar(xcen, ycen, date_obs):
if isinstance(date_obs, str):
date_obs = Time(date_obs)
reference_point = SkyCoord(-900*u.arcsec,250*u.arcsec, frame="helioprojective", obstime=Time('2022-10-19T20:00'))
obs_frame = Helioprojective(observer="earth", obstime=date_obs)
with propagate_with_solar_surface(reference_point):
reference_point_rotate = reference_point.transform_to(obs_frame)
if np.sqrt((reference_point_rotate.Tx - xcen)**2 + (reference_point_rotate.Ty - ycen)**2) < 150*u.arcsec:
return True
def get_iris_list():
hcr = requests.get('https://www.lmsal.com/hek/hcr?cmd=search-events3&outputformat=json'
'&startTime=2022-10-19T00:00&stopTime=2022-10-26T00:00&hasData=true'
'&hideMostLimbScans=true&obsDesc=orbiter&limit=200')
hcr = hcr.json()
iris_time_interval_raster = []
iris_time_interval_sas = []
for event in hcr['Events']:
if 'stare' in event['goal']:
iris_time_interval_sas.append(Time((event['startTime'], event['stopTime'])))
elif 'raster' in event['goal']:
iris_time_interval_raster.append(Time((event['startTime'], event['stopTime'])))
return iris_time_interval_sas, iris_time_interval_raster
iris_time_intervals_sas, iris_time_intervals_raster = get_iris_list()
hri_174_map_1024 = sunpy.map.Map("../../src/coalign_map/20221024/hri_174_map_shifted_toaia.fits")
hri_174_map_1020 = sunpy.map.Map('../../src/coalign_map/20221020/hri_174_map_1915_shifted_toaia.fits')
aia_171_map_1024 = sunpy.map.Map("../../src/AIA/20221024/171/lvl15/aia.lev1_euv_12s.2022-10-24T192003Z.171.image.fits")
aia_171_map_1024_crop = aia_171_map_1024.submap(SkyCoord(-600*u.arcsec,-100*u.arcsec,frame=aia_171_map_1024.coordinate_frame),
top_right=SkyCoord(-100*u.arcsec,600*u.arcsec,frame=aia_171_map_1024.coordinate_frame))
aia_171_map_1020 = sunpy.map.Map("../../src/AIA/20221020/171/lvl15/aia.lev1_euv_12s.2022-10-20T192027Z.171.image.fits")
aia_171_map_1020_crop = aia_171_map_1020.submap(SkyCoord(-1150*u.arcsec,-50*u.arcsec,frame=aia_171_map_1020.coordinate_frame),
top_right=SkyCoord(-650*u.arcsec,650*u.arcsec,frame=aia_171_map_1020.coordinate_frame))
phi_los_map_1024_shifted = sunpy.map.Map("../../src/coalign_map/20221024/phi_los_map_shifted.fits")
eis_195_intmap_shift_1024 = sunpy.map.Map("../../src/EIS/DHB_007_v2/20221025T0023/sunpymaps/eis_195_intmap_shift.fits")
eis_hhflare_195_intmap_shift_1024 = sunpy.map.Map("../../src/coalign_map/20221024/eis_hhflare_195_intmap_shift.fits")
iris_1400_sji_2322_map_rotate_crop_shift_1024 = sunpy.map.Map("../../src/coalign_map/20221024/iris_1400_sji_2322_0_map_rotate_crop_shift.fits")
iris_1400_sji_1920_map_rotate_shift_1024 = sunpy.map.Map("../../src/coalign_map/20221024/iris_1400_sji_1920_map_rotate_shift.fits")
spice_NeVIII_map_rotate_1024 = sunpy.map.Map("../../src/coalign_map/20221024/spice_NeVIII_intmap_derot_repro_hrifov.fits")
eis_195_intmap_shift_1020 = sunpy.map.Map("../../src/coalign_map/20221020/eis_195_intmap_shift.fits")
phi_los_map_1020_shifted = sunpy.map.Map("../../src/coalign_map/20221020/phi_los_map_shifted_to_aia.fits")
#IRIS SJI 1400 images starting from 19:20 are well aligned with AIA 1700 so no need to shift
iris_1400_sji_1920_map_shift_1020 = read_iris_sji("../../src/IRIS/20221020/1905/iris_l2_20221020_190518_3640007428_SJI_1400_t000.fits",
index=Time(hri_174_map_1020.meta['date_ear']),sdo_rsun=True)
iris_1400_sji_2351_map_shift_1020 = sunpy.map.Map('../../src/coalign_map/20221020/iris_1400_map_2351_shifted.fits')
spice_NeVIII_map_rotate_1020 = sunpy.map.Map("../../src/coalign_map/20221020/spice_NeVIII_intmap_derot_repro_hrifov.fits")
def get_map_edge_coords(map, step=1):
map_edges = sunpy.map.map_edges(map)
x_pix = []
y_pix = []
if map_edges[1].shape[0] % step != 0:
iter_1 = chain(range(0, map_edges[1].shape[0], step), [map_edges[1].shape[0]-1])
else:
iter_1 = range(0, map_edges[1].shape[0], step)
for ii in iter_1:
x_pix.append(map_edges[1][ii,0].value)
y_pix.append(map_edges[1][ii,1].value)
if map_edges[3].shape[0] % step != 0:
iter_3 = chain(range(0, map_edges[3].shape[0], step), [map_edges[3].shape[0]-1])
else:
iter_3 = range(0, map_edges[3].shape[0], step)
for ii in iter_3:
x_pix.append(map_edges[3][ii,0].value)
y_pix.append(map_edges[3][ii,1].value)
if map_edges[0].shape[0] % step != 0:
iter_0 = chain(range(map_edges[0].shape[0]-1, -1, -step), [0])
else:
iter_0 = range(map_edges[0].shape[0]-1, -1, -step)
for ii in iter_0:
x_pix.append(map_edges[0][ii,0].value)
y_pix.append(map_edges[0][ii,1].value)
if map_edges[2].shape[0] % step != 0:
iter_2 = chain(range(map_edges[2].shape[0]-1, -1, -step), [0])
else:
iter_2 = range(map_edges[2].shape[0]-1, -1, -step)
for ii in iter_2:
x_pix.append(map_edges[2][ii,0].value)
y_pix.append(map_edges[2][ii,1].value)
return map.pixel_to_world(x_pix*u.pix,y_pix*u.pix)
def get_map_edge_coords_after_propagate(map, target_map, replace_off_limb=True, step=2):
map_edge_coords = get_map_edge_coords(map,step=step)
map_edge_coords_propagated = []
for map_edge_coord in map_edge_coords:
if sunpy.map.coordinate_is_on_solar_disk(map_edge_coord):
with propagate_with_solar_surface(rotation_model='rigid'):
map_edge_coord_propagate = map_edge_coord.transform_to(target_map.coordinate_frame)
map_edge_coords_propagated.append(map_edge_coord_propagate)
elif replace_off_limb:
with Helioprojective.assume_spherical_screen(target_map.observer_coordinate, only_off_disk=True):
with propagate_with_solar_surface(rotation_model='rigid'):
map_edge_coords_propagated.append(map_edge_coord.transform_to(target_map.coordinate_frame))
return SkyCoord(map_edge_coords_propagated)
def get_spice_map_edge_coords(spice_map):
pix_y, pix_x = np.indices(spice_map.data.shape)
mask = np.isfinite(spice_map.data)
pix_x = pix_x[mask].flatten()
pix_y = pix_y[mask].flatten()
points = np.stack((pix_x, pix_y), axis=-1)
hull = ConvexHull(points)
hull_vertices = np.append(hull.vertices, hull.vertices[0])
return spice_map.pixel_to_world(points[hull_vertices,0]*u.pix, points[hull_vertices,1]*u.pix)
# calculate the edges of some maps including off-limb corona before the plotting because it is time consuming
eis_195_intmap_edge_in_aia = get_map_edge_coords_after_propagate(eis_195_intmap_shift_1020, aia_171_map_1020_crop,step=2)
WARNING: SunpyDeprecationWarning: The assume_spherical_screen function is deprecated and may be removed in a future version.
Use sunpy.coordinates.screens.SphericalScreen instead. [sunpy.util.decorators]
2025-04-08 11:37:27 - sunpy - WARNING: SunpyDeprecationWarning: The assume_spherical_screen function is deprecated and may be removed in a future version.
Use sunpy.coordinates.screens.SphericalScreen instead.
WARNING: SunpyDeprecationWarning: The assume_spherical_screen function is deprecated and may be removed in a future version.
Use sunpy.coordinates.screens.SphericalScreen instead. [sunpy.util.decorators]
2025-04-08 11:37:28 - sunpy - WARNING: SunpyDeprecationWarning: The assume_spherical_screen function is deprecated and may be removed in a future version.
Use sunpy.coordinates.screens.SphericalScreen instead.
iris_1400_sji_1920_edge_in_aia_1020 = get_map_edge_coords_after_propagate(iris_1400_sji_1920_map_shift_1020, aia_171_map_1020_crop,step=8)
WARNING: SunpyDeprecationWarning: The assume_spherical_screen function is deprecated and may be removed in a future version.
Use sunpy.coordinates.screens.SphericalScreen instead. [sunpy.util.decorators]
2025-04-08 11:37:45 - sunpy - WARNING: SunpyDeprecationWarning: The assume_spherical_screen function is deprecated and may be removed in a future version.
Use sunpy.coordinates.screens.SphericalScreen instead.
iris_1400_sji_2351_edge_in_aia_1020 = get_map_edge_coords_after_propagate(iris_1400_sji_2351_map_shift_1020, aia_171_map_1020_crop,step=16)
WARNING: SunpyDeprecationWarning: The assume_spherical_screen function is deprecated and may be removed in a future version.
Use sunpy.coordinates.screens.SphericalScreen instead. [sunpy.util.decorators]
2025-04-08 11:38:02 - sunpy - WARNING: SunpyDeprecationWarning: The assume_spherical_screen function is deprecated and may be removed in a future version.
Use sunpy.coordinates.screens.SphericalScreen instead.
solar_orbiter_loc = get_horizons_coord('solar orbiter',
{'start':'2022-10-18',
'stop':'2022-10-26T12:00:00',
'step':'1h'})
earth_loc = get_horizons_coord('399',
{'start':'2022-10-18',
'stop':'2022-10-26T12:00:00',
'step':'1h'})
2025-04-08 11:38:07 - sunpy - INFO: Obtained JPL HORIZONS location for Solar Orbiter (spacecraft) (-144)
INFO: Obtained JPL HORIZONS location for Solar Orbiter (spacecraft) (-144) [sunpy.coordinates.ephemeris]
2025-04-08 11:38:08 - sunpy - INFO: Obtained JPL HORIZONS location for Earth (399)
INFO: Obtained JPL HORIZONS location for Earth (399) [sunpy.coordinates.ephemeris]
np.linalg.norm(solar_orbiter_loc.cartesian.xyz.to_value(u.m), axis=0).shape
(205,)
def calc_angular_sep(coords1, coords2):
coords1_vec = coords1.cartesian.xyz.to_value(u.m)
coords2_vec = coords2.cartesian.xyz.to_value(u.m)
coords1_vec = coords1_vec / np.linalg.norm(coords1_vec, axis=0)
coords2_vec = coords2_vec / np.linalg.norm(coords2_vec, axis=0)
cos_sep = np.einsum('in,in->n', coords1_vec, coords2_vec)
return np.rad2deg(np.arccos(cos_sep))
solo_earth_sep = calc_angular_sep(solar_orbiter_loc, earth_loc)
fig = plt.figure(figsize=(10,9.5),constrained_layout=True)
gs1 = gridspec.GridSpec(3,3, figure=fig, height_ratios=[2,1,2],
width_ratios=[5,5*5/7,2],
hspace=0.01)
# gs10 = gs1[:2].subgridspec(1,2)
# gs20 = gs1[2].subgridspec(1,5)
# gs30 = gs1[3:].subgridspec(1,2)
ax_t = fig.add_subplot(gs1[1,:2])
ax_hgs_lon = ax_t.twinx()
ax_hri_1024 = fig.add_subplot(gs1[0,0], projection=hri_174_map_1024)
ax_hri_1020 = fig.add_subplot(gs1[2,0], projection=hri_174_map_1020)
ax_aia_1024 = fig.add_subplot(gs1[0,1], projection=aia_171_map_1024_crop)
ax_aia_1020 = fig.add_subplot(gs1[2,1], projection=aia_171_map_1020_crop)
hri_174_map_1024.plot(axes=ax_hri_1024, cmap="sdoaia171", title=False,
norm=ImageNormalize(vmin=np.nanpercentile(hri_174_map_1024.data, 0.2),
vmax=np.nanpercentile(hri_174_map_1024.data, 99.8),
stretch=AsinhStretch(0.05)))
text_hri_1024 = ax_hri_1024.text(1.04,0.97, r'\textbf{' + \
r'SolO EUI/HRI\textsubscript{EUV} 17.4\,nm' + \
r'}' + \
"\n" + \
r'\textbf{' + \
r'$t_{{\mathrm{{obs}},\oplus}}$: {}'.format(hri_174_map_1024.meta['date_ear'][:-4]) + \
r'}',
transform=ax_hri_1024.transAxes, color='white',
fontsize=10, ha='right', va='top',
path_effects=[path_effects.Stroke(linewidth=1.2, foreground='black'),
path_effects.Normal()])
hri_174_map_1020.plot(axes=ax_hri_1020, cmap="sdoaia171", title=False,
norm=ImageNormalize(vmin=np.nanpercentile(hri_174_map_1020.data, 0.2),
vmax=np.nanpercentile(hri_174_map_1020.data, 99.8),
stretch=AsinhStretch(0.05)))
text_hri_1020 = ax_hri_1020.text(1.04,0.97, r'\textbf{' + \
r'SolO EUI/HRI\textsubscript{EUV} 17.4\,nm' + \
r'}' + \
"\n" + \
r'\textbf{' + \
r'$t_{{\mathrm{{obs}},\oplus}}$: {}'.format(hri_174_map_1020.meta['date_ear'][:-4]) + \
r'}',
transform=ax_hri_1020.transAxes, color='white',
fontsize=10, ha='right', va='top',
path_effects=[path_effects.Stroke(linewidth=1.2, foreground='black'),
path_effects.Normal()])
aia_171_map_1024_crop.plot(axes=ax_aia_1024, cmap="sdoaia171", title=False,
norm=ImageNormalize(vmin=np.nanpercentile(aia_171_map_1024_crop.data, 0.2),
vmax=np.nanpercentile(aia_171_map_1024_crop.data, 99.8),
stretch=AsinhStretch(0.05)))
text_aia_1024 = ax_aia_1024.text(1.04,0.97, r'\textbf{' + \
r'SDO/AIA 17.1\,nm' + \
r'}' + \
"\n" + \
r'\textbf{' + \
r'{}'.format(aia_171_map_1024_crop.date.isot[:-4]) + \
r'}',
transform=ax_aia_1024.transAxes, color='white',
fontsize=10, ha='right', va='top',
path_effects=[path_effects.Stroke(linewidth=1.2, foreground='black'),
path_effects.Normal()])
aia_171_map_1020_crop.plot(axes=ax_aia_1020, cmap="sdoaia171", title=False,
norm=ImageNormalize(vmin=np.nanpercentile(aia_171_map_1020_crop.data, 0.2),
vmax=np.nanpercentile(aia_171_map_1020_crop.data, 99.8),
stretch=AsinhStretch(0.05)))
text_aia_1020 = ax_aia_1020.text(1.04,0.97, r'\textbf{' + \
r'SDO/AIA 17.1\,nm' + \
r'}' + \
"\n" + \
r'\textbf{' + \
r'{}'.format(aia_171_map_1020_crop.date.isot[:-4]) + \
r'}',
transform=ax_aia_1020.transAxes, color='white',
fontsize=10, ha='right', va='top',
path_effects=[path_effects.Stroke(linewidth=1.2, foreground='black'),
path_effects.Normal()])
with propagate_with_solar_surface(rotation_model='rigid'):
ax_hri_1024_bounds = ax_hri_1024.axis()
ax_aia_1024_bounds = ax_aia_1024.axis()
# line_eis_hhflare_hri_1024 = ax_hri_1024.plot_coord(get_map_edge_coords(eis_hhflare_195_intmap_shift_1024),
# color="#BDC0BA",lw=1,ls="--",alpha=0.9,label=r'HH_Flare')
line_eis_dhb_1024 = ax_hri_1024.plot_coord(get_map_edge_coords(eis_195_intmap_shift_1024),
color="#E83015",lw=1.5,ls="--",alpha=0.9,label=r'DHB_007_v2',
path_effects=[path_effects.SimpleLineShadow(offset=(-0.4,-0.4)),
path_effects.Normal()])
line_iris_raster_1024 = ax_hri_1024.plot_coord(get_map_edge_coords(iris_1400_sji_2322_map_rotate_crop_shift_1024),
color="#F8C3CD",lw=1.5,ls="--",alpha=0.9,label=r'IRIS/SJI',
path_effects=[path_effects.SimpleLineShadow(offset=(-0.4,-0.4)),
path_effects.Normal()])
# line_iris_sas_1024 = ax_hri_1024.plot_coord(get_map_edge_coords(iris_1400_sji_1920_map_rotate_shift_1024),
# color="#F7D842",lw=1.5,ls="--",alpha=0.9,label=r'IRIS/SJI S\&S')
line_phi_1024 = ax_hri_1024.plot_coord(get_map_edge_coords(phi_los_map_1024_shifted),
color="#58B2DC",lw=1.5,ls="--",alpha=0.9,label=r'PHI/HRT',
path_effects=[path_effects.SimpleLineShadow(offset=(-0.4,-0.4)),
path_effects.Normal()])
line_spice_1024 = ax_hri_1024.plot_coord(get_spice_map_edge_coords(spice_NeVIII_map_rotate_1024),
color="#1B813E",lw=1.5,ls="--",alpha=0.9,label=r'SPICE LC',
path_effects=[path_effects.SimpleLineShadow(offset=(-0.4,-0.4)),
path_effects.Normal()])
line_hri_1024 = ax_aia_1024.plot_coord(get_map_edge_coords(hri_174_map_1024),
color="#E03C8A",lw=1.5,ls="--",alpha=0.9,label=r'EUI/HRI',
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
# ax_aia_1024.plot_coord(get_map_edge_coords(eis_hhflare_195_intmap_shift_1024),
# color="#BDC0BA",lw=1,ls="--",alpha=0.9)
ax_aia_1024.plot_coord(get_map_edge_coords(eis_195_intmap_shift_1024),
color="#E83015",lw=1.5,ls="--",alpha=0.9,
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
ax_aia_1024.plot_coord(get_map_edge_coords(iris_1400_sji_2322_map_rotate_crop_shift_1024),
color="#F8C3CD",lw=1.5,ls="--",alpha=0.9,
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
# ax_aia_1024.plot_coord(get_map_edge_coords(iris_1400_sji_1920_map_rotate_shift_1024),
# color="#F7D842",lw=1,ls="--",alpha=0.9)
ax_aia_1024.plot_coord(get_map_edge_coords(phi_los_map_1024_shifted),
color="#58B2DC",lw=1.5,ls="--",alpha=0.9,
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
ax_aia_1024.plot_coord(get_spice_map_edge_coords(spice_NeVIII_map_rotate_1024),
color="#1B813E",lw=1.5,ls="--",alpha=0.9,
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
ax_hri_1024.axis(ax_hri_1024_bounds)
ax_aia_1024.axis(ax_aia_1024_bounds)
ax_aia_1024_legend_line_list = [line_eis_dhb_1024[0],line_iris_raster_1024[0],
line_phi_1024[0],line_spice_1024[0],line_hri_1024[0]]
# delete FOVs of observations not covering the upflow regions
# ax_aia_1024_legend_line_list = [line_eis_hhflare_hri_1024[0],line_eis_dhb_1024[0],line_iris_raster_1024[0],line_iris_sas_1024[0],
# line_phi_1024[0],line_spice_1024[0],line_hri_1024[0]]
ax_aia_1024.legend(ax_aia_1024_legend_line_list, [ln.get_label() for ln in ax_aia_1024_legend_line_list],
ncol=1,bbox_to_anchor=(1.1,0.1,0.3,0.93), frameon=False)
ax_hri_1020_bounds = ax_hri_1020.axis()
ax_aia_1020_bounds = ax_aia_1020.axis()
with propagate_with_solar_surface(rotation_model='rigid'):
line_eis_dhb_1020 = ax_hri_1020.plot_coord(get_map_edge_coords(eis_195_intmap_shift_1020),
color="#E83015",lw=1.5,ls="--",alpha=0.9,label=r'DHB_007_v2',
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
line_aia_limb = aia_171_map_1020.draw_limb(axes=ax_hri_1020, color='#B5CAA0', lw=1.5, alpha=0.9, ls='--',
label='SDO/AIA Limb',zorder=2,
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
line_hri_1020 = ax_aia_1020.plot_coord(get_map_edge_coords(hri_174_map_1020),
color="#E03C8A",lw=1.5,ls="--",alpha=0.9,label=r'EUI/HRI',
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()]
)
line_phi_1020 = ax_hri_1020.plot_coord(get_map_edge_coords(phi_los_map_1020_shifted),
color="#58B2DC",lw=1.5,ls="--",alpha=0.9,label=r'PHI/HRT',
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
ax_aia_1020.plot_coord(get_map_edge_coords(phi_los_map_1020_shifted),
color="#58B2DC",lw=1.5,ls="--",alpha=0.9,
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
line_iris_hc_raster = ax_hri_1020.plot_coord(get_map_edge_coords(iris_1400_sji_1920_map_shift_1020),
color="#F8C3CD",lw=1.5,ls="--",alpha=0.9,label=r'IRIS/SJI',
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
# line_iris_lc_raster = ax_hri_1020.plot_coord(get_map_edge_coords(iris_1400_sji_2351_map_shift_1020),
# color="#FEDFE1",lw=1,ls="--",alpha=0.9,label=r'IRIS/SJI LC Raster')
line_spice_1020 = ax_hri_1020.plot_coord(get_spice_map_edge_coords(spice_NeVIII_map_rotate_1020),
color="#1B813E",lw=1.5,ls="--",alpha=0.9,label=r'SPICE LC',
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
ax_aia_1020.plot_coord(get_spice_map_edge_coords(spice_NeVIII_map_rotate_1020),
color="#1B813E",lw=1.5,ls="--",alpha=0.9,
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
ax_aia_1020.plot_coord(eis_195_intmap_edge_in_aia,
color="#E83015",lw=1.5,ls="--",alpha=0.9,
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
ax_aia_1020.plot_coord(iris_1400_sji_1920_edge_in_aia_1020,
color="#F8C3CD",lw=1.5,ls="--",alpha=0.9,
path_effects=[path_effects.SimpleLineShadow(offset=(0.4,-0.4)),
path_effects.Normal()])
# ax_aia_1020.plot_coord(iris_1400_sji_2351_edge_in_aia_1020,
# color="#FEDFE1",lw=1,ls="--",alpha=0.9)
ax_aia_1020_legend_line_list = [line_eis_dhb_1020[0],line_aia_limb[0],line_hri_1020[0],line_phi_1020[0],
line_iris_hc_raster[0],line_spice_1020[0]]
# ax_aia_1020_legend_line_list = [line_eis_dhb_1020[0],line_aia_limb[0],line_hri_1020[0],line_phi_1020[0],
# line_iris_hc_raster[0],line_iris_lc_raster[0],line_spice_1020[0]]
ax_aia_1020.legend(ax_aia_1020_legend_line_list, [ln.get_label() for ln in ax_aia_1020_legend_line_list],
ncol=1,bbox_to_anchor=(1.1,0.1,0.3,0.93), frameon=False)
ax_hri_1020.axis(ax_hri_1020_bounds)
ax_aia_1020.axis(ax_aia_1020_bounds)
for ax_ in [ax_hri_1024, ax_aia_1024, ax_aia_1020]:
ax_.set_ylabel(' ')
ax_.set_xlabel(' ')
color_dict = {"HH_Flare":"grey","DHB_007_v2":"#CB4042",
"EL_DHB_01":"#89916B","HPW021VEL":"#66327C",
"Atlas_60":"#58B2DC"}
start_y_fraction = 0.1
end_y_fraction = 0.9
space_to_data_ratio = 0.618
data_height_fraction = (end_y_fraction - start_y_fraction)/(5 + 4*space_to_data_ratio)
space_height_fraction = data_height_fraction * space_to_data_ratio
for ii, row_ in eis_list_df.iterrows():
ax_t.axvspan(row_["obs_start"], row_["obs_end"],
start_y_fraction,
start_y_fraction + data_height_fraction, alpha=0.5, color=color_dict[row_["stud_acr"]],
label=row_["stud_acr"],linewidth=0.1)
for hri_slot in hri_time_slots:
ax_t.axvspan(hri_slot[0].to_datetime(), hri_slot[1].to_datetime(),
start_y_fraction + 1*(data_height_fraction + space_height_fraction),
start_y_fraction + 1*(data_height_fraction + space_height_fraction) + data_height_fraction,
alpha=0.5, color="#E79460",label="EUI/HRI",
linewidth=0.1)
for spice_long_ in spice_long_list:
ax_t.axvspan(spice_long_["Start time"], spice_long_["End time"],
start_y_fraction + 2*(data_height_fraction + space_height_fraction),
start_y_fraction + 2*(data_height_fraction + space_height_fraction) + data_height_fraction,
alpha=0.5, color="#227D51",label="SPICE LC",
linewidth=0.1)
for spice_short_ in spice_short_list:
ax_t.axvspan(spice_short_["Start time"], spice_short_["End time"],
start_y_fraction + 2*(data_height_fraction + space_height_fraction),
start_y_fraction + 2*(data_height_fraction + space_height_fraction) + data_height_fraction,
alpha=0.5, color="#B28FCE",label="SPICE HC",
linewidth=0.1)
for iris_time_intervals_sas_ in iris_time_intervals_sas:
ax_t.axvspan(iris_time_intervals_sas_[0].to_datetime(), iris_time_intervals_sas_[1].to_datetime(),
start_y_fraction + 3*(data_height_fraction + space_height_fraction),
start_y_fraction + 3*(data_height_fraction + space_height_fraction) + data_height_fraction,
alpha=0.5, color="#F7D842",label=r"IRIS S\&S",
linewidth=0.1)
for iris_time_intervals_raster_ in iris_time_intervals_raster:
ax_t.axvspan(iris_time_intervals_raster_[0].to_datetime(), iris_time_intervals_raster_[1].to_datetime(),
start_y_fraction + 3*(data_height_fraction + space_height_fraction),
start_y_fraction + 3*(data_height_fraction + space_height_fraction) + data_height_fraction,
alpha=1, color="#FEDFE1",label="IRIS Raster",
linewidth=0.1)
for phi_ in phi_list[0]:
ax_t.axvspan(Time(phi_["Start time"]).to_datetime(), Time(phi_["End time"]).to_datetime(),
start_y_fraction + 4*(data_height_fraction + space_height_fraction),
start_y_fraction + 4*(data_height_fraction + space_height_fraction) + data_height_fraction,
alpha=0.5, color="#86C166",label="PHI/HRT", linewidth=0.5)
ax_t.set_xlim(Time("2022-10-18").to_datetime(), Time("2022-10-26 12:00").to_datetime())
ax_t.set_ylabel('Instruments')
ax_t.set_xlabel('Time (DD/MM/2022)')
ax_hgs_lon.plot(solar_orbiter_loc.obstime.to_datetime(), -solo_earth_sep, color='#B5CAA0', lw=1,
zorder=0, alpha=0.5,ls='--')
ax_hgs_lon.set_ylabel('Ang. Sep. SolO/Earth (deg)')
handles, labels = ax_t.get_legend_handles_labels()
temp_dict = {k:v for k,v in zip(labels,handles)}
ax_t.legend(temp_dict.values(), temp_dict.keys(), loc="upper right", bbox_to_anchor=(1.1,0.1,0.3,1), ncol=1,
mode="expand", frameon=False)
ax_t.xaxis.set_major_formatter(mdates.DateFormatter('%d/%m'))
ax_t.set_yticks([start_y_fraction + ii*(data_height_fraction + space_height_fraction) + data_height_fraction/2
for ii in range(5)])
ax_t.set_yticklabels(["EIS","EUI/HRI","SPICE","IRIS", "PHI/HRT"])
time_range_1024 = Time(['2022-10-24T19:00:00','2022-10-25T02:52:00'])
ax_t_top = ax_t.secondary_xaxis('top', functions=(lambda x: x, lambda x: x))
fig.canvas.draw_idle() # let the figure draw first to get the correct tick positions
ax_t_top.set_xticklabels([])
ax_t_top.set_xticks(np.concatenate((ax_t_top.get_xticks(), time_range_1024.plot_date)))
flag_xtick_index = 0
for ii, (ax_t_top_xtickline, ax_t_top_xticklabel) in enumerate(zip(filter(lambda x: (x.get_marker() == 3),
ax_t_top.get_xticklines()),
ax_t_top.get_xticklabels())):
if np.isclose(ax_t_top_xtickline.get_xdata()[0],time_range_1024.plot_date,rtol=1e-10).any():
ax_t_top_xtickline.set_markeredgecolor("red")
ax_t_top_xtickline.set_markeredgewidth(3)
if flag_xtick_index == 0:
connect_patch = patches.ConnectionPatch(xyA=(ax_t_top_xtickline.get_xdata()[0], 1), xyB=(0,0),
coordsA="data", coordsB="axes fraction",axesA=ax_t, axesB=ax_hri_1024, color="red",
zorder=-1)
# somehow annotate on axes will break the gridspec and constrained_layout
# ax_t.annotate('', xy=(ax_t_top_xtickline.get_xdata()[0], 1), xytext=(0, 0),
# xycoords=ax_t_top.transData, textcoords=ax_hri_1024.transAxes,
# arrowprops=dict(facecolor="red", edgecolor="red", arrowstyle='-', shrinkA=0, shrinkB=0,alpha=0.5,zorder=5,
# lw=1.5))
flag_xtick_index += 1
else:
connect_patch = patches.ConnectionPatch(xyA=(ax_t_top_xtickline.get_xdata()[0], 1), xyB=(1,0),
coordsA="data", coordsB="axes fraction",axesA=ax_t, axesB=ax_aia_1024, color="red",
zorder=-1)
fig.add_artist(connect_patch)
time_range_1020 = Time(['2022-10-20T19:00:00','2022-10-21T03:00:00'])
ax_t_bottom = ax_t.secondary_xaxis('bottom', functions=(lambda x: x, lambda x: x))
ax_t_bottom.set_xticks(time_range_1020.plot_date)
ax_t_bottom.set_xticklabels([])
fig.canvas.draw_idle() # let the figure draw first to get the correct tick positions
flag_xtick_index = 0
for ii, (ax_t_bottom_xtickline, ax_t_bottom_xticklabel) in enumerate(zip(filter(lambda x: (x.get_marker() == 2),
ax_t_bottom.get_xticklines()),
ax_t_bottom.get_xticklabels())):
ax_t_bottom_xtickline.set_markeredgecolor("red")
ax_t_bottom_xtickline.set_markeredgewidth(3)
ax_t_bottom_xticklabel.set_visible(False)
if ii == 0:
connect_patch = patches.ConnectionPatch(xyA=(ax_t_bottom_xtickline.get_xdata()[0], 0), xyB=(0,1),
coordsA="data", coordsB="axes fraction",axesA=ax_t, axesB=ax_hri_1020, color="red",
zorder=-1)
else:
connect_patch = patches.ConnectionPatch(xyA=(ax_t_bottom_xtickline.get_xdata()[0], 0), xyB=(1,1),
coordsA="data", coordsB="axes fraction",axesA=ax_t, axesB=ax_aia_1020, color="red",
zorder=-1)
fig.add_artist(connect_patch)
ax_hri_1024.text(0.03,0.97,r'\textbf{a)}',color='white',transform=ax_hri_1024.transAxes,fontsize=12,
path_effects=[path_effects.Stroke(linewidth=1.2, foreground='black'),
path_effects.Normal()],ha='left',va='top')
ax_aia_1024.text(0.03*7/5,0.97,r'\textbf{b)}',color='white',transform=ax_aia_1024.transAxes,fontsize=12,
path_effects=[path_effects.Stroke(linewidth=1.2, foreground='black'),
path_effects.Normal()],ha='left',va='top')
ax_t.text(0.03*5/12,0.96,r'\textbf{c)}',color='black', transform=ax_t.transAxes,fontsize=12,
ha='left',va='top')
ax_hri_1020.text(0.03,0.97,r'\textbf{d)}',color='white',transform=ax_hri_1020.transAxes,fontsize=12,
path_effects=[path_effects.Stroke(linewidth=1.2, foreground='black'),
path_effects.Normal()],ha='left',va='top')
ax_aia_1020.text(0.03*7/5,0.97,r'\textbf{e)}',color='white',transform=ax_aia_1020.transAxes,fontsize=12,
path_effects=[path_effects.Stroke(linewidth=1.2, foreground='black'),
path_effects.Normal()],ha='left',va='top')
plt.savefig('../../figs/ms_eis_eui_upflow/fov_summary.pdf', bbox_inches='tight', dpi=300)
# plt.show() # Some how I need to add this line to make the jupyter notebook preview has the correct font
WARNING: SunpyMetadataWarning: Missing metadata for observer: assuming Earth-based observer. For frame 'heliographic_stonyhurst' the following metadata is missing: hglt_obs,hgln_obs,dsun_obs For frame 'heliographic_carrington' the following metadata is missing: crln_obs,crlt_obs,dsun_obs [sunpy.map.mapbase] 2025-04-08 11:38:11 - sunpy - WARNING: SunpyMetadataWarning: Missing metadata for observer: assuming Earth-based observer. For frame 'heliographic_stonyhurst' the following metadata is missing: hglt_obs,hgln_obs,dsun_obs For frame 'heliographic_carrington' the following metadata is missing: crln_obs,crlt_obs,dsun_obs