Skip to content

Latest commit

 

History

History
3447 lines (2904 loc) · 117 KB

supporting-information.org

File metadata and controls

3447 lines (2904 loc) · 117 KB

Alkaline Electrolyte and Fe Impurity Effects on the Performance and Active-phase Structure of NiOOH Thin Films for OER Catalysis Applications

\newpage \maketitle \raggedbottom \tableofcontents

Introduction

This document contains supporting figures, tables, images, and code for the work, “Alkaline electrolyte and Fe impurity effects on the performance and active-phase structure of NiOOH thin films for OER catalysis applications.” In particular, this document includes Python code for 1) fitting Gaussian functions to NiOOH Raman spectra and 2) the results of curve fitting for all NiOOH spectra analyzed for this manuscript. The code for fitting Gaussian functions to spectra data can be easily modified for the analysis of materials with similar Raman spectral signatures. In addition, this document contains Python code that generated all figures for this work.

The data files are also available as data.zip with the supporting information.

Electrochemical measurements

LSV with Electrolyte Switching in Purified LiOH and CsOH

Figure ref:fig-s1 shows the results of LSV while switching the electrolyte between purified LiOH (0.1 M) and CsOH (0.1 M). A cation effect on catalytic performance was observed in purified electrolyte. Based on Figure ref:fig-s1, purified CsOH promoted OER current densities that were ≈100 % higher than OER current densities promoted by purified LiOH.

./images/figures-supp-info/IvsV-Li-Cs-pure-10-08.png

LSV with Electrolyte Switching in Purified NaOH and KOH

Figure ref:fig-s2 shows the results of LSV while switching the electrolyte between purified NaOH (0.1 M) and KOH (0.1 M). Based on Figure ref:fig-s2, a relatively small cation effect was observed in purified NaOH and KOH. KOH promoted slightly higher OER current densities than NaOH. The differences in catalytic performance between purified CsOH and LiOH were smaller than the differences in catalytic performance observed in Figure ref:fig-s1.

./images/figures-supp-info/IvsV-Na-K-pure-01-16-15.png

LSV with Electrolyte Switching in Fe-saturated LiOH and CsOH

Figure ref:fig-s3 shows the results of LSV while switching the electrolyte between Fe-saturated LiOH (0.1 M) and CsOH (0.1 M). A cation effect on catalytic performance was observed in Fe-saturated electrolyte. Based on Figure ref:fig-s3, Fe-saturated CsOH promoted OER current densities that were ≈50 % higher than OER current densities promoted by Fe-saturated LiOH.

./images/figures-supp-info/IvsV-Li-Cs-iron-11-21.png

LSV with Electrolyte Switching in Fe-saturated NaOH and KOH

Figure ref:fig-s4 shows the results of LSV while switching the electrolyte between Fe-saturated NaOH (0.1 M) and KOH (0.1 M). A cation effect on catalyst performance was not observed between Fe-saturated NaOH and KOH. Most of the NaOH current densities (green) overlapped with the KOH current densities (black). Current densities likely diverged at overpotentials above ≈0.35 V due to differences in oxygen bubble coverage on the working electrode surface, which would impede the flow of current.

./images/figures-supp-info/IvsV-Na-K-iron-01-19.png

LSV during Raman Spectroscopy in Purified LiOH and CsOH

Figure ref:fig-s5 shows the results of LSV performed during Raman spectroscopy in purified LiOH (0.1 M) and CsOH (0.1 M). The corresponding Raman spectra are in Figure 3 (main text). Based on Figure ref:fig-s5, purified CsOH promoted OER current densities that were ≈50% higher than OER current densities promoted by purified LiOH. Spectra were collected at overpotentials of 240, 340, and 440 mV.

./images/figures-supp-info/IvsV-Raman-Li-Cs-pure-10-31.png

LSV during Raman Spectroscopy in Fe-saturated LiOH and CsOH

Figure ref:fig-s6 shows the results of LSV performed during Raman spectroscopy in Fe-saturated LiOH (0.1 M) and CsOH (0.1 M). The corresponding Raman spectra are in Figure 4 (main text). Based on Figure ref:fig-s6, Fe-saturated CsOH promoted OER current densities that were ≈50% higher than OER current densities promoted by Fe-saturated LiOH. Spectra were collected at overpotentials of 240, 340, and 440 mV.

./images/figures-supp-info/IvsV-Raman-Li-Cs-iron-11-19.png

Tafel Analysis

Table ref:tab:s1 shows the results of a Tafel analysis performed on LSV curves in purified and Fe-saturated LiOH, NaOH, KOH, and CsOH. Error represents one standard deviation from mean Tafel slope.

ElectrolyteTafel slope (mv/decade)
LiOH, purified56.95 \textpm \enspace 6.49
NaOH, purified61.66 \textpm \enspace 4.77
KOH, purified61.45 \textpm \enspace 2.70
CsOH, purified58.22 \textpm \enspace 8.74
LiOH, Fe-saturated21.39 \textpm \enspace 0.75
NaOH, Fe-saturated18.75 \textpm \enspace 1.09
KOH, Fe-saturated19.73 \textpm \enspace 0.96
CsOH, Fe-saturated21.57 \textpm \enspace 0.14

There was not a statistically significant difference between purified LiOH, NaOH, KOH, or CsOH; all Tafel slopes were ≈60 mV/decade. In addition, there was not a statistically significant difference between Fe-saturated LiOH, NaOH, KOH, or CsOH; all Tafel slopes were ≈20 mV/decade. Although these results do not provide much insight into the subtle differences in the current regimes, they clearly show that Fe had a significant effect on catalytic performance.

Raman Spectra of Ni(OH)2

Figure ref:fig-s7 shows Raman spectra collected on Ni(OH)2 thin films at 300 mV (vs. Hg/HgO). These were same thin films used for the LSV/Raman spectroscopy experiments described in the main body of this report, except the films were in a reduced state (i.e. Ni(OH)2) and OER was not occurring. Figure ref:fig-s7 shows no sharp Raman peaks at ≈480 cm-1 and ≈560 cm-1 (as in Figures 3 and 4, main text), indicating that the film was Ni(OH)2 at an overpotential of 300 mV.

./images/figures-supp-info/raman-nioh2-pure-iron.png

Results of Fitting Gaussian Functions to Raman spectra

Below is an expression with four Gaussian terms that was fit to Raman spectra for NiOOH.

$$y = ∑14 An exp\left (\frac{(x-Bn)2}{2Cn2}\right )$$

An is amplitude (a.u.), Bn is mean peak position (cm-1), Cn is standard deviation (cm-1), x is Raman shift (cm-1), and y is Raman signal (a.u.). Subscripts n=1 and n=2 correspond to the two Gaussian curves fit to the peak at ≈480cm-1 and subscripts n=3 and n=4 correspond to the two Gaussian curves fit to the peak at ≈560 cm-1.

Below are initial guess, fitted, and calculated output parameters for fittings performed on all NiOOH Raman spectra for this manuscript. To call the curve fitting funtion, the following was typed (default settings included): dgaus2p(filename, cntr=(470, 560), amp1=(20, 20), amp2=(20, 20), std1=(10, 5), std2=(10, 5), datarange=None, output=False, step=4). Aside from the file name and step number, only default parameters that needed to be adjusted were included in the following code blocks. Python code for the “dgaus2p” function can be found in the Appendix below.

Purified Electrolyte

LiOH

Trial 1
600 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-1-600mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(5, 5),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-1-600mV.fit', 'r') as f:
    print f.read()

700 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-1-700mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(5, 5),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-1-700mV.fit', 'r') as f:
    print f.read()

800 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-1-800mV.txt',
        cntr=(480, 560),
        amp1=(18, 18),
        amp2=(8, 8),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-1-800mV.fit', 'r') as f:
    print f.read()

Trial 2
600 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-2-600mV.txt',
        cntr=(480, 560),
        amp1=(15, 15),
        amp2=(8, 8),
        output=True,
        step=4)

# Print file containing input, fitted, and output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-2-600mV.fit', 'r') as f:
    print f.read()

700 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-2-700mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(10, 10),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-2-700mV.fit', 'r') as f:
    print f.read()

800 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-2-800mV.txt',
        cntr=(480, 560),
        amp1=(15, 15),
        amp2=(10, 10),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-2-800mV.fit', 'r') as f:
    print f.read()

Trial 3
600 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-3-600mV.txt',
        cntr=(480, 560),
        amp1=(20, 20),
        amp2=(10, 10),
        output=True,
        step=4)

# Print file containing input, fitted, and output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-3-600mV.fit', 'r') as f:
    print f.read()

700 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-3-700mV.txt',
        cntr=(480, 560),
        amp1=(25, 25),
        amp2=(15, 15),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-3-700mV.fit', 'r') as f:
    print f.read()

800 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-3-800mV.txt',
        cntr=(480, 560),
        amp1=(20, 20),
        amp2=(15, 15),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-3-800mV.fit', 'r') as f:
    print f.read()

CsOH

Trial 1
600 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-1-600mV.txt',
        cntr=(480, 560),
        amp1=(20, 20),
        amp2=(15, 15),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-1-600mV.fit', 'r') as f:
    print f.read()

700 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-1-700mV.txt',
        cntr=(480, 560),
        amp1=(25, 25),
        amp2=(15, 15),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-1-700mV.fit', 'r') as f:
    print f.read()

800 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-1-800mV.txt',
        cntr=(480, 560),
        amp1=(25, 25),
        amp2=(20, 20),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-1-800mV.fit', 'r') as f:
    print f.read()

Trial 2
600 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-2-600mV.txt',
        cntr=(480, 560),
        amp1=(20, 20),
        amp2=(12, 12),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-2-600mV.fit', 'r') as f:
    print f.read()

700 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-2-700mV.txt',
        cntr=(480, 560),
        amp1=(20, 20),
        amp2=(13, 13),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-2-700mV.fit', 'r') as f:
    print f.read()

800 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-2-800mV.txt',
        cntr=(480, 560),
        amp1=(22, 22),
        amp2=(13, 13),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-2-800mV.fit', 'r') as f:
    print f.read()

Trial 3
600 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-3-600mV.txt',
        cntr=(480, 560),
        amp1=(15, 15),
        amp2=(8, 8),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-3-600mV.fit', 'r') as f:
    print f.read()

700 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-3-700mV.txt',
        cntr=(480, 560),
        amp1=(20, 20),
        amp2=(12, 12),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-3-700mV.fit', 'r') as f:
    print f.read()

800 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-3-800mV.txt',
        cntr=(480, 560),
        amp1=(20, 20),
        amp2=(13, 13),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-3-800mV.fit', 'r') as f:
    print f.read()

Fe-saturated Electrolyte

LiOH

Trial 1
600 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-1-600mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(10, 10),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-1-600mV.fit', 'r') as f:
    print f.read()

700 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-1-700mV.txt',
        cntr=(480, 560),
        amp1=(15, 15),
        amp2=(10, 10),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-1-700mV.fit', 'r') as f:
    print f.read()

800 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-1-800mV.txt',
        cntr=(480, 560),
        amp1=(17, 17),
        amp2=(10, 10),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-1-800mV.fit', 'r') as f:
    print f.read()

Trial 2
600 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-2-600mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(8, 8),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-2-600mV.fit', 'r') as f:
    print f.read()

700 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-2-700mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(7, 7),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-2-700mV.fit', 'r') as f:
    print f.read()

800 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-2-800mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(8, 8),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-2-800mV.fit', 'r') as f:
    print f.read()

Trial 3
600 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-3-600mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(10, 10),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-3-600mV.fit', 'r') as f:
    print f.read()

700 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-3-700mV.txt',
        cntr=(480, 560),
        amp1=(10, 10),
        amp2=(7, 7),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-3-700mV.fit', 'r') as f:
    print f.read()

800 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-3-800mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(7, 7),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-3-800mV.fit', 'r') as f:
    print f.read()

CsOH

Trial 1
600 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-1-600mV.txt',
        cntr=(480, 560),
        amp1=(8, 8),
        amp2=(6, 6),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-1-600mV.fit', 'r') as f:
    print f.read()

700 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-1-700mV.txt',
        cntr=(480, 560),
        amp1=(10, 10),
        amp2=(6, 6),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-1-700mV.fit', 'r') as f:
    print f.read()

800 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-1-800mV.txt',
        cntr=(480, 560),
        amp1=(10, 10),
        amp2=(6, 6),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-1-800mV.fit', 'r') as f:
    print f.read()

Trial 2
600 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-2-600mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(8, 8),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-2-600mV.fit', 'r') as f:
    print f.read()

700 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-2-700mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(8, 8),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-2-700mV.fit', 'r') as f:
    print f.read()

800 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-2-800mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(8, 8),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-2-800mV.fit', 'r') as f:
    print f.read()

Trial 3
600 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-3-600mV.txt',
        cntr=(480, 560),
        amp1=(12, 12),
        amp2=(10, 10),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-3-600mV.fit', 'r') as f:
    print f.read()

700 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-3-700mV.txt',
        cntr=(480, 560),
        amp1=(15, 15),
        amp2=(10, 10),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-3-700mV.fit', 'r') as f:
    print f.read()

800 mV
from ramantools import dgaus2p

dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-3-800mV.txt',
        cntr=(480, 560),
        amp1=(18, 18),
        amp2=(12, 12),
        output=True,
        step=4)

# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-3-800mV.fit', 'r') as f:
    print f.read()

Experimental Apparatus

Patterned Electrode

Figure ref:fig-s8 shows the patterned three-electrode system (Pine Instruments) that was used for all experiments in this study. The Au working electrode is the yellow circle on the left side of the image. The Au counter electrode is the yellow area around the perimeter of the left side of the electrode. The Ag/AgCl reference electrode (RE) is the small, black circle on the left side of the image. An external Hg/HgO reference electrode was used instead of the Ag/AgCl reference electrode since all experiments were performed in alkaline electrolyte.

./images/apparatus/electrode.png

Electrochemical Cell for LSV with Electrolyte Switching

Figure ref:fig-s9 shows a top-view of the electrochemical cell used for the LSV electrolyte switching experiments. The patterned 3-electrode was connected to the white plug. The external Hg/HgO reference electrode is the clear plastic object with a black cap and white/blue tag.

./images/apparatus/ecell-bench-1.png

Figure ref:fig-s10 shows a side-view of the electrochemical cell shown above. This image provides a better view of the working and counter electrodes.

./images/apparatus/ecell-bench-2.png

Electrochemical Cell for LSV with Raman Spectroscopy

Figure ref:fig-s11 shows the electrochemical cell mounted in the Raman spectroscopy system. This configuration was used to perform Raman spectroscopy during LSV. A laser beam was emitted from the black and blue objective above the electrode.

./images/apparatus/ecell-raman.png

Ni(OH)2 for Electrolyte Purification

Figure ref:fig-s12 shows Ni(OH)2 in a polypropylene vial for electrolyte purification cite:trotochaud-2014-nickel-iron. Stock electrolyte soaked in Ni(OH)2 for at least 12 hours. The vial on the right shows electrolyte soaking in the adsorbent (i.e. Ni(OH)2). The vial on the left shows purified electrolyte after centrifugation, but before it was collected into a separate polypropylene vial for storage.

./images/apparatus/ni-hydr-purif.png

bibliographystyle:unsrt bibliography:references.bib

Appendix

Code for Generating LSV Figures

LSV with Electrolyte Switching in Purified LiOH and CsOH

# Generate I vs. V figure
# LSV: LiOH, CsOH (purified)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-li-cs-pure-10-08-mod.xlsx')
ex2 = xlrd.open_workbook('./data/lsv-data/lsv-li-cs-pure-10-03-mod.xlsx')

# LiOH
Li1 = ex1.sheet_by_index(0)                           # read data from Excel sheet
Li2 = ex1.sheet_by_index(1)
Li3 = ex1.sheet_by_index(2)
Li4 = ex1.sheet_by_index(3)
Li5 = ex2.sheet_by_index(0)
Li6 = ex2.sheet_by_index(1)
Li7 = ex2.sheet_by_index(2)

x = np.array(Li1.col_values(0)) - 0.365               # convert potential to overpotential (V)

LiI1 = np.array(Li1.col_values(1)) * 1000/0.0314159   # convert current (A) to current density (mA/cm2)
LiI2 = np.array(Li2.col_values(1)) * 1000/0.0314159
LiI3 = np.array(Li3.col_values(1)) * 1000/0.0314159
LiI4 = np.array(Li4.col_values(1)) * 1000/0.0314159
LiI5 = np.array(Li5.col_values(1)) * 1000/0.0314159
LiI6 = np.array(Li6.col_values(1)) * 1000/0.0314159
LiI7 = np.array(Li7.col_values(1)) * 1000/0.0314159
LiI = np.array([LiI2, LiI3, LiI4, LiI5, LiI6, LiI7])

# CsOH
Cs1 = ex1.sheet_by_index(4)                           # read data from Excel sheet
Cs2 = ex1.sheet_by_index(5)
Cs3 = ex1.sheet_by_index(6)
Cs4 = ex1.sheet_by_index(7)
Cs5 = ex2.sheet_by_index(3)
Cs6 = ex2.sheet_by_index(4)
Cs7 = ex2.sheet_by_index(5)

CsI1 = np.array(Cs1.col_values(1)) * 1000/0.0314159   # convert current (A) to current density (mA/cm2)
CsI2 = np.array(Cs2.col_values(1)) * 1000/0.0314159
CsI3 = np.array(Cs3.col_values(1)) * 1000/0.0314159
CsI4 = np.array(Cs4.col_values(1)) * 1000/0.0314159
CsI5 = np.array(Cs5.col_values(1)) * 1000/0.0314159
CsI6 = np.array(Cs6.col_values(1)) * 1000/0.0314159
CsI7 = np.array(Cs7.col_values(1)) * 1000/0.0314159
CsI = np.array([CsI2, CsI3, CsI4, CsI5, CsI6, CsI7])

# Calculate average current density
avgLiI = (LiI2 + LiI3 + LiI4 + LiI5 + LiI6 + LiI7) / 6
avgCsI = (CsI2 + CsI3 + CsI4 + CsI5 + CsI6 + CsI7) / 6

# Calculate standard deviation of specified data points
nth = 80                                               # interval for calculating std. dev.
stdLi, stdCs = [], []
for n in LiI.T[::-nth]:
    stdLi.append(np.std(n))
stdLi = np.array(stdLi)

for n in CsI.T[::-nth]:
    stdCs.append(np.std(n))
stdCs = np.array(stdCs)

xx = x[::-nth]                                         # potentials where std. dev. calculated

# Generate and format figure
plt.figure(figsize=(3, 4))

plt.plot(x, avgCsI, 'r', label='CsOH')                 # voltage vs. avg. current density
plt.errorbar(xx, avgCsI[::-nth], yerr=stdCs, lw=0, elinewidth=1, color='r') # error bars
plt.plot(x, avgLiI, 'b', label='LiOH')
plt.errorbar(xx, avgLiI[::-nth], yerr=stdLi, lw=0, elinewidth=1, color='b')

plt.legend(loc='upper left', fontsize='11')            # legend
plt.xlabel('Overpotential (V)')                        # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)')            # y-axis label
plt.axis([0.2, 0.6, -0.1, 3])                           # x,y axis values
plt.tight_layout()
plt.xticks([0.2, 0.3, 0.4, 0.5, 0.6], [0.2, 0.3, 0.4, 0.5, 0.6])

# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
    plt.savefig('./images/figures-supp-info/IvsV-Li-Cs-pure-10-08.{0}'.format(ext), dpi=300)

plt.show()

LSV with Electrolyte Switching in Fe-saturated LiOH and CsOH

#Generate I vs. V figure
#LiOH, CsOH - purified
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-li-cs-iron-11-21.xlsx')

# LiOH
Li1 = ex1.sheet_by_index(0)                           # read data from Excel sheet
Li2 = ex1.sheet_by_index(1)
Li3 = ex1.sheet_by_index(2)
Li4 = ex1.sheet_by_index(3)

x = np.array(Li1.col_values(0)) - 0.365               # potential to overpotential (V)

LiI1 = np.array(Li1.col_values(1)) * 1000/0.0314159   # current (A) to current density (mA/cm2)
LiI2 = np.array(Li2.col_values(1)) * 1000/0.0314159
LiI3 = np.array(Li3.col_values(1)) * 1000/0.0314159
LiI4 = np.array(Li4.col_values(1)) * 1000/0.0314159
LiI = np.array([LiI1, LiI2, LiI3, LiI4])

# CsOH
Cs1 = ex1.sheet_by_index(4)                           # read data from Excel sheet
Cs2 = ex1.sheet_by_index(5)
Cs3 = ex1.sheet_by_index(6)
Cs4 = ex1.sheet_by_index(7)

CsI1 = np.array(Cs1.col_values(1)) * 1000/0.0314159   # current (A) to current density (mA/cm2)
CsI2 = np.array(Cs2.col_values(1)) * 1000/0.0314159
CsI3 = np.array(Cs3.col_values(1)) * 1000/0.0314159
CsI4 = np.array(Cs4.col_values(1)) * 1000/0.0314159
CsI = np.array([CsI1, CsI2, CsI3, CsI4])

# Calculate average current density
avgLiI = (LiI1 + LiI2 + LiI3 + LiI4) / 4
avgCsI = (CsI1 + CsI2 + CsI3 + CsI4) / 4

# Calculate standard deviation of specified data points
nth = 60                                              # interval for calculating std. dev.
stdLi, stdCs = [], []
for n in LiI.T[::-nth]:
    stdLi.append(np.std(n))
stdLi = np.array(stdLi)

for n in CsI.T[::-nth]:
    stdCs.append(np.std(n))
stdCs = np.array(stdCs)

xx = x[::-nth]                                        # potentials where std. dev. calculated

# Generate and format figure
plt.figure(figsize=(3, 4))

plt.plot(x, avgCsI, 'r', label='CsOH')                #plot voltage vs. avg. current density
plt.errorbar(xx, avgCsI[::-nth], yerr=stdCs, lw=0, elinewidth=1, color='r') # error bars
plt.plot(x, avgLiI, 'b', label='LiOH')
plt.errorbar(xx, avgLiI[::-nth], yerr=stdLi, lw=0, elinewidth=1, color='b')

plt.legend(loc='upper left', fontsize='11')           # legend
plt.xlabel('Overpotential (V)')                       # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)')           # y-axis label
plt.axis([0.0, 0.5, -1, 25])                          # x,y axis values
plt.tight_layout()
plt.xticks([0.0, 0.1, 0.2, 0.3, 0.4, 0.5], [0.0, 0.1, 0.2, 0.3, 0.4, 0.5])

# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
    plt.savefig('./images/figures-supp-info/IvsV-Li-Cs-iron-11-21.{0}'.format(ext), dpi=300)

plt.show()

LSV with Electrolyte Switching in Purified NaOH and KOH

# Generate I vs. V figure
# LSV: LiOH, CsOH (purified)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-na-k-pure-01-16.xlsx')

# NaOH
Na1 = ex1.sheet_by_index(0)                          # read data from Excel sheet
Na2 = ex1.sheet_by_index(1)
Na3 = ex1.sheet_by_index(2)
Na4 = ex1.sheet_by_index(3)

x = np.array(Na1.col_values(0)) - 0.365              # potential to overpotential (V)

NaI1 = np.array(Na1.col_values(1)) * 1000/0.0314159  # current (A) to current density (mA/cm2)
NaI2 = np.array(Na2.col_values(1)) * 1000/0.0314159
NaI3 = np.array(Na3.col_values(1)) * 1000/0.0314159
NaI4 = np.array(Na4.col_values(1)) * 1000/0.0314159
NaI = np.array([NaI2, NaI3, NaI4])

# KOH
K1 = ex1.sheet_by_index(4)                           # read data from Excel sheet
K2 = ex1.sheet_by_index(5)
K3 = ex1.sheet_by_index(6)
K4 = ex1.sheet_by_index(7)

KI1 = np.array(K1.col_values(1)) * 1000/0.0314159    # current (A) to current density (mA/cm2)
KI2 = np.array(K2.col_values(1)) * 1000/0.0314159
KI3 = np.array(K3.col_values(1)) * 1000/0.0314159
KI4 = np.array(K4.col_values(1)) * 1000/0.0314159
KI = np.array([KI2, KI3, KI4])

# Calculate average current density
avgNaI = (NaI2 + NaI3 + NaI4) / 3
avgKI = (KI2 + KI3 + KI4) / 3

# Calculate standard deviation of specified data points
nth = 70                                             # interval for calculating std. dev.
stdNa, stdK = [], []
for n in NaI.T[::-nth]:
    stdNa.append(np.std(n))
stdNa = np.array(stdNa)

for n in KI.T[::-nth]:
    stdK.append(np.std(n))
stdK = np.array(stdK)
xx = x[::-nth]                                      # potentials where std. dev. calculated

# Generate and format figure
plt.figure(figsize=(3, 4))

plt.plot(x, avgKI, 'k', label='KOH')                #plot voltage vs. avg. current density
plt.errorbar(xx, avgKI[::-nth], yerr=stdK, lw=0, elinewidth=1, color='k') # error bars
plt.plot(x, avgNaI, 'g', label='NaOH')
plt.errorbar(xx, avgNaI[::-nth], yerr=stdNa, lw=0, elinewidth=1, color='g')

plt.legend(loc='upper left', fontsize='11')         # legend
plt.xlabel('Overpotential (V)')                     # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)')         # y-axis label
plt.axis([0.2, 0.6, -0.1, 2])                       # x,y axis values
plt.tight_layout()
plt.xticks([0.2, 0.3, 0.4, 0.5, 0.6], [0.2, 0.3, 0.4, 0.5, 0.6])

# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
    plt.savefig('./images/figures-supp-info/IvsV-Na-K-pure-01-16-15.{0}'.format(ext), dpi=300)

plt.show()

LSV with Electrolyte Switching in Fe-saturated NaOH and KOH

# Generate I vs. V figure
# LSV: NaOH, KOH (Fe-saturated)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-na-k-iron-01-19.xlsx')

# NaOH
Na1 = ex1.sheet_by_index(0)                          # read data from Excel sheet
Na2 = ex1.sheet_by_index(1)
Na3 = ex1.sheet_by_index(2)
Na4 = ex1.sheet_by_index(3)

x = np.array(Na1.col_values(0)) - 0.365              # potential to overpotential (V)

NaI1 = np.array(Na1.col_values(1)) * 1000/0.0314159  # current (A) to current density (mA/cm2)
NaI2 = np.array(Na2.col_values(1)) * 1000/0.0314159
NaI3 = np.array(Na3.col_values(1)) * 1000/0.0314159
NaI4 = np.array(Na4.col_values(1)) * 1000/0.0314159
NaI = np.array([NaI2, NaI3, NaI4])

# KOH
K1 = ex1.sheet_by_index(4)                           # read data from Excel sheet
K2 = ex1.sheet_by_index(5)
K3 = ex1.sheet_by_index(6)
K4 = ex1.sheet_by_index(7)

KI1 = np.array(K1.col_values(1)) * 1000/0.0314159    # current (A) to current density (mA/cm2)
KI2 = np.array(K2.col_values(1)) * 1000/0.0314159
KI3 = np.array(K3.col_values(1)) * 1000/0.0314159
KI4 = np.array(K4.col_values(1)) * 1000/0.0314159
KI = np.array([KI2, KI3, KI4])

# Calculate average current density
avgNaI = (NaI2 + NaI3 + NaI4) / 3
avgKI = (KI2 + KI3 + KI4) / 3

# Calculate standard deviation of specified data points
nth = 70                                            # interval for calculating std. dev.
stdNa, stdK = [], []
for n in NaI.T[::-nth]:
    stdNa.append(np.std(n))
stdNa = np.array(stdNa)

for n in KI.T[::-nth]:
    stdK.append(np.std(n))
stdK = np.array(stdK)
xx = x[::-nth]                                      # potentials where std. dev. calculated

# Generate and format figure
plt.figure(figsize=(3, 4))

plt.plot(x, avgKI, 'k', label='KOH')               # voltage vs. avg. current density
plt.errorbar(xx, avgKI[::-nth], yerr=stdK, lw=0, elinewidth=1, color='k') # error bars
plt.plot(x, avgNaI, 'g', label='NaOH')
plt.errorbar(xx, avgNaI[::-nth], yerr=stdNa, lw=0, elinewidth=1, color='g')

plt.legend(loc='upper left', fontsize='11')        # legend
plt.xlabel('Overpotential (V)')                    # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)')        # y-axis label
plt.axis([0.0, 0.5, -1, 30])                       # x,y axis values
plt.tight_layout()
plt.xticks([0.0, 0.1, 0.2, 0.3, 0.4, 0.5], [0.0, 0.1, 0.2, 0.3, 0.4, 0.5])

# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
    plt.savefig('./images/figures-supp-info/IvsV-Na-K-iron-01-19.{0}'.format(ext), dpi=300)

plt.show()

LSV with Electrolyte Switching in Purified LiOH, NaOH, KOH, and CsOH

# Generate I vs. V figure
# LSV; LiOH, CsOH (purified)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-li-cs-pure-10-08-mod.xlsx')
ex2 = xlrd.open_workbook('./data/lsv-data/lsv-li-cs-pure-10-03-mod.xlsx')
ex3 = xlrd.open_workbook('./data/lsv-data/lsv-na-k-pure-01-16.xlsx')

# LiOH
Li1 = ex1.sheet_by_index(0)                          # read data from Excel sheet
Li2 = ex1.sheet_by_index(1)
Li3 = ex1.sheet_by_index(2)
Li4 = ex1.sheet_by_index(3)
Li5 = ex2.sheet_by_index(0)
Li6 = ex2.sheet_by_index(1)
Li7 = ex2.sheet_by_index(2)

x = np.array(Li1.col_values(0)) - 0.365              # potential to overpotential (V)

LiI1 = np.array(Li1.col_values(1)) * 1000/0.0314159  # current (A) to current density (mA/cm2)
LiI2 = np.array(Li2.col_values(1)) * 1000/0.0314159
LiI3 = np.array(Li3.col_values(1)) * 1000/0.0314159
LiI4 = np.array(Li4.col_values(1)) * 1000/0.0314159
LiI5 = np.array(Li5.col_values(1)) * 1000/0.0314159
LiI6 = np.array(Li6.col_values(1)) * 1000/0.0314159
LiI7 = np.array(Li7.col_values(1)) * 1000/0.0314159
LiI = np.array([LiI2, LiI3, LiI4, LiI5, LiI6, LiI7])

# CsOH
Cs1 = ex1.sheet_by_index(4)                           # read data from Excel sheet
Cs2 = ex1.sheet_by_index(5)
Cs3 = ex1.sheet_by_index(6)
Cs4 = ex1.sheet_by_index(7)
Cs5 = ex2.sheet_by_index(3)
Cs6 = ex2.sheet_by_index(4)
Cs7 = ex2.sheet_by_index(5)

CsI1 = np.array(Cs1.col_values(1)) * 1000/0.0314159   # current (A) to current density (mA/cm2)
CsI2 = np.array(Cs2.col_values(1)) * 1000/0.0314159
CsI3 = np.array(Cs3.col_values(1)) * 1000/0.0314159
CsI4 = np.array(Cs4.col_values(1)) * 1000/0.0314159
CsI5 = np.array(Cs5.col_values(1)) * 1000/0.0314159
CsI6 = np.array(Cs6.col_values(1)) * 1000/0.0314159
CsI7 = np.array(Cs7.col_values(1)) * 1000/0.0314159
CsI = np.array([CsI2, CsI3, CsI4, CsI5, CsI6, CsI7])

# NaOH
Na1 = ex3.sheet_by_index(0)                           # read data from Excel sheet
Na2 = ex3.sheet_by_index(1)
Na3 = ex3.sheet_by_index(2)
Na4 = ex3.sheet_by_index(3)

x = np.array(Na1.col_values(0)) - 0.365               # potential to overpotential (V)

NaI1 = np.array(Na1.col_values(1)) * 1000/0.0314159   # current (A) to current density (mA/cm2)
NaI2 = np.array(Na2.col_values(1)) * 1000/0.0314159
NaI3 = np.array(Na3.col_values(1)) * 1000/0.0314159
NaI4 = np.array(Na4.col_values(1)) * 1000/0.0314159
NaI = np.array([NaI2, NaI3, NaI4])

# KOH
K1 = ex3.sheet_by_index(4)                            # read data from Excel sheet
K2 = ex3.sheet_by_index(5)
K3 = ex3.sheet_by_index(6)
K4 = ex3.sheet_by_index(7)

KI1 = np.array(K1.col_values(1)) * 1000/0.0314159     # current (A) to current density (mA/cm2)
KI2 = np.array(K2.col_values(1)) * 1000/0.0314159
KI3 = np.array(K3.col_values(1)) * 1000/0.0314159
KI4 = np.array(K4.col_values(1)) * 1000/0.0314159
KI = np.array([KI2, KI3, KI4])

# Calculate average current density
avgLiI = (LiI2 + LiI3 + LiI4 + LiI5 + LiI6 + LiI7) / 6
avgCsI = (CsI2 + CsI3 + CsI4 + CsI5 + CsI6 + CsI7) / 6
avgNaI = (NaI2 + NaI3 + NaI4) / 3
avgKI = (KI2 + KI3 + KI4) / 3

# Calculate standard deviation of specified data points
nth = 80                                               # interval for calculating std. dev.
stdLi, stdCs, stdNa, stdK = [], [], [], []
for n in LiI.T[::-nth]:
    stdLi.append(np.std(n))
stdLi = np.array(stdLi)

for n in CsI.T[::-nth]:
    stdCs.append(np.std(n))
stdCs = np.array(stdCs)

for n in NaI.T[::-nth]:
    stdNa.append(np.std(n))
stdNa = np.array(stdNa)

for n in KI.T[::-nth]:
    stdK.append(np.std(n))
stdK = np.array(stdK)

xx = x[::-nth]

# Generate and format figure
plt.figure(figsize=(3, 4))

plt.plot(x, avgCsI, 'r', label='CsOH')
plt.errorbar(xx, avgCsI[::-nth], yerr=stdCs, lw=0, elinewidth=1, color='r')

plt.plot(x, avgKI, 'k', label='KOH')            #plot voltage vs. avg. current density
plt.errorbar(xx, avgKI[::-nth], yerr=stdK, lw=0, elinewidth=1, color='k') # error bars

plt.plot(x, avgNaI, 'g', label='NaOH')
plt.errorbar(xx, avgNaI[::-nth], yerr=stdNa, lw=0, elinewidth=1, color='g')

plt.plot(x, avgLiI, 'b', label='LiOH')
plt.errorbar(xx, avgLiI[::-nth], yerr=stdLi, lw=0, elinewidth=1, color='b')

plt.legend(loc='upper left', fontsize='11')       # legend
plt.xlabel('Overpotential (V)')                   # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)')       # y-axis label
plt.axis([0.2, 0.6, -0.1, 3])                       # x,y axis values
plt.tight_layout()
plt.xticks([0.2, 0.3, 0.4, 0.5, 0.6], [0.2, 0.3, 0.4, 0.5, 0.6])

# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
    plt.savefig('./images/figures-main/IvsV-Na-K-Li-Cs-pure.{0}'.format(ext), dpi=300)

plt.show()

LSV with Electrolyte Switching in Fe-saturated LiOH, NaOH, KOH, and CsOH

# Generate I vs. V figure
# LSV: LiOH, NaOH, KOH, CsOH (Fe-saturated)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-li-cs-iron-11-21.xlsx')
ex2 = xlrd.open_workbook('./data/lsv-data/lsv-na-k-iron-01-19.xlsx')

# LiOH
Li1 = ex1.sheet_by_index(0)                          # read data from Excel sheet
Li2 = ex1.sheet_by_index(1)
Li3 = ex1.sheet_by_index(2)
Li4 = ex1.sheet_by_index(3)

x = np.array(Li1.col_values(0)) - 0.365               # potential to overpotential (V)

LiI1 = np.array(Li1.col_values(1)) * 1000/0.0314159   # current (A) to current density (mA/cm2)
LiI2 = np.array(Li2.col_values(1)) * 1000/0.0314159
LiI3 = np.array(Li3.col_values(1)) * 1000/0.0314159
LiI4 = np.array(Li4.col_values(1)) * 1000/0.0314159
LiI = np.array([LiI1, LiI2, LiI3, LiI4])

# CsOH
Cs1 = ex1.sheet_by_index(4)                           # read data from Excel sheet
Cs2 = ex1.sheet_by_index(5)
Cs3 = ex1.sheet_by_index(6)
Cs4 = ex1.sheet_by_index(7)

CsI1 = np.array(Cs1.col_values(1)) * 1000/0.0314159   # current (A) to current density (mA/cm2)
CsI2 = np.array(Cs2.col_values(1)) * 1000/0.0314159
CsI3 = np.array(Cs3.col_values(1)) * 1000/0.0314159
CsI4 = np.array(Cs4.col_values(1)) * 1000/0.0314159
CsI = np.array([CsI1, CsI2, CsI3, CsI4])

# NaOH
Na1 = ex2.sheet_by_index(0)                           # read data from Excel sheet
Na2 = ex2.sheet_by_index(1)
Na3 = ex2.sheet_by_index(2)
Na4 = ex2.sheet_by_index(3)

x = np.array(Na1.col_values(0)) - 0.365               # potential to overpotential (V)

NaI1 = np.array(Na1.col_values(1)) * 1000/0.0314159   # current (A) to current density (mA/cm2)
NaI2 = np.array(Na2.col_values(1)) * 1000/0.0314159
NaI3 = np.array(Na3.col_values(1)) * 1000/0.0314159
NaI4 = np.array(Na4.col_values(1)) * 1000/0.0314159
NaI = np.array([NaI2, NaI3, NaI4])

# KOH
K1 = ex2.sheet_by_index(4)                            # read data from Excel sheet
K2 = ex2.sheet_by_index(5)
K3 = ex2.sheet_by_index(6)
K4 = ex2.sheet_by_index(7)

KI1 = np.array(K1.col_values(1)) * 1000/0.0314159     # current (A) to current density (mA/cm2)
KI2 = np.array(K2.col_values(1)) * 1000/0.0314159
KI3 = np.array(K3.col_values(1)) * 1000/0.0314159
KI4 = np.array(K4.col_values(1)) * 1000/0.0314159
KI = np.array([KI2, KI3, KI4])

# Calculate average current density
avgLiI = (LiI1 + LiI2 + LiI3 + LiI4) / 4
avgCsI = (CsI1 + CsI2 + CsI3 + CsI4) / 4
avgNaI = (NaI2 + NaI3 + NaI4) / 3
avgKI = (KI2 + KI3 + KI4) / 3

# Calculate standard deviation of specified data points
nth = 80                                               # interval for calculating std. dev.
stdLi, stdCs, stdNa, stdK = [], [], [], []

for n in LiI.T[::-nth]:
    stdLi.append(np.std(n))
stdLi = np.array(stdLi)

for n in CsI.T[::-nth]:
    stdCs.append(np.std(n))
stdCs = np.array(stdCs)

for n in NaI.T[::-nth]:
    stdNa.append(np.std(n))
stdNa = np.array(stdNa)

for n in KI.T[::-nth]:
    stdK.append(np.std(n))
stdK = np.array(stdK)

xx = x[::-nth]

# Generate and format figure
plt.figure(figsize=(3, 4))

plt.plot(x, avgKI, 'k', label='KOH')                  #plot voltage vs. avg. current density
plt.errorbar(xx, avgKI[::-nth], yerr=stdK, lw=0, elinewidth=1, color='k') # error bars

plt.plot(x, avgNaI, 'g', label='NaOH')
plt.errorbar(xx, avgNaI[::-nth], yerr=stdNa, lw=0, elinewidth=1, color='g')

plt.plot(x, avgCsI, 'r', label='CsOH')
plt.errorbar(xx, avgCsI[::-nth], yerr=stdCs, lw=0, elinewidth=1, color='r')

plt.plot(x, avgLiI, 'b', label='LiOH')
plt.errorbar(xx, avgLiI[::-nth], yerr=stdLi, lw=0, elinewidth=1, color='b')

plt.legend(loc='upper left', fontsize='11')          # legend
plt.xlabel('Overpotential (V)')                      # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)')          # y-axis label
plt.axis([0.0, 0.6, -1, 30])                         # x,y axis values
plt.tight_layout()
plt.xticks([0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6], [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6])

# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
    plt.savefig('./images/figures-main/IvsV-Na-K-Li-Cs-iron.{0}'.format(ext), dpi=300)

plt.show()

LSV during Raman Spectroscopy in Purified LiOH and CsOH

# Generate I vs. V figure
# LSV during Raman spectroscopy: LiOH, CsOH (purified)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-raman-li-cs-pure-10-31.xlsx')

# LiOH
Li1 = ex1.sheet_by_index(0)                            # read data from Excel sheet
Li2 = ex1.sheet_by_index(1)
Li3 = ex1.sheet_by_index(2)
Li4 = ex1.sheet_by_index(3)

x = np.array(Li1.col_values(0)) - 0.365                # potential to overpotential (V)

LiI1 = np.array(Li1.col_values(1)) * 1000/0.0314159    # current (A) to current density (mA/cm2)
LiI2 = np.array(Li2.col_values(1)) * 1000/0.0314159
LiI3 = np.array(Li3.col_values(1)) * 1000/0.0314159
LiI4 = np.array(Li4.col_values(1)) * 1000/0.0314159
LiI = np.array([LiI2, LiI3, LiI4])

# CsOH
Cs1 = ex1.sheet_by_index(4)                            # read data from Excel sheet
Cs2 = ex1.sheet_by_index(5)
Cs3 = ex1.sheet_by_index(6)
Cs4 = ex1.sheet_by_index(7)

#CsV1 = np.array(Cs1.col_values(0)) - 0.365            # potential to overpotential (V)
CsI1 = np.array(Cs1.col_values(1)) * 1000/0.0314159    # current (A) to current density (mA/cm2)
CsI2 = np.array(Cs2.col_values(1)) * 1000/0.0314159
CsI3 = np.array(Cs3.col_values(1)) * 1000/0.0314159
CsI4 = np.array(Cs4.col_values(1)) * 1000/0.0314159
CsI = np.array([CsI2, CsI3, CsI4])

# Calculate average current density
avgLiI = (LiI2 + LiI3 + LiI4) / 3
avgCsI = (CsI2 + CsI3 + CsI4) / 3

# Calculate standard deviation of specified data points
nth = 80                                               # interval for calculating std. dev.
stdLi, stdCs = [], []
for n in LiI.T[::-nth]:
    stdLi.append(np.std(n))
stdLi = np.array(stdLi)

for n in CsI.T[::-nth]:
    stdCs.append(np.std(n))
stdCs = np.array(stdCs)

xx = x[::-nth]                                         # potentials where std. dev. calculated

# Generate and format figure
plt.figure(figsize=(3, 4))

plt.plot(x, avgCsI, 'r', label='CsOH')                 # plot voltage vs. avg. current density
plt.errorbar(xx, avgCsI[::-nth], yerr=stdCs, lw=0, elinewidth=1, color='r') # error bars
plt.plot(x, avgLiI, 'b', label='LiOH')
plt.errorbar(xx, avgLiI[::-nth], yerr=stdLi, lw=0, elinewidth=1, color='b')

plt.legend(loc='upper left', fontsize='11')            # legend
plt.xlabel('Overpotential (V)')                        # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)')            # y-axis label
plt.axis([0.2, 0.6, -0.1, 8])                          # x,y axis values
plt.tight_layout()
plt.xticks([0.2, 0.3, 0.4, 0.5, 0.6], [0.2, 0.3, 0.4, 0.5, 0.6])

# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
    plt.savefig('./images/figures-supp-info/IvsV-Raman-Li-Cs-pure-10-31.{0}'.format(ext), dpi=300)

plt.show()

LSV during Raman Spectroscopy in Fe-saturated LiOH and CsOH

# Generate I vs. V figure
# LSV during Raman spectroscopy: LiOH, CsOH (Fe-saturated)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-raman-li-cs-iron-11-19.xlsx')

# LiOH
Li1 = ex1.sheet_by_index(0)                           # read data from Excel sheet
Li2 = ex1.sheet_by_index(1)
Li3 = ex1.sheet_by_index(2)
Li4 = ex1.sheet_by_index(3)

x = np.array(Li1.col_values(0)) - 0.365               # potential to overpotential (V)

LiI1 = np.array(Li1.col_values(1)) * 1000/0.0314159   # current (A) to current density (mA/cm2)
LiI2 = np.array(Li2.col_values(1)) * 1000/0.0314159
LiI3 = np.array(Li3.col_values(1)) * 1000/0.0314159
LiI4 = np.array(Li4.col_values(1)) * 1000/0.0314159
LiI = np.array([LiI1, LiI3, LiI4])

# CsOH
Cs1 = ex1.sheet_by_index(4)                           # read data from Excel sheet
Cs2 = ex1.sheet_by_index(5)
Cs3 = ex1.sheet_by_index(6)
Cs4 = ex1.sheet_by_index(7)

CsI1 = np.array(Cs1.col_values(1)) * 1000/0.0314159   # current (A) to current density (mA/cm2)
CsI2 = np.array(Cs2.col_values(1)) * 1000/0.0314159
CsI3 = np.array(Cs3.col_values(1)) * 1000/0.0314159
CsI4 = np.array(Cs4.col_values(1)) * 1000/0.0314159
CsI = np.array([CsI1, CsI2, CsI3, CsI4])

# Calculate average current density
avgLiI = (LiI1 + LiI3 + LiI4) / 3
avgCsI = (LiI1 + CsI2 + CsI3 + CsI4) / 4

# Calculate standard deviation of specified data points
nth = 80                                               # interval for calculating std. dev.
stdLi, stdCs = [], []
for n in LiI.T[::-nth]:
    stdLi.append(np.std(n))
stdLi = np.array(stdLi)

for n in CsI.T[::-nth]:
    stdCs.append(np.std(n))
stdCs = np.array(stdCs)

xx = x[::-nth]

# Generate and format figure
plt.figure(figsize=(3, 4))

plt.plot(x, avgCsI, 'r', label='CsOH')                 # plot voltage vs. avg. current density
plt.errorbar(xx, avgCsI[::-nth], yerr=stdCs, lw=0, elinewidth=1, color='r') # error bars
plt.plot(x, avgLiI, 'b', label='LiOH')
plt.errorbar(xx, avgLiI[::-nth], yerr=stdLi, lw=0, elinewidth=1, color='b')

plt.legend(loc='upper left', fontsize='11')            # legend
plt.xlabel('Overpotential (V)')                        # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)')            # y-axis label
plt.axis([0.0, 0.6, -1, 16])                           # x,y axis values
plt.tight_layout()
plt.xticks([0.0, 0.2, 0.4, 0.6], [0.0, 0.2, 0.4, 0.6])

# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
    plt.savefig('./images/figures-supp-info/IvsV-Raman-Li-Cs-iron-11-19.{0}'.format(ext), dpi=300)

plt.show()

Code for Raman Peak Fitting

Below is a Python function for fitting Gaussian distributions to Raman spectra of NiOOH thin films. This function was called in other Python code blocks within this Supporting Information file. See section #sec-fitting.

import numpy as np
import matplotlib.pyplot as plt
from scipy.special import erf
from scipy.optimize import curve_fit
import os

def dgaus2p(filename,
            cntr=(470.0, 560.0),
            amp1=(20.0, 20.0),
            amp2=(20.0, 20.0),
            std1=(10.0, 5.0),
            std2=(10.0, 5.0),
            datarange=None,
            output=False,
            step=4):

    """Fitting Raman spectra data using the two Gaussian functions

    This function fits two double Gaussian fits for Raman peaks
    with overlapping tails.

    Parameters
    ----------
    filename : str
        The name of the file containing the data to be analyzed. Data is
        read in using the numpy.loadtxt function. Data should be separated
        into two rows, the first being the wavenumber, the second being
        signal intensity.

    cntr : list, optional
        Initial starting point for the center of each peak in wavenumbers.
        A float in the list for each peak.

    amp1 : list, optional
        Initial starting point for the amplitude of the frist Gaussian.
        A float in the list for each peak.

    amp2 : list, optional
        Initial starting point for the amplitude of the second Gaussian.
        A float in the list for each peak.

    std1 : list, optional
        Initial starting point for the standard deviation of the frist
        Gaussian. A float in the list for each peak.

    std2 : list, optional
        Initial starting point for the standard deviation of the second
        Gaussian. A float in the list for each peak.

    datarange : list, optional
        This is a list of two floats specifying the range of wavenumbers
        you want to analyze from the data file. Takes the entire range of
        data by default.

    output : bool , optional
        Whether or not the function returns an output .fit file.

    step : 1, 2, 3, or 4 : optional
        Specifies which step of the fitting process the user is working on:
        step = 1: Fittings the baseline (figure produced)
        step = 2: Choosing initial guess for peaks (figure produced)
        step = 3: Evaluate the fit (figure produced)
        step = 4: View and save the final figure (no figure)


    Returns
    -------
    results : array
        An array of: [center peak 1, center peak 2,
                      height peak 1, height peak 2,
                      area peak 1, area peak 2,
                      baseline slope, baseline intercept]

    fiterror : array
        An array of the fitting errors for: [center peak 1, center peak 2,
                                             height peak 1, height peak 2]

    popt : array
        An array of the optimized fitting parameters as output from the
        scipy.optimize.curve_fit function:
        Peak # :  1        2
                 [cntr[0], cntr[1],   # Peak center
                  amp1[0], amp1[1],   # Amplitude of Gaussian 1
                  amp2[0], amp2[1],   # Amplitude of Gaussian 2
                  std1[0], std1[1],   # Standard deviation of Gaussian 1
                  std2[0], std2[1])   # Standard deviation of Gaussian 2

    parguess : array
        An array of the initial fitting parameters:
        Peak # :  1        2
                 [cntr[0], cntr[1],   # Peak center
                  amp1[0], amp1[1],   # Amplitude of Gaussian 1
                  amp2[0], amp2[1],   # Amplitude of Gaussian 2
                  std1[0], std1[1],   # Standard deviation of Gaussian 1
                  std2[0], std2[1])   # Standard deviation of Gaussian 2

    See Also
    --------
    scipy.special.erf
    scipy.optimize.curve_fit
    """

    # This unpacks the data from the text file.
    S, I = np.loadtxt(filename, usecols=(0, 1), unpack=True)

    if datarange == None:
        datarange = [min(S), max(S)]

    # Define the low and high regions for baseline sampling
    dx = 80.
    low = datarange[0] + dx
    high = datarange[1] - dx

    # Seperate the data points to be used for fitting the baseline
    xbl = np.append(S[(S < low)], S[(S > high)])
    ybl = np.append(I[(S < low)], I[(S > high)])

    # Fits a line to the base line points
    blpars = np.polyfit(xbl, ybl, 1)
    blfit = np.poly1d(blpars)


    if step != 1 and step != 2 and step != 3 and step != 4:
        print 'Set step = 1, 2, 3, or 4 to continue'

    # Step 1: Choose low and high values for a satisfactory baseline
    if step == 1:
        plt.figure()
        plt.plot(S, I, label='data')
        plt.plot(S, blfit(S), 'r-', lw=2, label='base line')
        plt.xlabel('Raman shift (cm$^{-1}$)')
        plt.ylabel('Intensity (counts)')
        plt.legend(loc='best')
        plt.show()
        print 'When you are satisfied with the fit of the base line, set step = 2'
        exit()

    # Subtracts the baseline from the intensities
    I -= blfit(S)

    # Gaussians will only be fit the the data not used for the baseline
    nS = S[(S > low) & (S < high)]
    nI = I[(S > low) & (S < high)]

    # These are functions which define the types of fit which you could implement
    # Currently, the code only utilizes Gaussians
    # ----------------------------------------------------------------------
    def gaussian(x, pars):
        A = pars[0]    # amplitude
        mu = pars[1]   # means
        sig = pars[2]  # std dev
        return A * np.exp((-(x - mu)**2.) / ((2*sig)**2.))

    def sum_gaussian(x, *p):
        g1 = gaussian(x, [p[2], p[0], p[6]])
        g2 = gaussian(x, [p[3], p[0], p[7]])
        g3 = gaussian(x, [p[4], p[1], p[8]])
        g4 = gaussian(x, [p[5], p[1], p[9]])
        return g1 + g2 + g3 + g4
    # ----------------------------------------------------------------------

    # These are initial guesses of the tuning parameters for the Gaussian fits.
    # Peak # :  1        2
    parguess = (cntr[0], cntr[1],   # Peak center
                amp1[0], amp1[1],   # Amplitude of Gaussian 1
                amp2[0], amp2[1],   # Amplitude of Gaussian 2
                std1[0], std1[1],   # Standard deviation of Gaussian 1
                std2[0], std2[1])   # Standard deviation of Gaussian 2

    # Step 2: Fitting the curves to the data
    if step == 2:
        plt.figure()
        plt.plot(nS, nI, 'b-', label='Data')
        plt.plot(S, sum_gaussian(S, *parguess), 'g--', lw=3, label='Initial guess')
        plt.xlim(datarange[0], datarange[1])
        plt.ylim(0, max(nI) + 2)
        plt.xlabel('Raman shift (cm$^{-1}$)')
        plt.ylabel('Intensity (counts)')
        plt.legend(loc='best')
        plt.show()
        print 'Once the initial guess looks reasonable, set step = 3'
        exit()

    # This is a multivaraible curve fitting program which attempts to optimize the fitting parameters
    popt, pcov = curve_fit(sum_gaussian, S, I, parguess)

    peak1 = gaussian(S, [popt[2], popt[0], popt[6]]) + gaussian(S, [popt[3], popt[0], popt[7]])
    peak2 = gaussian(S, [popt[4], popt[1], popt[8]]) + gaussian(S, [popt[5], popt[1], popt[9]])

    # Step 3: Evaluate the fit
    if step == 3:
        plt.figure()
        plt.plot(nS, nI, 'b-', label='Data')
        plt.plot(S, sum_gaussian(S, *popt), 'r-', lw=3, label='Final Fit')
        plt.plot(S, peak1, 'm-', lw=3, label='Fit for peak 1')
        plt.plot(S, gaussian(S, [popt[4], popt[1], popt[8]]) + gaussian(S, [popt[5], popt[1], popt[9]]),
                 'c-', lw=3, label='Fit for peak 2')
        plt.xlim(low, high)
        plt.ylim(0, max(nI) + 2)
        plt.xlabel('Raman shift (cm$^{-1}$)')
        plt.ylabel('Intensity (counts)')
        plt.legend(loc='best')
        plt.show()
        print 'When you are satisfied with the peak fit, set step = 3'
        print 'else, return to step 2 and choose new fitting parameters'
        exit()

    # Step 4: A summary of the resulting fit
    if step == 4:
        ypeak1 = popt[2] + popt[3] + blfit(popt[0])
        ypeak2 = popt[4] + popt[5] + blfit(popt[1])

        area1 = -np.trapz(S, peak1)
        area2 = -np.trapz(S, peak2)

        savefile = filename.rstrip('txt')

        perr = np.sqrt(np.diag(pcov))

        pk1err = np.sqrt(perr[2]**2. + perr[3]**2 + 2 * pcov[2][3])
        pk2err = np.sqrt(perr[4]**2. + perr[5]**2 + 2 * pcov[4][5])

        results = np.array([popt[0], popt[1],
                            ypeak1, ypeak2,
                            area1, area2,
                            blpars[0], blpars[1]])

        fiterror = np.array([perr[0], perr[1],
                             pk1err, pk2err])

        if output:
            savefile = savefile + 'fit'

            f = 'Initial guess parameters:\n'
            f += '=========================\n'
            f += '                      Peak 1, Peak 2\n'
            f += 'Peak center =         {0:1.1f}, {1:1.2f}\n'.format(cntr[0], cntr[1])
            f += 'Amplitude fit 1 =     {0:1.1f}, {1:1.2f}\n'.format(amp1[0], amp1[1])
            f += 'Amplitude fit 2 =     {0:1.1f}, {1:1.2f}\n'.format(amp2[0], amp2[1])
            f += 'Standard dev. fit 1 = {0:1.1f}, {1:1.1f}\n'.format(std1[0], std1[1])
            f += 'Standard dev. fit 2 = {0:1.1f}, {1:1.1f}\n'.format(std2[0], std2[1])

            f += '\nBaseline parameters:\n'
            f += '===================\n'
            f += 'Slope =               {0:1.2f}\n'.format(blpars[0])
            f += 'Intercept =           {0:1.2f}\n'.format(blpars[1])

            f += '\nFitted parameters:\n'
            f += '==================\n'
            f += '                      Peak 1, Peak 2\n'
            f += 'Peak center =         {0:1.2f}, {1:1.2f}\n'.format(popt[0], popt[1])
            f += 'Amplitude fit 1 =     {0:1.2f}, {1:1.2f}\n'.format(popt[2], popt[3])
            f += 'Amplitude fit 2 =     {0:1.2f}, {1:1.2f}\n'.format(popt[4], popt[5])
            f += 'Standard dev. fit 1 = {0:1.2f}, {1:1.2f}\n'.format(popt[6], popt[7])
            f += 'Standard dev. fit 2 = {0:1.2f}, {1:1.2f}\n'.format(popt[8], popt[9])

            f += '\nCalculation output:\n'
            f += '======================\n'
            f += 'Mean peak 1 =         {0:1.1f} $\pm$ {1:1.2f}\n'.format(popt[0], perr[0])
            f += 'Mean peak 2 =         {0:1.1f} $\pm$ {1:1.2f}\n'.format(popt[1], perr[1])
            f += 'Height peak 1 =       {0:1.1f} $\pm$ {1:1.2f}\n'.format(ypeak1, pk1err)
            f += 'Height peak 2 =       {0:1.1f} $\pm$ {1:1.2f}\n'.format(ypeak2, pk2err)
            f += 'Area peak 1 =         {0:1.1f}\n'.format(area1)
            f += 'Area peak 2 =         {0:1.1f}'.format(area2)

            fl = open(savefile, 'w')
            fl.write(f)
            fl.close()

        return results, fiterror, popt, parguess

Code for Generating Raman Spectra Figures

Raman shift vs. Intensity, stacked - NiOOH - purified LiOH, CsOH

import numpy as np
import matplotlib.pyplot as plt
from ramantools import dgaus2p

# Put the name of your data files here
data_file_name = ['./data/raman-spectra-for-figs/purified/Ni-Li-pure-3-600mV.txt',
                  './data/raman-spectra-for-figs/purified/Ni-Li-pure-3-700mV.txt',
                  './data/raman-spectra-for-figs/purified/Ni-Li-pure-3-800mV.txt',
                  './data/raman-spectra-for-figs/purified/Ni-Cs-pure-1-600mV.txt',
                  './data/raman-spectra-for-figs/purified/Ni-Cs-pure-1-700mV.txt',
                  './data/raman-spectra-for-figs/purified/Ni-Cs-pure-2-800mV.txt']

def Gaussian(x, pars):
    A = pars[0]    # amplitude
    mu = pars[1]   # means
    sig = pars[2]  # std dev
    return A * np.exp((-(x - mu)**2.) / ((2*sig)**2.))

def sum_gaussian(x, pars):
    p = pars
    g1 = Gaussian(x, [p[2], p[0], p[6]])
    g2 = Gaussian(x, [p[3], p[0], p[7]])
    g3 = Gaussian(x, [p[4], p[1], p[8]])
    g4 = Gaussian(x, [p[5], p[1], p[9]])
    return g1 + g2 + g3 + g4

# Line will begin at offset from 0.
offset = [0, 30, 60,
          100, 130, 160] # Adjust y-position of Raman spectra
labels = ['240 mV', '340 mV', '440 mV',
          '240 mV', '340 mV', '440 mV']
cl = ['b', 'b', 'b',
      'k', 'k', 'k']

plt.figure(figsize=(3, 5))
for i, f in enumerate(data_file_name):

    # get fitting parameters
    R, E, P, ip = dgaus2p(f)

    # get Raman data
    S, I = np.loadtxt(f, usecols=(0, 1), unpack=True)

    # reproduce fit to raw data
    bl = np.poly1d([R[-2], R[-1]])
    F = sum_gaussian(S, list(P)) + bl(S)

    # plot the fit and the data
    plt.plot(S, I + offset[i], color=cl[i])
    plt.plot(S, F + offset[i], 'r-', lw=2)

    # Labels for curve
    # (x-position, y-position, alignment, alignment)
    plt.text(649, I[-1] + offset[i] + 15,
             labels[i],
             horizontalalignment='right',
             verticalalignment='bottom',
             fontsize='10')

    # Add guild lines to peak center (only for one fit)
    if i == 0:
        ctr1, ctr2 = P[0], P[1] # cm^-1

        plt.plot([ctr1, ctr1], [0, 300], 'k-')
        plt.plot([ctr2, ctr2], [0, 300], 'k-')

# Remove tick marks from y-axis
plt.tick_params(axis='y',
                which='both',
                left='off',
                right='off',
                labelleft='off')

plt.xlim(400, 650)
plt.ylim(0, 230)
plt.xlabel('Raman shift (cm$^{-1}$)')
plt.ylabel('Intensity (a.u.)')
plt.tight_layout()

# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
    plt.savefig('./images/figures-main/raman-combined-pure-10-31-14.{0}'.format(ext), dpi=300)

plt.show()

Raman shift vs. Intensity, stacked - Ni(OH)2 - purified LiOH, CsOH

# Generate figures of Raman spectra
# Ni(OH)2

import matplotlib.pyplot as plt
import xlrd
# open raman spectra data file
ex1 = xlrd.open_workbook('./data/raman-spectra-for-figs/NiOH2-Raman-spectra.xlsx')

# Raman shift vs. Intensity
Li_pure = ex1.sheet_by_index(0) # read data from Excel sheet
Cs_pure = ex1.sheet_by_index(1)
Li_iron = ex1.sheet_by_index(2)
Cs_iron = ex1.sheet_by_index(3)

# Purified electrolyte
Li_rs_pure = Li_pure.col_values(0)  # Raman shift
Li_int_pure = Li_pure.col_values(1) # intensity (a.u.)

Cs_rs_pure = Cs_pure.col_values(0)  # Raman shift
Cs_int_pure = Cs_pure.col_values(1) # intensity (a.u.)

# Fe-saturated electrolyte
Li_rs_iron = Li_iron.col_values(0)  # Raman shift
Li_int_iron = Li_iron.col_values(1) # intensity (a.u.)

Cs_rs_iron = Cs_iron.col_values(0)  # Raman shift
Cs_int_iron = Cs_iron.col_values(1) # intensity (a.u.)

# Plotting the above lists will yield ugly figures, since there are so many data points.
# Need to snip out enough useful data.

# Empty lists for data modifications
Li_rs_pure_m = []
Li_int_pure_m = []
Cs_rs_pure_m = []
Cs_int_pure_m = []

Li_rs_iron_m = []
Li_int_iron_m = []
Cs_rs_iron_m = []
Cs_int_iron_m = []

# Snip out some raw data before plotting
snip = range(0, len(Li_rs_pure), 5)          # all lists in code have same length
for i in snip:
    Li_rs_pure_m.append(Li_rs_pure[i])       # append useful data to new list
    Li_int_pure_m.append(Li_int_pure[i] - 5) # append and shift spectra
    Cs_rs_pure_m.append(Cs_rs_pure[i])
    Cs_int_pure_m.append(Cs_int_pure[i]+6)

    Li_rs_iron_m.append(Li_rs_iron[i])
    Li_int_iron_m.append(Li_int_iron[i]+ 10)
    Cs_rs_iron_m.append(Cs_rs_iron[i])
    Cs_int_iron_m.append(Cs_int_iron[i] + 35)

# Create and format figure
plt.figure(figsize=(3, 4))
plt.plot(Li_rs_pure_m, Li_int_pure_m, 'b', label = 'LiOH, purified')     # LiOH, purified
plt.plot(Cs_rs_pure_m, Cs_int_pure_m, 'r', label = 'CsOH, purified')     # CsOH, purified
plt.plot(Li_rs_iron_m, Li_int_iron_m, 'g', label = 'LiOH, Fe saturated') # LiOH, Fe saturated
plt.plot(Cs_rs_iron_m, Cs_int_iron_m, 'k', label = 'CsOH, Fe saturated') # CsOH, Fe saturated

# Spectra labels
# (x-position, y-position, label, alignment, alignment)
plt.text(540, 13, 'LiOH, purified', horizontalalignment='left', verticalalignment='bottom', fontsize='10')
plt.text(540, 30, 'CsOH, purified', horizontalalignment='left', verticalalignment='bottom', fontsize='10')
plt.text(540, 51, 'LiOH, Fe sat.', horizontalalignment='left', verticalalignment='bottom', fontsize='10')
plt.text(540, 69, 'CsOH, Fe sat.', horizontalalignment='left', verticalalignment='bottom', fontsize='10')

# Make y-axis text invisible
frame = plt.gca()
frame.axes.get_yaxis().set_ticks([])

plt.xlabel('Raman shift cm$^{-1}$')
plt.ylabel('Intensity (a.u.)')
plt.axis([250, 750, 0, 80])
plt.tight_layout()

# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
    plt.savefig('./images/figures-supp-info/raman-nioh2-pure-iron.{0}'.format(ext), dpi=300)

plt.show()