def load_def_omni(tint, cfg, data_path): """Loads Density Energy Flux spectrum Parameters ---------- tint : list of str Time interval cfg : dict Hash table from configuration file. Returns ------- """ ic = np.arange(1, 5) suf = "fpi_{}_{}".format(cfg["data_rate"], cfg["level"]) # Ion/electron omni directional energy flux def_omni_mms_i = [ get_data("DEFi_{}".format(suf), tint, i, data_path=data_path) for i in ic[:-1] ] def_omni_mms_e = [ get_data("DEFe_{}".format(suf), tint, i, data_path=data_path) for i in ic[:-1] ] def_omni_i, def_omni_e = [ avg_4sc(def_omni) for def_omni in [def_omni_mms_i, def_omni_mms_e] ] return def_omni_i, def_omni_e
def load_def_omni(tint, cfg): """Loads Density Energy Flux spectrum """ ic = np.arange(1, 5) suf = "fpi_{}_{}".format(cfg["data_rate"], cfg["level"]) # Ion/electron omni directional energy flux def_omni_mms_i = [ get_data("DEFi_{}".format(suf), tint, i) for i in ic[:-1] ] def_omni_mms_e = [ get_data("DEFe_{}".format(suf), tint, i) for i in ic[:-1] ] def_omni_i, def_omni_e = [ avg_4sc(def_omni) for def_omni in [def_omni_mms_i, def_omni_mms_e] ] return def_omni_i, def_omni_e
def st_derivative(r, b, mva, crossing_times): """ Computes velocity of the structure using spatio-temporal derivative method """ b_xyz = avg_4sc(b) # Gradient of the magnetic field grad_b = c_4_grad(r, b) db_dt = gradient(b_xyz) # Transform gradient to LMN frame l_grad_b = np.matmul(grad_b.data, mva[:, 0]) m_grad_b = np.matmul(grad_b.data, mva[:, 1]) n_grad_b = np.matmul(grad_b.data, mva[:, 2]) # Compute velocity of the structure using MDD v_str = np.zeros(db_dt.shape) v_str[:, 0] = np.sum(db_dt * l_grad_b, axis=1) / np.linalg.norm(l_grad_b, axis=1)**2 v_str[:, 1] = np.sum(db_dt * m_grad_b, axis=1) / np.linalg.norm(m_grad_b, axis=1)**2 v_str[:, 2] = np.sum(db_dt * n_grad_b, axis=1) / np.linalg.norm(n_grad_b, axis=1)**2 dt = calc_dt(b_xyz) y_m = np.abs(np.cumsum(-v_str[:, 1]) * dt) z_n = np.cumsum(-v_str[:, 2]) * dt v_str = ts_vec_xyz(b_xyz.time.data, -v_str) y_m = ts_scalar(b_xyz.time.data, y_m) z_n = ts_scalar(b_xyz.time.data, z_n) z_off = resample(t_eval(z_n, crossing_times), y_m) z_n -= z_off return v_str, y_m, z_n
def main(args): """main function """ # Read time intervals with open(args.config) as f: cfg = yaml.load(f, Loader=yaml.FullLoader) tint_over = cfg["tints"]["overview"] tint_flap = cfg["tints"]["flapping"] mms_ids = np.arange(1, 5) # Load spacecraft position r_mms = [ get_data("R_gsm", tint_over, i, data_path=cfg["data_path"]) for i in mms_ids ] # Load background magnetic field suf_b = "fgm_{}_{}".format(cfg["fgm"]["data_rate"], cfg["fgm"]["level"]) b_mms = [ get_data("B_gsm_{}".format(suf_b), tint_over, i, args.verbose, data_path=cfg["data_path"]) for i in mms_ids ] # Earth radius r_earth = constants.R_earth.value * 1e-3 # Spacecraft position and magnetic field at the center of mass of the # tetrahedron r_xyz = avg_4sc(r_mms) / r_earth b_xyz = avg_4sc(b_mms) # Load moments of the velocity distribution function moments_i, moments_e = load_moments(tint_over, cfg["fpi"], args, cfg["data_path"]) # Load omni directional energy flux def_omni = load_def_omni(tint_over, cfg["fpi"], cfg["data_path"]) # Unpack moments v_xyz_i, t_xyz_i = moments_i[1:3] _, t_xyz_e = moments_e[1:3] v_gsm_i = cotrans(v_xyz_i, "gse>gsm") # Unpack energy flux def_omni_i, def_omni_e = def_omni # Compute temperature tensor in field aligned coordinates t_xyzfac_i = rotate_tensor(t_xyz_i, "fac", b_xyz, "pp") t_xyzfac_e = rotate_tensor(t_xyz_e, "fac", b_xyz, "pp") # Get parallel, perpendicular and total temperature t_para_i, t_perp_i = [t_xyzfac_i[:, 0, 0], t_xyzfac_i[:, 1, 1]] t_para_e, t_perp_e = [t_xyzfac_e[:, 0, 0], t_xyzfac_e[:, 1, 1]] # Figure options legend_options = dict(frameon=True, ncol=3) spectr_options = dict(yscale="log", cscale="log", cmap="Spectral_r") # Plot fig = plt.figure(**cfg["figure"]["main"]) gsp1 = fig.add_gridspec(12, 1, **cfg["figure"]["gridspec"]) gsp10 = gsp1[1:9].subgridspec(4, 1, hspace=0) gsp11 = gsp1[10:].subgridspec(1, 1, hspace=0) # Create axes in the grid spec axs10 = [fig.add_subplot(gsp10[i]) for i in range(4)] axs11 = [fig.add_subplot(gsp11[i]) for i in range(1)] # Magnetic field plot_line(axs10[0], b_xyz) axs10[0].legend(["$B_x$", "$B_y$", "$B_z$"], loc="upper right", **legend_options) axs10[0].set_ylim([-23, 23]) axs10[0].set_ylabel("$B$ [nT]") # Ions bulk velocity plot_line(axs10[1], v_gsm_i) axs10[1].legend(["$V_{ix}$", "$V_{iy}$", "$V_{iz}$"], loc="upper right", **legend_options) axs10[1].set_ylabel("$V_i$ [km s$^{-1}$]") axs10[1].grid(True, which="both") # Ions energy spectrum axs10[2], caxs02 = plot_spectr(axs10[2], def_omni_i, clim=[1e4, 1e6], **spectr_options) plot_line(axs10[2], t_perp_i, color="k") plot_line(axs10[2], t_para_i, color="tab:blue") axs10[2].legend(["$T_{i,\\perp}$", "$T_{i,\\parallel}$"], loc="lower right", **legend_options) axs10[2].set_ylabel("$E_i$ [eV]") caxs02.set_ylabel("DEF" + "\n" + "[keV/(cm$^2$ s sr keV)]") axs10[2].grid(False, which="both") # Electrons energy spectrum axs10[3], caxs11 = plot_spectr(axs10[3], def_omni_e, clim=[1e5, 3e7], **spectr_options) plot_line(axs10[3], t_perp_e, color="k") plot_line(axs10[3], t_para_e, color="tab:blue") axs10[3].legend(["$T_{e,\\perp}$", "$T_{e,\\parallel}$"], loc="lower right", **legend_options) axs10[3].set_ylabel("$E_e$ [eV]") caxs11.set_ylabel("DEF" + "\n" + "[keV/(cm$^2$ s sr keV)]") axs10[3].grid(False, which="both") axs10[-1].get_shared_x_axes().join(*axs10) fig.align_ylabels(axs10) for ax in axs10[:-1]: ax.xaxis.set_ticklabels([]) axs10[-1].set_xlim(mdates.datestr2num(tint_over)) # Zoom plot_line(axs11[0], b_xyz) axs11[0].legend(["$B_x$", "$B_y$", "$B_z$"], loc="upper right", **legend_options) axs11[0].set_ylim([-15, 15]) axs11[0].set_ylabel("$B$ [nT]") axs11[0].grid(True, which="both") axs11[0].set_xlim(mdates.datestr2num(tint_flap)) span_options = dict(linestyle="--", linewidth=0.8, facecolor="none", edgecolor="k") span_tint(axs10, tint_flap, **span_options) axr = set_rlabel(axs10[0], r_xyz, spine=0, position="top") axr.set_xlabel("$X_{GSM}$ [$R_E$]\n$Y_{GSM}$ [$R_E$]\n$Z_{GSM}$ [$R_E$]", fontsize=9) axr.xaxis.set_label_coords(-.13, 1.1) zoom(axs11[0], axs10[-1], ec="k") print(axs10[-1].get_xticklabels()) # number subplots labels_pos = [0.02, 0.83] _ = make_labels(axs10 + axs11, labels_pos) if args.figname: fig.savefig(args.figname) else: plt.show()
def load_moments(tint, cfg, args): """ Load FPI moments of the velocity distribution functions. If the option moments is set to "part" then use partial moments instead. """ ic = np.arange(1, 5) suf = "fpi_{}_{}".format(cfg["data_rate"], cfg["level"]) if cfg["moments"] == "partial": # index to split partial moments (from quasi-neutrality assumption) part_idx_i, part_idx_e = [cfg[f"part_idx_{s}"] for s in ["i", "e"]] # Load partial moments # number density part_n_i = [ get_data("partNi_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] part_n_e = [ get_data("partNe_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] # bulk velocity part_v_i = [ get_data("partVi_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] part_v_e = [ get_data("partVe_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] # temperature tensor part_t_i = [ get_data("partTi_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] part_t_e = [ get_data("partTe_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] # pressure tensor part_p_i = [ get_data("partPi_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] part_p_e = [ get_data("partPe_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] # split partial moments # number density n_i = [part_n_i[i - 1][:, part_idx_i] for i in ic[:-1]] n_e = [part_n_e[i - 1][:, part_idx_e] for i in ic[:-1]] # bulk velocity v_i = [part_v_i[i - 1][:, part_idx_i, ...] for i in ic[:-1]] v_e = [part_v_e[i - 1][:, part_idx_e, ...] for i in ic[:-1]] # temperature tensor t_i = [part_t_i[i - 1][:, part_idx_i, ...] for i in ic[:-1]] t_e = [part_t_e[i - 1][:, part_idx_e, ...] for i in ic[:-1]] # pressure tensor p_i = [part_p_i[i - 1][:, part_idx_i, ...] for i in ic[:-1]] p_e = [part_p_e[i - 1][:, part_idx_e, ...] for i in ic[:-1]] elif cfg["moments"] == "full": # number density n_i = [ get_data("Ni_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] n_e = [ get_data("Ne_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] # bulk velocity v_i = [ get_data("Vi_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] v_e = [ get_data("Ve_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] # temperature tensor t_i = [ get_data("Ti_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] t_e = [ get_data("Te_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] # pressure tensor p_i = [ get_data("Pi_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] p_e = [ get_data("Pe_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] else: raise ValueError("Invalid moments type") # Load spintone correction spintone_i = [ get_data("STi_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] spintone_e = [ get_data("STe_gse_{}".format(suf), tint, i, args.verbose) for i in ic[:-1] ] # remove spintone correction v_i = [v - spintone_i[i] for i, v in enumerate(v_i)] v_e = [v - spintone_e[i] for i, v in enumerate(v_e)] moments_i = [n_i, v_i, t_i, p_i] moments_e = [n_e, v_e, t_e, p_e] moments_i = [avg_4sc(moment) for moment in moments_i] moments_e = [avg_4sc(moment) for moment in moments_e] return moments_i, moments_e
def main(args): """main function """ # Read time intervals with open(args.config) as f: cfg = yaml.load(f, Loader=yaml.FullLoader) tint_flap = cfg["tints"]["flapping"] tint_zoom = cfg["tints"]["close-up"] mms_ids = np.arange(1, 5) # Load spacecraft position and background magnetic field r_mms = [ get_data("R_gse", tint_flap, i, args.verbose, data_path=cfg["data_path"]) for i in mms_ids ] suf_b = "fgm_{}_{}".format(cfg["fgm"]["data_rate"], cfg["fgm"]["level"]) b_mms = [ get_data("B_gse_{}".format(suf_b), tint_flap, i, args.verbose, data_path=cfg["data_path"]) for i in mms_ids ] # Remove offset on z component of the background magnetic field b_mms = remove_bz_offset(b_mms) # Compute magnetic field at the center of mass of the tetrahedron j_xyz, _, b_xyz, _, _, _ = c_4_j(r_mms, b_mms) j_xyz *= 1e9 # j A.m^{-2}->nA.m^{-2} # Compute magnetic field at the center of mass of the tetrahedron b_xyz = avg_4sc(b_mms) # Compute MVA frame b_lmn, _, lmn = mva(b_xyz) # Correct minimum variance frame # lmn = np.vstack([lmn[:, 0], -lmn[:, 2], lmn[:, 1]]).T l = lmn[:, 0] m = np.mean(j_xyz.data, axis=0) / np.linalg.norm(np.mean(j_xyz, axis=0)) n = np.cross(l, m) / np.linalg.norm(np.cross(l, m)) m = np.cross(n, l) lmn = np.transpose(np.vstack([l, m, n])) b_xyz = time_clip(b_mms[args.mms_id - 1], tint_zoom) b_lmn = new_xyz(b_xyz, lmn) # Load electric field and magnetic field fluctuation # Load electric field suf_e = "edp_{}_{}".format(cfg["edp"]["data_rate"], cfg["edp"]["level"]) e_xyz = get_data("e_gse_{}".format(suf_e), tint_zoom, args.mms_id, args.verbose, data_path=cfg["data_path"]) # Load electric field suf_db = "scm_{}_{}".format(cfg["scm"]["data_rate"], cfg["scm"]["level"]) b_scm = get_data("b_gse_{}".format(suf_db), tint_zoom, args.mms_id, args.verbose, data_path=cfg["data_path"]) # Load density and pressure tensor moments_i, moments_e = load_moments(tint_flap, cfg["fpi"], args, data_path=cfg["data_path"]) # Unpack moments _, _, _, p_xyz_i = moments_i n_e, _, _, p_xyz_e = moments_e # Total pressure tensor p_xyz = p_xyz_i + resample(p_xyz_e, p_xyz_i) # Convert to field-aligned coordinates p_xyzfac = rotate_tensor(p_xyz, "fac", b_xyz, "pp") # Permittivity mu0 = constants.mu_0 # Thermal pressure (scalar) pth = 1e-9 * trace(p_xyzfac) / 3. # Magnetic pressure p_mag = 1e-18 * norm(b_xyz)**2 / (2 * mu0) # Plasma beta beta = resample(pth, b_xyz) / p_mag # Plasma parameters plasma_params = plasma_calc(b_xyz, n_e, n_e, n_e, n_e) # Convert electric field and magnetic field fluctuation to field aligned # coordinates e_xyzfac = convert_fac(e_xyz, b_xyz, [1, 0, 0]) # bandpass filter electric field and magnetic field fluctuation f_min = 4 e_xyzfac_hf = filt(e_xyzfac, f_min, 0, 3) cwt_options = dict(nf=100, f=[0.5, 1e3], plot=False) # Compute continuous wavelet transform of the electric field e_xyzfac_cwt = wavelet(e_xyzfac, **cwt_options) # Construct compressed spectrogram of E e_cwt_times, e_cwt_x, e_cwt_y, e_cwt_z = compress_cwt(e_xyzfac_cwt, nc=100) e_cwt = xr.DataArray(e_cwt_x + e_cwt_y + e_cwt_z, coords=[e_cwt_times, e_xyzfac_cwt.frequency], dims=["time", "frequency"]) # Compute continuous wavelet transform of the magnetic field fluctuations b_scm_cwt = wavelet(b_scm, **cwt_options) # Construct compressed spectrogram of E b_cwt_times, b_cwt_x, b_cwt_y, b_cwt_z = compress_cwt(b_scm_cwt, nc=100) b_cwt = xr.DataArray(b_cwt_x + b_cwt_y + b_cwt_z, coords=[b_cwt_times, b_scm_cwt.frequency], dims=["time", "frequency"]) # Plot fig, axs = plt.subplots(4, sharex="all", figsize=(6.5, 9)) fig.subplots_adjust(bottom=.05, top=.95, left=.15, right=.85, hspace=0.) kwargs_legend = dict(ncol=3, loc="upper right", frameon=True) kwargs_spectr = dict(cscale="log", yscale="log", cmap="Spectral_r", clim=[1e-7, 1e0]) plot_line(axs[0], b_lmn) axs[0].legend(["$B_L$", "$B_M$", "$B_N$"], **cfg["figure"]["legend"]) axs[0].set_ylabel("$B$ [nT]") axs[0].grid(True, which="both") plot_line(axs[1], e_xyzfac_hf) labels = ["$E_{\\perp 1}$", "$E_{\\perp 2}$", "$E_{\\parallel}$"] axs[1].legend(labels, **cfg["figure"]["legend"]) axs[1].set_ylabel("$E$ [mV m$^{-1}$]") axs[1].set_ylim([-9, 9]) axs[1].set_yticks([-6, 0, 6]) axs1b = axs[1].twinx() plot_line(axs1b, beta, color="k") axs1b.set_yscale("log") axs1b.set_ylabel("$\\beta$") axs1b.set_ylim([10**(.5) * 1e0, 10**(.5) * 1e3]) axs[1].grid(True, which="both") axs[2], caxs2 = plot_spectr(axs[2], e_cwt, **cfg["figure"]["spectrum"]) plot_line(axs[2], plasma_params.f_lh, color="k", label="$f_{lh}$") plot_line(axs[2], plasma_params.f_ce, color="w", label="$f_{ce}$") plot_line(axs[2], plasma_params.f_pp, color="red", label="$f_{pi}$") axs[2].set_ylim([0.5, 1e3]) axs[2].set_ylabel("$f$ [Hz]") caxs2.set_ylabel("$E^2$ " + "\n" + "[mV$^2$ m$^{-2}$ Hz$^{-1}$]") axs[2].legend(**cfg["figure"]["legend"]) axs[3], caxs3 = plot_spectr(axs[3], b_cwt, **cfg["figure"]["spectrum"]) plot_line(axs[3], plasma_params.f_lh, color="k", label="$f_{lh}$") plot_line(axs[3], plasma_params.f_ce, color="w", label="$f_{ce}$") plot_line(axs[3], plasma_params.f_pp, color="red", label="$f_{pi}$") axs[3].set_ylim([0.5, 1e3]) axs[3].set_ylabel("$f$ [Hz]") caxs3.set_ylabel("$B^2$ " + "\n" + "[nT$^2$ Hz$^{-1}$]") axs[3].legend(**cfg["figure"]["legend"]) fig.align_ylabels(axs) axs[1].text(.85, .15, "$f > ${:2.1f} Hz".format(f_min), transform=axs[1].transAxes) # Time interval of the flapping axs[-1].set_xlim(mdates.date2num(tint_zoom)) # Add panels labels labels_pos = [0.02, 0.90] _ = make_labels(axs, labels_pos) if args.figname: fig.savefig(args.figname, **cfg["figure"]["save"]) else: plt.show()
def main(args): """main function """ # Read time intervals with open(args.config) as f: cfg = yaml.load(f, Loader=yaml.FullLoader) tint_flap = cfg["tints"]["flapping"] tint_zoom = cfg["tints"]["close-up"] mms_ids = np.arange(1, 5) # Load spacecraft position r_mms = [ get_data("R_gse", tint_flap, i, data_path=cfg["data_path"]) for i in mms_ids ] # Load background magnetic field suf_b = "fgm_{}_{}".format(cfg["fgm"]["data_rate"], cfg["fgm"]["level"]) b_mms = [ get_data("B_gse_{}".format(suf_b), tint_flap, i, args.verbose, data_path=cfg["data_path"]) for i in mms_ids ] # Load electric field suf_e = "edp_{}_{}".format(cfg["edp"]["data_rate"], cfg["edp"]["level"]) e_mms = [ get_data("e_gse_{}".format(suf_e), tint_flap, i, args.verbose, data_path=cfg["data_path"]) for i in mms_ids ] # Load moments from FPI moments_i, moments_e = load_moments(tint_flap, cfg["fpi"], args, data_path=cfg["data_path"]) # Remove offset on z component of the background magnetic field b_mms = remove_bz_offset(b_mms) # Compute current density j_xyz, _, b_xyz, _, _, _ = c_4_j(r_mms, b_mms) j_xyz *= 1e9 # j A.m^{-2}->nA.m^{-2} # Compute electric field at the center of mass of the tetrahedron e_xyz = avg_4sc(e_mms) # Compute new coordinates system lmn = lmn_cs(b_xyz, moments_i[1]) # Resample magnetic field and current density to electric field sampling b_xyz, j_xyz = [resample(field, e_xyz) for field in [b_xyz, j_xyz]] # Transform fields to MVA frame b_lmn, e_lmn, j_lmn = [new_xyz(x_, lmn) for x_ in [b_xyz, e_xyz, j_xyz]] # Resample ion/electron moments to electric field sampling moments_i = [resample(mom, e_xyz) for mom in moments_i] moments_e = [resample(mom, e_xyz) for mom in moments_e] # Transform moments moments_lmn_i = [moments_i[0], None, None, None] moments_lmn_e = [moments_e[0], None, None, None] moments_lmn_i[1:] = [new_xyz(mom, lmn) for mom in moments_i[1:]] moments_lmn_e[1:] = [new_xyz(mom, lmn) for mom in moments_e[1:]] # Compute terms of the Ohm's law vxb_lmn_i, vxb_lmn_e, jxb_lmn = calc_ol_terms(b_lmn, j_lmn, moments_lmn_i, moments_lmn_e) # Compute ion scale total contribution s_lmn = -vxb_lmn_i + jxb_lmn # Plot fig = plt.figure(**cfg["figure"]["main"]) gs0 = fig.add_gridspec(2, 1, **cfg["figure"]["gridspec"]) gs00 = gs0[:1].subgridspec(4, 1, hspace=0) gs10 = gs0[1:].subgridspec(4, 1, hspace=0) axs0 = [fig.add_subplot(gs00[i]) for i in range(4)] axs1 = [fig.add_subplot(gs10[i]) for i in range(4)] for axs in [axs0, axs1]: plot_line(axs[0], b_lmn) axs[0].legend(["$B_L$", "$B_M$", "$B_N$"], **cfg["figure"]["legend"]) axs[0].set_ylabel("$B$" + "\n" + "[nT]") axs[0].grid(True, which="both") plot_line(axs[1], jxb_lmn[:, 1], label="$J\\times B / ne$") plot_line(axs[1], -vxb_lmn_i[:, 1], label="$-V_i\\times B$") plot_line(axs[1], s_lmn[:, 1], label="$J\\times B / ne -V_i\\times B$") plot_line(axs[1], e_lmn[:, 1], label="$E_{EDP}$") axs[1].set_ylim([-12, 12]) axs[1].set_ylabel("$E_M$" + "\n" + "[mV m$^{-1}$]") axs[1].grid(True, which="both") plot_line(axs[2], jxb_lmn[:, 2], label="$J\\times B / ne$") plot_line(axs[2], -vxb_lmn_i[:, 2], label="$-V_i\\times B$") plot_line(axs[2], s_lmn[:, 2], label="$J\\times B / ne -V_i\\times B$") plot_line(axs[2], e_lmn[:, 2], label="$E_{EDP}$") axs[2].legend(frameon=True, ncol=2, bbox_to_anchor=(1, 1.3), loc="upper right") axs[2].set_ylim([-12, 12]) axs[2].set_ylabel("$E_N$" + "\n" + "[mV m$^{-1}$]") axs[2].grid(True, which="both") plot_line(axs[3], norm(e_xyz + vxb_lmn_i), color="deeppink", label="$| E+V_{i}\\times B |$") plot_line(axs[3], norm(jxb_lmn), color="tab:blue", label="$|J\\times B / ne|$") axs[3].legend(**cfg["figure"]["legend"]) axs[3].set_ylim([0, 12]) axs[3].set_ylabel("$|E|$" + "\n" + "[mV m$^{-1}$]") axs[3].grid(True, which="both") axs[-1].get_shared_x_axes().join(*axs) fig.align_ylabels(axs) for ax in axs[:-1]: ax.xaxis.set_ticklabels([]) axs0[-1].set_xlim(mdates.date2num(tint_flap)) axs1[-1].set_xlim(mdates.date2num(tint_zoom)) # zoom zoom(axs1[0], axs0[-1], ec="k") span_options = dict(linestyle="--", linewidth=0.8, facecolor="none", edgecolor="k") span_tint(axs0, tint_zoom, **span_options) # number subplots labels_pos = [0.02, 0.83] _ = make_labels(axs0 + axs1, labels_pos) if args.figname: fig.savefig(args.figname, **cfg["figure"]["save"]) else: plt.show()