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+
291467def 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.
0 commit comments