import os
import sys
import time
from datetime import datetime, timedelta
import astropy.units as u
from matplotlib.dates import AutoDateFormatter, AutoDateLocator
# Function to format the y-axis as integer frequencies
[docs]
def setup_time_axis(ax, start, end, minticks=5, maxticks=10):
"""
Set up the time axis for a plot with specific tick intervals based on the time range,
ensuring a minimum and maximum number of ticks.
:param ax: The axis to set up the time axis for.
:type ax: matplotlib.axes.Axes
:param start: The start time of the plot.
:type start: astropy.time.Time
:param end: The end time of the plot.
:type end: astropy.time.Time
:param minticks: Minimum number of major ticks desired.
:type minticks: int
:param maxticks: Maximum number of major ticks desired.
:type maxticks: int
"""
# Calculate the total time range in minutes
total_minutes = (end - start).to(u.min).value
# Create locator for major ticks
major_locator = AutoDateLocator(minticks=minticks, maxticks=maxticks)
ax.xaxis.set_major_locator(major_locator)
# Create formatter for major ticks
formatter = AutoDateFormatter(major_locator)
if total_minutes < 1:
formatter.scaled[1.0] = '%H:%M:%S.%f' # Show milliseconds for very short durations
elif total_minutes < 60:
formatter.scaled[1.0] = '%H:%M:%S' # Show seconds for short durations
else:
formatter.scaled[1.0] = '%H:%M' # For longer durations, show only hours and minutes
formatter.scaled[1 / 24] = '%H:%M'
formatter.scaled[1 / (24 * 60)] = '%H:%M'
formatter.scaled[1 / (24 * 60 * 60)] = '%H:%M:%S'
ax.xaxis.set_major_formatter(formatter)
# Create locator for minor ticks
minor_locator = AutoDateLocator(minticks=minticks * 5, maxticks=minticks * 5) # More minor ticks
ax.xaxis.set_minor_locator(minor_locator)
# Set x-axis limits
ax.set_xlim(start.plot_date, end.plot_date)
[docs]
def plot(timestamp=None, timerange=None, figdir='/common/lwa/spec_v2/daily/', figname=None, combine=True,
clip=[10, 99.995], clip_ovrolwa=None, clip_eovsa=None, add_logo=False, fast_plot=True, interactive=False,
overwrite=False, fix_tlim=False, fix_vrange=False):
"""
Plot the OVRO-LWA and EOVSA spectrograms along with STIX and GOES light curves for a given timestamp or time range.
:param timestamp: The timestamp for the data to be plotted. If not provided, the current UTC time is used.
:type timestamp: datetime.datetime, optional
:param timerange: The time range to be plotted. If provided, it overrides the timestamp.
:type timerange: list of datetime.datetime, optional
:param figdir: Directory where the figures will be saved, defaults to '/common/lwa/spec_v2/daily/'.
:type figdir: str, optional
:param figname: The file name for the combined figure. If not provided, it is generated based on the timestamp.
:type figname: str, optional
:param combine: If True, combine all plots into a single figure, defaults to True. Otherwise, save each plot (OVRO-LWA, EOVSA, STIX, GOES) separately.
:type combine: bool, optional
:param clip: Default percentile values applied to both EOVSA and OVRO-LWA spectrograms when dataset-specific values are not provided, defaults to [10, 99.995].
:type clip: list of float, optional
:param clip_ovrolwa: Percentile values for clipping the OVRO-LWA spectrogram. Falls back to ``clip`` if not provided.
:type clip_ovrolwa: list of float, optional
:param clip_eovsa: Percentile values for clipping the EOVSA spectrogram. Falls back to ``clip`` if not provided.
:type clip_eovsa: list of float, optional
:param add_logo: If True, add logos to the plots, defaults to False.
:type add_logo: bool, optional
:param fast_plot: If True, use fast plotting methods, defaults to True. If you want to plot the full resolution, set it to False. But it will take longer to plot. If the time range is less than 30 minutes, it will automatically set to False.
:type fast_plot: bool, optional
:param interactive: If False, suppress plot display and use the 'Agg' backend, defaults to False.
:type interactive: bool, optional
:return: List of file paths to the saved figures.
:rtype: list of str
Examples:
---------
from suncasa.utils import ovsa_spectrogram as ovsp
from datetime import datetime
# Example 1: Plotting the synoptic spectrogram for 2024 July 31
ovsp.plot(datetime(2024, 7, 31), figdir='/data1/workdir/')
# Example 2: Plotting the synoptic spectrogram for a specific time interval on 2024 July 31
ovsp.plot(timerange=[datetime(2024, 7, 31, 17, 20), datetime(2024, 7, 31, 20, 40)],
figdir='/data1/workdir/', fast_plot=True, clip=[5, 99.995])
# Example 3: Plotting the synoptic spectrogram for a specific time interval on 2024 July 31 in full resolution
ovsp.plot(timerange=[datetime(2024, 7, 31, 18, 20), datetime(2024, 7, 31, 18, 40)],
figdir='/data1/workdir/', fast_plot=False, clip=[5, 99.995])
# Example 4: Plotting the synoptic spectrogram for a specific time interval on 2025 December 10 and saving to web directory
ovsp.plot(timerange=[datetime(2025, 12, 10, 22, 0), datetime(2025, 12, 10, 23, 0)],
figdir=f'/common/webplots/SynopticImg/eovsamedia/eovsa-browser/2025/12/10/', fast_plot=False, clip=[10, 99.5])
"""
t0 = time.time()
if clip is None:
clip = [10, 99.995]
if clip_ovrolwa is None:
clip_ovrolwa = clip
if clip_eovsa is None:
clip_eovsa = clip
import numpy as np
import pandas as pd
import sunpy.timeseries as ts
from astropy.time import Time
from stixdcpy.quicklook import LightCurves
from sunpy.net import Fido
from sunpy.net import attrs as a
from sunpy.time import parse_time
from suncasa.dspec import dspec as ds
import matplotlib
import matplotlib.colors as mcolors
from matplotlib import pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.ticker import FuncFormatter
if add_logo:
from ovrolwasolar.visualization import njit_logo_str, nsf_logo
import base64
import io
import matplotlib.image as mpimg
if not interactive:
try:
matplotlib.use('Agg') # Use the Agg backend
except Exception as e:
print(f'Error: {e}')
print('Failed to set the backend to Agg. Use default backend.')
plt.ioff()
else:
try:
if os.name == 'posix':
if sys.platform == 'darwin':
matplotlib.use('MacOSX')
else:
matplotlib.use('QtAgg')
except Exception as e:
print(f'Error: {e}')
print('Failed to set the specified backend. Using default backend.')
plt.ion()
if timestamp is None:
if timerange is not None:
timestamp = timerange[0]
if timerange[1] - timerange[0] < timedelta(minutes=30):
fast_plot = False
else:
# Set the current timestamp if none is provided
timestamp = datetime.utcnow() - timedelta(days=1)
# Ensure the output directory exists
os.makedirs(figdir, exist_ok=True)
if combine:
if figname is None:
# Define the file name for the combined figure
figname = os.path.join(figdir, f'fig-OVSA_spec_{timestamp.strftime("%Y%m%d")}.jpg')
if timerange is None and os.path.exists(figname):
if overwrite:
os.system(f'rm -f {figname}')
else:
print(f'Combined figure for {timestamp.strftime("%Y-%m-%d")} already exists. Skipping.')
return [figname]
else:
# Define file names for each figure
figname_eovsa = os.path.join(figdir, f'fig-eovsa_spec_{timestamp.strftime("%Y%m%d")}.jpg')
figname_ovrolwa = os.path.join(figdir, f'fig-ovrolwa_spec_{timestamp.strftime("%Y%m%d")}.jpg')
figname_stix = os.path.join(figdir, f'fig-stix_lc_{timestamp.strftime("%Y%m%d")}.jpg')
figname_goes = os.path.join(figdir, f'fig-goes_lc_{timestamp.strftime("%Y%m%d")}.jpg')
# Define paths for the data files
ovrolwapath = '/common/lwa/spec_v2/fits/'
ovrolwa_specfile = os.path.join(ovrolwapath, timestamp.strftime("%Y%m%d.fits"))
eovsapath = f'/data1/eovsa/fits/synoptic/{timestamp.strftime("%Y/%m/%d")}/'
eovsa_specfile = os.path.join(eovsapath, timestamp.strftime("EOVSA_TPall_%Y%m%d.fts"))
if fix_tlim:
'''pstart = Time(t.iso[:10]+' 13:30').plot_date
prange = [pstart,pstart+13./24]'''
start_time = timestamp.replace(hour=13, minute=30, second=0)
end_time = start_time + timedelta(hours=13)
timerange = Time([start_time, end_time])
# Define default time range if no data is available
default_start_time = Time(timestamp.replace(hour=14, minute=0, second=0))
default_end_time = Time((timestamp + timedelta(days=1)).replace(hour=2, minute=0, second=0))
if combine:
fig, axs = plt.subplots(4, 1, figsize=(12, 12), sharex=True, height_ratios=[2, 2, 3, 4])
ax_goes, ax_stix, ax_eovsa, ax_ovrolwa = axs
else:
# Initialize figures and axes
fig_ovrolwa, ax_ovrolwa = plt.subplots(1, 1, figsize=(15, 4))
fig_eovsa, ax_eovsa = plt.subplots(1, 1, figsize=(15, 4))
fig_stix, ax_stix = plt.subplots(1, 1, figsize=(15, 3))
fig_goes, ax_goes = plt.subplots(1, 1, figsize=(15, 3))
# Load OVRO-LWA spectrogram data
print(f'processing OVRO-LWA spectrogram data for {timestamp.strftime("%Y-%m-%d")}')
if os.path.exists(ovrolwa_specfile):
cmap = 'viridis'
ovrolwa_bkgtim = None
d_ovrolwa = ds.Dspec()
d_ovrolwa.read(ovrolwa_specfile, source='lwa')
d_ovrolwa.pol = 'IV'
timerange_ovrolwa = None
if timerange is not None:
timerange_ovrolwa = list(Time(timerange).iso)
vmax = np.nanpercentile(d_ovrolwa.data, 99.995)
vmin = np.nanpercentile(d_ovrolwa.data, 5)
norm_I_ovrolwa = mcolors.LogNorm(vmin=vmin, vmax=vmax)
if fix_vrange:
## Set the dynamic range to at least a decade.
vmin = 0.7
vmax = max(vmin*50, np.nanpercentile(d_ovrolwa.data, clip_ovrolwa[1]))
norm_I_ovrolwa = mcolors.LogNorm(vmin=vmin, vmax=vmax)
print(f'Fix OVRO-LWA vrange to [{vmin}, {vmax}] SFU')
minmaxpercentile = False
else:
minmaxpercentile = True
d_ovrolwa.plot(pol='I', timerange=timerange_ovrolwa, bkgtim=ovrolwa_bkgtim, plot_fast=fast_plot,
norm=norm_I_ovrolwa,
percentile=clip_ovrolwa, minmaxpercentile=minmaxpercentile, freq_unit='MHz', cmap=cmap, axes=ax_ovrolwa)
ovrolwa_tim = d_ovrolwa.time_axis
ovro_lwa_start, ovro_lwa_end = ovrolwa_tim[0], ovrolwa_tim[-1]
else:
ax_ovrolwa.plot([], [])
ax_ovrolwa.text(0.5, 0.5, 'No OVRO-LWA data available', transform=ax_ovrolwa.transAxes,
ha='center', va='center', fontsize=12, color='gray')
ax_ovrolwa.set_ylabel('Frequency [MHz]')
if timestamp>= datetime(2025, 4, 18):
ax_ovrolwa.set_ylim(15, 85)
else:
ax_ovrolwa.set_ylim(29.033934, 83.871824)
ovro_lwa_start, ovro_lwa_end = default_start_time, default_end_time
divider = make_axes_locatable(ax_ovrolwa)
cax_spec = divider.append_axes('right', size='1.5%', pad=0.05)
cax_spec.set_visible(False)
ax_ovrolwa.set_yscale('log')
ax_ovrolwa.yaxis.set_minor_formatter(FuncFormatter(int_formatter))
ax_ovrolwa.set_title(f'OVRO-LWA Dynamic Spectrum (Stokes I)')
print(f'processing EOVSA spectrogram data for {timestamp.strftime("%Y-%m-%d")}')
# Load EOVSA spectrogram data
ax = ax_eovsa
if os.path.exists(eovsa_specfile):
cmap = 'viridis'
eovsa_bkgtim = None
timerange_eovsa = None
if timerange is not None:
timerange_eovsa = list(Time(timerange).iso)
# norm_I_eovsa = mcolors.Normalize(vmin=None, vmax=None)
d_eovsa = ds.Dspec()
d_eovsa.read(eovsa_specfile, source='eovsa')
data = d_eovsa.data
bkgspec = np.nanpercentile(data, 1, axis=1)
d_eovsa.data = data - bkgspec[:, np.newaxis]
d_eovsa.data[d_eovsa.data < 0] = 0
fghz_eovsa = d_eovsa.freq_axis/1e9
bad_fghz = [1.742, 2.72]
d_eovsa.data[np.logical_and(fghz_eovsa > bad_fghz[0], fghz_eovsa < bad_fghz[1])] = np.nan
vmax = np.nanpercentile(d_eovsa.data, 99.995)
vmin = np.nanpercentile(d_eovsa.data, 5)
norm_I_eovsa = mcolors.LogNorm(vmin=vmin, vmax=vmax)
if fix_vrange:
vmin = 5
vmax = max(vmin*10, np.nanpercentile(d_eovsa.data, clip_eovsa[1]))
norm_I_eovsa = mcolors.LogNorm(vmin=vmin, vmax=vmax)
minmaxpercentile = False
print(f'Fix EOVSA vrange to [{vmin}, {vmax}] SFU')
else:
minmaxpercentile = True
d_eovsa.plot(pol='I', timerange=timerange_eovsa, bkgtim=eovsa_bkgtim, plot_fast=False, norm=norm_I_eovsa,
percentile=clip_eovsa, minmaxpercentile=minmaxpercentile, freq_unit='GHz', cmap=cmap, axes=ax_eovsa)
eovsa_tim = d_eovsa.time_axis
eovsa_start, eovsa_end = eovsa_tim[0], eovsa_tim[-1]
else:
ax_eovsa.plot([], [])
ax_eovsa.text(0.5, 0.5, 'No EOVSA data available', transform=ax_eovsa.transAxes,
ha='center', va='center', fontsize=12, color='gray')
ax_eovsa.set_ylabel('Frequency [GHz]')
ax_eovsa.set_ylim(1.1053711, 17.979687)
eovsa_start, eovsa_end = default_start_time, default_end_time
divider = make_axes_locatable(ax_eovsa)
cax_spec = divider.append_axes('right', size='1.5%', pad=0.05)
cax_spec.set_visible(False)
ax_eovsa.set_yscale('log')
ax_eovsa.yaxis.set_major_formatter(FuncFormatter(int_formatter))
ax_eovsa.yaxis.set_minor_formatter(FuncFormatter(int_formatter))
ax_eovsa.set_title(f'EOVSA Dynamic Spectrum (Stokes I)')
if timerange is None:
# Determine the overall time range based on available data
overall_start = min(ovro_lwa_start, eovsa_start)
overall_end = max(ovro_lwa_end, eovsa_end)
else:
## if timerange is provided, override the overall time range
overall_start = Time(timerange[0])
overall_end = Time(timerange[1])
if combine:
if fix_tlim:
pass
else:
figname = os.path.join(figdir,
f'fig-OVSA_spec_{timerange[0].strftime("%Y%m%dT%H%M%S")}-{timerange[1].strftime("%Y%m%dT%H%M%S")}.jpg')
else:
if fix_tlim:
pass
else:
figname_eovsa = os.path.join(figdir,
f'fig-eovsa_spec_{timerange[0].strftime("%Y%m%dT%H%M%S")}-{timerange[1].strftime("%Y%m%dT%H%M%S")}.jpg')
figname_ovrolwa = os.path.join(figdir,
f'fig-ovrolwa_spec_{timerange[0].strftime("%Y%m%dT%H%M%S")}-{timerange[1].strftime("%Y%m%dT%H%M%S")}.jpg')
figname_stix = os.path.join(figdir,
f'fig-stix_lc_{timerange[0].strftime("%Y%m%dT%H%M%S")}-{timerange[1].strftime("%Y%m%dT%H%M%S")}.jpg')
figname_goes = os.path.join(figdir,
f'fig-goes_lc_{timerange[0].strftime("%Y%m%dT%H%M%S")}-{timerange[1].strftime("%Y%m%dT%H%M%S")}.jpg')
print(f'processing STIX light curves for {timestamp.strftime("%Y-%m-%d")}')
# Load STIX light curves
lc = LightCurves.from_sdc(start_utc=overall_start.iso, end_utc=overall_end.iso, ltc=True)
if len(lc.counts) > 0:
lc.peek(ax=ax_stix)
else:
ax_stix.plot([], [])
ax_stix.set_ylabel('Counts')
ax_stix.set_ylim(20, 2e6)
ax_stix.text(0.5, 0.5, 'No STIX data available', transform=ax_stix.transAxes,
ha='center', va='center', fontsize=12, color='gray')
ax_stix.set_yscale('log')
ax_stix.set_title(f'STIX Quick-look Light Curves')
divider = make_axes_locatable(ax_stix)
cax_spec = divider.append_axes('right', size='1.5%', pad=0.05)
cax_spec.set_visible(False)
if combine:
pass
else:
fig_stix.subplots_adjust(bottom=0.15)
print(f'processing GOES X-ray light curves for {timestamp.strftime("%Y-%m-%d")}')
# Download GOES X-ray light curves
try:
def _has_downloaded_files(fetch_result) -> bool:
if fetch_result is None:
return False
try:
return len(fetch_result) > 0
except Exception:
return False
xrs_client = None
try:
from sunpy.net.dataretriever.sources.goes import XRSClient
xrs_client = XRSClient()
except Exception:
try:
from sunpy.net.dataretriever.sources.goes_xrs import XRSClient
xrs_client = XRSClient()
except Exception:
xrs_client = None
def _search_and_fetch_goes(time_attr, sat_num=None):
attrs = [time_attr, a.Instrument('XRS')]
if sat_num is not None:
try:
attrs.append(a.goes.SatelliteNumber(sat_num))
except Exception:
pass
if xrs_client is not None and hasattr(xrs_client, "search") and hasattr(xrs_client, "fetch"):
query = xrs_client.search(*attrs)
if len(query) == 0 and sat_num is not None:
query = xrs_client.search(time_attr, a.Instrument('XRS'))
if len(query) == 0:
return None
return xrs_client.fetch(query)
query = Fido.search(*attrs)
if len(query) == 0 and sat_num is not None:
query = Fido.search(time_attr, a.Instrument('XRS'))
if len(query) == 0:
return None
return Fido.fetch(query)
goes_files = None
time_attr = a.Time(
overall_start.datetime - timedelta(minutes=10),
overall_end.datetime + timedelta(minutes=10),
)
for sat_num in (18, 17, 16):
try:
goes_files = _search_and_fetch_goes(time_attr, sat_num=sat_num)
if _has_downloaded_files(goes_files):
break
except Exception as e:
msg = str(e)
if "not understood by any clients" in msg:
print(f'Error: {msg}. GOES XRS client unavailable; using NOAA JSON fallback.')
goes_files = None
break
print(f'Error: {msg}. Failed GOES-{sat_num} query; trying another satellite.')
goes_files = None
goes_ts = None
if _has_downloaded_files(goes_files):
goes = ts.TimeSeries(goes_files)
if isinstance(goes, list):
df_comb = goes[0].to_dataframe()
df_comb = df_comb[(df_comb["xrsa_quality"] == 0) & (df_comb["xrsb_quality"] == 0)]
for g in goes[1:]:
df = g.to_dataframe()
df = df[(df["xrsa_quality"] == 0) & (df["xrsb_quality"] == 0)]
df_comb = pd.concat([df_comb, df])
else:
df_comb = goes.to_dataframe()
if df_comb is not None and len(df_comb) > 0:
units = dict([("xrsa", u.W / u.m ** 2), ("xrsb", u.W / u.m ** 2)])
meta = dict({"instrument": "GOES X-ray sensor", "measurements": "primary", "type": "quicklook"})
goes_ts = ts.TimeSeries(df_comb[['xrsa', 'xrsb']], meta, units, source="xrs")
else:
print('GOES files contained no usable data; falling back to NOAA JSON.')
if goes_ts is None:
goes_json_data = pd.read_json("https://services.swpc.noaa.gov/json/goes/primary/xrays-7-day.json")
goes_short = goes_json_data[goes_json_data["energy"] == "0.05-0.4nm"]
goes_long = goes_json_data[goes_json_data["energy"] == "0.1-0.8nm"]
time_array = parse_time(goes_short["time_tag"])
filtered_indices = (time_array >= overall_start) & (time_array <= overall_end)
filtered_short = goes_short[filtered_indices]
filtered_long = goes_long[filtered_indices]
filtered_time_array = time_array[filtered_indices]
if len(filtered_time_array) == 0:
raise ValueError(
'No GOES data available in NOAA 7-day JSON feed for requested time range.'
)
goes_data = pd.DataFrame(
{
"xrsa": filtered_short["flux"].values,
"xrsb": filtered_long["flux"].values,
},
index=filtered_time_array.datetime,
)
units = dict([("xrsa", u.W / u.m ** 2), ("xrsb", u.W / u.m ** 2)])
meta = dict({"instrument": "GOES X-ray sensor", "measurements": "primary", "type": "quicklook"})
goes_ts = ts.TimeSeries(goes_data, meta, units, source="xrs")
goes_ts.plot(axes=ax_goes)
except Exception as e:
print(f'Error: {e}. Proceeding without GOES data.')
ax_goes.plot([], [])
ax_goes.set_ylim(1e-9, 1e-2)
ax_goes.text(0.5, 0.5, 'No GOES data available', transform=ax_goes.transAxes,
ha='center', va='center', fontsize=12, color='gray')
ax_goes.set_yscale('log')
ax_goes.set_ylabel('Flux [W/m²]')
divider = make_axes_locatable(ax_goes)
cax_spec = divider.append_axes('right', size='1.5%', pad=0.05)
cax_spec.set_visible(False)
ax_goes.set_title(f'GOES X-ray Light Curves')
if combine:
pass
else:
fig_goes.subplots_adjust(bottom=0.15)
# Set up the time axis for each plot
setup_time_axis(ax_ovrolwa, overall_start, overall_end)
setup_time_axis(ax_eovsa, overall_start, overall_end)
setup_time_axis(ax_stix, overall_start, overall_end)
setup_time_axis(ax_goes, overall_start, overall_end)
for ax in [ax_ovrolwa, ax_eovsa, ax_stix, ax_goes]:
ax.set_xlabel(f'Time [UTC, {timestamp.strftime("%Y %b %d")}]')
if combine:
for ax in axs[:-1]:
ax.tick_params(axis='x', which='both', labelbottom=False)
ax.set_xlabel('')
fig.tight_layout()
if add_logo:
ax_logo1 = fig.add_axes([0.89, 0.91, 0.15, 0.08])
img1 = base64.b64decode(njit_logo_str)
img1 = io.BytesIO(img1)
img1 = mpimg.imread(img1, format='png')
ax_logo1.imshow(img1)
ax_logo1.axis('off')
ax_logo2 = fig.add_axes([0.81, 0.91, 0.15, 0.09])
img2 = base64.b64decode(nsf_logo)
img2 = io.BytesIO(img2)
img2 = mpimg.imread(img2, format='png')
ax_logo2.imshow(img2)
ax_logo2.axis('off')
fig.savefig(figname, dpi=300)
print(f'Saved combined figure to {figname}')
figout = [figname]
else:
if add_logo:
for fig in [fig_ovrolwa, fig_eovsa, fig_stix, fig_goes]:
ax_logo1 = fig.add_axes([0.89, 0.91, 0.15, 0.08])
img1 = base64.b64decode(njit_logo_str)
img1 = io.BytesIO(img1)
img1 = mpimg.imread(img1, format='png')
ax_logo1.imshow(img1)
ax_logo1.axis('off')
ax_logo2 = fig.add_axes([0.81, 0.91, 0.15, 0.09])
img2 = base64.b64decode(nsf_logo)
img2 = io.BytesIO(img2)
img2 = mpimg.imread(img2, format='png')
ax_logo2.imshow(img2)
ax_logo2.axis('off')
fig_eovsa.savefig(figname_eovsa, dpi=300)
fig_ovrolwa.savefig(figname_ovrolwa, dpi=300)
fig_stix.savefig(figname_stix, dpi=300)
fig_goes.savefig(figname_goes, dpi=300)
print(f'Saved EOVSA figure to {figname_eovsa}')
print(f'Saved OVRO-LWA figure to {figname_ovrolwa}')
print(f'Saved STIX figure to {figname_stix}')
print(f'Saved GOES figure to {figname_goes}')
figout = [figname_eovsa, figname_ovrolwa, figname_stix, figname_goes]
#
# plt.show() # Optionally show all figures
if not interactive:
plt.close('all')
t1 = time.time()
print(f'Plotting took {t1 - t0:.2f} seconds.')
return figout
if __name__ == '__main__':
import os
from datetime import datetime, timedelta
from suncasa.utils import ovsa_spectrogram as ovsp
[docs]
current_date = datetime.now()
previous_day = (current_date - timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0)
print(f'plotting OVSA spectrogram for {previous_day.strftime("%Y-%m-%d")}')
ovsp.plot(previous_day, figdir=f'/common/webplots/SynopticImg/eovsamedia/eovsa-browser/{previous_day.strftime("%Y/%m/%d")}/', clip=[10, 99.5], fix_tlim=True, fix_vrange=True, overwrite=True)
# import os
# from datetime import datetime, timedelta
# from suncasa.utils import ovsa_spectrogram as ovsp
#
# # start_date = datetime(2023, 7, 26)
# # end_date = datetime(2025, 8, 30)
# # start_date = datetime(2024, 5, 9)
# # end_date = datetime(2024, 5, 12)
# start_date = datetime(2025, 9, 15)
# end_date = datetime(2025, 10, 7)
#
# current_date = start_date
# while current_date <= end_date:
# try:
# print(f'plotting OVSA spectrogram for {current_date.strftime("%Y-%m-%d")}')
# ovsp.plot(current_date, figdir=f'/common/webplots/SynopticImg/eovsamedia/eovsa-browser/{current_date.strftime("%Y/%m/%d")}/', clip=[10, 99.5], fix_tlim=True, fix_vrange=True, overwrite=True)
# except Exception as e:
# print(f"Error processing date {current_date}: {e}")
# current_date += timedelta(days=1)
#