Source code for lstid_processing.model.plots

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Full license can be found in License.md
#
# DISTRIBUTION STATEMENT A: Approved for public release. Distribution is
# unlimited.
# ----------------------------------------------------------------------------
"""Create some useful plots for the SAMI3 concatonated data."""

import cmocean
import datetime as dt
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import pandas as pds

import lstid_processing.plot_rout as pr
from lstid_processing.model import analysis


[docs] def plot_f2_peak_char_and_diff(sami, f2_inds, nt=None, dat_keys=None, start=dt.datetime(2014, 3, 25, 22), stop=dt.datetime(2014, 3, 26, 6)): """Plot the F2 peak characteristics and hemispheric differences. Parameters ---------- sami : xr.Dataset Dataset with concatonated SAMI3 data f2_inds : dict Dict with north and south indices for the F2 peaks along a field line nt : int or NoneType Event time index or None to not include a vertical line marking this point (default=None) dat_keys : list-like List of data keys to plot, if None uses altitude and field-aligned neutral wind (default=None) start : dt.datetime Starting time for plot (default=dt.datetime(2014, 3, 25, 22)) stop : dt.datetime Ending time for plot (default=dt.datetime(2014, 3, 26, 6)) Returns ------- fig : plt.Figure Figure handle """ # Set the defaults if needed if dat_keys is None: dat_keys = ['zalt', 'vnq'] # Initialize the figure fig = plt.figure(figsize=(6.51, 7.68)) # Set in size for 2 data variables axes = [fig.add_subplot(len(dat_keys), 1, 1 + i) for i in range(len(dat_keys))] # Cycle through each data variable, plotting the North, South, and N-S stimes = sami['datetime'].values for i, ax in enumerate(axes): ax.plot(stimes, sami[dat_keys[i]].values[f2_inds['north']], '-', color=pr.nrl_colors(0), lw=2, label='North') ax.plot(stimes, sami[dat_keys[i]].values[['south']], '--', color=pr.nrl_colors(1), lw=2, label='South') ax.plot(stimes, sami[dat_keys[i]].values[f2_inds['north']] - sami[dat_keys[i]].values[f2_inds['south']], '-.', color=pr.nrl_colors(4), lw=2, label='North-South') # Format the axes ax.set_xlim(start, stop) ax.set_ylabel('{:s} ({:s})'.format(dat_keys[i], sami[dat_keys[i]].units)) ax.grid() if i > len(axes) - 1: ax.xaxis.set_major_formatter(mpl.ticker.FormatStrFormatter('')) else: ax.xaxis.set_major_formatter(mpl.dates.DateFormatter('%j\n%H:%M')) ax.set_xlabel('Universal Time') if nt is not None: ylim = ax.get_ylim() ax.plot([stimes[nt], stimes[nt]], ylim, 'k-', lw=2) if i == 0: ax.legend(fontsize='medium', ncols=3, loc=1, bbox_to_anchor=(.94, 1.23)) # Format the figure fig.subplots_adjust(top=.84, hspace=.05) fig.suptitle( 'Field Line F$_2$ Peak Characteristics\n{:} - {:} UT'.format( start.strftime('%d %b %Y %H:%M'), stop.strftime('%d %b %Y %H:%M')), fontsize='medium') return fig
[docs] def plot_dom_acceleration(sami, nt, nlind, dom_acc=None, nfinds=None, nz_sat=None, nz_north=None, nz_south=None): """Plot the dominate acceleration terms for a single time and meridian. Parameters ---------- sami : xr.Dataset Dataset with concatonated SAMI3 data nt : int Time index nlind : int 'nl' meridian index dom_acc : array-like or NoneType Array of values specifying the dominant acceleration term or None to calculate (default=None) nfinds : list-like or None List of 'nf' indices for field lines to be plotted (default=None) nz_sat : list-like or None List of 'nz' indices corresponding to the `nfinds` indices for satellite locations (default=None) nz_north : list-like or None List of 'nz' indices corresponding to the `nfinds` indices for northern F2 peak locations (default=None) nz_south : list-like or None List of 'nz' indices corresponding to the `nfinds` indices for southern F2 peak locations (default=None) Returns ------- fig : plt.Figure Figure handle """ # Get the acceleration terms, if needed if dom_acc is None: dom_acc = analysis.get_dominant_acceleration(sami) # Initialize the figure fig = plt.figure() ax = fig.add_subplot(111) # Set the contour levels levels = np.linspace(0, 3, 4) # Plot the acceleration terms con = ax.contourf(sami['glat'][nt, nlind], sami['zalt'][nt, nlind], dom_acc[nt], cmap=cmocean.cm.deep, levels=levels) # Format the plot ax.set_xlim(-15, 30) ax.set_ylim(100, 1000) ax.set_ylabel('Altitude (km)') ax.set_xlabel(r'Geodetic Latitude ($^\circ$)') pr.add_colorbar(fig, con, 0, 3, zinc=4, name='Strongest O$^+$ Variations', loc=[0.88, 0.11, 0.02, 0.77]) # Format the figure fig.subplots_adjust(right=.87) fig.suptitle('{:}'.format(sami['datetime'].values[nt].strftime( '%d %b %Y %H:%M UT')), fontsize='medium') # Add lines, if desired if nfinds is not None: for i, nfind in enumerate(nfinds): ax.plot(sami['glat'][nt, nlind, nfind], sami['zalt'][nt, nlind, nfind], 'w--', lw=2) if nz_sat is not None: ax.plot(sami['glat'][nt, nlind, nfind, nz_sat[i]], sami['zalt'][nt, nlind, nfind, nz_sat[i]], 'wo', ms=10, mfc='none') if nz_north is not None: ax.plot(sami['glat'][nt, nlind, nfind, nz_north[i]], sami['zalt'][nt, nlind, nfind, nz_north[i]], 'wX', ms=10) if nz_south is not None: ax.plot(sami['glat'][nt, nlind, nfind, nz_south[i]], sami['zalt'][nt, nlind, nfind, nz_south[i]], 'wX', ms=10) return fig
[docs] def plot_dens_var(sami, nlind, nfind, nzind, sat_key, nt=None, nt_color='k', title='', start=dt.datetime(2014, 3, 25, 22), stop=dt.datetime(2014, 3, 26, 6)): """Plot the electron, O+, and H+ density variations at a desired location. Parameters ---------- sami : xr.Dataset Dataset with concatonated SAMI3 data nlind : int 'nl' index nfind : int 'nf' index nzind : int 'nf' index nt : int or None Time index to plot a vertical line marking time or None (default=None) nt_color : str Color for vertical line (default='k') sat_key : str Single character string used to specify the satellite/meridian for the data variations (e.g., 'c' or 'd') title ; str Figure title string (default='') start : dt.datetime Starting time for plot (default=dt.datetime(2014, 3, 25, 22)) stop : dt.datetime Ending time for plot (default=dt.datetime(2014, 3, 26, 6)) Returns ------- fig : plt.Figure Figure handle """ # Set the data keys dkeys = ['rel_dene_{:s}'.format(sat_key), 'rel_deni1_{:s}'.format(sat_key), 'rel_deni2_{:s}'.format(sat_key)] labels = [r'$\Delta N_e/N_e$', r'$\Delta N_{H^+}/N_{H^+}$', r'$\Delta N_{O^+}/N_{O^+}$'] percent = [100, 100 * sami['deni1'].values[nt, nlind, nlind, nzind] / sami['dene'].values[nt, nlind, nlind, nzind], 100 * sami['deni2'].values[nt, nlind, nlind, nzind] / sami['dene'].values[nt, nlind, nlind, nzind]] # Initialize figure fig = plt.figure(figsize=(8.34, 6.75)) axes = [fig.add_subplot(len(dkeys), 1, 1 + i) for i in range(len(dkeys))] # Cycle through each data type for i, ax in enumerate(axes): if nt is not None: ax.plot([sami['datetime'].values[nt], sami['datetime'].values[nt]], [-3000, 3000], '-', color=nt_color, lw=2) # Plot the data ax.plot(sami['datetime'].values, sami[dkeys[i]][:, nzind], '--', color=pr.nrl_colors(0), lw=2) # Format the axis ax.set_ylim(-.05, .05) ax.set_xlim(start, stop) ax.grid() ax.set_ylabel(labels[i]) if i < len(axes) - 1: ax.xaxis.set_major_formatter(mpl.ticker.FormatStrFormatter('')) else: ax.xaxis.set_major_formatter(mpl.dates.DateFormatter('%j\n%H:%M')) ax.set_xlabel('Universal Time') if i == 0: ax.text(16154.85, 0.06, 'Percent Ion or Electron Composition') ax.text(16155.12, 0.3, '{:.1f}%'.format(percent[i])) # Set the title fig.suptitle( r'SAMI3 for {:d} at {:.1f}$^\circ$N, {:.1f}$^\circ$E, {:.1f} km'.format( start.year, sami['glat'].values[nt, nlind, nfind, nzind], sami['glon'].values[nt, nlind, nfind, nzind], sami['zalt'].values[nt, nlind, nfind, nzind]), fontsize='medium') return fig
[docs] def plot_field_lines_w_linear_var(sami, nt, nlind, nfinds, nz_sat, nz_north, nz_south, colors, sat_labels): """Plot the 6-panel conjunction figure. Parameters ---------- sami : xr.Dataset SAMI3 standard or concatonated data set nt : int Time index nlind : int 'nl' index nfinds : list-like List of two 'nl' indexes nz_sat : list-like List of 'nz' indices corresponding to the `nfinds` indices for satellite locations nz_north : list-like List of 'nz' indices corresponding to the `nfinds` indices for northern F2 peak locations nz_south : list-like or None List of 'nz' indices corresponding to the `nfinds` indices for southern F2 peak locations colors : list-like This that contains two colors for each satellite as a list, for example [['orange', 'tan'], ['k', 'grey']] sat_labels : list-like List of satellite labels Returns ------- fig : plt.Figure Figure handle """ # Make plot with many variables fig = plt.figure(figsize=(14.5, 4.8)) axes = [fig.add_subplot(2, 3, 1 + i) for i in range(6)] twins = [None for axes in range(6)] # Cycle through each satellite for i, nfind in enumerate(nfinds): # Create the field-line plot with satellite and peak density locations. # Start by plotting the field line axes[0].plot(sami['glat'].values[nlind, nfind, :], sami['zalt'].values[nlind, nfind, :], '-', color=colors[i][0], label=sat_labels[i], lw=2) # Plot the F2 peaks on top of the field line axes[0].plot(sami['glat'].values[nlind, nfind, nz_north[i]], sami['zalt'].values[nlind, nfind, nz_north[i]], 'X', color=colors[i][1], ms=10) axes[0].plot(sami['glat'].values[nlind, nfind, nz_south[i]], sami['zalt'].values[nlind, nfind, nz_south[i]], 'X', color=colors[i][1], ms=10) # Plot the satellite location on top of the field line axes[0].plot(sami['glat'].values[nlind, nfind, nz_sat[i]], sami['zalt'].values[nlind, nfind, nz_sat[i]], 'o', color='w', ms=10, markeredgecolor=colors[i][0], markeredgewidth=2, zorder=1) # Create the electron density plot axes[3].plot(sami['glat'].values[nlind, nfind, :], sami['dene'].values[nt, nlind, nfind, :], '-', color=colors[i][0], label=sat_labels[i], lw=2) # Plot the F2 peaks on top of the electron density axes[3].plot(sami['glat'].values[nlind, nfind, nz_north[i]], sami['dene'].values[nt, nlind, nfind, nz_north[i]], 'X', color=colors[i][1], ms=10) axes[3].plot(sami['glat'].values[nlind, nfind, nz_south[i]], sami['dene'].values[nt, nlind, nfind, nz_south[i]], 'X', color=colors[i][1], ms=10) # Plot the satellite location on top of the electron density axes[3].plot(sami['glat'].values[nlind, nfind, nz_sat[i]], sami['dene'].values[nt, nlind, nfind, nz_sat[i]], 'o', color='w', ms=10, markeredgecolor=colors[i][0], markeredgewidth=2, zorder=1) # Create the DMSP time variation plot iax = 1 + i * 3 axes[iax].plot( np.full(shape=(2,), fill_value=sami['hrut'].values[nt]), [-300, 300], 'k-', lw=2) axes[iax].plot(sami['hrut'].values, sami['rel_vnq_d'].values[:, nz_sat[i]] / 100.0, '--', color='blue', label='u$_{||}$', lw=2) axes[iax].plot(sami['hrut'].values, sami['rel_vnp_d'].values[:, nz_sat[i]] / 100.0, ':', color='cornflowerblue', label='u$_{exb_{mer}}$', lw=2) axes[iax].plot(sami['hrut'].values, sami['rel_vsi2_d'].values[:, nz_sat[i]] / 100.0, '--', color='green', label='v$_{||_{O^+}}$', lw=2) axes[iax].plot(sami['hrut'].values, sami['rel_u1p_d'].values[:, nz_sat[i]] / 100.0, ':', color='yellowgreen', label='v$_{exb_{mer}}$', lw=2) axes[iax].plot([sami['hrut'].values[nt], sami['hrut'].values[nt]], [-200, 200], '-', color=colors[i][0], lw=2) # Set the common formatting axes[iax].set_ylabel('{:s}\n{:s}'.format(sat_labels[i], 'filtered vel (m s$^{-1}$)')) axes[iax].set_xlim(0, 4) axes[iax].yaxis.grid() # Plot along the twin if twins[iax] is None: twins[iax] = axes[iax].twinx() twins[iax].yaxis.label.set_color('darkviolet') twins[iax].tick_params(axis='y', colors='darkviolet') twins[iax].plot(sami['hrut'].values, sami['rel_dene_d'].values[:, nz_sat[i]], '-', color='darkviolet', lw=2, label='Electron Density') twins[iax].plot(sami['hrut'].values, sami['rel_denn2_d'].values[:, nz_sat[i]], '-.', color='darkviolet', lw=2, label='O Density') # Create the lat variation plot iax = 2 + i * 3 axes[iax].plot( np.full(shape=2, fill_value=sami['glat'].values[nlind, nfind, nz_north[i]]), [-500, 500], '-', color=colors[i][1], lw=2) axes[iax].plot( np.full(shape=2, fill_value=sami['glat'].values[nlind, nfind, nz_south[i]]), [-500, 500], '-', color=colors[i][1], lw=2) axes[iax].plot( np.full(shape=2, fill_value=sami['glat'].values[nlind, nfind, nz_sat[i]]), [-500, 500], '-', color=colors[i][0], lw=2) axes[iax].plot(sami['glat'].values[nlind, nfind, :], sami['rel_vnq_d'].values[nt, :] / 100.0, '--', color='blue', label='u$_{||}$', lw=2) axes[iax].plot(sami['glat'].values[nlind, nfind, :], sami['rel_vnp_d'].values[nt, :] / 100.0, ':', color='cornflowerblue', label='u$_{exb_{mer}}$', lw=2) axes[iax].plot(sami['glat'].values[nlind, nfind, :], sami['rel_vsi2_d'].values[nt, :] / 100.0, '--', color='green', label='v$_{||_{O^+}}$', lw=2) axes[iax].plot(sami['glat'].values[nlind, nfind, :], sami['rel_u1p_d'].values[nt, :] / 100.0, ':', color='yellowgreen', label='v$_{exb_{mer}}$', lw=2) # Intialize the twin if twins[iax] is None: twins[iax] = axes[iax].twinx() twins[iax].set_ylabel(r'$\Delta$ N / N') twins[iax].yaxis.label.set_color('darkviolet') twins[iax].tick_params(axis='y', colors='darkviolet') # Plot along the latitude twin twins[iax].plot(sami['glat'].values[nlind, nfind, :], sami['rel_dene_d'].values[nt, :], '-', color='darkviolet', lw=2, label='Electron Density') twins[iax].plot(sami['glat'].values[nlind, nfind, :], sami['rel_denn2_d'].values[nt, :], '-.', color='darkviolet', lw=2, label='O Density') # Set the common formatting axes[iax].set_xlim( sami['glat'].values[nlind, nfind, nz_south[i]] - 1.0, sami['glat'].values[nlind, nfind, nz_north[i]] + 1.0) axes[iax].yaxis.grid() # Format the field-line axis axes[0].set_ylim(0, 1000) axes[0].set_ylabel('Altitude (km)') axes[0].xaxis.set_major_formatter(mpl.ticker.FormatStrFormatter('')) # Format the electron density axis axes[3].ticklabel_format(style='sci', scilimits=(-3, 3), axis='y') axes[3].yaxis.major.formatter._useMathText = True axes[3].set_xlabel(r'Geographic Latitude ($^\circ$)') axes[3].set_ylabel('N$_e$ (cm$^{-3}$)') # Format the time plot axes axes[1].set_ylim(-40, 40) axes[1].xaxis.set_major_formatter(mpl.ticker.FormatStrFormatter('')) axes[4].set_ylim(-15, 15) axes[4].set_xlabel('Universal Time (h)') twins[1].set_ylim(-.2, .2) twins[4].set_ylim(-.03, .03) # Format the latitude plot axes axes[2].set_ylim(-20, 20) axes[5].set_ylim(-15, 15) twins[2].set_ylim(-.1, .1) twins[5].set_ylim(-.15, .15) axes[2].xaxis.set_major_formatter(mpl.ticker.FormatStrFormatter('')) axes[5].set_xlabel(r'Geographic Latitude ($^\circ$)') # Add the legend and adjust the spacing fig.subplots_adjust(left=.07, right=.93, wspace=.35) axes[0].legend(loc=1, ncol=2, bbox_to_anchor=[1.05, 1.36]) axes[2].legend(ncol=4, loc=1, bbox_to_anchor=[0.0, 1.36]) twins[2].legend(ncol=2, loc=1, bbox_to_anchor=[1.3, 1.36]) return fig
[docs] def get_plot_tid_peaks(sami, nt_start, nt_stop, nlind, nfind, nzinds, dat_keys, dat_labels=None, dat_scale=None, peak_height=None, add_lines=True, add_line_labels=False, min_lat=None, min_sec=None, min_lat_break=None, min_lin_fit=None, max_lat=None, max_sec=None, max_lat_break=None, max_lin_fit=None): """Calculate and plot the TID peaks for a given time and altitude range. Parameters ---------- sami : xr.Dataset SAMI3 concatonated data set nt_start: int Starting time index nt_stop : int Ending time index nlind : int 'nl' index nfind : int 'nf' index nzinds : list-like List of 'nz' indices corresponding to, e.g., the topside ionosphere dat_keys : list-like or str List of data keys to plot or a satellite string to use defaults dat_labels : list-like or NoneType List of data labels, will be overwritten if `dat_keys` is a satellite string (default=None) dat_scale : list-like or NoneType List of data scales for keys, if a satellite string is used for `dat_keys` this will be reset (default=None) peak_height : list-like or NoneType List of peak height minima for keys, if a satellite string is used for `dat_keys` this will be reset (default=None) add_lines : bool Add linear fits to plot (default=True) add_line_labels : bool Add the linear fits to the legend (default=False) min_lat : dict or NoneType Latitudes corresponding to the minima indices with keys corresponding to data variables or None to calculate (default=None) min_sec : dict or NoneType Seconds from the starting time corresponding to the minima indices with keys corresponding to data variables or None to calculate (default=None) min_lat_break : dict or NoneType Indices of the latitude breaks with keys corresponding to data variables for the minima or None to calculate (default=None) min_lin_fit : dict or NoneType Output from scipy.stats.linregress for each valid fit period or None to calculate (default=None) max_lat : dict or NoneType Latitudes corresponding to the maxima indices with keys corresponding to data variables or None to calculate (default=None) max_sec : dict or NoneType Seconds from the starting time corresponding to the maxima indices with keys corresponding to data variables or None to calculate (default=None) max_lat_break : dict or NoneType Indices of the latitude breaks with keys corresponding to data variables for the maxim aor None to calculate (default=None) max_lin_fit : dict or NoneType Output from scipy.stats.linregress for each valid fit period or None to calculate (default=None) Returns ------- min_lat : dict Latitudes corresponding to the minima indices with keys corresponding to data variables min_sec : dict Seconds from the starting time corresponding to the minima indices with keys corresponding to data variables min_lat_break : dict Indices of the latitude breaks with keys corresponding to data variables for the minima min_lin_fit : dict Output from scipy.stats.linregress for each valid fit period max_lat : dict Latitudes corresponding to the maxima indices with keys corresponding to data variables max_sec : dict Seconds from the starting time corresponding to the maxima indices with keys corresponding to data variables max_lat_break : dict Indices of the latitude breaks with keys corresponding to data variables for the maxima max_lin_fit : dict Output from scipy.stats.linregress for each valid fit period fig : plt.Figure Figure handle """ # Get a subset in time of the SAMI3 dataset sel_sami = sami.sel(num_times=sami['datetime'].num_times[nt_start:nt_stop]) start = pds.to_datetime(sami['datetime'][nt_start].values).to_pydatetime() # Set the data keys, if needed if dat_keys in ['c', 'd']: if dat_keys == 'd': peak_heights = [5.0, 0.025, 5.0] else: peak_heights = [None, 0.025, None] dat_keys = ["_".join([dkey, dat_keys]) for dkey in [ 'rel_vnq', 'rel_dene', 'rel_vsi2']] dat_scale = [100.0, 1.0, 100.0] dat_labels = ['\n'.join([r'$\Delta$ u$_{||}$', r'Geo Lat ($^\circ$N)']), '\n'.join([r'$\Delta N_e/N_e$', r'Geo Lat ($^\circ$N)']), '\n'.join([r'$\Delta$ v$_{{||}_{O^+}}$', r'Geo Lat ($^\circ$N)'])] if None in [dat_scale, dat_labels, peak_heights]: raise ValueError('must provide dat_scale, dat_labels, and peak_heights') # Calculate any data that is needed if None in [min_lat, min_sec, min_lat_break]: # Get the peak indices min_ind, max_ind = analysis.get_topside_peaks( sel_sami, nzinds, dat_keys, dat_scale, peak_heights) # Get the data along the minima min_lat, min_sec, min_lat_break = analysis.find_linear_breaks( sel_sami, nlind, nfind, nzinds, min_ind) else: max_ind = None if None in [max_lat, max_sec, max_lat_break]: if max_ind is None: # Get the peak indices min_ind, max_ind = analysis.get_topside_peaks( sel_sami, nzinds, dat_keys, dat_scale, peak_heights) # Get the data along the minima max_lat, max_sec, max_lat_break = analysis.find_linear_breaks( sel_sami, nlind, nfind, nzinds, max_ind) if min_lin_fit is None: min_lin_fit = analysis.fit_lines_to_peaks(min_lat, min_sec, min_lat_break) if max_lin_fit is None: max_lin_fit = analysis.fit_lines_to_peaks(max_lat, max_sec, max_lat_break) # Create the figure fig = plt.figure(figsize=(7.98, 7.3)) ax = {dkey: fig.add_subplot(len(dat_keys), 1, 1 + i) for i, dkey in enumerate(dat_keys)} # Cycle through each of the axes ylim = [None, None] for i, dkey in enumerate(dat_keys): # Plot the minima ax[dkey].plot([start + dt.timedelta(seconds=tval) for tval in min_sec[dkey]], min_lat[dkey], 'o', color=pr.nrl_colors(1), label='Minima') # Plot the maxima ax[dkey].plot([start + dt.timedelta(seconds=tval) for tval in max_sec[dkey]], max_lat[dkey], 's', color=pr.nrl_colors(0), label='Maxima') # Add the line fits, if desired if add_lines: # Cycle through each minima fit for fit in min_lin_fit[dkey]: xcalc = np.linspace(fit[1], fit[2], 100) xplot = [start + dt.timedelta(seconds=x) for x in xcalc] yplot = fit[0].slope * xcalc + fit[0].intercept if add_line_labels: label = "{:.3f}x {:s} {:.3f}; r={:.2f}".format( fit[0].slope, "+" if fit[0].intercept >= 0 else "-", fit[0].intercept, fit[0].rvalue) else: label = None ax[dkey].plot(xplot, yplot, "--", color=pr.nrl_colors(3), label=label, lw=2) # Cycle through each maxima fit for fit in max_lin_fit[dkey]: xcalc = np.linspace(fit[1], fit[2], 100) xplot = [start + dt.timedelta(seconds=x) for x in xcalc] yplot = fit[0].slope * xcalc + fit[0].intercept if add_line_labels: label = "{:.3f}x {:s} {:.3f}; r={:.2f}".format( fit[0].slope, "+" if fit[0].intercept >= 0 else "-", fit[0].intercept, fit[0].rvalue) else: label = None ax[dkey].plot(xplot, yplot, "-.", color=pr.nrl_colors(4), label=label, lw=2) # Format the axis ax[dkey].set_ylabel(dat_labels[i]) ax[dkey].yaxis.set_major_locator(mpl.ticker.MultipleLocator(10)) ax[dkey].grid() ax[dkey].set_xlim(sel_sami['datetime'].values[0], sel_sami['datetime'].values[-1]) spec = ax[dkey].get_subplotspec() if spec.is_last_row(): ax[dkey].xaxis.set_major_formatter( mpl.dates.DateFormatter('%j\n%H:%M')) ax[dkey].set_xlabel('Universal Time') else: ax[dkey].xaxis.set_major_formatter( mpl.ticker.FormatStrFormatter('')) if spec.is_first_row(): ax[dkey].legend(fontsize='small', numpoints=1, loc=1, bbox_to_anchor=(.75, 1.25), ncols=2) # Get the y-axis limits ax_ylim = ax[dkey].get_ylim() if ylim[0] is None or ylim[0] < ax_ylim[0]: ylim[0] = ax_ylim[0] if ylim[1] is None or ylim[1] > ax_ylim[1]: ylim[1] = ax_ylim[1] for aa in ax.values(): aa.set_ylim(ylim) return(min_lat, min_sec, min_lat_break, min_lin_fit, max_lat, max_sec, max_lat_break, max_lin_fit, fig)