Scripts to produce publication-ready figures.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

174 lines
6.6 KiB

import os, csv
from pathlib import Path
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
sns.set_theme(style="ticks")
def parse_NIST_data(path, min_J, max_J, max_wavenumber):
data_list = []
with open(path) as f:
reader = csv.reader(f, delimiter="\t")
data_list = list(reader)
#collect data
Parity = np.zeros(len(data_list))
J = np.zeros(len(data_list))
Wavenumber = np.zeros(len(data_list))
for i in range(1, len(data_list)):
try:
tmp = data_list[:][i]
if not tmp[0] == '' and tmp[0].find('*') != -1:
Parity[i] = 1
elif not tmp[0] == '':
Parity[i] = 0
J[i] = int(tmp[1])
Wavenumber[i] = float(tmp[3])
except ValueError:
J[i] = np.nan
Wavenumber[i] = np.nan
remove_idxs = []
for i in range(1, len(data_list)):
p = Parity[i]
j = J[i]
wn = Wavenumber[i]
if np.isnan(p) or np.isnan(j) or np.isnan(wn):
remove_idxs.append(i)
Parity = np.delete(Parity, remove_idxs)
J = np.delete(J, remove_idxs)
Wavenumber = np.delete(Wavenumber, remove_idxs)
#sort data
sorting_indices = np.argsort(J)
Parity = Parity[sorting_indices]
J = J[sorting_indices]
Wavenumber = Wavenumber[sorting_indices]
# splice data to within user-defined range of Js
splice_idx_start = np.where(J==min_J)[0][0]
splice_idx_stop = len(J) - 1 - np.where(J[::-1]==max_J)[0][0]
Parity = Parity[splice_idx_start:splice_idx_stop]
J = J[splice_idx_start:splice_idx_stop]
Wavenumber = Wavenumber[splice_idx_start:splice_idx_stop]
# splice data to within user-defined range of Wavenumbers
splice_idxs = [i for i in range(len(Wavenumber)) if Wavenumber[i] > max_wavenumber]
Parity = [ele for idx, ele in enumerate(Parity) if idx not in splice_idxs]
J = [ele for idx, ele in enumerate(J) if idx not in splice_idxs]
Wavenumber = [ele for idx, ele in enumerate(Wavenumber) if idx not in splice_idxs]
# Create a Pandas data frame with the data
dataset = pd.DataFrame(np.array(list(zip(Parity, J, Wavenumber))), columns=['Parity', 'J', 'Wavenumber'])
return dataset
def plot_level_structure_with_red_and_blue_transitions(*args, **kwargs):
#start plotting
f, ax = plt.subplots(figsize=(4, 8))
named_colors = ['r', 'm']
Red_Blue_colors = ['#ab162a', '#cf5246', '#eb9172', '#fac8af', '#faeae1', '#e6eff4', '#bbdaea', '#7bb6d6', '#3c8abe', '#1e61a5']
#draw levels
plot_handle = sns.scatterplot(x='J', y='Wavenumber', data = dataframe, s=2000, hue = 'Parity', palette = sns.color_palette(named_colors), marker = '_', linewidth=1.5, legend=False)
#write electronic configuration for GS
ax.text(gs_J + 0.15, gs_wavenumber + 400, '$6s^2$')
#draw guide line for GS
#plt.axhline(y=gs_wavenumber, color='m', linestyle='--', linewidth=1, alpha=0.5)
#write wavelength of red transition
ax.text(red_J - 0.4, red_wavenumber * 0.5, '$626.082 ~ \mathrm{nm}$', color = '#db2929')
ax.text(red_J - 0.4, red_wavenumber * 0.46, '$(\\Gamma = 2\\pi\\times 136 ~ \mathrm{kHz})$', fontsize = 8, color = '#db2929')
#draw red transition arrow
ax.annotate('',
xy=(red_J, red_wavenumber),
xytext=(gs_J, gs_wavenumber),
arrowprops=dict(color='#db2929', alpha=0.8, width=1.5),
horizontalalignment='right',
verticalalignment='top')
#write electronic configuration for triplet excited state
ax.text(red_J + 0.35, red_wavenumber + 200, '$6s6p(^3P_1)$', fontsize = 10)
#draw guide line for triplet excited state
plt.axhline(y=red_wavenumber, color='m', linestyle='--', linewidth=1, alpha=0.5)
#write wavelength of red transition
ax.text(blue_J - 1.5, blue_wavenumber * 0.55, '$421.291~ \mathrm{nm}$', color = '#2630ea')
ax.text(blue_J - 1.55, blue_wavenumber * 0.52, '$(\\Gamma = 2\\pi\\times 32.2 ~ \mathrm{MHz})$', fontsize = 8, color = '#2630ea')
#draw blue transition arrow
ax.annotate('',
xy=(blue_J, blue_wavenumber),
xytext=(gs_J, gs_wavenumber),
arrowprops=dict(color='#2630ea', alpha=0.8, width=3.5),
horizontalalignment='right',
verticalalignment='top')
#write electronic configuration for singlet excited state
ax.text(blue_J + 0.35, blue_wavenumber + 200, '$6s6p(^1P_1)$', fontsize = 10)
#draw guide line for singlet excited state
plt.axhline(y=blue_wavenumber, color='m', linestyle='--', linewidth=1, alpha=0.5)
#figure options
f.canvas.draw()
plt.xlabel('$J$', fontsize=16)
plt.ylabel('$\\tilde{v}~(cm^{-1})$', fontsize=16)
plt.ylabel('$\\lambda~(nm)$', fontsize=16)
plot_handle.set_xticks(range(min_J-1, max_J+2))
ax.get_xticklabels()[0].set_visible(False)
ax.get_xticklabels()[-1].set_visible(False)
ax.get_xticklines()[0].set_visible(False)
ax.get_xticklines()[-2].set_visible(False)
yticklabels = [item.get_text() for item in ax.get_yticklabels()]
yticklabels = ['' if item.startswith('') or item.startswith('0') else item for item in yticklabels]
yticks = [float(item) if item != '' else 0.0 for item in yticklabels]
new_yticks = np.arange(min(yticks), max(yticks), 4000)
plot_handle.set_yticks(new_yticks)
new_yticklabels = [round(1e7/item) if item != 0 else item for item in new_yticks]
ax.set_yticklabels(new_yticklabels)
ax.get_yticklabels()[0].set_visible(False)
ax.get_yticklabels()[-1].set_visible(False)
ax.get_yticklines()[0].set_visible(False)
ax.get_yticklines()[-2].set_visible(False)
plt.tick_params(axis='both', which='major', labelsize=14)
#plt.show()
f.savefig(Path(home_path + os.sep + 'result.pdf'), format='pdf', bbox_inches = "tight")
if __name__ == '__main__':
min_J = 8
max_J = 9
max_wavenumber = 25500.0
#Ground State: [Xe]4f^{10} 6s^2(^5I_8)
gs_J = 8
gs_wavenumber = 0.0
#626 nm transition GS ---> [Xe]4f^{10}(^5I_8) 6s6p(^3P_1)(8,1)_9
red_J = 9
red_wavenumber = 15972.35
#421 nm transition GS ---> [Xe]4f^{10}(^5I_8) 6s6p(^1P_1)(8,1)_9
blue_J = 9
blue_wavenumber = 23736.610
NIST_Dy_level_data_filename= 'Dylevels.txt'
home_path = str(Path(__file__).parent.resolve())
dataframe = parse_NIST_data(home_path + os.sep + NIST_Dy_level_data_filename, min_J, max_J, max_wavenumber)
plot_level_structure_with_red_and_blue_transitions(dataframe, gs_J, gs_wavenumber, red_J, red_wavenumber, blue_J, blue_wavenumber, home_path)