Skip to content

Commit a305360

Browse files
author
R Bailey
committed
Added plot_solarwind_science option for more B-field components.
1 parent 02b9113 commit a305360

3 files changed

Lines changed: 187 additions & 6 deletions

File tree

predstorm/data.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2445,13 +2445,14 @@ def merge_Data(satdata1, satdata2, keys=None):
24452445
# Make combined array data
24462446
datadict[k] = np.concatenate((satdata1[k], int_var))
24472447

2448-
MergedData = SatData(datadict, source=satdata1.source+'+'+satdata2.source)
24492448
tf = "%Y-%m-%d %H:%M:%S"
24502449
if satdata1.h['DataSource'] == satdata2.h['DataSource']:
2450+
MergedData = SatData(datadict, source=satdata1.source)
24512451
MergedData.h['DataSource'] = satdata1.h['DataSource']
24522452
MergedData.h['Instruments'] = satdata1.h['Instruments']
24532453
MergedData.h['FileVersion'] = satdata1.h['FileVersion']
24542454
else:
2455+
MergedData = SatData(datadict, source=satdata1.source+'+'+satdata2.source)
24552456
MergedData.h['DataSource'] = '{} ({} - {}) & {} ({} - {})'.format(satdata1.h['DataSource'],
24562457
datetime.strftime(num2date(satdata1['time'][0]), tf),
24572458
datetime.strftime(num2date(satdata1['time'][-1]), tf),

predstorm/plot.py

Lines changed: 179 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
# --------------------------- PLOTTING FUNCTIONS ----------------------------------------
4444
# =======================================================================================
4545

46-
def plot_solarwind_and_dst_prediction(DSCOVR_data, STEREOA_data, DST_data, DSTPRED_data, newell_coupling=None, dst_label='Dst Temerin & Li 2002', past_days=3.5, future_days=7., verification_mode=False, timestamp=None, **kwargs):
46+
def plot_solarwind_and_dst_prediction(DSCOVR_data, STEREOA_data, DST_data, DSTPRED_data, newell_coupling=None, dst_label='Dst Temerin & Li 2002', past_days=3.5, future_days=7., verification_mode=False, timestamp=None, outfile='predstorm_real.png', **kwargs):
4747
"""
4848
Plots solar wind variables, past from DSCOVR and future/predicted from STEREO-A.
4949
Total B-field and Bz (top), solar wind speed (second), particle density (third)
@@ -278,8 +278,8 @@ def plot_solarwind_and_dst_prediction(DSCOVR_data, STEREOA_data, DST_data, DSTPR
278278
filename_eps = filename.replace('png', 'eps')
279279

280280
if not verification_mode:
281-
plt.savefig('predstorm_real.png')
282-
logger.info('Real-time plot saved as predstorm_real.png!')
281+
plt.savefig(outfile)
282+
logger.info('Real-time plot saved as {}!'.format(outfile))
283283

284284
#if not server: # Just plot and exit
285285
# plt.show()
@@ -288,6 +288,182 @@ def plot_solarwind_and_dst_prediction(DSCOVR_data, STEREOA_data, DST_data, DSTPR
288288
logger.info('Plot saved as png:\n'+ filename)
289289

290290

291+
def plot_solarwind_science(DSCOVR_data, STEREOA_data, verification_mode=False, timestamp=None, past_days=7, future_days=7, outfile='predstorm_science.png', **kwargs):
292+
"""
293+
Plots solar wind variables, past from DSCOVR and future/predicted from STEREO-A.
294+
Total B-field and Bz (top), solar wind speed (second), particle density (third)
295+
and Dst (fourth) from Kyoto and model prediction.
296+
297+
Parameters
298+
==========
299+
DSCOVR_data : list[minute data, hourly data]
300+
DSCOVR data in different time resolutions.
301+
STEREOA_data : list[minute data, hourly data]
302+
STEREO-A data in different time resolutions.
303+
lw : int (default=1)
304+
Linewidth for plotting functions.
305+
fs : int (default=11)
306+
Font size for all text in plot.
307+
ms : int (default=5)
308+
Marker size for markers in plot.
309+
figsize : tuple(float=width, float=height) (default=(14,12))
310+
Figure size (in inches) for output file.
311+
verification_mode : bool (default=False)
312+
If True, verification mode will produce a plot of the predicted Dst
313+
for model verification purposes.
314+
timestamp : datetime obj
315+
Time for 'now' label in plot.
316+
317+
Returns
318+
=======
319+
plt.savefig : .png file
320+
File saved to XXX
321+
"""
322+
323+
figsize = kwargs.get('figsize', pltcfg.figsize)
324+
lw = kwargs.get('lw', pltcfg.lw)
325+
fs = kwargs.get('fs', pltcfg.fs)
326+
date_fmt = kwargs.get('date_fmt', pltcfg.date_fmt)
327+
c_dst = kwargs.get('c_dst', pltcfg.c_dst)
328+
c_dis = kwargs.get('c_dis', pltcfg.c_dis)
329+
c_ec = kwargs.get('c_ec', pltcfg.c_ec)
330+
c_sta = kwargs.get('c_sta', pltcfg.c_sta)
331+
c_sta_dst = kwargs.get('c_sta_dst', pltcfg.c_sta_dst)
332+
ms_dst = kwargs.get('c_dst', pltcfg.ms_dst)
333+
fs_legend = kwargs.get('fs_legend', pltcfg.fs_legend)
334+
fs_ylabel = kwargs.get('fs_legend', pltcfg.fs_ylabel)
335+
fs_title = kwargs.get('fs_title', pltcfg.fs_title)
336+
337+
# Set style:
338+
sns.set_context(pltcfg.sns_context)
339+
sns.set_style(pltcfg.sns_style)
340+
341+
# Make figure object:
342+
fig = plt.figure(1,figsize=(20,8))
343+
axes = []
344+
345+
# Set data objects:
346+
stam, sta = STEREOA_data
347+
dism, dis = DSCOVR_data
348+
349+
# For the minute data, check which are the intervals to show for STEREO-A until end of plot
350+
sta_index_future=np.where(np.logical_and(stam['time'] > dism['time'][-1], \
351+
stam['time'] < dism['time'][-1]+future_days))[0]
352+
353+
if timestamp == None:
354+
timestamp = datetime.utcnow()
355+
timeutc = mdates.date2num(timestamp)
356+
357+
n_plots = 3
358+
359+
plotstart = timeutc - past_days
360+
plotend = timeutc + future_days
361+
362+
# SUBPLOT 1: Total B-field and Bz
363+
# -------------------------------
364+
ax1 = fig.add_subplot(n_plots,1,1)
365+
axes.append(ax1)
366+
367+
# Total B-field and Bz (DSCOVR)
368+
plt.plot_date(dism['time'], dism['btot'],'-', c='black', label='B', linewidth=lw)
369+
plt.plot_date(dism['time'], dism['bx'],'-', c='teal', label='Bx', linewidth=lw)
370+
plt.plot_date(dism['time'], dism['by'],'-', c='orange', label='By', linewidth=lw)
371+
plt.plot_date(dism['time'], dism['bz'],'-', c='purple', label='Bz', linewidth=lw)
372+
373+
# STEREO-A minute resolution data with timeshift
374+
plt.plot_date(stam['time'][sta_index_future], stam['btot'][sta_index_future],
375+
'-', c='black', alpha=0.5, linewidth=0.5)
376+
plt.plot_date(stam['time'][sta_index_future], stam['br'][sta_index_future],
377+
'-', c='teal', alpha=0.5, linewidth=0.5)
378+
plt.plot_date(stam['time'][sta_index_future], stam['bt'][sta_index_future],
379+
'-', c='orange', alpha=0.5, linewidth=0.5)
380+
plt.plot_date(stam['time'][sta_index_future], stam['bn'][sta_index_future],
381+
'-', c='purple', alpha=0.5, linewidth=0.5)
382+
383+
# Indicate 0 level for Bz
384+
plt.plot_date([plotstart,plotend], [0,0],'--k', alpha=0.5, linewidth=1)
385+
plt.ylabel('Magnetic field [nT]', fontsize=fs_ylabel)
386+
387+
# For y limits check where the maximum and minimum are for DSCOVR and STEREO taken together:
388+
bplotmax=np.nanmax(np.concatenate((dism['btot'],stam['btot'][sta_index_future])))+5
389+
bplotmin=np.nanmin(np.concatenate((dism['bz'],stam['bn'][sta_index_future]))-5)
390+
391+
plt.ylim((-13, 13))
392+
393+
if 'stereo' in stam.source.lower():
394+
pred_source = 'STEREO-Ahead Beacon'
395+
elif 'omni' in stam.source.lower():
396+
pred_source = '27-day SW-Recurrence Model (OMNI)'
397+
plt.title('L1 real time solar wind from NOAA SWPC for '+ datetime.strftime(timestamp, "%Y-%m-%d %H:%M")+ ' UT & {}'.format(pred_source), fontsize=fs_title)
398+
399+
# SUBPLOT 2: Solar wind speed
400+
# ---------------------------
401+
ax2 = fig.add_subplot(n_plots,1,2)
402+
axes.append(ax2)
403+
404+
# Plot solar wind speed (DSCOVR):
405+
plt.plot_date(dism['time'], dism['speed'],'-', c='black', label='speed',linewidth=lw)
406+
plt.ylabel('Speed $\mathregular{[km \\ s^{-1}]}$', fontsize=fs_ylabel)
407+
408+
# Plot STEREO-A data with timeshift and savgol filter
409+
plt.plot_date(stam['time'][sta_index_future],signal.savgol_filter(stam['speed'][sta_index_future],11,1),'-',
410+
c='black', alpha=0.5, linewidth=lw)
411+
412+
# Add speed levels:
413+
pltcfg.plot_speed_lines(xlims=[plotstart, plotend])
414+
415+
# For y limits check where the maximum and minimum are for DSCOVR and STEREO taken together:
416+
vplotmax=np.nanmax(np.concatenate((dism['speed'],signal.savgol_filter(stam['speed'][sta_index_future],11,1))))+100
417+
vplotmin=np.nanmin(np.concatenate((dism['speed'],signal.savgol_filter(stam['speed'][sta_index_future],11,1)))-50)
418+
plt.ylim(vplotmin, vplotmax)
419+
420+
plt.annotate('now', xy=(timeutc,vplotmax-(vplotmax-vplotmin)*0.25), xytext=(timeutc+0.05,vplotmax-(vplotmax-vplotmin)*0.25), color='k', fontsize=14)
421+
422+
# SUBPLOT 3: Solar wind density
423+
# -----------------------------
424+
ax3 = fig.add_subplot(n_plots,1,3)
425+
axes.append(ax3)
426+
427+
# Plot solar wind density:
428+
plt.plot_date(dism['time'], dism['density'],'-k', label='density',linewidth=lw)
429+
plt.ylabel('Density $\mathregular{[ccm^{-3}]}$',fontsize=fs_ylabel)
430+
# For y limits check where the maximum and minimum are for DSCOVR and STEREO taken together:
431+
plt.ylim([0,np.nanmax(np.nanmax(np.concatenate((dism['density'],stam['density'][sta_index_future])))+10)])
432+
433+
#plot STEREO-A data with timeshift and savgol filter
434+
plt.plot_date(stam['time'][sta_index_future], signal.savgol_filter(stam['density'][sta_index_future],5,1),
435+
'-', c='black', alpha=0.5, linewidth=lw)
436+
437+
# GENERAL FORMATTING
438+
# ------------------
439+
for ax in axes:
440+
ax.set_xlim([plotstart,plotend])
441+
ax.tick_params(axis="x", labelsize=fs)
442+
ax.tick_params(axis="y", labelsize=fs)
443+
ax.legend(loc=2,ncol=4,fontsize=fs_legend)
444+
445+
# Dates on x-axes:
446+
myformat = mdates.DateFormatter(date_fmt)
447+
ax.xaxis.set_major_formatter(myformat)
448+
449+
# Vertical line for NOW:
450+
ax.plot_date([timeutc,timeutc],[-2000,100000],'-k', linewidth=2)
451+
452+
# Liability text:
453+
pltcfg.group_info_text()
454+
pltcfg.liability_text()
455+
456+
#save plot
457+
if not verification_mode:
458+
plot_label = 'realtime'
459+
else:
460+
plot_label = 'verify'
461+
462+
if not verification_mode:
463+
plt.savefig(outfile)
464+
logger.info('Real-time plot saved as {}!'.format(outfile))
465+
466+
291467
def plot_stereo_dscovr_comparison(stam, dism, dst, timestamp=None, look_back=20, outfile=None, **kwargs):
292468
"""Plots the last days of STEREO-A and DSCOVR data for comparison alongside
293469
the predicted and real Dst.

predstorm_l5.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@
107107
import heliosat
108108
import predstorm as ps
109109
from predstorm.config.constants import AU, dist_to_L1
110-
from predstorm.plot import plot_solarwind_and_dst_prediction
110+
from predstorm.plot import plot_solarwind_and_dst_prediction, plot_solarwind_science
111111
from predstorm.predict import dst_loss_function
112112

113113
# GET INPUT PARAMETERS
@@ -171,7 +171,8 @@ def main():
171171
if rec_dism['time'][-1] > rec_27days['time'][-1]:
172172
rec_dism.cut(starttime=num2date(rec_27days['time'][-1]))
173173
rec_new = ps.merge_Data(rec_27days, rec_dism)
174-
rec_new.cut(starttime=num2date(timenow-90)) # don't keep more than three months
174+
rec_new.cut(starttime=num2date(timenow-365)) # don't keep more than 1 year
175+
rec_new.source = 'NOAA-L1'
175176
with open(rec_model_path, 'wb') as f:
176177
pickle.dump(rec_new, f)
177178
elif run_mode == 'historic':
@@ -340,6 +341,9 @@ def main():
340341
future_days=plot_future_days,
341342
dst_label=dst_label,
342343
timestamp=timestamp)
344+
plt.close()
345+
plot_solarwind_science([dism, sw_past], [sw_future_min, sw_future],
346+
timestamp=timestamp)
343347
# ********************************************************************
344348

345349

0 commit comments

Comments
 (0)