This notebook reproduces Fig. 7 in the paper, which shows the the frequency change $\Delta f$ as a function of lateral particle position $x$ for the first five eigenmodes (N = 1 - 5), with the MNP either above the major axis of the ellipse (y = 0 nm) or shifted by 20 nm in y-direction. The frequency change for each mode is shown for three values of the nanoparticle-disc separation: d = 5 nm, d = 20 nm, d = 50 nm.
In [1]:
import matplotlib.pyplot as plt
import pandas as pd
from style_helpers import style_cycle_fig7
%matplotlib inline
plt.style.use('style_sheets/fig7.mplstyle')
Define which values of $z$, $y$ and $N$ are going to appear in the figure.
In [2]:
dvals = [5, 20, 50]
yvals = [0, 20]
Nvals = [1, 2, 3, 4, 5]
Read the data frame with the eigenmode data and filter out the parameter values relevant for this plot.
In [3]:
df = pd.read_csv('../data/eigenmode_info_data_frame.csv')
df = df.query('(has_particle == True) & (d_particle == 20) & (Ms_particle == 1e6) & '
'(d in [5, 20, 50]) & (Hz == 8e4)')
df = df.sort_values('x')
Define a series of helper functions.
In [4]:
def draw_zero_line(ax):
"""
Draw a horizontal line representing delta_f = 0.
"""
ax.plot([-90, 90], [0, 0], color='#888888', linestyle='-', linewidth=1)
In [5]:
def add_y_value_annotation(ax, y):
"""
Add annotation to indicate y-value used in this row
of subplots. Example: "y = 20 nm"
"""
ax.annotate(r'$y={y:d}$ nm'.format(y=y), xy=(1.00, 0.5), xytext=(15, 0),
ha='left', va='center', rotation=90,
xycoords='axes fraction', textcoords='offset points', fontsize=18)
In [6]:
def adjust_subplot_appearance(ax):
"""
Set correct axis limits and ticks positions for subplot.
"""
ax.set_xticks([-60, 0, 60])
ax.set_yticks([-300, 0, 300, 600])
ax.set_ylim((-75, 625))
ax.xaxis.set_ticks_position('bottom' if i == 1 else 'none')
ax.yaxis.set_ticks_position('left' if j == 0 else 'none')
In [7]:
def get_data_values_for_subplot(df, y, d, N):
"""
Filter the data frame `df` to obtain the values of `x` and `delta_f`
for the subplot corresponding to the given values of `y`, `d`, `N`.
"""
query_string = '(y == {y}) and (d == {d}) and (N == {N})'.format(y=y, d=d, N=N)
df_subplot = df.query(query_string)
xvals = df_subplot['x']
fvals = df_subplot['freq_diff'] * 1e3 # in MHz, not GHz
return xvals, fvals
In [8]:
def draw_subplot(df, axes, i, j, y, N):
"""
Draw the three curves (for d = 5 nm, 20 nm, 50 nm) into each subplot.
"""
ax = axes[i, j]
draw_zero_line(ax)
adjust_subplot_appearance(ax)
for d, style in zip(reversed(dvals), style_cycle_fig7):
xvals, fvals = get_data_values_for_subplot(df, y, d, N)
line, = ax.plot(xvals, fvals, label='d={d} nm'.format(d=d), marker=' ', **style)
if style['linestyle'] == 'dashed':
line.set_dashes([5, 4]) # 5 points on, 4 off
In [9]:
def add_column_titles(axes):
"""
Add titles "N=1", "N=2", etc. to the columns.
"""
for N in Nvals:
ax = axes[0, N-1]
ax.set_title(r'N$={N}$'.format(N=N), y=1.15)
In [10]:
def add_axis_labels(axes):
"""
Set overall axis labels.
Horizontal axis: "x (nm)"
Vertical axis: "\Delta f (MHz)"
"""
axes[1, 2].set_xlabel('x (nm)')
axes[0, 0].annotate(r'$\Delta f$ (MHz)',
xy=(-0.5, 0.4), xytext=(0, 0), ha='right', va='top', rotation=90,
xycoords='axes fraction', textcoords='offset points', fontsize=20)
In [11]:
def add_legend(axes):
"""
Add legend in top right corner of the grid.
"""
# We reverse the labels so that they appear in the natural order
# with "d = 5 nm" at the top and "d = 20 nm" at the bottom.
handles, labels = axes[0, 4].get_legend_handles_labels()
axes[0, 4].legend(handles[::-1], labels[::-1], loc='upper right', bbox_to_anchor=(1.0, 1.18), handlelength=2)
Finally we can produce the plot for Fig. 7.
In [12]:
fig, axes = plt.subplots(nrows=2, ncols=5, sharex=True, sharey=True, figsize=(10, 4.5))
for i, y in enumerate(yvals):
for j, N in enumerate(Nvals):
draw_subplot(df, axes, i, j, y, N)
add_y_value_annotation(axes[0, 4], y=0)
add_y_value_annotation(axes[1, 4], y=20)
add_column_titles(axes)
add_axis_labels(axes)
add_legend(axes)