Electrochemistry - Mass spectrometry tutorial

This tutorial is to show the most advanced tools to date for ixdat analysis of EC-MS data.

It is based on the data analysis done for Spectro Inlets Application Note #2 - Quantification

There are three parts:

  • Importing, plotting and exporting data
  • Analyzing EC-MS calibrations
  • Using EC-MS calibrations

Importing, plotting, and exporting

First, we import and plot the dataset we would like to calibrate.

importing ixdat v0.2.5 from C:UsersAnnaWiniwarteranaconda3libsite-packagesixdat__init__.py

----------  Importing EC_MS v0.7.5 ----------
from C:UsersAnnaWiniwarteranaconda3libsite-packagesEC_MS__init__.py


wasnt able to evaluate '====='
wasnt able to evaluate '====='
wasnt able to evaluate '====='
[<AxesSubplot:xlabel='time / [s]', ylabel='signal / [A]'>,
 <AxesSubplot:xlabel='time / [s]', ylabel='Voltage [V]'>,
 None,
 <AxesSubplot:ylabel='Current [mA]'>]
../../_images/EC-MS_ixdat_tutorial_2_2.png

That was a lot. Let’s zoom in on an interesting part.

Tip: if you’re using a backend for matplotlib that returns scalable plots (not Jupyter notebooks), you can easily zoom into your plot to find the timestamps at start and end of the part you find interesting. A left mouse click into the plot will print the time where the mouse is pointing to. A right click at a different point following a left click will print the start and end as well as length of the timespan in between.

[<AxesSubplot:xlabel='time / [s]', ylabel='signal / [A]'>,
 <AxesSubplot:xlabel='time / [s]', ylabel='Voltage [V]'>,
 None,
 <AxesSubplot:ylabel='Current [mA]'>]
../../_images/EC-MS_ixdat_tutorial_4_1.png

The EC data looks a bit noisy - let’s use the EC data as saved by ECLab here instead. First we import the MS data only from the Zilien data file:

Note, if you use Zilien vs. 2.6.0 or higher, Zilien will export the same data as saved by ECLab, so this will no longer be necessary.

Then we import the electrochemistry data from the text files exported by ECLab:

And combine everything:

[<AxesSubplot:xlabel='time / [s]', ylabel='signal / [A]'>,
 <AxesSubplot:xlabel='time / [s]', ylabel='Ewe/V'>,
 None,
 <AxesSubplot:ylabel='raw_current'>]
../../_images/EC-MS_ixdat_tutorial_10_1.png ../../_images/EC-MS_ixdat_tutorial_10_2.png

Now that looks better! Let’s export that bit so we can share it with someone without exceeding an attachment limit:

ixdat can of course read the files it exports:

skipping the following line:
ixdat version = 0.2.5

skipping the following line:
backend_name = BackendBase(none, address=none)
[<AxesSubplot:xlabel='time / [s]', ylabel='signal / [A]'>,
 <AxesSubplot:xlabel='time / [s]', ylabel='Ewe/V'>,
 None,
 <AxesSubplot:ylabel='<I>/mA'>]
../../_images/EC-MS_ixdat_tutorial_14_2.png

Calibrations

EC-MS calibration

Now, we analyze EC-MS calibration measurements. The code is taken from here:

https://github.com/ScottSoren/pyCOox_public/blob/main/paper_I_fig_S1/paper_I_fig_S1.py

We know the geometric area of the electrode, so we can normalize the current: it’s a 5mm diameter disk, area = 0.196 cm^2 We used an RHE reference electrode, so we assume that the potential difference between our reference electrode and the RHE potential is zero. We did not determine the Ohmic drop, but we will assume that it was 0 (even though that is not entirely correct), to demonstrate how we can calibrate for it.

[<AxesSubplot:xlabel='time / [s]', ylabel='signal / [A]'>,
 <AxesSubplot:xlabel='time / [s]', ylabel='$U_{RHE}$ / [V] $_{ohm. corr.}$'>,
 None,
 <AxesSubplot:ylabel='J / [mA cm$^{-2}$]'>]
../../_images/EC-MS_ixdat_tutorial_17_1.png

There is some data here before the hydrogen calibration measurement starts; let’s shift t=0 to the right, to when the CPs start. Note that if you re-run this part, the time will be shifted further every time. Outcomment it if you do not want to move the start further.

The raw data is easily plotted with the plot_measurement function, which doesn’t only create a figure, but also returns a list of three axes for (i) ms, (ii) potential, and (iii) current. See help(meas.plot_measurement) for customization.

We will be adding to these axes later to indicate the timespans used for the calibrations.

../../_images/EC-MS_ixdat_tutorial_21_0.png

Now, this is a standard EC-MS plot, which is in itself not bad. Still, sometimes one might like to change something about it, let’s say the size of the axis labels, the position of the legend, or the dimensions of the figure. To do this, we can name the figure by getting it via the first axis, which then allows us to modify the plot like any regular matplotlib plot. This only works if the plot has not been printed yet, so we need to define axes_a again at the beginning. Let’s make the plot wider, as an example:

../../_images/EC-MS_ixdat_tutorial_23_0.png

Great! Now we’re ready to use this data to calibrate for H2 at m/z=2. For this we use the ixdat method ecms_calibration_curve, which automatically selects and integrates M2 signal and electrochemical current in the given timespans.

../../_images/EC-MS_ixdat_tutorial_25_0.png ../../_images/EC-MS_ixdat_tutorial_25_1.png

Because we asked for return_ax, two arguments are returned: The first, which we call cal_result_H2, is a MSCalResult for H2. The second, which we call ax_H2, is the axis where it plots the calibration curve. As we asked for axes_measurement, to be plotted on axes_a, the areas that were integrated are highlighted on that axes.

The attribute cal_result_H2.F is the slope of the calibration curve, which is the sensitivity factor in C/mol. (Note that this calibration_curve works with integrals rather than simply the rates. The latter is not yet implemented in ixdat.)

MSCalResult(name=H2@M2, mol=H2, mass=M2, F=0.3378605863775754)

Tip: instead of selecting the time spans manually, you can also use the option of passing a selector_name (str) (Name of selector which identifies the periods of steady electrolysis for automatic selection of timespans of steady electrolysis. E.g. "selector" or "Ns" for biologic EC data) and a selector_list instead of the tspan_list. Note that you need to have information on the different parts of the EC data in your measurement data to take advanatge of this. If you used a Zilien version < 2.6.0 when running the measurement, this requires that you import the EC data from the ECLab. Here, we can use the data imported to meas_combi.

First, let’s figure out what we should pass to selector list. To this end, we can plot the selector we want to use in our regular EC-MS plot, for example instead of the current:

../../_images/EC-MS_ixdat_tutorial_29_0.png
Following tspans were selected for calibration: [[1945.0643708705902, 2245.06396317482], [2545.064355611801, 2845.0639481544495], [3145.0643405914307, 3445.0639328956604], [3745.0643253326416, 4045.06391787529], [4345.0643100738525, 4645.063902616501]]
MSCalResult(name=H2@M2, mol=H2, mass=M2, F=0.3378605863775754)
../../_images/EC-MS_ixdat_tutorial_30_1.png ../../_images/EC-MS_ixdat_tutorial_30_2.png

Now, let’s do the same for oxygen. First, let’s find the right section of the measurement and plot it, so we can find the tspan.

[<AxesSubplot:xlabel='time / [s]', ylabel='signal / [A]'>,
 <AxesSubplot:xlabel='time / [s]', ylabel='$U_{RHE}$ / [V] $_{ohm. corr.}$'>,
 None,
 <AxesSubplot:ylabel='J / [mA cm$^{-2}$]'>]
../../_images/EC-MS_ixdat_tutorial_32_1.png ../../_images/EC-MS_ixdat_tutorial_33_0.png ../../_images/EC-MS_ixdat_tutorial_33_1.png
MSCalResult(name=O2@M32, mol=O2, mass=M32, F=0.01182634523322349)

Congratulations! We have now calibrated for hydrogen and oxygen, using electrochemical calibration. However, this approach limits our calibration to those products that we can produce electrochemically with close to 100% faradaic efficiency. Instead, we can take advantage of the gas system of the EC-MS and directly introduce calibration gases to the chip.

Gas calibration

Let’s first do this for hydrogen and oxygen to compare with the results from the electrochemical gas calibration.

First we need to import the data, of course. The Zilien datafile doesn’t contain any EC data in this case, which confuses the reader - we therefore specify technique="MS".

<AxesSubplot:xlabel='time / [s]', ylabel='signal / [A]'>
../../_images/EC-MS_ixdat_tutorial_36_1.png ../../_images/EC-MS_ixdat_tutorial_36_2.png

Now, the gas calibration works a bit differently than the EC-MS calibration, as it relies on knowing the flux of molecules into the MS for the inlet used. Therefore, the calibration is not done for a specific measurement, but rather for an MSInlet object, which requires a slightly different sytnax.

Let’s first define the inlet object: ixdat’s default MS inlet is a Spectro Inlets EC-MS chip. The chip object contains information about the inlet, such as it’s dimensions, the temperature and pressure, as well as functions for calculating the molar flux of a pure gas (the carrier gas) to the capillary, and for using this flux to calculate a sensitivity factor.

(In principle, the chip’s capillary size should be calibrated, but this usually only changes the results by a few percent, and is not yet implemented in ixdat.)

Now we can use the method gas_flux_calibration_curve to do a gas calibration. Note, this method relies on the calculation of the flux of the carrier gas through the capillary and assumes that this flux will not be affected by the change in gas composition due to the analytes. This assumption likely holds as long as the gas concentration is <10% (better <1%), but is ideally only used for small analyte concentrations. A new, more powerful method is in development and will be introduced in a separate tutorial soon.

MSCalResult(name=H2_M2_gas, mol=H2, mass=M2, F=0.3191356304426369)
../../_images/EC-MS_ixdat_tutorial_40_1.png ../../_images/EC-MS_ixdat_tutorial_40_2.png

Great! Now that we know how to do this, we can also do it for our oxygen and ethylene calibrations.

MSCalResult(name=O2_M32_gas, mol=O2, mass=M32, F=0.09198714869342346)
MSCalResult(name=C2H4@M26, mol=C2H4, mass=M26, F=0.08057166014411674)
../../_images/EC-MS_ixdat_tutorial_42_1.png ../../_images/EC-MS_ixdat_tutorial_42_2.png ../../_images/EC-MS_ixdat_tutorial_42_3.png ../../_images/EC-MS_ixdat_tutorial_42_4.png

Saving the calibration

We might want to use the calibration for other measurements later, so let’s create an ECMSCalibration object and save the calibration.

Applying a calibration to your dataset

In the following we will explore how to apply the EC-MS calibration we determined above to a dataset. There are several ways of how you can pass a calibration to an ECMSMeasurement objects. We will only address two ways here.

Let’s start by loading the calibration object that we saved earlier, as well as loading some uncalibrated data and plotting it.

skipping the following line:
ixdat version = 0.2.5

skipping the following line:
backend_name = BackendBase(none, address=none)
[<AxesSubplot:xlabel='time / [s]', ylabel='signal / [A]'>,
 <AxesSubplot:xlabel='time / [s]', ylabel='Ewe/V'>,
 None,
 <AxesSubplot:ylabel='<I>/mA'>]
../../_images/EC-MS_ixdat_tutorial_47_2.png

And apply the calibration on the data:

[MSCalResult(name=H2@M2, mol=H2, mass=M2, F=0.3378605863775754), MSCalResult(name=O2@M32, mol=O2, mass=M32, F=0.01182634523322349), MSCalResult(name=H2_M2_gas, mol=H2, mass=M2, F=0.3191356304426369), MSCalResult(name=O2_M32_gas, mol=O2, mass=M32, F=0.09198714869342346), MSCalResult(name=C2H4@M26, mol=C2H4, mass=M26, F=0.08057166014411674)]
[<AxesSubplot:xlabel='time / [s]', ylabel='signal / [A]'>,
 <AxesSubplot:xlabel='time / [s]', ylabel='$U_{RHE}$ / [V]'>,
 None,
 <AxesSubplot:ylabel='J / [mA cm$^{-2}$]'>]
../../_images/EC-MS_ixdat_tutorial_49_2.png

As we only provide the calibration for some of the masses, the standard plot is still showing uncalibrated MS data. If we pass the list of molecules where we do have a calibration, then plot_measurement() will plot the calibrated fluxes instead.

[<AxesSubplot:xlabel='time / [s]', ylabel='signal / [mol/s]'>,
 <AxesSubplot:xlabel='time / [s]', ylabel='$U_{RHE}$ / [V]'>,
 None,
 <AxesSubplot:ylabel='J / [mA cm$^{-2}$]'>]
../../_images/EC-MS_ixdat_tutorial_51_1.png

Alternatively, if we calculate the calibration factors in the same ixdat session as our data treatment, we can also directly apply the calibration without having to create the calibration object first. In this way, we can also make sure that we use a specific calibration factor if we have determined several for one analyte.

skipping the following line:
ixdat version = 0.2.5

skipping the following line:
backend_name = BackendBase(none, address=none)

[MSCalResult(name=H2@M2, mol=H2, mass=M2, F=0.3378605863775754), MSCalResult(name=O2@M32, mol=O2, mass=M32, F=0.01182634523322349), MSCalResult(name=H2_M2_gas, mol=H2, mass=M2, F=0.3191356304426369), MSCalResult(name=O2_M32_gas, mol=O2, mass=M32, F=0.09198714869342346), MSCalResult(name=C2H4@M26, mol=C2H4, mass=M26, F=0.08057166014411674)]
[MSCalResult(name=H2@M2, mol=H2, mass=M2, F=0.3378605863775754), MSCalResult(name=O2_M32_gas, mol=O2, mass=M32, F=0.09198714869342346)]
[<AxesSubplot:xlabel='time / [s]', ylabel='signal / [mol/s]'>,
 <AxesSubplot:xlabel='time / [s]', ylabel='$U_{RHE}$ / [V]'>,
 None,
 <AxesSubplot:ylabel='J / [mA cm$^{-2}$]'>]
../../_images/EC-MS_ixdat_tutorial_54_2.png

Plotting calibrated EC-MS data

Now that we’ve calibrated the data, we want to make some nice plots. In the sections below, we will explore some ways of using ixdat’s plotter and modify the plots using matplotlib.

EC-MS plot calibrated gases using two y axes

../../_images/EC-MS_ixdat_tutorial_57_0.png

— Cyclic voltammetry MS plot of two of the cycles —

../../_images/EC-MS_ixdat_tutorial_59_0.png

EC-MS plot with carrier gases on right y-axis (uncalibrated) and products on left (calibrated)

Note that it is not possible to mix linear and logarithmic scales in one plot with ixdat.

../../_images/EC-MS_ixdat_tutorial_61_0.png

EC-MS plot with a third with system parameters added

In some cases it can be interesting to co-plot some other data, e.g. system parameters like iongauge pressure or MFC flow rates. Let’s have a look at the iongauge pressure during one of the CV cycles and plot that in a third panel of our regular EC-MS plots.

[<matplotlib.lines.Line2D at 0x2be40b32640>]
../../_images/EC-MS_ixdat_tutorial_63_1.png

Congratulations! You have reached the end of this tutorial and are now an expert in loading, calibrating and plotting EC-MS data using ixdat.