Propagation Delay Calculation
Latest source notebook:
pyccapt/calibration/tutorials/jupyter_files/L_and_t0_determination.ipynb
This workflow is currently maintained as a Jupyter notebook only and does not have a matching Google Colab notebook.
Propagation Delay Calculation and flight path distance estimation¶
In this tutorial we will see how to calculate the $t_0$ with the known sample. To ensure accurate estimation you should select your peak within the big mc range. You should also make your calculation for a small volume specially and for a small variation of voltage. Another pont is that you should choose a narrow window around your peaks.
import pandas as pd
# Activate intractive functionality of matplotlib
%matplotlib ipympl
# Activate auto reload
%load_ext autoreload
%autoreload 2
%reload_ext autoreload
# import libraries
import os
import numpy as np
import subprocess
from sklearn import linear_model
import matplotlib.pyplot as plt
from ipywidgets import fixed, interact_manual, widgets
from ipywidgets import Output
from IPython.display import clear_output
# Local module and scripts
from pyccapt.calibration.calibration import share_variables
from pyccapt.calibration.data_tools import data_tools, data_loadcrop, dataset_path_qt
from pyccapt.calibration.mc import mc_tools
from pyccapt.calibration.tutorials.tutorials_helpers import helper_data_loader
from pyccapt.calibration.calibration import widgets as wd
from pyccapt.calibration.calibration import mc_plot
from pyccapt.calibration.tutorials.tutorials_helpers import helper_t_0_tune
variables = share_variables.Variables()
By clicking on the button below, you can select the dataset file you want to use. The dataset file can be in various formats, including HDF5, EPOS, POS, ATO, and CSV.
button = widgets.Button(description='load dataset')
@button.on_click
def open_file_on_click_r(b):
global dataset_path
folder_path = variables.last_directory
script = '..//..//data_tools//run_dataset_path_qt.py'
cmd = f"python {script} {folder_path}"
result = subprocess.run(cmd, capture_output=True, text=True, shell=True)
dataset_path = result.stdout.strip()
variables.last_directory = dataset_path
button
!conda install --yes --prefix {sys.prefix} pytables
tdc, pulse_mode, flight_path_length, t0, max_mc, det_diam = wd.dataset_instrument_specification_selection()
display(tdc, flight_path_length, pulse_mode, t0, max_mc)
# extract needed data from Pandas data frame as a numpy array
# create an instance of the Variables object
variables = share_variables.Variables()
variables.pulse_mode = pulse_mode
dataset_main_path = os.path.dirname(dataset_path)
dataset_main_path = os.path.dirname(dataset_main_path)
dataset_name_with_extention = os.path.basename(dataset_path)
variables.dataset_name = os.path.splitext(dataset_name_with_extention)[0]
variables.result_data_path = dataset_main_path + '/t_0_flight_path_distance/'
variables.result_data_name = variables.dataset_name
variables.result_path = dataset_main_path + '/t_0_flight_path_distance/'
if not os.path.isdir(variables.result_path):
os.makedirs(variables.result_path, mode=0o777, exist_ok=True)
helper_data_loader.load_data(dataset_path, max_mc.value, flight_path_length.value, pulse_mode.value, tdc.value, variables)
data_tools.extract_data(variables.data, variables, flight_path_length.value, max_mc.value)
display(variables.data)
The maximum possible TOF is: 5010 ns
=============================
The data will be saved on the path: T:/Monajem/APT_data/2382_Jan-10-2025_15-12_NiC9_Al/2382_Jan-10-2025_15-12_NiC9_Al/data_processing/
=============================
The dataset name after saving is: 2382_Jan-10-2025_15-12_NiC9_Al
=============================
The figures will be saved on the path: T:/Monajem/APT_data/2382_Jan-10-2025_15-12_NiC9_Al/2382_Jan-10-2025_15-12_NiC9_Al/data_processing/
=============================
{'apt': ['experiment_chamber_vacuum', 'id', 'num_events', 'num_raw_signals', 'temperature', 'timestamps'], 'dld': ['high_voltage', 'laser_pulse', 'start_counter', 't', 'voltage_pulse', 'x', 'y'], 'tdc': ['channel', 'high_voltage', 'laser_pulse', 'start_counter', 'time_data', 'voltage_pulse']}
The data is loaded in raw mode
The number of data that is removed: 43356
Total number of Ions: 23050746
The maximum possible time of flight is: 5010
| x (nm) | y (nm) | z (nm) | mc (Da) | mc_uc (Da) | high_voltage (V) | pulse | t (ns) | t_c (ns) | x_det (cm) | y_det (cm) | delta_p | multi | start_counter | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.00 | 328.000 | 1560.517326 | 0.0 | 1.211429 | 0.786939 | 0.0 | 0.0 | 12877 |
| 1 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.00 | 328.000 | 3862.638198 | 0.0 | 1.315918 | -0.538776 | 0.0 | 0.0 | 12897 |
| 2 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.00 | 328.000 | 4725.038556 | 0.0 | 1.795918 | -0.884898 | 0.0 | 0.0 | 328 |
| 3 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.00 | 328.000 | 4286.572326 | 0.0 | 1.126531 | -1.453061 | 0.0 | 0.0 | 5238 |
| 4 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.00 | 328.000 | 2820.023316 | 0.0 | -3.983673 | -0.153469 | 0.0 | 0.0 | 6942 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 23050741 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 4200.38 | 840.076 | 682.816770 | 0.0 | 2.390204 | -2.259592 | 0.0 | 0.0 | 19720 |
| 23050742 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 4200.38 | 840.076 | 4706.048754 | 0.0 | 1.776327 | -1.191837 | 0.0 | 0.0 | 19721 |
| 23050743 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 4200.38 | 840.076 | 3621.936114 | 0.0 | -2.279184 | 1.423673 | 0.0 | 0.0 | 19852 |
| 23050744 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 4200.38 | 840.076 | 183.910986 | 0.0 | 2.491429 | -2.357551 | 0.0 | 0.0 | 19921 |
| 23050745 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 4200.38 | 840.076 | 3537.884466 | 0.0 | 1.345306 | -1.240816 | 0.0 | 0.0 | 19951 |
23050746 rows × 14 columns
interact_manual = interact_manual.options(manual_name="Run")
interact_manual(data_loadcrop.plot_crop_experiment_history, data=fixed(variables.data), variables=fixed(variables), max_tof=widgets.FloatText(value=variables.max_tof), frac=widgets.FloatText(value=1.0),
bins=fixed((1200,800)), figure_size=fixed((7,3)),
draw_rect=fixed(False), data_crop=fixed(False), pulse_plot=widgets.Dropdown(options=[('False', False), ('True', True)]), dc_plot=widgets.Dropdown(options=[('True', True), ('False', False)]),
pulse_mode=widgets.Dropdown(options=[('voltage', 'voltage'), ('laser', 'laser')]), save=widgets.Dropdown(options=[('False', False), ('True', True)]),
figname=widgets.Text(value='exp_hist'));
Extract the data from the dataset file in numpy array format.
# extract needed data from Pandas data frame as numpy array
variables.dld_high_voltage = variables.data['high_voltage (V)'].to_numpy()
variables.dld_pulse = variables.data['pulse'].to_numpy()
variables.dld_t = variables.data['t (ns)'].to_numpy()
variables.dld_x_det = variables.data['x_det (cm)'].to_numpy()
variables.dld_y_det = variables.data['y_det (cm)'].to_numpy()
In the next cell by changing the t0 value you can correct the position of H1 or any other known peak. this correction would be helpful for the position of the peaks in the m/c calibration process.
helper_t_0_tune.call_fine_tune_t_0(variables, flight_path_length, pulse_mode, t0)
Remove the data with m/c greater than max m/c and x, y, t = 0. Also add the needed colums for calibration. The data types of the final cropped dataset is displayed below.
# add the columns in the dataset for x, y, z, mc, mc calibrated, and t calibrated
helper_data_loader.add_columns(variables, max_mc)
# again extract the update data to the variables
data_tools.extract_data(variables.data, variables, flight_path_length.value, max_mc.value)
display(variables.data)
The number of data over max_mc: 0 The number of data with having t, x, and y equal to zero is: 0 The maximum possible time of flight is: 5010
| x (nm) | y (nm) | z (nm) | mc (Da) | mc_uc (Da) | high_voltage (V) | pulse | t (ns) | t_c (ns) | x_det (cm) | y_det (cm) | delta_p | multi | start_counter | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.202547 | 500.00 | 328.000 | 180.687726 | 0.0 | 0.515918 | -3.781224 | 0.0 | 0.0 | 6487 |
| 1 | 0.0 | 0.0 | 0.0 | 0.0 | 4.505837 | 500.00 | 328.000 | 672.941250 | 0.0 | -2.021224 | -1.018776 | 0.0 | 0.0 | 7743 |
| 2 | 0.0 | 0.0 | 0.0 | 0.0 | 4.471881 | 500.00 | 328.000 | 670.198050 | 0.0 | -2.213878 | -0.277551 | 0.0 | 0.0 | 9222 |
| 3 | 0.0 | 0.0 | 0.0 | 0.0 | 3.823231 | 500.00 | 328.000 | 648.519912 | 0.0 | -2.439184 | -3.226122 | 0.0 | 0.0 | 15619 |
| 4 | 0.0 | 0.0 | 0.0 | 0.0 | 1.718742 | 500.00 | 328.000 | 432.177444 | 0.0 | -1.502041 | -1.786122 | 0.0 | 0.0 | 13295 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 17571608 | 0.0 | 0.0 | 0.0 | 0.0 | 15.745673 | 4200.38 | 840.076 | 500.112792 | 0.0 | 0.515918 | 1.900408 | 0.0 | 0.0 | 18484 |
| 17571609 | 0.0 | 0.0 | 0.0 | 0.0 | 63.442003 | 4200.38 | 840.076 | 998.956854 | 0.0 | 3.738776 | 0.512653 | 0.0 | 0.0 | 18532 |
| 17571610 | 0.0 | 0.0 | 0.0 | 0.0 | 54.048280 | 4200.38 | 840.076 | 878.345208 | 0.0 | 0.444082 | 0.235102 | 0.0 | 0.0 | 19294 |
| 17571611 | 0.0 | 0.0 | 0.0 | 0.0 | 29.187147 | 4200.38 | 840.076 | 682.816770 | 0.0 | 2.390204 | -2.259592 | 0.0 | 0.0 | 19720 |
| 17571612 | 0.0 | 0.0 | 0.0 | 0.0 | 1.421180 | 4200.38 | 840.076 | 183.910986 | 0.0 | 2.491429 | -2.357551 | 0.0 | 0.0 | 19921 |
17571613 rows × 14 columns
plot the histogram of the mass spectrum select the peak that you want to use for t_0 calibration. preferably, the peaks have to be chosen from low to high mass.
interact_manual(
mc_plot.hist_plot,
variables=fixed(variables),
bin_size=widgets.FloatText(value=0.1),
log=widgets.Dropdown(options=[('True', True), ('False', False)]),
target=widgets.Dropdown(options=[('mc_calib', 'mc_calib'), ('tof_calib', 'tof_calib')]),
normalize=widgets.Dropdown(options=[('False', False),('True', True)]),
prominence=widgets.IntText(value=100),
distance=widgets.IntText(value=100),
percent=widgets.IntText(value=50),
selector=fixed('peak'),
figname=widgets.Text(value='hist'),
lim=widgets.IntText(value=variables.max_mc),
peaks_find=widgets.Dropdown(options=[('True', True), ('False', False)]),
peaks_find_plot=widgets.Dropdown(options=[('True', True), ('False', False)]),
plot_ranged_peak=fixed(False),
plot_ranged_colors=fixed(False),
mrp_all=fixed(False),
background=fixed(None),
grid=widgets.Dropdown(options=[('True', True), ('False', False)]),
ranging_mode=fixed(False),
range_sequence=fixed([]),
range_mc=fixed([]),
range_detx=fixed([]),
range_dety=fixed([]),
range_x=fixed([]),
range_y=fixed([]),
range_z=fixed([]),
range_vol=fixed([]),
save_fig=widgets.Dropdown(options=[('False', False), ('True', True)]),
print_info=fixed(True),
legend_mode=fixed('long'),
draw_calib_rect=fixed(False),
figure_size=fixed((9, 5)),
plot_show=fixed(True),
fast_calibration=fixed(False));
For the selected peak you have to select the mass-to-charge ratio of the peak. You can select the mass-to-charge ratio from the dropdown list below. You can also select the charge of the peak. After that you can add the peak to the list by clicking on the add button. You can also delete the selected peak from the list by clicking on the delete button. You can reset the list by clicking on the reset button.
isotopeTableFile = '../../../files/isotopeTable.h5'
dataframe = pd.read_hdf(isotopeTableFile, mode='r')
elementsList = dataframe['element']
elementIsotopeList = dataframe['isotope']
elementMassList = dataframe['weight']
abundanceList = dataframe['abundance']
elements = list(zip(elementsList, elementIsotopeList, elementMassList, abundanceList))
dropdownList = []
for element in elements:
tupleElement = ("{} ({}) ({:.2f})".format(element[0], element[1], element[3]), "{}({})[{}]".format(element[0], element[1], element[2]))
dropdownList.append(tupleElement)
chargeList = [(1,1,),(2,2,),(3,3,),(4,4,)]
dropdown = wd.dropdownWidget(dropdownList,"Elements")
dropdown.observe(wd.on_change)
chargeDropdown = wd.dropdownWidget(chargeList,"Charge")
chargeDropdown.observe(wd.on_change_charge)
wd.compute_element_isotope_values_according_to_selected_charge()
buttonAdd = wd.buttonWidget("ADD")
buttonDelete = wd.buttonWidget("DELETE")
buttonReset = wd.buttonWidget("RESET")
display(dropdown, chargeDropdown, buttonAdd, buttonDelete, buttonReset)
def buttonAdd_f(b,):
with out:
clear_output(True)
wd.onClickAdd(b, variables)
display()
def buttonDelete_f(b,):
with out:
clear_output(True)
wd.onClickDelete(b, variables)
display()
def buttonResett_f(b,):
with out:
clear_output(True)
wd.onClickReset(b, variables)
display()
listMaterial = buttonAdd.on_click(buttonAdd_f)
buttonDelete.on_click(buttonDelete_f)
buttonReset.on_click(buttonResett_f)
# listMaterial = buttonAdd.on_click(wd.onClickAdd)
# buttonDelete.on_click(wd.onClickDelete)
# buttonReset.on_click(wd.onClickReset)
out = Output()
display(out)
# The correct peak location based on your sample
peaks_ideal = variables.list_material
print('peak ideal mass:', peaks_ideal)
peak_x = variables.peaks_x_selected
print('peak actual mass:', peak_x)
print('The peak index are:', variables.peaks_index_list)
peak ideal mass: [1.01, 13.49, 26.98] peak actual mass: [1.0056877090795528, 15.139860809258154, 30.57718462080074] The peak index are: [0, 1, 2]
Here for each peak a mask will be created.
pick_ions_plot = []
mask = np.zeros(len(variables.mc_uc), dtype=bool)
mc_seb_ideal = np.zeros(len(variables.mc_uc))
# creat mask for each peak base on the peak loc. and window size
index = 0
for i in variables.peaks_index_list:
mask_tmp = np.logical_and((variables.x_hist[round(variables.peak_widths[2][i])] < variables.mc_uc), (variables.mc_uc < variables.x_hist[round(variables.peak_widths[3][i])]))
# Count the number of True values in the original mask_tmp
true_indices = np.where(mask_tmp)[0]
num_true_values = len(true_indices)
# If there are more than 5000 True values, randomly choose 5000 of them
if num_true_values > 5000:
selected_indices = np.random.choice(true_indices, size=5000, replace=False)
# Create a new mask with the same length as the original, initialized with False
new_mask = np.full_like(mask_tmp, False)
# Set the selected indices to True in the new mask
new_mask[selected_indices] = True
# Update the original mask_tmp with the new mask
mask_tmp = new_mask
print('peak left and right sides are:', variables.x_hist[round(variables.peak_widths[2][i])], variables.x_hist[round(variables.peak_widths[3][i])])
mask = np.logical_or(mask, mask_tmp)
mc_seb_ideal[mask_tmp==True] = peaks_ideal[index]
index += 1
bb = np.zeros(len(variables.mc_uc))
pick_ions_plot.append(mask_tmp)
peak left and right sides are: 1.0056877090795528 1.105930071492167 peak left and right sides are: 14.538406634782469 15.641072621321225 peak left and right sides are: 29.37427627184937 31.47936588251427
Here we plot ions in each peak base on the TOF and (x,y) position
for i in range(len(pick_ions_plot)):
fig1, ax1 = plt.subplots(figsize=(6, 6))
dld_x_masked = variables.dld_x_det[pick_ions_plot[i]]
dld_y_masked = variables.dld_y_det[pick_ions_plot[i]]
dld_t_masked = variables.dld_t[pick_ions_plot[i]]
if len(dld_x_masked) > 1000:
mask_plot = np.random.randint(0, len(dld_x_masked), 1000)
x = plt.scatter(dld_x_masked[mask_plot], dld_t_masked[mask_plot], color="blue", label='X', alpha=0.1)
y = plt.scatter(dld_y_masked[mask_plot], dld_t_masked[mask_plot], color="red", label='Y', alpha=0.1)
else:
x = plt.scatter(dld_x_masked, dld_t_masked, color="blue", label='X', alpha=0.1)
y = plt.scatter(dld_y_masked, dld_t_masked, color="red", label='Y', alpha=0.1)
ax1.set_ylabel("Time of flight (ns)", color="red", fontsize=10)
ax1.set_xlabel("position (cm)", color="red", fontsize=10)
plt.grid(color='aqua', alpha=0.3, linestyle='-.', linewidth=2)
plt.legend(handles=[x, y], loc='upper right')
plt.ylim(bottom=plt.yticks()[0][0], top=plt.yticks()[0][-1])
plt.xlim(left=plt.xticks()[0][0], right=plt.xticks()[0][-1])
plt.savefig(variables.result_path + 'position_peak.png', format="png", dpi=600)
plt.savefig(variables.result_path + 'position_peak.svg', format="svg", dpi=600)
plt.show()
As you saw the TOF changes base on the (x,y) of the events. Therefore we creat a mask to only select the ions in center (8m m*8mm) of detector. This helps to cansel out the variation in TOF due to hit position.
Reformulate the equation:
# use mask_equal to have equal number of ions for each peak
# only peak the value in the center of detector 10mm * 10mm
detector_squre = 0.5
vol_variation = 5500 # peak only for 200 voltage variation for vol_variation +/- 100
fig1, ax1 = plt.subplots(figsize=(6, 6))
dld_x_masked = variables.dld_x_det[mask]
dld_y_masked = variables.dld_y_det[mask]
dld_t_masked = variables.dld_t[mask]
dld_highVoltage_masked = variables.dld_high_voltage[mask]
dld_pulse_masked = variables.dld_pulse[mask]
mask_tmp_middle = np.logical_and((np.abs(dld_x_masked) < detector_squre), (np.abs(dld_y_masked) < detector_squre))
mask_tmp_mvoltage = mask_tmp_mvoltage = np.logical_and((dld_highVoltage_masked < (np.mean(dld_highVoltage_masked)+200)), (dld_highVoltage_masked > (np.mean(dld_highVoltage_masked)-200)))
mask_tmp_mvoltage = np.ones(len(mask_tmp_middle), dtype=bool)
mask_f = np.logical_and(mask_tmp_mvoltage, mask_tmp_middle)
dld_x_masked = dld_x_masked[mask_f]
dld_y_masked = dld_y_masked[mask_f]
dld_t_masked = dld_t_masked[mask_f]
dld_highVoltage_masked = dld_highVoltage_masked[mask_f]
dld_pulse_masked = dld_pulse_masked[mask_f]
mc_seb_reg_masked = mc_seb_ideal[mask]
mc_seb_reg_masked = mc_seb_reg_masked[mask_f]
x = plt.scatter(dld_x_masked, dld_t_masked, color="blue", label='X', alpha=0.1)
y = plt.scatter(dld_y_masked, dld_t_masked, color="red", label='Y', alpha=0.1)
ax1.set_ylabel("Time of flight (ns)", color="red", fontsize=10)
ax1.set_xlabel("position (cm)", color="red", fontsize=10)
plt.grid(color='aqua', alpha=0.3, linestyle='-.', linewidth=2)
plt.legend(handles=[x, y], loc='upper right')
plt.ylim(bottom=plt.yticks()[0][0], top=plt.yticks()[0][-1])
plt.xlim(left=plt.xticks()[0][0], right=plt.xticks()[0][-1])
plt.savefig(variables.result_path + 'center.png' , format="png", dpi=600)
plt.savefig(variables.result_path + 'center.svg' , format="svg", dpi=600)
plt.show()
We calculate the ${t_0}$ base on:
seb_t = dld_t_masked * 1E-9 # tof in s
seb_factor = np.sqrt(mc_seb_reg_masked * 1.66E-27 / (2 * 1.6E-19 * dld_highVoltage_masked))
seb_factor = seb_factor * 1E6
seb_t = seb_t * 1E9
t0_seb_fixed = np.mean(np.array([seb_t]).squeeze(0) - (flight_path_length.value * np.array([seb_factor]).squeeze(0).reshape(-1, 1)))
print('Linear fixed path lenght -- the flight path lenght(slop): {:.2f}'.format(flight_path_length.value), '(mm)', '\nthe corrected t_0(intercept): {:.2f}'.format(t0_seb_fixed), '(ns)')
Linear fixed path lenght -- the flight path lenght(slop): 110.00 (mm) the corrected t_0(intercept): 36.10 (ns)
# Plot outputs
# fig1, ax1 = plt.subplots(figsize=(5.5/2.54, 5.5/2.54))
fig1, ax1 = plt.subplots(figsize=(5.5, 5.5))
peaks_data = plt.scatter(seb_factor, seb_t, label='Ions', alpha=1, color='slategray')
axes = plt.gca()
x_vals = np.array(axes.get_xlim())
linear_fix, = plt.plot(x_vals, t0_seb_fixed + flight_path_length.value * x_vals, '--', color='red', label='line' )
plt.grid(color='aqua', alpha=0.3, linestyle='-.', linewidth=2)
# plt.legend(handles=[linear_fix, peaks_data], loc='lower right')
ax1.set_ylabel("Time of Flight (ns)", fontsize=8)
ax1.set_xlabel(r"$\sqrt{\frac{\frac{m}{n}}{2e \alpha V}} (ns/mm)$", fontsize=8)
plt.tight_layout()
plt.ylim(bottom=plt.yticks()[0][0], top=plt.yticks()[0][-1])
plt.xlim(left=plt.xticks()[0][0], right=plt.xticks()[0][-1])
plt.savefig(variables.result_path + 'fixed_flight_path.svg', format="svg", dpi=600)
plt.savefig(variables.result_path + 'fixed_flight_path.png', format="png", dpi=600)
plt.show()
linear = linear_model.LinearRegression()
linear.fit(np.array([seb_factor]).squeeze(0).reshape(-1, 1), np.array([seb_t]).squeeze(0))
d_seb = linear.coef_.item()
t0_seb = linear.intercept_.item()
print('Linear -- the corrected flight path lenght(slop): {:.2f}'.format(d_seb), '(mm)', '\nthe corrected t_0(intercept): {:.2f}'.format(t0_seb), '(ns)')
Linear -- the corrected flight path lenght(slop): 109.94 (mm) the corrected t_0(intercept): 36.31 (ns)
# Plot outputs
# fig1, ax1 = plt.subplots(figsize=(5.5/2.54, 5.5/2.54))
fig1, ax1 = plt.subplots(figsize=(5.5, 5.5))
peaks_data = plt.scatter(seb_factor, seb_t, color="slategray", label='Ion', alpha=0.1)
axes = plt.gca()
x_vals = np.array(axes.get_xlim())
linear, = plt.plot(x_vals, t0_seb + d_seb * x_vals, '--', color='r', label='fit' )
plt.grid(color='aqua', alpha=0.3, linestyle='-.', linewidth=2)
# plt.legend(handles=[peaks_data, linear, rigid, huber,lasso], loc='lower right')
ax1.set_ylabel("Time of flight (ns)", fontsize=8)
ax1.set_xlabel(r"$\sqrt{\frac{\frac{m}{n}}{2e \alpha V}} (ns/mm)$", fontsize=8)
plt.legend(handles=[linear, peaks_data], loc='lower right')
plt.tight_layout()
plt.ylim(bottom=plt.yticks()[0][0], top=plt.yticks()[0][-1])
plt.xlim(left=plt.xticks()[0][0], right=plt.xticks()[0][-1])
plt.savefig(variables.result_path + 'regression.svg', format="svg", dpi=600)
plt.savefig(variables.result_path + 'regression.png', format="png", dpi=600)
plt.show()
Plot the m/c with new ${t_0}$:
# # recalulate the mc based on the new t_0
# t_0_f = 36.01
# mc = mc_tools.tof2mc(variables.dld_t, t_0_f, variables.dld_high_voltage, variables.dld_x_det, variables.dld_y_det, flight_path_length.value,
# variables.dld_pulse, mode=pulse_mode.value)
# mc_hist = mc_plot.AptHistPlotter(mc[mc < 40], variables)
# y, x = mc_hist.plot_histogram(bin_width=0.1, label='mc', steps='stepfilled', log=True, grid=True, fig_size=(9, 5))
# peaks, properties, peak_widths, prominences = mc_hist.find_peaks_and_widths(prominence=10, distance=100, percent=50)
# mc_hist.plot_peaks()
# mc_hist.plot_hist_info_legend(label='mc', background=None, loc='right')