import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch, Circle, Rectangle
import matplotlib.patches as patches
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
# 设置中文字体(如果需要显示中文)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# 创建图形和子图布局
fig = plt.figure(figsize=(16, 8))
gs = fig.add_gridspec(2, 2, width_ratios=[1, 1], height_ratios=[3, 1])
# 左上方主图:愈合动力学曲线
ax_main = fig.add_subplot(gs[0, 0])
# 左下方:k值柱状图
ax_inset = fig.add_subplot(gs[1, 0])
# 右侧机理图
ax_mech = fig.add_subplot(gs[:, 1])
# 设置整体背景色
fig.patch.set_facecolor('#f8f9fa')
# ==================== 左上方主图:愈合动力学曲线 ====================
# 模拟数据点
time_80 = np.array([0, 5, 10, 15, 20, 25, 30]) # 分钟
wca_80 = np.array([20, 80, 120, 140, 147, 150, 152])
time_120 = np.array([0, 4, 8, 12, 16, 20, 24, 30])
wca_120 = np.array([20, 85, 125, 142, 149, 151, 152, 152])
time_60 = np.array([0, 10, 20, 30, 40, 50, 60])
wca_60 = np.array([20, 45, 75, 105, 125, 140, 148])
# 25°C数据(时间转换为分钟)
time_25 = np.array([0, 360, 720, 1080, 1440]) # 分钟 (0, 6, 12, 18, 24小时)
wca_25 = np.array([20, 90, 125, 142, 150])
# 绘制曲线
ax_main.plot(time_80, wca_80, 'r-', linewidth=3, label='80°C', marker='o', markersize=6)
ax_main.plot(time_120, wca_120, 'm--', linewidth=2, label='120°C', marker='s', markersize=5)
ax_main.plot(time_60, wca_60, 'b-', linewidth=2, label='60°C', marker='^', markersize=5)
ax_main.plot(time_25, wca_25, 'g-', linewidth=2, label='25°C', marker='d', markersize=5)
# 设置坐标轴
ax_main.set_xlabel('时间 (分钟)', fontsize=12)
ax_main.set_ylabel('水接触角 (WCA, °)', fontsize=12)
ax_main.set_ylim(0, 160)
ax_main.set_xlim(0, 1500) # 扩展到24小时(1440分钟)
ax_main.grid(True, alpha=0.3)
# 添加第二个x轴(小时单位)
ax2 = ax_main.twiny()
ax2.set_xlim(0, 25) # 0-25小时
ax2.set_xlabel('时间 (小时)', fontsize=12)
ax2.spines['top'].set_position(('outward', 40))
# 标注阶段
ax_main.axvline(x=15, color='gray', linestyle=':', alpha=0.7)
ax_main.axvline(x=360, color='gray', linestyle=':', alpha=0.7) # 6小时
ax_main.text(7, 40, '快速恢复阶段\n(0-15min @80-120°C\n0-6h @25°C)',
fontsize=9, bbox=dict(boxstyle="round,pad=0.3", fc="lightblue", alpha=0.7))
ax_main.text(200, 140, '缓慢稳定阶段\n(15-30min @80-120°C\n6-24h @25°C)',
fontsize=9, bbox=dict(boxstyle="round,pad=0.3", fc="lightgreen", alpha=0.7))
ax_main.legend(loc='lower right', fontsize=10)
# ==================== 左下方:k值柱状图 ====================
temperatures = ['25°C', '60°C', '80°C', '120°C']
k_values = [0.004, 0.048, 0.12, 0.13]
colors = ['green', 'blue', 'red', 'magenta']
bars = ax_inset.bar(temperatures, k_values, color=colors, alpha=0.7)
ax_inset.set_ylabel('愈合速率常数 k (min⁻¹)', fontsize=10)
ax_inset.set_ylim(0, 0.14)
# 在柱子上添加数值和倍数关系
for i, (bar, k) in enumerate(zip(bars, k_values)):
height = bar.get_height()
ax_inset.text(bar.get_x() + bar.get_width()/2., height + 0.005,
f'{k:.3f}', ha='center', va='bottom', fontsize=9)
if i == 2: # 80°C柱子
ax_inset.text(bar.get_x() + bar.get_width()/2., height/2,
'最大值', ha='center', va='center', fontsize=9,
bbox=dict(boxstyle="round,pad=0.2", fc="yellow", alpha=0.7))
# 添加倍数关系标注
ax_inset.annotate('', xy=(1, 0.12), xytext=(1, 0.048),
arrowprops=dict(arrowstyle='<->', color='black', lw=1.5))
ax_inset.text(1.2, 0.08, '2.5×', fontsize=10, fontweight='bold')
ax_inset.annotate('', xy=(0, 0.12), xytext=(0, 0.004),
arrowprops=dict(arrowstyle='<->', color='black', lw=1.5))
ax_inset.text(0.2, 0.06, '30×', fontsize=10, fontweight='bold')
# ==================== 右侧:愈合机理示意图 ====================
# 设置右侧子图范围
ax_mech.set_xlim(0, 10)
ax_mech.set_ylim(0, 8)
ax_mech.axis('off') # 不显示坐标轴
# 绘制三个状态
states = [
{"x": 1, "title": "状态 I: 初始损伤", "wca": "WCA ≈ 20°", "desc": "表面被划伤,亲水颗粒暴露"},
{"x": 4, "title": "阶段 1: 快速恢复", "wca": "WCA = 130°-140°", "desc": "PDMS链快速迁移\n恢复低表面能层"},
{"x": 7, "title": "阶段 2: 缓慢稳定", "wca": "WCA = 150°-153°", "desc": "颗粒重排形成\n微纳分级粗糙结构"}
]
# 绘制表面和颗粒
for i, state in enumerate(states):
x = state["x"]
# 表面基线
ax_mech.plot([x-0.8, x+0.8], [2, 2], 'k-', linewidth=2)
# 划痕(只在状态I显示)
if i == 0:
ax_mech.plot([x-0.2, x+0.2], [2.1, 1.9], 'r-', linewidth=3)
# 颗粒(用圆圈表示)
n_particles = 15
for j in range(n_particles):
px = x - 0.7 + (j % 5) * 0.35
py = 2.2 + (j // 5) * 0.3
# 状态I:亲水颗粒(空心)
if i == 0:
circle = plt.Circle((px, py), 0.08, fill=False, edgecolor='blue', linewidth=1.5)
# 状态2和3:PDMS覆盖的颗粒(实心)
else:
circle = plt.Circle((px, py), 0.08, facecolor='orange', alpha=0.7)
ax_mech.add_patch(circle)
# PDMS链(状态2和3)
if i > 0:
for j in range(8):
px = x - 0.6 + j * 0.2
# 绘制弯曲的PDMS链
t = np.linspace(0, 3, 50)
y_curve = 1.5 + 0.3 * np.sin(t + j * 0.5)
x_curve = px + 0.01 * t
ax_mech.plot(x_curve, y_curve, 'orange', linewidth=1.5, alpha=0.8)
# 状态3:更粗糙的结构(用更大的起伏表示)
if i == 2:
roughness_x = np.linspace(x-0.8, x+0.8, 20)
roughness_y = 2 + 0.15 * np.sin(8 * roughness_x)
ax_mech.plot(roughness_x, roughness_y, 'b-', linewidth=1, alpha=0.6)
# 添加状态标题和说明
ax_mech.text(x, 6.5, state["title"], ha='center', fontsize=12, fontweight='bold')
ax_mech.text(x, 6, state["wca"], ha='center', fontsize=11,
bbox=dict(boxstyle="round,pad=0.3", fc="lightyellow", alpha=0.8))
ax_mech.text(x, 5.5, state["desc"], ha='center', fontsize=10,
bbox=dict(boxstyle="round,pad=0.3", fc="lightgray", alpha=0.7))
# 添加箭头表示过程
ax_mech.annotate('', xy=(3.2, 4), xytext=(1.8, 4),
arrowprops=dict(arrowstyle='->', lw=2, color='red'))
ax_mech.annotate('', xy=(6.2, 4), xytext=(4.8, 4),
arrowprops=dict(arrowstyle='->', lw=2, color='red'))
# 添加水滴示意图
for i, y in enumerate([3.5, 4, 4.5]):
# 绘制水滴形状
theta = np.linspace(0, 2*np.pi, 100)
r = 0.15
drop_x = 8.5 + r * np.cos(theta)
drop_y = y + r * 2 * np.sin(theta) # 椭圆形状更像水滴
ax_mech.fill(drop_x, drop_y, 'lightblue', alpha=0.6)
# 添加接触角标注
if i == 0:
ax_mech.text(9, y, '亲水', fontsize=9)
elif i == 2:
ax_mech.text(9, y, '超疏水', fontsize=9)
# ==================== 添加整体标题和说明文本框 ====================
plt.suptitle('自愈合超疏水涂层愈合过程与动力学示意图', fontsize=16, fontweight='bold')
# 添加说明文本框
text_box = """
温度选择权衡:
• 80°C: 最佳平衡点 - 高愈合效率(k=0.12 min⁻¹)且保持纤维完整性
• 120°C: 速率增益有限(k=0.13 min⁻¹)但可能导致纤维收缩
• 25°C: 无需外部加热,适合现场修复(24h内WCA恢复至150°)
"""
ax_main.text(0.02, 0.02, text_box, transform=ax_main.transAxes, fontsize=10,
bbox=dict(boxstyle="round,pad=0.5", fc="white", alpha=0.8),
verticalalignment='bottom')
# 调整布局
plt.tight_layout()
plt.subplots_adjust(top=0.92, bottom=0.08, left=0.05, right=0.95, hspace=0.3, wspace=0.2)
# 保存图片
plt.savefig('self_healing_superhydrophobic_coating.png', dpi=300, bbox_inches='tight')
plt.savefig('self_healing_superhydrophobic_coating.pdf', bbox_inches='tight')
# 显示图片
plt.show()