基于摩尔浓度的 NaOH 溶液 pH 值

在处理化学浓度时,pH 标度的对数特性常常使数据可视化变得棘手。如果在标准线性标度上绘制 pH 值与摩尔浓度的关系,会得到一条"曲棍球棒"形状的曲线,掩盖了离子间的比例关系。

在本文中,我们将使用 Python 和 matplotlib 可视化氢氧化钠(NaOH)从 0 到高浓度 3 摩尔的 pH 值,对比线性对数标度,看看哪种方式能提供更好的洞察。

NaOH 摩尔浓度的 pH 值

化学逻辑

由于 NaOH 是强碱,会完全解离。为了在较宽范围内准确计算 pH 值——尤其是超过 1.0M 时——我们先计算 pOH:

$$pOH = -\log_{10}[OH^-]$$

$$pH = 14 - pOH$$

有趣的是,在 3M NaOH 时,pOH 为负值($\approx -0.48$),这意味着pH 值实际上升至 14.48,打破了教科书中"0 到 14"的常规。

Python 实现

我们使用 numpy 生成浓度范围,并使用 matplotlib.pyplot 配合 ggplot 样式获得简洁专业的外观。注意,我们生成两个独立的图表以突出不同的视角。

ph_naoh_molarity.py
#!/usr/bin/env python3
# SPDX-License-Identifier: CC0-1.0
import numpy as np
import matplotlib.pyplot as plt

# 设置样式为 ggplot
plt.style.use('ggplot')

def calculate_ph(molarity):
    """计算给定 NaOH 摩尔浓度的 pH 值,包含水的自电离。"""
    kw = 1e-14
    # 求解 [OH-] 的二次方程,以准确处理低浓度情况
    oh_conc = (molarity + np.sqrt(molarity**2 + 4 * kw)) / 2
    poh = -np.log10(oh_conc)
    return 14 - poh

# 线性图的数据(0 到 3M)
x_linear = np.linspace(0, 3, 1000)
y_linear = calculate_ph(x_linear)

# 对数图的数据(0.01 到 3M)
# 使用 logspace 确保在对数标度上平滑绘图
x_log = np.logspace(np.log10(0.01), np.log10(3), 1000)
y_log = calculate_ph(x_log)

# 创建线性标度图
plt.figure(figsize=(10, 6))
plt.plot(x_linear, y_linear, color='#E24A33', linewidth=2.5, label='pH Value')
plt.title('pH of NaOH Solution (Linear Scale: 0M to 3M)', fontsize=14, fontweight='bold')
plt.xlabel('Molarity of NaOH (mol/L)', fontsize=12)
plt.ylabel('pH', fontsize=12)
plt.ylim(7, 15)
plt.grid(True, linestyle='--', alpha=0.7)
plt.legend()
plt.tight_layout()
plt.savefig('ph_linear_scale.png', dpi=300)
plt.close()

# 创建对数标度图
plt.figure(figsize=(10, 6))
plt.plot(x_log, y_log, color='#348ABD', linewidth=2.5, label='pH Value')
plt.xscale('log')
plt.title('pH of NaOH Solution (Log Scale: 0.01M to 3M)', fontsize=14, fontweight='bold')
plt.xlabel('Molarity of NaOH (Logarithmic Scale mol/L)', fontsize=12)
plt.ylabel('pH', fontsize=12)
plt.ylim(11.5, 15) # 聚焦于 0.01M-3M 窗口的范围
plt.grid(True, which="both", linestyle='--', alpha=0.7)
plt.legend()
plt.tight_layout()
plt.savefig('ph_log_scale.png', dpi=300)
plt.close()

# 为了满足系统在标签中提供单一"主"文件名的要求,
# 我也会保存一个合并版本。
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 12))

# 线性图
ax1.plot(x_linear, y_linear, color='#E24A33', linewidth=2.5)
ax1.set_title('Linear Scale (0M to 3M)', fontsize=14, fontweight='bold')
ax1.set_ylabel('pH')
ax1.set_ylim(7, 15)

# 对数图
ax2.plot(x_log, y_log, color='#348ABD', linewidth=2.5)
ax2.set_xscale('log')
ax2.set_title('Logarithmic Scale (0.01M to 3M)', fontsize=14, fontweight='bold')
ax2.set_xlabel('Molarity of NaOH (mol/L)')
ax2.set_ylabel('pH')
ax2.set_ylim(11.5, 15)

plt.tight_layout()
plt.savefig('pH NaOH molarity.svg', dpi=300)

Check out similar posts by category: Chemistry