从粒度分布曲线获取指定Y值对应X轴值,np.interp函数失效求助
解决粒度分布曲线插值及水平线绘制问题
问题原因
np.interp() 要求用于插值的x参数必须是单调递增序列,但你的df2.p_finer是从100递减到0的单调序列,这导致插值函数无法正常工作。
修正后的完整代码
from pandas import DataFrame import numpy as np import pandas as pd import matplotlib.pyplot as plt data = {'opening': [4.75, 2, 0.850, 0.425, 0.250, 0.150, 0.075], 'mass_retained': [0, 10.7, 14.3, 20.8, 23.8, 15.7, 9.2]} df = DataFrame(data) def calculate_percent_finer(df): total_mass = df.mass_retained.sum() arr = [] for count, sieve in enumerate(df.opening.values): cumulative_mass = sum(df.mass_retained.values[:count+1]) percent_finer = ((total_mass - cumulative_mass) / total_mass) * 100 arr.append(percent_finer) return df.assign(p_finer=arr) df2 = calculate_percent_finer(df) # 按p_finer升序排序,得到单调递增序列,满足np.interp要求 df_sorted = df2.sort_values(by='p_finer').reset_index(drop=True) # 计算D10、D50、D90(对应Y=10、50、90的粒度值) target_percents = [10, 50, 90] grain_sizes = np.interp(target_percents, df_sorted.p_finer, df_sorted.opening) D10, D50, D90 = grain_sizes print(f"D10: {D10:.3f} mm, D50: {D50:.3f} mm, D90: {D90:.3f} mm") # 绘制粒度分布曲线 plt.style.use('bmh') plt.plot(df2.opening, df2.p_finer, '-gD', label='Grain Size Distribution') plt.gca().invert_xaxis() # 绘制Y=10、50、90的水平线及对应粒度垂直线 colors = ['r', 'b', 'orange'] for p, gs, c in zip(target_percents, grain_sizes, colors): plt.axhline(y=p, color=c, linestyle='--', alpha=0.7, label=f'{p}% Passing') plt.axvline(x=gs, color=c, linestyle=':', alpha=0.7) # 标记交点 plt.scatter(gs, p, color=c, s=50, zorder=5) # 添加数值标签 plt.text(gs*1.1, p+2, f'{gs:.3f} mm', color=c) plt.xlabel('Grain Size (mm)') plt.ylabel('Percent Passing') plt.legend() plt.tight_layout() plt.show()
关键说明
- 对
df2按p_finer升序排序,确保np.interp()的x参数为单调递增序列,保证插值结果准确。 - 使用
axhline()绘制水平参考线,axvline()绘制对应粒度的垂直参考线,配合散点和文本标签直观展示对应关系。 - 输出的D10、D50、D90值是插值得到的精确粒度,符合土工试验中粒度特征值的计算逻辑。
内容的提问来源于stack exchange,提问作者Irfan Ahmad
相关产品推荐
相关产品推荐

