2. Interactive content in MarkDown#
2.1. Plots#
In a printed book, graphs can be included as figures. We can do the same in an online book, but we can also do much more. The simplest extension is to not create a figure file, which we then include, but to create the figure from code. The upshot of this approach is that students can see how the figure is made. For example, Fig. 2.1 below shows the van der Waals free energy density,
(2.1)#\[
f_\mathrm{VdW}(\rho) = k_\mathrm{B} T \rho \left[\ln\left(\frac{\rho}{1-b \rho}\right) - 1\right] - a \rho^2,
\]
combined with the common tangent construction to obtain the densities of coexisting phases.
Show code cell source
%config InlineBackend.figure_formats = ['svg']
import numpy as np
import matplotlib.pyplot as plt
from myst_nb import glue
from scipy.optimize import fsolve
# Global parameters
kbt = 1 # --> all energy (f, a, ...) in units of k_B T
linear_coefficient = 2.5 # add a term linear in rho to f_vdw for a nicer plot
# this linear term has no impact on the conditions for phase coexistence
# Colors
grey = '#eeeeee' # light grey fill
line = '#e96868' # red line
nucleatn_color = '#6a8ba4' # dark blue for nucleation&growth
spinodal_color = '#BBDEF0' # light blue for spinodal decomposition
def f_vdw(rho, a, b):
"""
Calculates the free energy density for a Van der Waals fluid.
"""
return kbt*rho*(np.log(rho/(1-b*rho)) - 1) - a*rho**2 + linear_coefficient*kbt*rho
def f_vdw_prime(rho, a, b):
"""
Calculates the derivative w.r.t. the density rho of the free energy
density of a VdW fluid.
"""
return kbt*np.log(rho/(1-b*rho)) + kbt*b*rho/(1-b*rho) - 2*a*rho + linear_coefficient*kbt
def conditions_for_coexistence(x, a, b):
"""
Function that should be zero when phases coexist. A vector with
one element mu1 - mu2, and one element p1 - p2.
"""
rho1 = x[0]
rho2 = x[1]
mu1 = f_vdw_prime(rho1, a, b)
mu2 = f_vdw_prime(rho2, a, b)
f1 = f_vdw(rho1, a, b)
f2 = f_vdw(rho2, a, b)
mu_deficit = mu1 - mu2
p_deficit = rho1*mu1 - f1 - rho2*mu2 + f2
return [mu_deficit, p_deficit]
def f_mix(rho_av, a, b):
"""
Free energy density for a mixture of gas (density rho1) and liquid (density
rho2). The gas and liquid densities (rho1 and rho2) are found numerically.
"""
rhosol = fsolve(conditions_for_coexistence, x0=[0.05, 0.7], args=(a,b))
rho1 = rhosol[0]
rho2 = rhosol[1]
return f_vdw(rho1, a, b) + (f_vdw(rho2, a, b) - f_vdw(rho1, a, b))/(rho2-rho1) * (rho_av - rho1)
## Prepare all the graphs that are to be plotted
# Define the range of densities to plot
rho = np.linspace(0.001, 0.95, 1000)
# Set the parameters a and b
a = 4
b = 1
# Find the densities at which the gas and liquid phases coexist by solving
# numerically. If you use different a and b you might need to change the
# guesses, x0.
rhosol = fsolve(conditions_for_coexistence, x0=[0.05, 0.8], args=(a,b))
## Make the plot
fig, ax = plt.subplots(figsize=(6,4))
# Put axes on the zeros
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
# Remove label at 0.0
ax.set_xticks([0.2, 0.4, 0.6, 0.8])
# Plot the graphs
ax.plot(rho, f_vdw(rho, a, b), color=line)
ax.plot(rho, f_mix(rho, a, b), 'k')
# Create markers rho1 and rho2
rho1_marker_y = np.linspace(0, f_vdw(rhosol[0], a, b), 10)
rho1_marker_x = np.ones(rho1_marker_y.shape)*rhosol[0]
ax.plot(rho1_marker_x, rho1_marker_y, 'k--')
rho2_marker_y = np.linspace(0, f_vdw(rhosol[1], a, b), 10)
rho2_marker_x = np.ones(rho2_marker_y.shape)*rhosol[1]
ax.plot(rho2_marker_x, rho2_marker_y, 'k--')
ax.text(rhosol[0], 0.01, r'$\rho_1$')
ax.text(rhosol[1], 0.01, r'$\rho_2$')
# Labels
ax.set_xlabel(r'density $\rho$'), ax.set_ylabel(r'free energy density $f$')
# Limits
ax.set_xlim([0, rho[-1]])
ax.set_ylim([-0.4, 0.05])
# Save graph to load in figure later (special Jupyter Book feature)
glue("free_energy_density", fig, display=False)
2.2. Interactive plots#
We can make the plot in Fig. 2.1 even more useful by making it interactive, letting students see how the plot changes if we change a parameter, without having access in the code. The interactive version is shown in the figure below.