Source code for FIREQ_PLOTTER.plotting.plot_2d

"""Interactive 2D line plot of the experiment data."""

import json
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np

from .common import TIME_MULTIPLIER, add_sliders, get_var_names, load_exported_dataframe


[docs] def _plot_2d( exp_dir: str, plot_magnitude: bool = True, plot_imag: bool = False, plot_real: bool = False, save: bool = False, ) -> None: """Interactive 2D plot of the experiment data. :param exp_dir: experiment directory. :type exp_dir: str :param plot_magnitude: plot the magnitude. :type plot_magnitude: bool :param plot_imag: plot the imaginary part. :type plot_imag: bool :param plot_real: plot the real part. :type plot_real: bool :param save: also save the figure as a_figure.png. :type save: bool """ exp_path = Path(exp_dir) dataframe = load_exported_dataframe(exp_path) if dataframe is None: return # Load experiment configuration with open(exp_path / "config.json") as f: config = json.load(f) output_type = config["sys_config"]["/axisAcquisitionIP_0"]["$output_type"] var_names = get_var_names(dataframe) if output_type in ("raw", "decimated"): xlabel = "Time" slider_vars = var_names else: if not var_names: print(f"No sweep variables in experiment {exp_path.name}; use plot_iq for accumulated data.") return xlabel = var_names[0] slider_vars = var_names[1:] var_values = { name: np.linspace( config["variables"][name]["start"], config["variables"][name]["stop"], config["variables"][name]["num"], ) for name in var_names } plt.style.use("seaborn-v0_8-darkgrid") fig, ax = plt.subplots(figsize=(8, 5)) plt.subplots_adjust(bottom=0.08 * max(2, len(slider_vars) + 1)) lines = {} if plot_real: lines["real"], = ax.plot([], [], lw=2, label="Real") if plot_imag: lines["imag"], = ax.plot([], [], "--", lw=2, label="Imag") if plot_magnitude: lines["mag"], = ax.plot([], [], ":", lw=2, label="Magnitude") ax.legend() ax.set_xlabel(xlabel) ax.set_ylabel("Amplitude") ax.set_title(exp_path.name) def update(_: object = None) -> None: """Redraw the plot with the current slider selections. :param _: slider value (unused). :type _: object """ df = dataframe # Apply slider selections for var in slider_vars: idx = int(sliders[var].val) df = df[df.index.get_level_values(var) == idx] if df.empty: return if output_type in ("raw", "decimated"): x = ( df.index.get_level_values("time").to_numpy() * TIME_MULTIPLIER[output_type] ) y = df["value"].to_numpy() else: # REAL sweep values instead of integer indices x = var_values[var_names[0]] y = df["value"].to_numpy() if "real" in lines: lines["real"].set_data(x, np.real(y)) if "imag" in lines: lines["imag"].set_data(x, np.imag(y)) if "mag" in lines: lines["mag"].set_data(x, np.abs(y)) ax.relim() ax.autoscale_view() fig.canvas.draw_idle() sliders = add_sliders(slider_vars, var_values, update) update() if save: plt.savefig(exp_path / "a_figure.png") plt.show()