Module pylars.plotting.plotfixwindow

Collection of functions to plot and analyse the fixed window processing.

Expand source code
"""Collection of functions to plot and analyse the fixed window processing.
"""

from typing import Optional, Tuple
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import pylars


def plot_LED_window(waveform: np.ndarray, led_window, figax=None):
    """Plot the LED window on top of the waveform.
    """
    if figax is None:
        fig, ax = plt.subplots(1, 1, figsize=(6, 4), dpi=60)
    else:
        fig, ax = figax

    ax = pylars.plotting.plot_waveform(waveform, ax=ax)
    ax.fill_betweenx([0, 16000], led_window[0], led_window[1],
                     alpha=0.1, color='C1')

    return fig, ax


def plot_LED_window_from_file(filename: str,
                              led_window: Tuple[int, int],
                              module: Optional[int] = None,
                              channel: Optional[str] = None,
                              wf_number: Optional[int] = None,
                              figax: Optional[Tuple] = None):
    """Plot the LED window on top of the waveform directly from a file.
    """

    process = pylars.processing.fixwindowprocessor.window_processor(
        baseline_samples=50, led_window=(105, 155))
    if module is None:
        module = 0

    print(f"Loading raw data from {filename}")
    process.load_raw_data(path_to_raw=filename, module=module)

    if channel is None:
        channel = str(np.random.choice(process.raw_data.channels))
        print(f"No channel specified, choosing random channel: {channel}")

    if wf_number is None:
        wf_number = int(np.random.choice(process.raw_data.n_waveforms))
        print(f"No waveform number specified, choosing random waveform:"
              f"{wf_number}")

    channel_data = process.raw_data.get_channel_data(channel)

    if figax is None:
        fig, ax = plt.subplots(1, 1, figsize=(6, 4), dpi=60)
    else:
        fig, ax = figax

    fig, ax = plot_LED_window(channel_data[wf_number],
                              led_window=led_window,
                              figax=(fig, ax))

    if figax is None:
        plt.show()
    else:
        return fig, ax


def plot_LED_all_channels(df_processed, figax=None):
    """Plot max ADC counts, amplitude and area for all channels.
    """
    if figax is None:
        fig, axs = plt.subplots(1, 3, figsize=(13, 4), sharey=True, dpi=60)
    else:
        fig, axs = figax

    plt.subplots_adjust(wspace=0)
    for ch in np.unique(df_processed['channel']):
        axs[0].hist(df_processed[df_processed['channel'] == ch]['led_ADCcounts'],
                    bins=100, histtype='step', label=f'{ch}')

        axs[1].hist(df_processed[df_processed['channel'] == ch]['led_amplitude'],
                    bins=100, histtype='step',)

        axs[2].hist(df_processed[df_processed['channel'] == ch]['led_area'],
                    bins=100, histtype='step',)

    axs[0].set_xlabel('max ADC counts')
    axs[0].set_ylabel('Counts')
    axs[1].set_xlabel('Amplitude [ADC counts]')
    axs[2].set_xlabel('Area [integrated yADC counts]')

    fig.legend(ncol=6, loc='upper center', bbox_to_anchor=(0.5, 1.05))

    [_ax.grid(color='lightgray', linestyle='--', linewidth=0.5) for _ax in axs]

    if figax is None:
        plt.show()
    else:
        return fig, axs


def plot_light_levels(led_processed_df: pd.DataFrame,
                      led_width: int,
                      channel: Optional[str] = None,
                      module: Optional[int] = None,
                      figax: Optional[Tuple] = None):
    """Plot the LED area histogram for all the available light levels."""

    select_mask = ((led_processed_df['LEDwidth'] == led_width) &
                   (led_processed_df['channel'] == channel) &
                   (led_processed_df['module'] == module))
    _df = led_processed_df[select_mask]

    if figax is None:
        fig, axs = plt.subplots(2, 1, figsize=(6, 8), dpi=60)
    else:
        fig, axs = figax

    _ledvoltages = np.unique(_df['LEDvoltage'])
    _median_amplitudes = []
    _std_amplitudes = []
    for _v in _ledvoltages:
        _mask = _df['LEDvoltage'] == _v
        axs[0].hist(_df[_mask]['led_area'],
                    bins=np.linspace(-1000, 25000, 500), histtype='step', label=f'{_v} V')
        _amp = np.median(_df[_mask]['led_area'])
        _std = np.std(_df[_mask]['led_area'])
        _median_amplitudes.append(_amp)
        _std_amplitudes.append(_std)
    axs[0].set_yscale('log')

    axs[1].errorbar(_ledvoltages, _median_amplitudes,
                    yerr=_std_amplitudes, marker='o',
                    ls='-')
    axs[1].set_xlabel('LED voltage [V]')
    axs[1].set_ylabel('Median Area [ADC counts]')
    axs[1].grid(color='lightgray', linestyle='--', linewidth=0.5)

    axs[0].set_xlabel('Area [ADC counts]')
    axs[0].set_ylabel('Counts')
    axs[0].legend(loc='center left', bbox_to_anchor=(1., 0.5),
                  title='LED voltage')
    axs[0].grid(color='lightgray', linestyle='--', linewidth=0.5)

    if figax is None:
        plt.show()
    else:
        return fig, axs


def plot_1_pe_fit_led(df_processed, led_voltage, module,
                      channel, A, mu, sigma, figax=None):
    """Plot the SPE Gaussean fit of the LED area histogram."""
    if figax is None:
        fig, ax = plt.subplots(1, 1, figsize=(5, 3), dpi=120)
    else:
        fig, ax = figax

    df_processed_mask = ((df_processed['module'] == module) &
                         (df_processed['channel'] == channel) &
                         (df_processed['LEDvoltage'] == led_voltage))
    hist = ax.hist(df_processed[df_processed_mask]['led_area'],
                   bins=np.linspace(-2000, 20000, 300), histtype='step')

    _x = np.linspace(mu * 0.5, mu * 1.5, 1000)
    ax.fill_between(_x, pylars.utils.common.Gaussian(_x, A, mu, sigma),
                    color='C1', alpha=1, zorder=-1)  # , ls = '--', linewidth = '2')
    [ax.axvline(mu * n, color='C1', ls='--', alpha=1) for n in range(5)]

    # ax.set_yscale('log')
    # ax.set_ylabel('Counts')
    #ax.set_xlabel('Area (window)')
    ax.set_ylim(0, 6000)
    if figax is None:
        plt.show()
    else:
        return fig, ax


def plot_gains_occ(df_gains, figaxs=None):
    """Plot the gains and occupancies for all the tiles."""
    if figaxs is None:
        fig, axs = plt.subplots(2, 1, figsize=(4, 4),
                                dpi=120, sharex=True,
                                gridspec_kw={'hspace': 0, 'wspace': 0},
                                constrained_layout=False)
        axs = axs.flatten()

    _x = np.arange(len(df_gains))
    axs[0].errorbar(_x, df_gains['gain'], yerr=df_gains['gain_err'],
                    ls='', capsize=4, marker='.')

    axs[1].errorbar(_x, df_gains['occ'], yerr=df_gains['occ_err'],
                    ls='', capsize=4, marker='.')

    axs[0].set_xticks(_x, df_gains['tile'])
    # axs[0].set_ylim(0,1.5)
    axs[0].set_ylabel('Gain [$10^6$]')
    axs[1].set_ylabel('Occupancy')
    # axs[1].set_ylim(-0.1,3.9)
    if figaxs is None:
        plt.show()

    else:
        return (fig, axs)


def plot_gain_evolution(gain_evolution: pd.DataFrame,
                        tile_list: list, mod,
                        figax=None):
    """Plot the gain evolution for a list of tiles."""

    if figax is None:
        fig, ax = plt.subplots(1, 1, figsize=(6, 4), dpi=120)
    else:
        fig, ax = figax

    for _tile in tile_list:
        _df = gain_evolution[gain_evolution['tile'] == _tile]
        ax.errorbar(_df['start'], _df['gain'], yerr=_df['gain_err'],
                    ls='--',
                    marker='.', label=_tile)
    ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left',
              title='Tile',
              labelspacing=1.0)
    ax.set_ylim(0, None)  # type:ignore
    ax.set_title(f'Gain evolution - ADC #{mod}')
    ax.tick_params(axis='x', rotation=45)
    ax.set_ylabel('SiPM Gain [M]')
    # plt.twinx()
    # plt.plot(tt09['datetime'], tt09['TT09'], 'k--', alpha = 0.3,
    #          zorder = -10,label='Gast temperature')

    # plt.axvline(np.datetime64('2024-06-14T17:00:00'),ls = '--', color = 'gray', alpha = 0.8)
    # plt.text(np.datetime64('2024-06-14T08:00:00'), 0.78,
    #          'Filling complete', color = 'gray',rotation=90)

    if figax is None:
        fig.savefig(f'21062024_mod{mod}.png')
        plt.show()
    else:
        return fig, ax


def plot_gains_occ_ledvoltage(LED_calib, module, channel, labels):
    """Plot the gains and occupancies for a given module and channel as a
    function of the LED voltage."""
    fig, ax = plt.subplots(1, 1, figsize=(6, 3))
    _df = LED_calib.results_df
    _df = _df[(_df['module'] == module) &
              (_df['channel'] == channel) &
              (_df['LEDvoltage'] > 1)]
    ax.errorbar(_df['LEDvoltage'], _df['gain'], yerr=_df['gain_err'], fmt='o')
    ax.set_xlabel('LED voltage [V]')
    ax.set_ylabel('Gain [ADC/PE/10^6]')
    ax.set_title(labels[f"mod{module}"][channel])

    ax1 = ax.twinx()
    ax1.errorbar(_df['LEDvoltage'], _df['occ'],
                 yerr=_df['occ_err'], fmt='o',
                 color='C1')
    ax1.set_ylabel('Occupancy [PE]', color='C1')
    ax.grid()
    plt.show()

Functions

def plot_1_pe_fit_led(df_processed, led_voltage, module, channel, A, mu, sigma, figax=None)

Plot the SPE Gaussean fit of the LED area histogram.

Expand source code
def plot_1_pe_fit_led(df_processed, led_voltage, module,
                      channel, A, mu, sigma, figax=None):
    """Plot the SPE Gaussean fit of the LED area histogram."""
    if figax is None:
        fig, ax = plt.subplots(1, 1, figsize=(5, 3), dpi=120)
    else:
        fig, ax = figax

    df_processed_mask = ((df_processed['module'] == module) &
                         (df_processed['channel'] == channel) &
                         (df_processed['LEDvoltage'] == led_voltage))
    hist = ax.hist(df_processed[df_processed_mask]['led_area'],
                   bins=np.linspace(-2000, 20000, 300), histtype='step')

    _x = np.linspace(mu * 0.5, mu * 1.5, 1000)
    ax.fill_between(_x, pylars.utils.common.Gaussian(_x, A, mu, sigma),
                    color='C1', alpha=1, zorder=-1)  # , ls = '--', linewidth = '2')
    [ax.axvline(mu * n, color='C1', ls='--', alpha=1) for n in range(5)]

    # ax.set_yscale('log')
    # ax.set_ylabel('Counts')
    #ax.set_xlabel('Area (window)')
    ax.set_ylim(0, 6000)
    if figax is None:
        plt.show()
    else:
        return fig, ax
def plot_LED_all_channels(df_processed, figax=None)

Plot max ADC counts, amplitude and area for all channels.

Expand source code
def plot_LED_all_channels(df_processed, figax=None):
    """Plot max ADC counts, amplitude and area for all channels.
    """
    if figax is None:
        fig, axs = plt.subplots(1, 3, figsize=(13, 4), sharey=True, dpi=60)
    else:
        fig, axs = figax

    plt.subplots_adjust(wspace=0)
    for ch in np.unique(df_processed['channel']):
        axs[0].hist(df_processed[df_processed['channel'] == ch]['led_ADCcounts'],
                    bins=100, histtype='step', label=f'{ch}')

        axs[1].hist(df_processed[df_processed['channel'] == ch]['led_amplitude'],
                    bins=100, histtype='step',)

        axs[2].hist(df_processed[df_processed['channel'] == ch]['led_area'],
                    bins=100, histtype='step',)

    axs[0].set_xlabel('max ADC counts')
    axs[0].set_ylabel('Counts')
    axs[1].set_xlabel('Amplitude [ADC counts]')
    axs[2].set_xlabel('Area [integrated yADC counts]')

    fig.legend(ncol=6, loc='upper center', bbox_to_anchor=(0.5, 1.05))

    [_ax.grid(color='lightgray', linestyle='--', linewidth=0.5) for _ax in axs]

    if figax is None:
        plt.show()
    else:
        return fig, axs
def plot_LED_window(waveform: numpy.ndarray, led_window, figax=None)

Plot the LED window on top of the waveform.

Expand source code
def plot_LED_window(waveform: np.ndarray, led_window, figax=None):
    """Plot the LED window on top of the waveform.
    """
    if figax is None:
        fig, ax = plt.subplots(1, 1, figsize=(6, 4), dpi=60)
    else:
        fig, ax = figax

    ax = pylars.plotting.plot_waveform(waveform, ax=ax)
    ax.fill_betweenx([0, 16000], led_window[0], led_window[1],
                     alpha=0.1, color='C1')

    return fig, ax
def plot_LED_window_from_file(filename: str, led_window: Tuple[int, int], module: Union[int, NoneType] = None, channel: Union[str, NoneType] = None, wf_number: Union[int, NoneType] = None, figax: Union[Tuple, NoneType] = None)

Plot the LED window on top of the waveform directly from a file.

Expand source code
def plot_LED_window_from_file(filename: str,
                              led_window: Tuple[int, int],
                              module: Optional[int] = None,
                              channel: Optional[str] = None,
                              wf_number: Optional[int] = None,
                              figax: Optional[Tuple] = None):
    """Plot the LED window on top of the waveform directly from a file.
    """

    process = pylars.processing.fixwindowprocessor.window_processor(
        baseline_samples=50, led_window=(105, 155))
    if module is None:
        module = 0

    print(f"Loading raw data from {filename}")
    process.load_raw_data(path_to_raw=filename, module=module)

    if channel is None:
        channel = str(np.random.choice(process.raw_data.channels))
        print(f"No channel specified, choosing random channel: {channel}")

    if wf_number is None:
        wf_number = int(np.random.choice(process.raw_data.n_waveforms))
        print(f"No waveform number specified, choosing random waveform:"
              f"{wf_number}")

    channel_data = process.raw_data.get_channel_data(channel)

    if figax is None:
        fig, ax = plt.subplots(1, 1, figsize=(6, 4), dpi=60)
    else:
        fig, ax = figax

    fig, ax = plot_LED_window(channel_data[wf_number],
                              led_window=led_window,
                              figax=(fig, ax))

    if figax is None:
        plt.show()
    else:
        return fig, ax
def plot_gain_evolution(gain_evolution: pandas.core.frame.DataFrame, tile_list: list, mod, figax=None)

Plot the gain evolution for a list of tiles.

Expand source code
def plot_gain_evolution(gain_evolution: pd.DataFrame,
                        tile_list: list, mod,
                        figax=None):
    """Plot the gain evolution for a list of tiles."""

    if figax is None:
        fig, ax = plt.subplots(1, 1, figsize=(6, 4), dpi=120)
    else:
        fig, ax = figax

    for _tile in tile_list:
        _df = gain_evolution[gain_evolution['tile'] == _tile]
        ax.errorbar(_df['start'], _df['gain'], yerr=_df['gain_err'],
                    ls='--',
                    marker='.', label=_tile)
    ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left',
              title='Tile',
              labelspacing=1.0)
    ax.set_ylim(0, None)  # type:ignore
    ax.set_title(f'Gain evolution - ADC #{mod}')
    ax.tick_params(axis='x', rotation=45)
    ax.set_ylabel('SiPM Gain [M]')
    # plt.twinx()
    # plt.plot(tt09['datetime'], tt09['TT09'], 'k--', alpha = 0.3,
    #          zorder = -10,label='Gast temperature')

    # plt.axvline(np.datetime64('2024-06-14T17:00:00'),ls = '--', color = 'gray', alpha = 0.8)
    # plt.text(np.datetime64('2024-06-14T08:00:00'), 0.78,
    #          'Filling complete', color = 'gray',rotation=90)

    if figax is None:
        fig.savefig(f'21062024_mod{mod}.png')
        plt.show()
    else:
        return fig, ax
def plot_gains_occ(df_gains, figaxs=None)

Plot the gains and occupancies for all the tiles.

Expand source code
def plot_gains_occ(df_gains, figaxs=None):
    """Plot the gains and occupancies for all the tiles."""
    if figaxs is None:
        fig, axs = plt.subplots(2, 1, figsize=(4, 4),
                                dpi=120, sharex=True,
                                gridspec_kw={'hspace': 0, 'wspace': 0},
                                constrained_layout=False)
        axs = axs.flatten()

    _x = np.arange(len(df_gains))
    axs[0].errorbar(_x, df_gains['gain'], yerr=df_gains['gain_err'],
                    ls='', capsize=4, marker='.')

    axs[1].errorbar(_x, df_gains['occ'], yerr=df_gains['occ_err'],
                    ls='', capsize=4, marker='.')

    axs[0].set_xticks(_x, df_gains['tile'])
    # axs[0].set_ylim(0,1.5)
    axs[0].set_ylabel('Gain [$10^6$]')
    axs[1].set_ylabel('Occupancy')
    # axs[1].set_ylim(-0.1,3.9)
    if figaxs is None:
        plt.show()

    else:
        return (fig, axs)
def plot_gains_occ_ledvoltage(LED_calib, module, channel, labels)

Plot the gains and occupancies for a given module and channel as a function of the LED voltage.

Expand source code
def plot_gains_occ_ledvoltage(LED_calib, module, channel, labels):
    """Plot the gains and occupancies for a given module and channel as a
    function of the LED voltage."""
    fig, ax = plt.subplots(1, 1, figsize=(6, 3))
    _df = LED_calib.results_df
    _df = _df[(_df['module'] == module) &
              (_df['channel'] == channel) &
              (_df['LEDvoltage'] > 1)]
    ax.errorbar(_df['LEDvoltage'], _df['gain'], yerr=_df['gain_err'], fmt='o')
    ax.set_xlabel('LED voltage [V]')
    ax.set_ylabel('Gain [ADC/PE/10^6]')
    ax.set_title(labels[f"mod{module}"][channel])

    ax1 = ax.twinx()
    ax1.errorbar(_df['LEDvoltage'], _df['occ'],
                 yerr=_df['occ_err'], fmt='o',
                 color='C1')
    ax1.set_ylabel('Occupancy [PE]', color='C1')
    ax.grid()
    plt.show()
def plot_light_levels(led_processed_df: pandas.core.frame.DataFrame, led_width: int, channel: Union[str, NoneType] = None, module: Union[int, NoneType] = None, figax: Union[Tuple, NoneType] = None)

Plot the LED area histogram for all the available light levels.

Expand source code
def plot_light_levels(led_processed_df: pd.DataFrame,
                      led_width: int,
                      channel: Optional[str] = None,
                      module: Optional[int] = None,
                      figax: Optional[Tuple] = None):
    """Plot the LED area histogram for all the available light levels."""

    select_mask = ((led_processed_df['LEDwidth'] == led_width) &
                   (led_processed_df['channel'] == channel) &
                   (led_processed_df['module'] == module))
    _df = led_processed_df[select_mask]

    if figax is None:
        fig, axs = plt.subplots(2, 1, figsize=(6, 8), dpi=60)
    else:
        fig, axs = figax

    _ledvoltages = np.unique(_df['LEDvoltage'])
    _median_amplitudes = []
    _std_amplitudes = []
    for _v in _ledvoltages:
        _mask = _df['LEDvoltage'] == _v
        axs[0].hist(_df[_mask]['led_area'],
                    bins=np.linspace(-1000, 25000, 500), histtype='step', label=f'{_v} V')
        _amp = np.median(_df[_mask]['led_area'])
        _std = np.std(_df[_mask]['led_area'])
        _median_amplitudes.append(_amp)
        _std_amplitudes.append(_std)
    axs[0].set_yscale('log')

    axs[1].errorbar(_ledvoltages, _median_amplitudes,
                    yerr=_std_amplitudes, marker='o',
                    ls='-')
    axs[1].set_xlabel('LED voltage [V]')
    axs[1].set_ylabel('Median Area [ADC counts]')
    axs[1].grid(color='lightgray', linestyle='--', linewidth=0.5)

    axs[0].set_xlabel('Area [ADC counts]')
    axs[0].set_ylabel('Counts')
    axs[0].legend(loc='center left', bbox_to_anchor=(1., 0.5),
                  title='LED voltage')
    axs[0].grid(color='lightgray', linestyle='--', linewidth=0.5)

    if figax is None:
        plt.show()
    else:
        return fig, axs