Module pylars.plotting.plotpeaks
Expand source code
from typing import List, Optional, Union
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
from matplotlib.patches import Circle, Rectangle
def plot_sensor_layout(layout: np.ndarray,
r_tpc: Optional[float] = None,
labels: Optional[List[str]] = None,
ax=None):
"""Generate the rectangles of where sensors are, the basis of a
hitpattern.
Args:
layout (np.ndarray): layout of array, each row a sensor.
r_tpc (Optional[float], optional): _description_. Defaults to None.
ax (_type_, optional): Axes. Defaults to None.
"""
if ax is None:
fig, ax = plt.subplots(1, 1)
for i, _sensor in enumerate(layout):
xy = (_sensor[0], _sensor[2])
width = _sensor[1] - _sensor[0]
height = _sensor[3] - _sensor[2]
ax.add_patch(Rectangle(xy, width, height, fill=False,
color='k', zorder=10))
if labels is not None:
ax.text(xy[0] + width / 2, xy[1] + height / 2, labels[i],
ha='center', va='center', zorder=10)
if r_tpc is not None:
ax.add_patch(Circle((0, 0), r_tpc, color='r', fill=False,
label='TPC edge'))
return ax
def plot_hitpattern(hitpattern: Union[np.ndarray, List[float]],
layout: np.ndarray,
labels: Optional[List[str]] = None,
r_tpc: Optional[float] = None,
cmap: str = 'gnuplot',
log: bool = False,
ax=None):
"""Plot a beautiful hitpattern.
Args:
hitpattern (Union[np.ndarray, List[float]]): array with the are per
sensor.
layout (np.ndarray): layout of the sensor array (x1,x2,y1,y2) corners.
labels (Optional[List[str]], optional): ordered labels to put in the
center of each sensor. Defaults to None.
r_tpc (Optional[float], optional): plot a line at the tpc edge.
Defaults to None.
cmap (str, optional): name of colormap to use. Defaults to 'gnuplot'.
log (bool, optional): plot the log10 of pe instead of pe. Defaults
to False.
ax (_type_, optional): axis where to draw the hitpattern. Defaults
to None.
Returns:
(axis, mappable): axis with the hitpattern drawned and the mappable
for a colorbar.
"""
if ax is None:
fig, ax = plt.subplots(1, 1)
cm = plt.get_cmap(cmap) # type: ignore
if log == True:
hitpattern = np.log10(hitpattern)
color_max = max(hitpattern)
color_min = min(hitpattern)
for i, _sensor in enumerate(layout):
pe = hitpattern[i]
xy = (_sensor[0], _sensor[2])
width = _sensor[1] - _sensor[0]
height = _sensor[3] - _sensor[2]
ax.add_patch(Rectangle(xy, width, height, fill=True,
edgecolor='k',
facecolor=cm((pe - color_min) /
(color_max - color_min))))
if labels is not None:
ax.text(xy[0] + width / 2, xy[1] + height / 2, labels[i],
ha='center', va='center', zorder=10)
if r_tpc is not None:
ax.add_patch(Circle((0, 0), r_tpc, color='r', fill=False,
label='TPC edge'))
norm = matplotlib.colors.Normalize(vmin=color_min, vmax=color_max)
mappable = matplotlib.cm.ScalarMappable( # type: ignore
norm=norm, cmap=cmap)
return (ax, mappable)
def plot_identified_peaks_individual_single(_area: float,
_length: int,
_position: int,
_amplitude: float,
sum_waveform: np.ndarray,
x_unit: str = 'sample',
detail_text: bool = True,
figax: Optional[tuple] = None) -> Optional[tuple]:
"""Make a plot of an identified peak in a waveform.
Args:
_area (float): area of the peak in PE
_length (int): length of the peak in samples
_position (int): position of the peak in samples
_amplitude (float): amplitude of the peak in PE/ns
sum_waveform (np.ndarray): array with the sum waveform PEs
over samples
x_unit (str, optional): units to use on the x axis: sample or time.
Defaults to 'sample'.
"""
if figax is None:
fig, ax = plt.subplots(figsize=(8, 4))
else:
fig, ax = figax
_start = _position - 200 if _position - 200 > 0 else 0
_end = _position + _length + 200 if _position + _length + \
200 < len(sum_waveform) else len(sum_waveform)
ax.plot(np.arange(_start, _end),
sum_waveform[_start: _end], label='Sum waveform')
ax.plot(sum_waveform, color='C0')
# ax.fill_between(y1 = 0,
# y2 = sum_waveform[_position: _position+_length],
# x=np.arange(_position, _position+_length),
# color='C4',
# alpha = 0.3,
# linestyle='--')
ax.axvline(x=_position, color='C1', linestyle='--')
ax.axvline(x=_position + _length, color='C1', linestyle='--')
ax.set_ylabel('PE/ns')
ax.set_xlabel('# Sample')
if x_unit == 'time':
ax.set_xticks(ax.get_xticks(), ax.get_xticks() * 10 / 1000)
ax.set_xlabel('Time [us]')
ax.set_xlim(_start, _end)
if detail_text:
text_for_box = (f'Area: {_area:.2f} PE\nLength: {_length:d} samples\n'
f'Position: {_position:d} samples\n'
f'Amplitude: {_amplitude:.2f} PE/ns')
ax.text(0.95, 0.95, text_for_box, transform=ax.transAxes, fontsize=10,
verticalalignment='top',
horizontalalignment='right',
bbox=dict(boxstyle='round', facecolor='gray', alpha=0.1))
if figax is None:
plt.show()
else:
return fig, ax
def plot_identified_peaks_individual_all(lengths: list,
positions: list,
amplitudes: list,
sum_waveform: np.ndarray,
x_unit: str = 'sample',
figax: Optional[tuple] = None):
"""Highlight all the identified peaks in a waveform.
Args:
lengths (list): list of lengths resulting from wf processing
positions (list): list of positions resulting from wf processing
amplitudes (list): list of amplitudes resulting from wf processing
sum_waveform (np.ndarray): array with the sum waveform PEs
over samples
"""
if figax is None:
fig, ax = plt.subplots(figsize=(8, 4))
else:
fig, ax = figax
ax.plot(sum_waveform, label='Sum waveform')
for _lenght, _position in zip(lengths, positions):
ax.fill_betweenx(y=[0, max(amplitudes)], x1=_position, x2=_position + _lenght,
color='C4', alpha=0.3, linestyle='--')
ax.set_ylabel('PE/ns')
ax.set_xlabel('# Sample')
if x_unit == 'time':
ax.set_xticks(ax.get_xticks(), ax.get_xticks() * 10 / 1000)
ax.set_xlabel('Time [us]')
ax.set_xlim(sum_waveform[0], sum_waveform[-1])
if figax is None:
plt.show()
else:
return fig, ax
def plot_identified_peaks_each_channel(areas_individual_channels: list,
positions: list,
lengths: list,
marker: str = '.',
x_unit: str = 'sample',
figax: Optional[tuple] = None):
"""Plot the identified peaks in each channel by balls.
Args:
areas_individual_channels (list): _description_
positions (list): _description_
lengths (list): _description_
figax (Optional[tuple], optional): _description_. Defaults to None.
Returns:
_type_: _description_
"""
chn_colors = {0: 'C0', 1: 'C1', 2: 'C2', 3: 'C3', 4: 'C4', 5: 'C5', 6: 'C6',
7: 'C0', 8: 'C1', 9: 'C2', 10: 'C3', 11: 'C4'}
if figax is None:
fig, ax = plt.subplots(figsize=(10, 3))
else:
fig, ax = figax
for _peak_id, areas_individual_channels_peak in enumerate(
areas_individual_channels):
_middle_of_peak = positions[_peak_id] + lengths[_peak_id] // 2
for _ch_n in range(areas_individual_channels_peak.shape[0]):
_ch_ycoord = areas_individual_channels_peak.shape[0] - _ch_n
_area_of_peak = areas_individual_channels_peak[_ch_n]
if _area_of_peak > 0:
ax.scatter(x=_middle_of_peak,
y=_ch_ycoord,
s=_area_of_peak**0.7,
color=chn_colors[_ch_n],
alpha=0.8,
marker=marker) # type: ignore
ax.set_yticks(range(1, 13),
['M', 'L', 'K', 'J', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A'])
if x_unit == 'time':
ax.set_xticks(ax.get_xticks(), ax.get_xticks() * 10 / 1000)
ax.set_xlabel('Time [µs]')
#ax.set_xlim(_start, _end)
if figax is None:
plt.show()
else:
return fig, ax
def plot_identified_peaks_each_channel_waveforms(
waveforms_pe_single_event: np.ndarray,
x_unit: str = 'sample',
figax: Optional[tuple] = None):
"""Plot the identified peaks in each channel by waveforms.
Args:
areas_individual_channels (list): _description_
positions (list): _description_
lengths (list): _description_
figax (Optional[tuple], optional): _description_. Defaults to None.
Returns:
_type_: _description_
"""
chn_colors = {0: 'C0', 1: 'C1', 2: 'C2', 3: 'C3', 4: 'C4', 5: 'C5', 6: 'C6',
7: 'C0', 8: 'C1', 9: 'C2', 10: 'C3', 11: 'C4'}
if figax is None:
fig, ax = plt.subplots(figsize=(10, 3))
else:
fig, ax = figax
max_value_y = np.max(waveforms_pe_single_event)
for _ch_i in range(waveforms_pe_single_event.shape[0]):
_ch_ycoord = waveforms_pe_single_event.shape[0] - _ch_i
ax.fill_between(x=np.arange(waveforms_pe_single_event.shape[1]),
y1=_ch_ycoord,
y2=waveforms_pe_single_event[_ch_i,
:] / max_value_y * 1.5 + _ch_ycoord,
color=chn_colors[_ch_i],
alpha=0.6)
ax.set_yticks(range(1, 13),
['M', 'L', 'K', 'J', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A'])
if x_unit == 'time':
ax.set_xticks(ax.get_xticks(), ax.get_xticks() * 10 / 1000)
ax.set_xlabel('Time [µs]')
#ax.set_xlim(_start, _end)
if figax is None:
plt.show()
else:
return fig, ax
def plot_full_waveform_peaks(areas: list,
lengths: list,
positions: list,
amplitudes: list,
sum_waveform_single: np.ndarray,
areas_individual_channels: list,
array_layout: np.ndarray,
array_labels: list,):
"""Make plot of the full waveform with the identified peaks.
Args:
areas (list): area of the identified peaks in the waveform
lengths (list): length of the identified peaks in the waveform
positions (list): position of the identified peaks in the waveform
amplitudes (list): amplitude of the identified peaks in the waveform
sum_waveform_single (np.ndarray): sum waveform of the event
areas_individual_channels (list): areas of the peak seen in
each channel
array_layout (np.ndarray): layout of the array
array_labels (list): labels of the array
"""
fig = plt.figure(figsize=(14, 6))
gs = GridSpec(2, 2, width_ratios=[1, 0.5], height_ratios=[1, 1])
ax_sumwf = fig.add_subplot(gs[0, 0])
ax_individual_ch = fig.add_subplot(gs[1, 0], sharex=ax_sumwf)
ax_hitp = fig.add_subplot(gs[0, 1])
ax_text = fig.add_subplot(gs[1, 1])
fig.subplots_adjust(hspace=0, wspace=0.1)
ax_sumwf = plot_identified_peaks_individual_all(
lengths,
positions,
amplitudes,
sum_waveform_single,
x_unit='time',
figax=(fig, ax_sumwf))
ax_individual_ch = plot_identified_peaks_each_channel(
areas_individual_channels,
positions,
lengths,
x_unit='time',
figax=(fig, ax_individual_ch))
biggest_peak_id = np.where(areas == max(areas))[0][0]
ax_hitp, _map = plot_hitpattern(
hitpattern=areas_individual_channels[biggest_peak_id],
layout=array_layout,
labels=array_labels,
r_tpc=160 / 2,
cmap='coolwarm',
log=False,
ax=ax_hitp,)
ax_hitp.set_xlim(-100, 100)
ax_hitp.set_ylim(-100, 100)
ax_hitp.set_aspect('equal')
ax_hitp.set_xlabel('x [mm]')
ax_hitp.set_ylabel('y [mm]')
fig.colorbar(_map, label='Peak Area [PE]', ax=ax_hitp)
text_for_box = (f'Area: {areas[biggest_peak_id]:.2f} PE\n'
# type: ignore
f'Length: {lengths[biggest_peak_id]/100:.2f} µs\n'
# type: ignore
f'Position: {positions[biggest_peak_id]/100:.2f} µs\n'
f'Amplitude: {amplitudes[biggest_peak_id]:.2f} PE/ns')
ax_text.text(
0.5,
0.4,
s=text_for_box,
ha='center',
va='center',
fontsize=12)
ax_text.axis('off')
plt.show()
def plot_peak_info(peak_id: int, areas: list, lengths: list,
positions: list, amplitudes: list,
sum_waveform_single: np.ndarray,
areas_individual_channels: list,
array_layout: np.ndarray, array_labels: list,
waveforms_pe_single_event: Optional[np.ndarray] = None,
save_fig: Optional[str] = None):
"""Fancy plot of the peak information, i.e., the sum waveform, the
hitpattern, the individual channel waveforms and the peak information.
Args:
peak_id (int): number of the peak in the waveform
areas (list): area of the identified peaks in the waveform
lengths (list): length of the identified peaks in the waveform
positions (list): position of the identified peaks in the waveform
amplitudes (list): amplitude of the identified peaks in the waveform
sum_waveform_single (np.ndarray): sum waveform of the event
areas_individual_channels (list): areas of the peak seen in
each channel
array_layout (np.ndarray): layout of the array
array_labels (list): labels of the array
waveforms_pe_single_event (Optional[np.ndarray], optional): waveforms
of each channel to make an even fancier plot. Defaults to None.
save_fig (Optional[str], optional): path to save the figure (include
extension). Defaults to None.
"""
fig = plt.figure(figsize=(14, 6), dpi=100)
gs = GridSpec(2, 2, width_ratios=[1, 0.5], height_ratios=[1, 0.8])
ax_sumwf = fig.add_subplot(gs[0, 0])
ax_individual_ch = fig.add_subplot(gs[1, 0], sharex=ax_sumwf)
ax_hitp = fig.add_subplot(gs[0, 1])
ax_text = fig.add_subplot(gs[1, 1])
fig.subplots_adjust(hspace=0, wspace=0.1)
_area = areas[peak_id]
_length = lengths[peak_id]
_position = positions[peak_id]
_amplitude = amplitudes[peak_id]
fig, ax_sumwf = plot_identified_peaks_individual_single(_area, # type: ignore
_length,
_position,
_amplitude,
sum_waveform_single,
x_unit='time',
detail_text=False,
figax=(fig, ax_sumwf))
_start = _position - 200 if _position - 200 > 0 else 0
_end = _position + _length + 200 if _position + _length + \
200 < len(sum_waveform_single) else len(sum_waveform_single)
if waveforms_pe_single_event is not None:
fig, ax_individual_ch = plot_identified_peaks_each_channel_waveforms(
waveforms_pe_single_event,
x_unit='time',
figax=(fig, ax_individual_ch)) # type: ignore
else:
fig, ax_individual_ch = plot_identified_peaks_each_channel( # type: ignore
areas_individual_channels,
positions,
lengths,
x_unit='time',
figax=(fig, ax_individual_ch))
ax_sumwf.set_xlim(_start, _end)
ax_individual_ch.set_xlim(_start, _end)
# ax_sumwf.set_xticklabels([])
ax_hitp, _map = plot_hitpattern(
hitpattern=np.log10(areas_individual_channels[peak_id]), # /1e5,
layout=array_layout,
labels=array_labels,
r_tpc=160 / 2,
cmap='coolwarm',
log=False,
ax=ax_hitp,)
ax_hitp.set_xlim(-100, 100)
ax_hitp.set_ylim(-100, 100)
ax_hitp.set_aspect('equal')
ax_hitp.set_xlabel('x [mm]')
ax_hitp.set_ylabel('y [mm]')
cbar = fig.colorbar(_map,
label='Peak Area log10 [PE]',
ax=ax_hitp)
#new_ticks = [3.5, 4 , 4.5, 5 ]
#new_ticklabels = ['$10^{3.5}$', '$10^4$', '$10^{4.5}$', '$10^5$']
# cbar.set_ticks(new_ticks)
# cbar.set_ticklabels(new_ticklabels) # type: ignore
text_for_box = (f'Area: {areas[peak_id]:.2f} PE\n'
f'Length: {lengths[peak_id]/100:.2f} µs\n'
f'Position: {positions[peak_id]/100:.2f} µs\n'
f'Amplitude: {amplitudes[peak_id]:.2f} PE/ns')
ax_text.text(
0.5,
0.4,
s=text_for_box,
ha='center',
va='center',
fontsize=12)
ax_text.axis('off')
if save_fig:
plt.savefig(save_fig)
plt.show()
Functions
def plot_full_waveform_peaks(areas: list, lengths: list, positions: list, amplitudes: list, sum_waveform_single: numpy.ndarray, areas_individual_channels: list, array_layout: numpy.ndarray, array_labels: list)
-
Make plot of the full waveform with the identified peaks.
Args
areas
:list
- area of the identified peaks in the waveform
lengths
:list
- length of the identified peaks in the waveform
positions
:list
- position of the identified peaks in the waveform
amplitudes
:list
- amplitude of the identified peaks in the waveform
sum_waveform_single
:np.ndarray
- sum waveform of the event
areas_individual_channels
:list
- areas of the peak seen in each channel
array_layout
:np.ndarray
- layout of the array
array_labels
:list
- labels of the array
Expand source code
def plot_full_waveform_peaks(areas: list, lengths: list, positions: list, amplitudes: list, sum_waveform_single: np.ndarray, areas_individual_channels: list, array_layout: np.ndarray, array_labels: list,): """Make plot of the full waveform with the identified peaks. Args: areas (list): area of the identified peaks in the waveform lengths (list): length of the identified peaks in the waveform positions (list): position of the identified peaks in the waveform amplitudes (list): amplitude of the identified peaks in the waveform sum_waveform_single (np.ndarray): sum waveform of the event areas_individual_channels (list): areas of the peak seen in each channel array_layout (np.ndarray): layout of the array array_labels (list): labels of the array """ fig = plt.figure(figsize=(14, 6)) gs = GridSpec(2, 2, width_ratios=[1, 0.5], height_ratios=[1, 1]) ax_sumwf = fig.add_subplot(gs[0, 0]) ax_individual_ch = fig.add_subplot(gs[1, 0], sharex=ax_sumwf) ax_hitp = fig.add_subplot(gs[0, 1]) ax_text = fig.add_subplot(gs[1, 1]) fig.subplots_adjust(hspace=0, wspace=0.1) ax_sumwf = plot_identified_peaks_individual_all( lengths, positions, amplitudes, sum_waveform_single, x_unit='time', figax=(fig, ax_sumwf)) ax_individual_ch = plot_identified_peaks_each_channel( areas_individual_channels, positions, lengths, x_unit='time', figax=(fig, ax_individual_ch)) biggest_peak_id = np.where(areas == max(areas))[0][0] ax_hitp, _map = plot_hitpattern( hitpattern=areas_individual_channels[biggest_peak_id], layout=array_layout, labels=array_labels, r_tpc=160 / 2, cmap='coolwarm', log=False, ax=ax_hitp,) ax_hitp.set_xlim(-100, 100) ax_hitp.set_ylim(-100, 100) ax_hitp.set_aspect('equal') ax_hitp.set_xlabel('x [mm]') ax_hitp.set_ylabel('y [mm]') fig.colorbar(_map, label='Peak Area [PE]', ax=ax_hitp) text_for_box = (f'Area: {areas[biggest_peak_id]:.2f} PE\n' # type: ignore f'Length: {lengths[biggest_peak_id]/100:.2f} µs\n' # type: ignore f'Position: {positions[biggest_peak_id]/100:.2f} µs\n' f'Amplitude: {amplitudes[biggest_peak_id]:.2f} PE/ns') ax_text.text( 0.5, 0.4, s=text_for_box, ha='center', va='center', fontsize=12) ax_text.axis('off') plt.show()
def plot_hitpattern(hitpattern: Union[numpy.ndarray, List[float]], layout: numpy.ndarray, labels: Union[List[str], NoneType] = None, r_tpc: Union[float, NoneType] = None, cmap: str = 'gnuplot', log: bool = False, ax=None)
-
Plot a beautiful hitpattern.
Args
hitpattern
:Union[np.ndarray, List[float]]
- array with the are per sensor.
layout
:np.ndarray
- layout of the sensor array (x1,x2,y1,y2) corners.
labels
:Optional[List[str]]
, optional- ordered labels to put in the center of each sensor. Defaults to None.
r_tpc
:Optional[float]
, optional- plot a line at the tpc edge. Defaults to None.
cmap
:str
, optional- name of colormap to use. Defaults to 'gnuplot'.
log
:bool
, optional- plot the log10 of pe instead of pe. Defaults to False.
ax
:_type_
, optional- axis where to draw the hitpattern. Defaults to None.
Returns
(axis, mappable): axis with the hitpattern drawned and the mappable for a colorbar.
Expand source code
def plot_hitpattern(hitpattern: Union[np.ndarray, List[float]], layout: np.ndarray, labels: Optional[List[str]] = None, r_tpc: Optional[float] = None, cmap: str = 'gnuplot', log: bool = False, ax=None): """Plot a beautiful hitpattern. Args: hitpattern (Union[np.ndarray, List[float]]): array with the are per sensor. layout (np.ndarray): layout of the sensor array (x1,x2,y1,y2) corners. labels (Optional[List[str]], optional): ordered labels to put in the center of each sensor. Defaults to None. r_tpc (Optional[float], optional): plot a line at the tpc edge. Defaults to None. cmap (str, optional): name of colormap to use. Defaults to 'gnuplot'. log (bool, optional): plot the log10 of pe instead of pe. Defaults to False. ax (_type_, optional): axis where to draw the hitpattern. Defaults to None. Returns: (axis, mappable): axis with the hitpattern drawned and the mappable for a colorbar. """ if ax is None: fig, ax = plt.subplots(1, 1) cm = plt.get_cmap(cmap) # type: ignore if log == True: hitpattern = np.log10(hitpattern) color_max = max(hitpattern) color_min = min(hitpattern) for i, _sensor in enumerate(layout): pe = hitpattern[i] xy = (_sensor[0], _sensor[2]) width = _sensor[1] - _sensor[0] height = _sensor[3] - _sensor[2] ax.add_patch(Rectangle(xy, width, height, fill=True, edgecolor='k', facecolor=cm((pe - color_min) / (color_max - color_min)))) if labels is not None: ax.text(xy[0] + width / 2, xy[1] + height / 2, labels[i], ha='center', va='center', zorder=10) if r_tpc is not None: ax.add_patch(Circle((0, 0), r_tpc, color='r', fill=False, label='TPC edge')) norm = matplotlib.colors.Normalize(vmin=color_min, vmax=color_max) mappable = matplotlib.cm.ScalarMappable( # type: ignore norm=norm, cmap=cmap) return (ax, mappable)
def plot_identified_peaks_each_channel(areas_individual_channels: list, positions: list, lengths: list, marker: str = '.', x_unit: str = 'sample', figax: Union[tuple, NoneType] = None)
-
Plot the identified peaks in each channel by balls.
Args
areas_individual_channels
:list
- description
positions
:list
- description
lengths
:list
- description
figax
:Optional[tuple]
, optional- description. Defaults to None.
Returns
_type_
- description
Expand source code
def plot_identified_peaks_each_channel(areas_individual_channels: list, positions: list, lengths: list, marker: str = '.', x_unit: str = 'sample', figax: Optional[tuple] = None): """Plot the identified peaks in each channel by balls. Args: areas_individual_channels (list): _description_ positions (list): _description_ lengths (list): _description_ figax (Optional[tuple], optional): _description_. Defaults to None. Returns: _type_: _description_ """ chn_colors = {0: 'C0', 1: 'C1', 2: 'C2', 3: 'C3', 4: 'C4', 5: 'C5', 6: 'C6', 7: 'C0', 8: 'C1', 9: 'C2', 10: 'C3', 11: 'C4'} if figax is None: fig, ax = plt.subplots(figsize=(10, 3)) else: fig, ax = figax for _peak_id, areas_individual_channels_peak in enumerate( areas_individual_channels): _middle_of_peak = positions[_peak_id] + lengths[_peak_id] // 2 for _ch_n in range(areas_individual_channels_peak.shape[0]): _ch_ycoord = areas_individual_channels_peak.shape[0] - _ch_n _area_of_peak = areas_individual_channels_peak[_ch_n] if _area_of_peak > 0: ax.scatter(x=_middle_of_peak, y=_ch_ycoord, s=_area_of_peak**0.7, color=chn_colors[_ch_n], alpha=0.8, marker=marker) # type: ignore ax.set_yticks(range(1, 13), ['M', 'L', 'K', 'J', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A']) if x_unit == 'time': ax.set_xticks(ax.get_xticks(), ax.get_xticks() * 10 / 1000) ax.set_xlabel('Time [µs]') #ax.set_xlim(_start, _end) if figax is None: plt.show() else: return fig, ax
def plot_identified_peaks_each_channel_waveforms(waveforms_pe_single_event: numpy.ndarray, x_unit: str = 'sample', figax: Union[tuple, NoneType] = None)
-
Plot the identified peaks in each channel by waveforms.
Args
areas_individual_channels
:list
- description
positions
:list
- description
lengths
:list
- description
figax
:Optional[tuple]
, optional- description. Defaults to None.
Returns
_type_
- description
Expand source code
def plot_identified_peaks_each_channel_waveforms( waveforms_pe_single_event: np.ndarray, x_unit: str = 'sample', figax: Optional[tuple] = None): """Plot the identified peaks in each channel by waveforms. Args: areas_individual_channels (list): _description_ positions (list): _description_ lengths (list): _description_ figax (Optional[tuple], optional): _description_. Defaults to None. Returns: _type_: _description_ """ chn_colors = {0: 'C0', 1: 'C1', 2: 'C2', 3: 'C3', 4: 'C4', 5: 'C5', 6: 'C6', 7: 'C0', 8: 'C1', 9: 'C2', 10: 'C3', 11: 'C4'} if figax is None: fig, ax = plt.subplots(figsize=(10, 3)) else: fig, ax = figax max_value_y = np.max(waveforms_pe_single_event) for _ch_i in range(waveforms_pe_single_event.shape[0]): _ch_ycoord = waveforms_pe_single_event.shape[0] - _ch_i ax.fill_between(x=np.arange(waveforms_pe_single_event.shape[1]), y1=_ch_ycoord, y2=waveforms_pe_single_event[_ch_i, :] / max_value_y * 1.5 + _ch_ycoord, color=chn_colors[_ch_i], alpha=0.6) ax.set_yticks(range(1, 13), ['M', 'L', 'K', 'J', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A']) if x_unit == 'time': ax.set_xticks(ax.get_xticks(), ax.get_xticks() * 10 / 1000) ax.set_xlabel('Time [µs]') #ax.set_xlim(_start, _end) if figax is None: plt.show() else: return fig, ax
def plot_identified_peaks_individual_all(lengths: list, positions: list, amplitudes: list, sum_waveform: numpy.ndarray, x_unit: str = 'sample', figax: Union[tuple, NoneType] = None)
-
Highlight all the identified peaks in a waveform.
Args
lengths
:list
- list of lengths resulting from wf processing
positions
:list
- list of positions resulting from wf processing
amplitudes
:list
- list of amplitudes resulting from wf processing
sum_waveform
:np.ndarray
- array with the sum waveform PEs over samples
Expand source code
def plot_identified_peaks_individual_all(lengths: list, positions: list, amplitudes: list, sum_waveform: np.ndarray, x_unit: str = 'sample', figax: Optional[tuple] = None): """Highlight all the identified peaks in a waveform. Args: lengths (list): list of lengths resulting from wf processing positions (list): list of positions resulting from wf processing amplitudes (list): list of amplitudes resulting from wf processing sum_waveform (np.ndarray): array with the sum waveform PEs over samples """ if figax is None: fig, ax = plt.subplots(figsize=(8, 4)) else: fig, ax = figax ax.plot(sum_waveform, label='Sum waveform') for _lenght, _position in zip(lengths, positions): ax.fill_betweenx(y=[0, max(amplitudes)], x1=_position, x2=_position + _lenght, color='C4', alpha=0.3, linestyle='--') ax.set_ylabel('PE/ns') ax.set_xlabel('# Sample') if x_unit == 'time': ax.set_xticks(ax.get_xticks(), ax.get_xticks() * 10 / 1000) ax.set_xlabel('Time [us]') ax.set_xlim(sum_waveform[0], sum_waveform[-1]) if figax is None: plt.show() else: return fig, ax
def plot_identified_peaks_individual_single(_area: float, _length: int, _position: int, _amplitude: float, sum_waveform: numpy.ndarray, x_unit: str = 'sample', detail_text: bool = True, figax: Union[tuple, NoneType] = None) ‑> Union[tuple, NoneType]
-
Make a plot of an identified peak in a waveform.
Args
_area
:float
- area of the peak in PE
_length
:int
- length of the peak in samples
_position
:int
- position of the peak in samples
_amplitude
:float
- amplitude of the peak in PE/ns
sum_waveform
:np.ndarray
- array with the sum waveform PEs over samples
x_unit
:str
, optional- units to use on the x axis: sample or time. Defaults to 'sample'.
Expand source code
def plot_identified_peaks_individual_single(_area: float, _length: int, _position: int, _amplitude: float, sum_waveform: np.ndarray, x_unit: str = 'sample', detail_text: bool = True, figax: Optional[tuple] = None) -> Optional[tuple]: """Make a plot of an identified peak in a waveform. Args: _area (float): area of the peak in PE _length (int): length of the peak in samples _position (int): position of the peak in samples _amplitude (float): amplitude of the peak in PE/ns sum_waveform (np.ndarray): array with the sum waveform PEs over samples x_unit (str, optional): units to use on the x axis: sample or time. Defaults to 'sample'. """ if figax is None: fig, ax = plt.subplots(figsize=(8, 4)) else: fig, ax = figax _start = _position - 200 if _position - 200 > 0 else 0 _end = _position + _length + 200 if _position + _length + \ 200 < len(sum_waveform) else len(sum_waveform) ax.plot(np.arange(_start, _end), sum_waveform[_start: _end], label='Sum waveform') ax.plot(sum_waveform, color='C0') # ax.fill_between(y1 = 0, # y2 = sum_waveform[_position: _position+_length], # x=np.arange(_position, _position+_length), # color='C4', # alpha = 0.3, # linestyle='--') ax.axvline(x=_position, color='C1', linestyle='--') ax.axvline(x=_position + _length, color='C1', linestyle='--') ax.set_ylabel('PE/ns') ax.set_xlabel('# Sample') if x_unit == 'time': ax.set_xticks(ax.get_xticks(), ax.get_xticks() * 10 / 1000) ax.set_xlabel('Time [us]') ax.set_xlim(_start, _end) if detail_text: text_for_box = (f'Area: {_area:.2f} PE\nLength: {_length:d} samples\n' f'Position: {_position:d} samples\n' f'Amplitude: {_amplitude:.2f} PE/ns') ax.text(0.95, 0.95, text_for_box, transform=ax.transAxes, fontsize=10, verticalalignment='top', horizontalalignment='right', bbox=dict(boxstyle='round', facecolor='gray', alpha=0.1)) if figax is None: plt.show() else: return fig, ax
def plot_peak_info(peak_id: int, areas: list, lengths: list, positions: list, amplitudes: list, sum_waveform_single: numpy.ndarray, areas_individual_channels: list, array_layout: numpy.ndarray, array_labels: list, waveforms_pe_single_event: Union[numpy.ndarray, NoneType] = None, save_fig: Union[str, NoneType] = None)
-
Fancy plot of the peak information, i.e., the sum waveform, the hitpattern, the individual channel waveforms and the peak information.
Args
peak_id
:int
- number of the peak in the waveform
areas
:list
- area of the identified peaks in the waveform
lengths
:list
- length of the identified peaks in the waveform
positions
:list
- position of the identified peaks in the waveform
amplitudes
:list
- amplitude of the identified peaks in the waveform
sum_waveform_single
:np.ndarray
- sum waveform of the event
areas_individual_channels
:list
- areas of the peak seen in each channel
array_layout
:np.ndarray
- layout of the array
array_labels
:list
- labels of the array
waveforms_pe_single_event
:Optional[np.ndarray]
, optional- waveforms of each channel to make an even fancier plot. Defaults to None.
save_fig
:Optional[str]
, optional- path to save the figure (include extension). Defaults to None.
Expand source code
def plot_peak_info(peak_id: int, areas: list, lengths: list, positions: list, amplitudes: list, sum_waveform_single: np.ndarray, areas_individual_channels: list, array_layout: np.ndarray, array_labels: list, waveforms_pe_single_event: Optional[np.ndarray] = None, save_fig: Optional[str] = None): """Fancy plot of the peak information, i.e., the sum waveform, the hitpattern, the individual channel waveforms and the peak information. Args: peak_id (int): number of the peak in the waveform areas (list): area of the identified peaks in the waveform lengths (list): length of the identified peaks in the waveform positions (list): position of the identified peaks in the waveform amplitudes (list): amplitude of the identified peaks in the waveform sum_waveform_single (np.ndarray): sum waveform of the event areas_individual_channels (list): areas of the peak seen in each channel array_layout (np.ndarray): layout of the array array_labels (list): labels of the array waveforms_pe_single_event (Optional[np.ndarray], optional): waveforms of each channel to make an even fancier plot. Defaults to None. save_fig (Optional[str], optional): path to save the figure (include extension). Defaults to None. """ fig = plt.figure(figsize=(14, 6), dpi=100) gs = GridSpec(2, 2, width_ratios=[1, 0.5], height_ratios=[1, 0.8]) ax_sumwf = fig.add_subplot(gs[0, 0]) ax_individual_ch = fig.add_subplot(gs[1, 0], sharex=ax_sumwf) ax_hitp = fig.add_subplot(gs[0, 1]) ax_text = fig.add_subplot(gs[1, 1]) fig.subplots_adjust(hspace=0, wspace=0.1) _area = areas[peak_id] _length = lengths[peak_id] _position = positions[peak_id] _amplitude = amplitudes[peak_id] fig, ax_sumwf = plot_identified_peaks_individual_single(_area, # type: ignore _length, _position, _amplitude, sum_waveform_single, x_unit='time', detail_text=False, figax=(fig, ax_sumwf)) _start = _position - 200 if _position - 200 > 0 else 0 _end = _position + _length + 200 if _position + _length + \ 200 < len(sum_waveform_single) else len(sum_waveform_single) if waveforms_pe_single_event is not None: fig, ax_individual_ch = plot_identified_peaks_each_channel_waveforms( waveforms_pe_single_event, x_unit='time', figax=(fig, ax_individual_ch)) # type: ignore else: fig, ax_individual_ch = plot_identified_peaks_each_channel( # type: ignore areas_individual_channels, positions, lengths, x_unit='time', figax=(fig, ax_individual_ch)) ax_sumwf.set_xlim(_start, _end) ax_individual_ch.set_xlim(_start, _end) # ax_sumwf.set_xticklabels([]) ax_hitp, _map = plot_hitpattern( hitpattern=np.log10(areas_individual_channels[peak_id]), # /1e5, layout=array_layout, labels=array_labels, r_tpc=160 / 2, cmap='coolwarm', log=False, ax=ax_hitp,) ax_hitp.set_xlim(-100, 100) ax_hitp.set_ylim(-100, 100) ax_hitp.set_aspect('equal') ax_hitp.set_xlabel('x [mm]') ax_hitp.set_ylabel('y [mm]') cbar = fig.colorbar(_map, label='Peak Area log10 [PE]', ax=ax_hitp) #new_ticks = [3.5, 4 , 4.5, 5 ] #new_ticklabels = ['$10^{3.5}$', '$10^4$', '$10^{4.5}$', '$10^5$'] # cbar.set_ticks(new_ticks) # cbar.set_ticklabels(new_ticklabels) # type: ignore text_for_box = (f'Area: {areas[peak_id]:.2f} PE\n' f'Length: {lengths[peak_id]/100:.2f} µs\n' f'Position: {positions[peak_id]/100:.2f} µs\n' f'Amplitude: {amplitudes[peak_id]:.2f} PE/ns') ax_text.text( 0.5, 0.4, s=text_for_box, ha='center', va='center', fontsize=12) ax_text.axis('off') if save_fig: plt.savefig(save_fig) plt.show()
def plot_sensor_layout(layout: numpy.ndarray, r_tpc: Union[float, NoneType] = None, labels: Union[List[str], NoneType] = None, ax=None)
-
Generate the rectangles of where sensors are, the basis of a hitpattern.
Args
layout
:np.ndarray
- layout of array, each row a sensor.
r_tpc
:Optional[float]
, optional- description. Defaults to None.
ax
:_type_
, optional- Axes. Defaults to None.
Expand source code
def plot_sensor_layout(layout: np.ndarray, r_tpc: Optional[float] = None, labels: Optional[List[str]] = None, ax=None): """Generate the rectangles of where sensors are, the basis of a hitpattern. Args: layout (np.ndarray): layout of array, each row a sensor. r_tpc (Optional[float], optional): _description_. Defaults to None. ax (_type_, optional): Axes. Defaults to None. """ if ax is None: fig, ax = plt.subplots(1, 1) for i, _sensor in enumerate(layout): xy = (_sensor[0], _sensor[2]) width = _sensor[1] - _sensor[0] height = _sensor[3] - _sensor[2] ax.add_patch(Rectangle(xy, width, height, fill=False, color='k', zorder=10)) if labels is not None: ax.text(xy[0] + width / 2, xy[1] + height / 2, labels[i], ha='center', va='center', zorder=10) if r_tpc is not None: ax.add_patch(Circle((0, 0), r_tpc, color='r', fill=False, label='TPC edge')) return ax