clidx commited on
Commit
a083866
·
verified ·
1 Parent(s): 8272240

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +600 -267
src/streamlit_app.py CHANGED
@@ -1,378 +1,711 @@
1
  import streamlit as st
2
  import pandas as pd
3
  import math
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  # 语言配置
6
  LANGUAGES = {
7
  "中文": {
8
  "page_title": "溶剂分数转换器",
9
- "main_title": "🧪 溶剂摩尔分数与体积分数转换器",
10
- "conversion_mode": "转换模式",
11
  "mode_mole_to_vol": "摩尔分数 → 体积分数",
12
  "mode_vol_to_mole": "体积分数 → 摩尔分数",
 
 
 
 
13
  "select_conversion": "选择转换方向:",
14
- "solvent_selection": "溶剂选择",
15
  "select_solvents": "选择两种溶剂或自定义参数:",
16
  "solvent_a": "溶剂A:",
17
  "solvent_b": "溶剂B:",
18
- "custom": "自定义",
19
  "molar_mass": "摩尔质量",
20
  "density": "密度",
21
- "input_mole_fraction": "输入摩尔分数",
22
- "input_volume_fraction": "输入体积分数",
 
23
  "mole_fraction_of": "摩尔分数",
24
  "volume_fraction_of": "体积分数",
25
- "result_volume_fraction": "计算结果 - 体积分数",
26
- "result_mole_fraction": "计算结果 - 摩尔分数",
27
- "verification": "验证",
28
- "detailed_info": "详细信息",
29
- "solvent_params": "溶剂参数",
 
 
30
  "solvent": "溶剂",
31
  "mole_fraction": "摩尔分数",
32
  "volume_fraction": "体积分数",
33
- "calculation_formula": "计算公式",
 
34
  "formula_mole_to_vol_title": "**摩尔分数转换为体积分数:**",
35
  "formula_vol_to_mole_title": "**体积分数转换为摩尔分数:**",
 
 
 
 
36
  "formula_where": "其中:",
37
- "usage_instructions": "使用说明",
38
  "instruction_1": "1. **选择转换模式**: 在侧边栏选择转换方向",
39
  "instruction_2": "2. **选择溶剂**: 从预设的常见溶剂中选择,或选择\"自定义\"输入参数",
40
- "instruction_3": "3. **输入数值**: 使用滑块调整摩尔分数或体积分数",
41
  "instruction_4": "4. **查看结果**: 右侧显示转换结果和详细信息",
42
- "note": "**注意**: 本计算假设理想混合,实际情况可能存在偏差。",
43
- "language": "语言"
 
44
  },
45
  "English": {
46
  "page_title": "Solvent Fraction Converter",
47
- "main_title": "🧪 Solvent Mole Fraction & Volume Fraction Converter",
48
- "conversion_mode": "Conversion Mode",
49
  "mode_mole_to_vol": "Mole Fraction → Volume Fraction",
50
  "mode_vol_to_mole": "Volume Fraction → Mole Fraction",
 
 
 
 
51
  "select_conversion": "Select conversion direction:",
52
- "solvent_selection": "Solvent Selection",
53
  "select_solvents": "Select two solvents or customize parameters:",
54
  "solvent_a": "Solvent A:",
55
  "solvent_b": "Solvent B:",
56
- "custom": "Custom",
57
  "molar_mass": "Molar Mass",
58
  "density": "Density",
59
- "input_mole_fraction": "Input Mole Fraction",
60
- "input_volume_fraction": "Input Volume Fraction",
 
61
  "mole_fraction_of": "Mole fraction of",
62
  "volume_fraction_of": "Volume fraction of",
63
- "result_volume_fraction": "Results - Volume Fraction",
64
- "result_mole_fraction": "Results - Mole Fraction",
65
- "verification": "Verification",
66
- "detailed_info": "Detailed Information",
67
- "solvent_params": "Solvent Parameters",
 
 
68
  "solvent": "Solvent",
69
  "mole_fraction": "Mole Fraction",
70
  "volume_fraction": "Volume Fraction",
71
- "calculation_formula": "Calculation Formula",
 
72
  "formula_mole_to_vol_title": "**Mole Fraction to Volume Fraction:**",
73
  "formula_vol_to_mole_title": "**Volume Fraction to Mole Fraction:**",
 
 
 
 
74
  "formula_where": "Where:",
75
- "usage_instructions": "Usage Instructions",
76
  "instruction_1": "1. **Select Conversion Mode**: Choose conversion direction in sidebar",
77
  "instruction_2": "2. **Select Solvents**: Choose from preset common solvents or select 'Custom' to input parameters",
78
- "instruction_3": "3. **Input Values**: Use sliders to adjust mole fraction or volume fraction",
79
  "instruction_4": "4. **View Results**: Results and detailed information are displayed on the right",
80
- "note": "**Note**: This calculation assumes ideal mixing; actual situations may deviate.",
81
- "language": "Language"
 
82
  }
83
  }
84
 
85
- # 常见溶剂的摩尔质量和密度数据库(中英文对照)
86
  SOLVENTS_DB = {
87
  "中文": {
88
- "水": {"M": 18.02, "density": 1.000, "en": "Water"},
89
- "乙醇": {"M": 46.07, "density": 0.789, "en": "Ethanol"},
90
- "甲醇": {"M": 32.04, "density": 0.792, "en": "Methanol"},
91
- "异丙醇": {"M": 60.10, "density": 0.786, "en": "Isopropanol"},
92
- "丙酮": {"M": 58.08, "density": 0.784, "en": "Acetone"},
93
- "乙酸乙酯": {"M": 88.11, "density": 0.902, "en": "Ethyl Acetate"},
94
- "甲苯": {"M": 92.14, "density": 0.867, "en": "Toluene"},
95
- "二氯甲烷": {"M": 84.93, "density": 1.326, "en": "Dichloromethane"},
96
- "氯仿": {"M": 119.38, "density": 1.489, "en": "Chloroform"},
97
- "四氢呋喃": {"M": 72.11, "density": 0.889, "en": "Tetrahydrofuran"},
98
- "二甲基亚砜": {"M": 78.13, "density": 1.100, "en": "Dimethyl Sulfoxide"},
99
- "N,N-二甲基甲酰胺": {"M": 73.09, "density": 0.944, "en": "N,N-Dimethylformamide"},
100
- "乙腈": {"M": 41.05, "density": 0.786, "en": "Acetonitrile"},
101
- "正己烷": {"M": 86.18, "density": 0.659, "en": "n-Hexane"},
102
- "环己烷": {"M": 84.16, "density": 0.779, "en": "Cyclohexane"},
103
- "苯": {"M": 78.11, "density": 0.876, "en": "Benzene"},
104
- "乙二醇": {"M": 62.07, "density": 1.113, "en": "Ethylene Glycol"},
105
- "甘油": {"M": 92.09, "density": 1.261, "en": "Glycerol"}
106
  },
107
  "English": {
108
- "Water": {"M": 18.02, "density": 1.000, "cn": "水"},
109
- "Ethanol": {"M": 46.07, "density": 0.789, "cn": "乙醇"},
110
- "Methanol": {"M": 32.04, "density": 0.792, "cn": "甲醇"},
111
- "Isopropanol": {"M": 60.10, "density": 0.786, "cn": "异丙醇"},
112
- "Acetone": {"M": 58.08, "density": 0.784, "cn": "丙酮"},
113
- "Ethyl Acetate": {"M": 88.11, "density": 0.902, "cn": "乙酸乙酯"},
114
- "Toluene": {"M": 92.14, "density": 0.867, "cn": "甲苯"},
115
- "Dichloromethane": {"M": 84.93, "density": 1.326, "cn": "二氯甲烷"},
116
- "Chloroform": {"M": 119.38, "density": 1.489, "cn": "氯仿"},
117
- "Tetrahydrofuran": {"M": 72.11, "density": 0.889, "cn": "四氢呋喃"},
118
- "Dimethyl Sulfoxide": {"M": 78.13, "density": 1.100, "cn": "二甲基亚砜"},
119
- "N,N-Dimethylformamide": {"M": 73.09, "density": 0.944, "cn": "N,N-二甲基甲酰胺"},
120
- "Acetonitrile": {"M": 41.05, "density": 0.786, "cn": "乙腈"},
121
- "n-Hexane": {"M": 86.18, "density": 0.659, "cn": "正己烷"},
122
- "Cyclohexane": {"M": 84.16, "density": 0.779, "cn": "环己烷"},
123
- "Benzene": {"M": 78.11, "density": 0.876, "cn": "苯"},
124
- "Ethylene Glycol": {"M": 62.07, "density": 1.113, "cn": "乙二醇"},
125
- "Glycerol": {"M": 92.09, "density": 1.261, "cn": "甘油"}
126
  }
127
  }
128
 
129
  # 语言选择
130
- language = st.sidebar.selectbox("Language/语言:", ["中文", "English"])
131
- lang = LANGUAGES[language]
132
-
133
- # 配置页面
134
- st.set_page_config(
135
- page_title=lang["page_title"],
136
- page_icon="🧪",
137
- layout="wide"
138
- )
139
-
140
- # 页面标题
141
- st.title(lang["main_title"])
142
- st.markdown("---")
143
-
144
- # 侧边栏 - 转换模式选择
145
- st.sidebar.header(lang["conversion_mode"])
146
- conversion_mode = st.sidebar.radio(
147
- lang["select_conversion"],
148
- [lang["mode_mole_to_vol"], lang["mode_vol_to_mole"]]
149
  )
 
150
 
151
- # 溶剂选择
152
- st.sidebar.header(lang["solvent_selection"])
153
- st.sidebar.write(lang["select_solvents"])
154
-
155
- # 获取当前语言的溶剂列表
156
- current_solvents = SOLVENTS_DB[language]
157
- solvent_names = list(current_solvents.keys()) + [lang["custom"]]
158
-
159
- # 溶剂A选择
160
- solvent_a_name = st.sidebar.selectbox(lang["solvent_a"], solvent_names)
161
-
162
- if solvent_a_name == lang["custom"]:
163
- col1, col2 = st.sidebar.columns(2)
164
- with col1:
165
- M_a = st.number_input(f"{lang['molar_mass']} A (g/mol):", value=18.02, min_value=0.1, step=0.01)
166
- with col2:
167
- rho_a = st.number_input(f"{lang['density']} A (g/cm³):", value=1.000, min_value=0.1, step=0.001)
168
- else:
169
- M_a = current_solvents[solvent_a_name]["M"]
170
- rho_a = current_solvents[solvent_a_name]["density"]
171
- st.sidebar.write(f"{lang['molar_mass']}: {M_a} g/mol")
172
- st.sidebar.write(f"{lang['density']}: {rho_a} g/cm³")
173
 
174
- # 溶剂B选择
175
- solvent_b_name = st.sidebar.selectbox(lang["solvent_b"], solvent_names)
 
 
176
 
177
- if solvent_b_name == lang["custom"]:
178
- col1, col2 = st.sidebar.columns(2)
179
- with col1:
180
- M_b = st.number_input(f"{lang['molar_mass']} B (g/mol):", value=46.07, min_value=0.1, step=0.01)
181
- with col2:
182
- rho_b = st.number_input(f"{lang['density']} B (g/cm³):", value=0.789, min_value=0.1, step=0.001)
183
- else:
184
- M_b = current_solvents[solvent_b_name]["M"]
185
- rho_b = current_solvents[solvent_b_name]["density"]
186
- st.sidebar.write(f"{lang['molar_mass']}: {M_b} g/mol")
187
- st.sidebar.write(f"{lang['density']}: {rho_b} g/cm³")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
 
189
  # 主界面内容
190
- col1, col2 = st.columns(2)
191
 
192
- if conversion_mode == lang["mode_mole_to_vol"]:
193
- with col1:
194
- st.header(lang["input_mole_fraction"])
195
- x_a = st.number_input(
196
- f"{lang['mole_fraction_of']} {solvent_a_name} (x_A):",
197
- min_value=0.0,
198
- max_value=1.0,
199
- value=0.5,
200
- step=0.001,
201
- format="%.4f"
202
- )
203
- x_b = 1.0 - x_a
204
- st.write(f"{lang['mole_fraction_of']} {solvent_b_name} (x_B): {x_b:.4f}")
205
-
206
- # 计算体积分数
207
  V_ratio_a = x_a * M_a / rho_a
208
  V_ratio_b = x_b * M_b / rho_b
209
  V_total = V_ratio_a + V_ratio_b
210
-
211
  if V_total > 0:
212
  phi_a = V_ratio_a / V_total
213
  phi_b = V_ratio_b / V_total
214
  else:
215
  phi_a = phi_b = 0
216
-
217
- with col2:
218
- st.header(lang["result_volume_fraction"])
219
- st.metric(f"{lang['volume_fraction_of']} {solvent_a_name} (φ_A)", f"{phi_a:.4f}")
220
- st.metric(f"{lang['volume_fraction_of']} {solvent_b_name} (φ_B)", f"{phi_b:.4f}")
221
-
222
- # 验证
223
- st.write(f"{lang['verification']}: φ_A + φ_B = {phi_a + phi_b:.4f}")
224
-
225
- else: # 体积分数 → 摩尔分数
226
- with col1:
227
- st.header(lang["input_volume_fraction"])
228
- phi_a = st.number_input(
229
- f"{lang['volume_fraction_of']} {solvent_a_name} (φ_A):",
230
- min_value=0.0,
231
- max_value=1.0,
232
- value=0.5,
233
- step=0.001,
234
- format="%.4f"
235
- )
236
- phi_b = 1.0 - phi_a
237
- st.write(f"{lang['volume_fraction_of']} {solvent_b_name} (φ_B): {phi_b:.4f}")
238
-
239
- # 计算摩尔分数
240
  n_ratio_a = phi_a * rho_a / M_a
241
  n_ratio_b = phi_b * rho_b / M_b
242
  n_total = n_ratio_a + n_ratio_b
243
-
244
  if n_total > 0:
245
  x_a = n_ratio_a / n_total
246
  x_b = n_ratio_b / n_total
247
  else:
248
  x_a = x_b = 0
249
-
250
- with col2:
251
- st.header(lang["result_mole_fraction"])
252
- st.metric(f"{lang['mole_fraction_of']} {solvent_a_name} (x_A)", f"{x_a:.4f}")
253
- st.metric(f"{lang['mole_fraction_of']} {solvent_b_name} (x_B)", f"{x_b:.4f}")
254
-
255
- # 验证
256
- st.write(f"{lang['verification']}: x_A + x_B = {x_a + x_b:.4f}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
 
258
- # 详细信息展示
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  st.markdown("---")
260
- st.header(lang["detailed_info"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
 
262
  col1, col2, col3 = st.columns(3)
263
 
264
  with col1:
265
- st.subheader(lang["solvent_params"])
266
  df_params = pd.DataFrame({
267
  lang["solvent"]: [solvent_a_name, solvent_b_name],
268
  f"{lang['molar_mass']} (g/mol)": [M_a, M_b],
269
  f"{lang['density']} (g/cm³)": [rho_a, rho_b]
270
  })
271
- st.dataframe(df_params)
272
 
273
  with col2:
274
- if conversion_mode == lang["mode_mole_to_vol"]:
275
- st.subheader(lang["mole_fraction"])
276
  df_mole = pd.DataFrame({
277
  lang["solvent"]: [solvent_a_name, solvent_b_name],
278
- lang["mole_fraction"]: [x_a, x_b]
279
  })
280
- st.dataframe(df_mole)
281
- else:
282
- st.subheader(lang["volume_fraction"])
 
283
  df_vol = pd.DataFrame({
284
  lang["solvent"]: [solvent_a_name, solvent_b_name],
285
- lang["volume_fraction"]: [phi_a, phi_b]
286
  })
287
- st.dataframe(df_vol)
288
 
289
  with col3:
290
- if conversion_mode == lang["mode_mole_to_vol"]:
291
- st.subheader(lang["volume_fraction"])
292
- df_vol_result = pd.DataFrame({
293
  lang["solvent"]: [solvent_a_name, solvent_b_name],
294
- lang["volume_fraction"]: [phi_a, phi_b]
295
  })
296
- st.dataframe(df_vol_result)
297
- else:
298
- st.subheader(lang["mole_fraction"])
299
- df_mole_result = pd.DataFrame({
300
- lang["solvent"]: [solvent_a_name, solvent_b_name],
301
- lang["mole_fraction"]: [x_a, x_b]
302
- })
303
- st.dataframe(df_mole_result)
304
-
305
- # 公式说明
306
- st.markdown("---")
307
- st.header(lang["calculation_formula"])
308
 
309
- if conversion_mode == lang["mode_mole_to_vol"]:
310
- if language == "中文":
311
- st.markdown(f"""
312
- {lang["formula_mole_to_vol_title"]}
313
-
314
- $$\\phi_A = \\frac{{x_A \\cdot M_A / \\rho_A}}{{x_A \\cdot M_A / \\rho_A + x_B \\cdot M_B / \\rho_B}}$$
315
-
316
- $$\\phi_B = \\frac{{x_B \\cdot M_B / \\rho_B}}{{x_A \\cdot M_A / \\rho_A + x_B \\cdot M_B / \\rho_B}}$$
317
-
318
- {lang["formula_where"]}
319
- - $x_A, x_B$: 摩尔分数
320
- - $\\phi_A, \\phi_B$: 体积分数
321
- - $M_A, M_B$: 摩尔质量 (g/mol)
322
- - $\\rho_A, \\rho_B$: 密度 (g/cm³)
323
- """)
324
- else:
325
- st.markdown(f"""
326
- {lang["formula_mole_to_vol_title"]}
327
-
328
- $$\\phi_A = \\frac{{x_A \\cdot M_A / \\rho_A}}{{x_A \\cdot M_A / \\rho_A + x_B \\cdot M_B / \\rho_B}}$$
329
-
330
- $$\\phi_B = \\frac{{x_B \\cdot M_B / \\rho_B}}{{x_A \\cdot M_A / \\rho_A + x_B \\cdot M_B / \\rho_B}}$$
331
-
332
- {lang["formula_where"]}
333
- - $x_A, x_B$: Mole fractions
334
- - $\\phi_A, \\phi_B$: Volume fractions
335
- - $M_A, M_B$: Molar mass (g/mol)
336
- - $\\rho_A, \\rho_B$: Density (g/cm³)
337
- """)
338
- else:
339
- if language == "中文":
340
- st.markdown(f"""
341
- {lang["formula_vol_to_mole_title"]}
342
-
343
- $$x_A = \\frac{{\\phi_A \\cdot \\rho_A / M_A}}{{\\phi_A \\cdot \\rho_A / M_A + \\phi_B \\cdot \\rho_B / M_B}}$$
344
-
345
- $$x_B = \\frac{{\\phi_B \\cdot \\rho_B / M_B}}{{\\phi_A \\cdot \\rho_A / M_A + \\phi_B \\cdot \\rho_B / M_B}}$$
346
-
347
- {lang["formula_where"]}
348
- - $\\phi_A, \\phi_B$: 体积分数
349
- - $x_A, x_B$: 摩尔分数
350
- - $M_A, M_B$: 摩尔质量 (g/mol)
351
- - $\\rho_A, \\rho_B$: 密度 (g/cm³)
352
- """)
353
- else:
354
- st.markdown(f"""
355
- {lang["formula_vol_to_mole_title"]}
356
-
357
- $$x_A = \\frac{{\\phi_A \\cdot \\rho_A / M_A}}{{\\phi_A \\cdot \\rho_A / M_A + \\phi_B \\cdot \\rho_B / M_B}}$$
358
-
359
- $$x_B = \\frac{{\\phi_B \\cdot \\rho_B / M_B}}{{\\phi_A \\cdot \\rho_A / M_A + \\phi_B \\cdot \\rho_B / M_B}}$$
360
-
361
- {lang["formula_where"]}
362
- - $\\phi_A, \\phi_B$: Volume fractions
363
- - $x_A, x_B$: Mole fractions
364
- - $M_A, M_B$: Molar mass (g/mol)
365
- - $\\rho_A, \\rho_B$: Density (g/cm³)
366
- """)
367
 
368
  # 使用说明
369
- st.markdown("---")
370
- st.header(lang["usage_instructions"])
371
- st.markdown(f"""
372
- {lang["instruction_1"]}
373
- {lang["instruction_2"]}
374
- {lang["instruction_3"]}
375
- {lang["instruction_4"]}
 
 
 
376
 
 
 
 
377
  {lang["note"]}
378
- """)
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
  import pandas as pd
3
  import math
4
+ import plotly.graph_objects as go
5
+ import plotly.express as px
6
+
7
+ # 页面配置(必须在最开始)
8
+ st.set_page_config(
9
+ page_title="溶剂分数转换器",
10
+ page_icon="🧪",
11
+ layout="wide",
12
+ initial_sidebar_state="expanded"
13
+ )
14
+
15
+ # 自定义CSS样式
16
+ st.markdown("""
17
+ <style>
18
+ /* 主标题样式 */
19
+ .main-title {
20
+ font-size: 2.5rem;
21
+ font-weight: bold;
22
+ text-align: center;
23
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
24
+ -webkit-background-clip: text;
25
+ -webkit-text-fill-color: transparent;
26
+ margin-bottom: 2rem;
27
+ }
28
+
29
+ /* 卡片样式 */
30
+ .metric-card {
31
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
32
+ padding: 1rem;
33
+ border-radius: 10px;
34
+ color: white;
35
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
36
+ margin-bottom: 1rem;
37
+ }
38
+
39
+ /* 侧边栏样式 */
40
+ .sidebar .sidebar-content {
41
+ background: linear-gradient(180deg, #667eea 0%, #764ba2 100%);
42
+ }
43
+
44
+ /* 公式框样式 */
45
+ .formula-box {
46
+ background: #f8f9fa;
47
+ border: 2px solid #e9ecef;
48
+ border-radius: 10px;
49
+ padding: 1.5rem;
50
+ margin: 1rem 0;
51
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
52
+ }
53
+
54
+ /* 信息框样式 */
55
+ .info-box {
56
+ background: linear-gradient(135deg, #74b9ff 0%, #0984e3 100%);
57
+ color: white;
58
+ padding: 1rem;
59
+ border-radius: 10px;
60
+ margin: 1rem 0;
61
+ }
62
+
63
+ /* 警告框样式 */
64
+ .warning-box {
65
+ background: linear-gradient(135deg, #fd79a8 0%, #e84393 100%);
66
+ color: white;
67
+ padding: 1rem;
68
+ border-radius: 10px;
69
+ margin: 1rem 0;
70
+ }
71
+
72
+ /* 数据表格样式 */
73
+ .dataframe {
74
+ border-radius: 10px;
75
+ overflow: hidden;
76
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
77
+ }
78
+ </style>
79
+ """, unsafe_allow_html=True)
80
 
81
  # 语言配置
82
  LANGUAGES = {
83
  "中文": {
84
  "page_title": "溶剂分数转换器",
85
+ "main_title": "🧪 溶剂摩尔分数、体积分数与质量分数转换器",
86
+ "conversion_mode": "🔄 转换模式",
87
  "mode_mole_to_vol": "摩尔分数 → 体积分数",
88
  "mode_vol_to_mole": "体积分数 → 摩尔分数",
89
+ "mode_mole_to_mass": "摩尔分数 → 质量分数",
90
+ "mode_mass_to_mole": "质量分数 → 摩尔分数",
91
+ "mode_vol_to_mass": "体积分数 → 质量分数",
92
+ "mode_mass_to_vol": "质量分数 → 体积分数",
93
  "select_conversion": "选择转换方向:",
94
+ "solvent_selection": "🧫 溶剂选择",
95
  "select_solvents": "选择两种溶剂或自定义参数:",
96
  "solvent_a": "溶剂A:",
97
  "solvent_b": "溶剂B:",
98
+ "custom": "🛠️ 自定义",
99
  "molar_mass": "摩尔质量",
100
  "density": "密度",
101
+ "input_mole_fraction": "📥 输入摩尔分数",
102
+ "input_volume_fraction": "📥 输入体积分数",
103
+ "input_mass_fraction": "📥 输入质量分数",
104
  "mole_fraction_of": "摩尔分数",
105
  "volume_fraction_of": "体积分数",
106
+ "mass_fraction_of": "质量分数",
107
+ "result_volume_fraction": "📊 计算结果 - 体积分数",
108
+ "result_mole_fraction": "📊 计算结果 - 摩尔分数",
109
+ "result_mass_fraction": "📊 计算结果 - 质量分数",
110
+ "verification": "✅ 验证",
111
+ "detailed_info": "📋 详细信息",
112
+ "solvent_params": "🔬 溶剂参数",
113
  "solvent": "溶剂",
114
  "mole_fraction": "摩尔分数",
115
  "volume_fraction": "体积分数",
116
+ "mass_fraction": "质量分数",
117
+ "calculation_formula": "📐 计算公式",
118
  "formula_mole_to_vol_title": "**摩尔分数转换为体积分数:**",
119
  "formula_vol_to_mole_title": "**体积分数转换为摩尔分数:**",
120
+ "formula_mole_to_mass_title": "**摩尔分数转换为质量分数:**",
121
+ "formula_mass_to_mole_title": "**质量分数转换为摩尔分数:**",
122
+ "formula_vol_to_mass_title": "**体积分数转换为质量分数:**",
123
+ "formula_mass_to_vol_title": "**质量分数转换为体积分数:**",
124
  "formula_where": "其中:",
125
+ "usage_instructions": "📖 使用说明",
126
  "instruction_1": "1. **选择转换模式**: 在侧边栏选择转换方向",
127
  "instruction_2": "2. **选择溶剂**: 从预设的常见溶剂中选择,或选择\"自定义\"输入参数",
128
+ "instruction_3": "3. **输入数值**: 输入摩尔分数、体积分数或质量分数",
129
  "instruction_4": "4. **查看结果**: 右侧显示转换结果和详细信息",
130
+ "note": "⚠️ **注意**: 本计算假设理想混合,实际情况可能存在偏差。",
131
+ "language": "🌐 语言",
132
+ "visualization": "📈 可视化"
133
  },
134
  "English": {
135
  "page_title": "Solvent Fraction Converter",
136
+ "main_title": "🧪 Solvent Mole Fraction, Volume Fraction & Mass Fraction Converter",
137
+ "conversion_mode": "🔄 Conversion Mode",
138
  "mode_mole_to_vol": "Mole Fraction → Volume Fraction",
139
  "mode_vol_to_mole": "Volume Fraction → Mole Fraction",
140
+ "mode_mole_to_mass": "Mole Fraction → Mass Fraction",
141
+ "mode_mass_to_mole": "Mass Fraction → Mole Fraction",
142
+ "mode_vol_to_mass": "Volume Fraction → Mass Fraction",
143
+ "mode_mass_to_vol": "Mass Fraction → Volume Fraction",
144
  "select_conversion": "Select conversion direction:",
145
+ "solvent_selection": "🧫 Solvent Selection",
146
  "select_solvents": "Select two solvents or customize parameters:",
147
  "solvent_a": "Solvent A:",
148
  "solvent_b": "Solvent B:",
149
+ "custom": "🛠️ Custom",
150
  "molar_mass": "Molar Mass",
151
  "density": "Density",
152
+ "input_mole_fraction": "📥 Input Mole Fraction",
153
+ "input_volume_fraction": "📥 Input Volume Fraction",
154
+ "input_mass_fraction": "📥 Input Mass Fraction",
155
  "mole_fraction_of": "Mole fraction of",
156
  "volume_fraction_of": "Volume fraction of",
157
+ "mass_fraction_of": "Mass fraction of",
158
+ "result_volume_fraction": "📊 Results - Volume Fraction",
159
+ "result_mole_fraction": "📊 Results - Mole Fraction",
160
+ "result_mass_fraction": "📊 Results - Mass Fraction",
161
+ "verification": " Verification",
162
+ "detailed_info": "📋 Detailed Information",
163
+ "solvent_params": "🔬 Solvent Parameters",
164
  "solvent": "Solvent",
165
  "mole_fraction": "Mole Fraction",
166
  "volume_fraction": "Volume Fraction",
167
+ "mass_fraction": "Mass Fraction",
168
+ "calculation_formula": "📐 Calculation Formula",
169
  "formula_mole_to_vol_title": "**Mole Fraction to Volume Fraction:**",
170
  "formula_vol_to_mole_title": "**Volume Fraction to Mole Fraction:**",
171
+ "formula_mole_to_mass_title": "**Mole Fraction to Mass Fraction:**",
172
+ "formula_mass_to_mole_title": "**Mass Fraction to Mole Fraction:**",
173
+ "formula_vol_to_mass_title": "**Volume Fraction to Mass Fraction:**",
174
+ "formula_mass_to_vol_title": "**Mass Fraction to Volume Fraction:**",
175
  "formula_where": "Where:",
176
+ "usage_instructions": "📖 Usage Instructions",
177
  "instruction_1": "1. **Select Conversion Mode**: Choose conversion direction in sidebar",
178
  "instruction_2": "2. **Select Solvents**: Choose from preset common solvents or select 'Custom' to input parameters",
179
+ "instruction_3": "3. **Input Values**: Input mole fraction, volume fraction or mass fraction",
180
  "instruction_4": "4. **View Results**: Results and detailed information are displayed on the right",
181
+ "note": "⚠️ **Note**: This calculation assumes ideal mixing; actual situations may deviate.",
182
+ "language": "🌐 Language",
183
+ "visualization": "📈 Visualization"
184
  }
185
  }
186
 
187
+ # 常见溶剂的摩尔质量和密度数据库
188
  SOLVENTS_DB = {
189
  "中文": {
190
+ "水": {"M": 18.02, "density": 1.000, "en": "Water", "color": "#3498db"},
191
+ "乙醇": {"M": 46.07, "density": 0.789, "en": "Ethanol", "color": "#e74c3c"},
192
+ "甲醇": {"M": 32.04, "density": 0.792, "en": "Methanol", "color": "#9b59b6"},
193
+ "异丙醇": {"M": 60.10, "density": 0.786, "en": "Isopropanol", "color": "#f39c12"},
194
+ "丙酮": {"M": 58.08, "density": 0.784, "en": "Acetone", "color": "#2ecc71"},
195
+ "乙酸乙酯": {"M": 88.11, "density": 0.902, "en": "Ethyl Acetate", "color": "#1abc9c"},
196
+ "甲苯": {"M": 92.14, "density": 0.867, "en": "Toluene", "color": "#34495e"},
197
+ "二氯甲烷": {"M": 84.93, "density": 1.326, "en": "Dichloromethane", "color": "#e67e22"},
198
+ "氯仿": {"M": 119.38, "density": 1.489, "en": "Chloroform", "color": "#95a5a6"},
199
+ "四氢呋喃": {"M": 72.11, "density": 0.889, "en": "Tetrahydrofuran", "color": "#8e44ad"},
200
+ "二甲基亚砜": {"M": 78.13, "density": 1.100, "en": "Dimethyl Sulfoxide", "color": "#27ae60"},
201
+ "N,N-二甲基甲酰胺": {"M": 73.09, "density": 0.944, "en": "N,N-Dimethylformamide", "color": "#16a085"},
202
+ "乙腈": {"M": 41.05, "density": 0.786, "en": "Acetonitrile", "color": "#2980b9"},
203
+ "正己烷": {"M": 86.18, "density": 0.659, "en": "n-Hexane", "color": "#d35400"},
204
+ "环己烷": {"M": 84.16, "density": 0.779, "en": "Cyclohexane", "color": "#7f8c8d"},
205
+ "苯": {"M": 78.11, "density": 0.876, "en": "Benzene", "color": "#c0392b"},
206
+ "乙二醇": {"M": 62.07, "density": 1.113, "en": "Ethylene Glycol", "color": "#8e44ad"},
207
+ "甘油": {"M": 92.09, "density": 1.261, "en": "Glycerol", "color": "#f1c40f"}
208
  },
209
  "English": {
210
+ "Water": {"M": 18.02, "density": 1.000, "cn": "水", "color": "#3498db"},
211
+ "Ethanol": {"M": 46.07, "density": 0.789, "cn": "乙醇", "color": "#e74c3c"},
212
+ "Methanol": {"M": 32.04, "density": 0.792, "cn": "甲醇", "color": "#9b59b6"},
213
+ "Isopropanol": {"M": 60.10, "density": 0.786, "cn": "异丙醇", "color": "#f39c12"},
214
+ "Acetone": {"M": 58.08, "density": 0.784, "cn": "丙酮", "color": "#2ecc71"},
215
+ "Ethyl Acetate": {"M": 88.11, "density": 0.902, "cn": "乙酸乙酯", "color": "#1abc9c"},
216
+ "Toluene": {"M": 92.14, "density": 0.867, "cn": "甲苯", "color": "#34495e"},
217
+ "Dichloromethane": {"M": 84.93, "density": 1.326, "cn": "二氯甲烷", "color": "#e67e22"},
218
+ "Chloroform": {"M": 119.38, "density": 1.489, "cn": "氯仿", "color": "#95a5a6"},
219
+ "Tetrahydrofuran": {"M": 72.11, "density": 0.889, "cn": "四氢呋喃", "color": "#8e44ad"},
220
+ "Dimethyl Sulfoxide": {"M": 78.13, "density": 1.100, "cn": "二甲基亚砜", "color": "#27ae60"},
221
+ "N,N-Dimethylformamide": {"M": 73.09, "density": 0.944, "cn": "N,N-二甲基甲酰胺", "color": "#16a085"},
222
+ "Acetonitrile": {"M": 41.05, "density": 0.786, "cn": "乙腈", "color": "#2980b9"},
223
+ "n-Hexane": {"M": 86.18, "density": 0.659, "cn": "正己烷", "color": "#d35400"},
224
+ "Cyclohexane": {"M": 84.16, "density": 0.779, "cn": "环己烷", "color": "#7f8c8d"},
225
+ "Benzene": {"M": 78.11, "density": 0.876, "cn": "苯", "color": "#c0392b"},
226
+ "Ethylene Glycol": {"M": 62.07, "density": 1.113, "cn": "乙二醇", "color": "#8e44ad"},
227
+ "Glycerol": {"M": 92.09, "density": 1.261, "cn": "甘油", "color": "#f1c40f"}
228
  }
229
  }
230
 
231
  # 语言选择
232
+ language = st.sidebar.selectbox(
233
+ "🌐 Language/语言:",
234
+ ["中文", "English"],
235
+ help="Choose your preferred language / 选择您的首选语言"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  )
237
+ lang = LANGUAGES[language]
238
 
239
+ # 主标题
240
+ st.markdown(f'<h1 class="main-title">{lang["main_title"]}</h1>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
 
242
+ # 添加分隔线
243
+ st.markdown("""
244
+ <div style="height: 2px; background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); margin: 2rem 0;"></div>
245
+ """, unsafe_allow_html=True)
246
 
247
+ # 侧边栏配置
248
+ with st.sidebar:
249
+ st.markdown("### " + lang["conversion_mode"])
250
+ conversion_mode = st.radio(
251
+ "",
252
+ [lang["mode_mole_to_vol"], lang["mode_vol_to_mole"],
253
+ lang["mode_mole_to_mass"], lang["mode_mass_to_mole"],
254
+ lang["mode_vol_to_mass"], lang["mode_mass_to_vol"]],
255
+ help="选择您需要的转换方向"
256
+ )
257
+
258
+ st.markdown("---")
259
+ st.markdown("### " + lang["solvent_selection"])
260
+
261
+ # 获取当前语言的溶剂列表
262
+ current_solvents = SOLVENTS_DB[language]
263
+ solvent_names = list(current_solvents.keys()) + [lang["custom"]]
264
+
265
+ # 溶剂A选择
266
+ solvent_a_name = st.selectbox(
267
+ lang["solvent_a"],
268
+ solvent_names,
269
+ help="选择第一种溶剂"
270
+ )
271
+
272
+ if solvent_a_name == lang["custom"]:
273
+ col1, col2 = st.columns(2)
274
+ with col1:
275
+ M_a = st.number_input(f"{lang['molar_mass']} A (g/mol):", value=18.02, min_value=0.1, step=0.01)
276
+ with col2:
277
+ rho_a = st.number_input(f"{lang['density']} A (g/cm³):", value=1.000, min_value=0.1, step=0.001)
278
+ else:
279
+ M_a = current_solvents[solvent_a_name]["M"]
280
+ rho_a = current_solvents[solvent_a_name]["density"]
281
+ st.info(f"📊 {lang['molar_mass']}: **{M_a}** g/mol \n📊 {lang['density']}: **{rho_a}** g/cm³")
282
+
283
+ # 溶剂B选择
284
+ solvent_b_name = st.selectbox(
285
+ lang["solvent_b"],
286
+ solvent_names,
287
+ help="选择第二种溶剂"
288
+ )
289
+
290
+ if solvent_b_name == lang["custom"]:
291
+ col1, col2 = st.columns(2)
292
+ with col1:
293
+ M_b = st.number_input(f"{lang['molar_mass']} B (g/mol):", value=46.07, min_value=0.1, step=0.01)
294
+ with col2:
295
+ rho_b = st.number_input(f"{lang['density']} B (g/cm³):", value=0.789, min_value=0.1, step=0.001)
296
+ else:
297
+ M_b = current_solvents[solvent_b_name]["M"]
298
+ rho_b = current_solvents[solvent_b_name]["density"]
299
+ st.info(f"📊 {lang['molar_mass']}: **{M_b}** g/mol \n📊 {lang['density']}: **{rho_b}** g/cm³")
300
 
301
  # 主界面内容
302
+ col1, col2 = st.columns([1, 1], gap="large")
303
 
304
+ # 定义计算函数
305
+ def calculate_conversion(mode, input_val, M_a, M_b, rho_a, rho_b):
306
+ """计算转换结果"""
307
+ if mode == lang["mode_mole_to_vol"]:
308
+ x_a, x_b = input_val, 1.0 - input_val
 
 
 
 
 
 
 
 
 
 
309
  V_ratio_a = x_a * M_a / rho_a
310
  V_ratio_b = x_b * M_b / rho_b
311
  V_total = V_ratio_a + V_ratio_b
 
312
  if V_total > 0:
313
  phi_a = V_ratio_a / V_total
314
  phi_b = V_ratio_b / V_total
315
  else:
316
  phi_a = phi_b = 0
317
+ return (x_a, x_b), (phi_a, phi_b), None
318
+
319
+ elif mode == lang["mode_vol_to_mole"]:
320
+ phi_a, phi_b = input_val, 1.0 - input_val
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
  n_ratio_a = phi_a * rho_a / M_a
322
  n_ratio_b = phi_b * rho_b / M_b
323
  n_total = n_ratio_a + n_ratio_b
 
324
  if n_total > 0:
325
  x_a = n_ratio_a / n_total
326
  x_b = n_ratio_b / n_total
327
  else:
328
  x_a = x_b = 0
329
+ return (x_a, x_b), (phi_a, phi_b), None
330
+
331
+ elif mode == lang["mode_mole_to_mass"]:
332
+ x_a, x_b = input_val, 1.0 - input_val
333
+ mass_a = x_a * M_a
334
+ mass_b = x_b * M_b
335
+ mass_total = mass_a + mass_b
336
+ if mass_total > 0:
337
+ w_a = mass_a / mass_total
338
+ w_b = mass_b / mass_total
339
+ else:
340
+ w_a = w_b = 0
341
+ return (x_a, x_b), None, (w_a, w_b)
342
+
343
+ elif mode == lang["mode_mass_to_mole"]:
344
+ w_a, w_b = input_val, 1.0 - input_val
345
+ n_ratio_a = w_a / M_a
346
+ n_ratio_b = w_b / M_b
347
+ n_total = n_ratio_a + n_ratio_b
348
+ if n_total > 0:
349
+ x_a = n_ratio_a / n_total
350
+ x_b = n_ratio_b / n_total
351
+ else:
352
+ x_a = x_b = 0
353
+ return (x_a, x_b), None, (w_a, w_b)
354
+
355
+ elif mode == lang["mode_vol_to_mass"]:
356
+ phi_a, phi_b = input_val, 1.0 - input_val
357
+ mass_a = phi_a * rho_a
358
+ mass_b = phi_b * rho_b
359
+ mass_total = mass_a + mass_b
360
+ if mass_total > 0:
361
+ w_a = mass_a / mass_total
362
+ w_b = mass_b / mass_total
363
+ else:
364
+ w_a = w_b = 0
365
+ return None, (phi_a, phi_b), (w_a, w_b)
366
+
367
+ elif mode == lang["mode_mass_to_vol"]:
368
+ w_a, w_b = input_val, 1.0 - input_val
369
+ vol_a = w_a / rho_a
370
+ vol_b = w_b / rho_b
371
+ vol_total = vol_a + vol_b
372
+ if vol_total > 0:
373
+ phi_a = vol_a / vol_total
374
+ phi_b = vol_b / vol_total
375
+ else:
376
+ phi_a = phi_b = 0
377
+ return None, (phi_a, phi_b), (w_a, w_b)
378
 
379
+ # 输入区域
380
+ with col1:
381
+ # 初始化 input_val 默认值
382
+ input_val = 0.5
383
+
384
+ if conversion_mode in [lang["mode_mole_to_vol"], lang["mode_mole_to_mass"]]:
385
+ st.markdown(f"### {lang['input_mole_fraction']}")
386
+ input_val = st.number_input(
387
+ f"{lang['mole_fraction_of']} {solvent_a_name} (x_A):",
388
+ min_value=0.0,
389
+ max_value=1.0,
390
+ value=0.5,
391
+ step=0.001,
392
+ format="%.4f",
393
+ help="输入溶剂A的摩尔分数"
394
+ )
395
+ complement_val = 1.0 - input_val
396
+ st.metric(
397
+ f"{lang['mole_fraction_of']} {solvent_b_name} (x_B)",
398
+ f"{complement_val:.4f}",
399
+ help="溶剂B的摩尔分数(自动计算)"
400
+ )
401
+
402
+ elif conversion_mode in [lang["mode_vol_to_mole"], lang["mode_vol_to_mass"]]:
403
+ st.markdown(f"### {lang['input_volume_fraction']}")
404
+ input_val = st.number_input(
405
+ f"{lang['volume_fraction_of']} {solvent_a_name} (φ_A):",
406
+ min_value=0.0,
407
+ max_value=1.0,
408
+ value=0.5,
409
+ step=0.001,
410
+ format="%.4f",
411
+ help="输入溶剂A的体积分数"
412
+ )
413
+ complement_val = 1.0 - input_val
414
+ st.metric(
415
+ f"{lang['volume_fraction_of']} {solvent_b_name} (φ_B)",
416
+ f"{complement_val:.4f}",
417
+ help="溶剂B的体积分数(自动计算)"
418
+ )
419
+
420
+ elif conversion_mode in [lang["mode_mass_to_mole"], lang["mode_mass_to_vol"]]:
421
+ st.markdown(f"### {lang['input_mass_fraction']}")
422
+ input_val = st.number_input(
423
+ f"{lang['mass_fraction_of']} {solvent_a_name} (w_A):",
424
+ min_value=0.0,
425
+ max_value=1.0,
426
+ value=0.5,
427
+ step=0.001,
428
+ format="%.4f",
429
+ help="输入溶剂A的质量分数"
430
+ )
431
+ complement_val = 1.0 - input_val
432
+ st.metric(
433
+ f"{lang['mass_fraction_of']} {solvent_b_name} (w_B)",
434
+ f"{complement_val:.4f}",
435
+ help="溶剂B的质量分数(自动计算)"
436
+ )
437
+
438
+ # 计算结果
439
+ mole_result, vol_result, mass_result = calculate_conversion(
440
+ conversion_mode, input_val, M_a, M_b, rho_a, rho_b
441
+ )
442
+
443
+ # 结果显示区域
444
+ with col2:
445
+ if conversion_mode == lang["mode_mole_to_vol"]:
446
+ st.markdown(f"### {lang['result_volume_fraction']}")
447
+ col2_1, col2_2 = st.columns(2)
448
+ with col2_1:
449
+ st.metric(
450
+ f"φ_A ({solvent_a_name})",
451
+ f"{vol_result[0]:.4f}",
452
+ delta=f"{vol_result[0] - mole_result[0]:.4f}",
453
+ help="溶剂A的体积分数"
454
+ )
455
+ with col2_2:
456
+ st.metric(
457
+ f"φ_B ({solvent_b_name})",
458
+ f"{vol_result[1]:.4f}",
459
+ delta=f"{vol_result[1] - mole_result[1]:.4f}",
460
+ help="溶剂B的体积分数"
461
+ )
462
+
463
+ elif conversion_mode == lang["mode_vol_to_mole"]:
464
+ st.markdown(f"### {lang['result_mole_fraction']}")
465
+ col2_1, col2_2 = st.columns(2)
466
+ with col2_1:
467
+ st.metric(
468
+ f"x_A ({solvent_a_name})",
469
+ f"{mole_result[0]:.4f}",
470
+ delta=f"{mole_result[0] - vol_result[0]:.4f}",
471
+ help="溶剂A的摩尔分数"
472
+ )
473
+ with col2_2:
474
+ st.metric(
475
+ f"x_B ({solvent_b_name})",
476
+ f"{mole_result[1]:.4f}",
477
+ delta=f"{mole_result[1] - vol_result[1]:.4f}",
478
+ help="溶剂B的摩尔分数"
479
+ )
480
+
481
+ elif conversion_mode == lang["mode_mole_to_mass"]:
482
+ st.markdown(f"### {lang['result_mass_fraction']}")
483
+ col2_1, col2_2 = st.columns(2)
484
+ with col2_1:
485
+ st.metric(
486
+ f"w_A ({solvent_a_name})",
487
+ f"{mass_result[0]:.4f}",
488
+ delta=f"{mass_result[0] - mole_result[0]:.4f}",
489
+ help="溶剂A的质量分数"
490
+ )
491
+ with col2_2:
492
+ st.metric(
493
+ f"w_B ({solvent_b_name})",
494
+ f"{mass_result[1]:.4f}",
495
+ delta=f"{mass_result[1] - mole_result[1]:.4f}",
496
+ help="溶剂B的质量分数"
497
+ )
498
+
499
+ elif conversion_mode == lang["mode_mass_to_mole"]:
500
+ st.markdown(f"### {lang['result_mole_fraction']}")
501
+ col2_1, col2_2 = st.columns(2)
502
+ with col2_1:
503
+ st.metric(
504
+ f"x_A ({solvent_a_name})",
505
+ f"{mole_result[0]:.4f}",
506
+ delta=f"{mole_result[0] - mass_result[0]:.4f}",
507
+ help="溶剂A的摩尔分数"
508
+ )
509
+ with col2_2:
510
+ st.metric(
511
+ f"x_B ({solvent_b_name})",
512
+ f"{mole_result[1]:.4f}",
513
+ delta=f"{mole_result[1] - mass_result[1]:.4f}",
514
+ help="溶剂B的摩尔分数"
515
+ )
516
+
517
+ elif conversion_mode == lang["mode_vol_to_mass"]:
518
+ st.markdown(f"### {lang['result_mass_fraction']}")
519
+ col2_1, col2_2 = st.columns(2)
520
+ with col2_1:
521
+ st.metric(
522
+ f"w_A ({solvent_a_name})",
523
+ f"{mass_result[0]:.4f}",
524
+ delta=f"{mass_result[0] - vol_result[0]:.4f}",
525
+ help="溶���A的质量分数"
526
+ )
527
+ with col2_2:
528
+ st.metric(
529
+ f"w_B ({solvent_b_name})",
530
+ f"{mass_result[1]:.4f}",
531
+ delta=f"{mass_result[1] - vol_result[1]:.4f}",
532
+ help="溶剂B的质量分数"
533
+ )
534
+
535
+ elif conversion_mode == lang["mode_mass_to_vol"]:
536
+ st.markdown(f"### {lang['result_volume_fraction']}")
537
+ col2_1, col2_2 = st.columns(2)
538
+ with col2_1:
539
+ st.metric(
540
+ f"φ_A ({solvent_a_name})",
541
+ f"{vol_result[0]:.4f}",
542
+ delta=f"{vol_result[0] - mass_result[0]:.4f}",
543
+ help="溶剂A的体积分数"
544
+ )
545
+ with col2_2:
546
+ st.metric(
547
+ f"φ_B ({solvent_b_name})",
548
+ f"{vol_result[1]:.4f}",
549
+ delta=f"{vol_result[1] - mass_result[1]:.4f}",
550
+ help="溶剂B的体积分数"
551
+ )
552
+
553
+ # 验证信息
554
+ st.markdown("---")
555
+ if mole_result:
556
+ st.success(f"✅ 摩尔分数验证: {mole_result[0] + mole_result[1]:.6f}")
557
+ if vol_result:
558
+ st.success(f"✅ 体积分数验证: {vol_result[0] + vol_result[1]:.6f}")
559
+ if mass_result:
560
+ st.success(f"✅ 质量分数验证: {mass_result[0] + mass_result[1]:.6f}")
561
+
562
+ # 可视化部分
563
  st.markdown("---")
564
+ st.markdown(f"### {lang['visualization']}")
565
+
566
+ # 创建饼图
567
+ fig = go.Figure()
568
+
569
+ if mole_result:
570
+ fig.add_trace(go.Pie(
571
+ labels=[solvent_a_name, solvent_b_name],
572
+ values=[mole_result[0], mole_result[1]],
573
+ name="摩尔分数",
574
+ domain=dict(x=[0, 0.3]),
575
+ title="摩尔分数",
576
+ marker_colors=[current_solvents.get(solvent_a_name, {}).get('color', '#3498db'),
577
+ current_solvents.get(solvent_b_name, {}).get('color', '#e74c3c')]
578
+ ))
579
+
580
+ if vol_result:
581
+ fig.add_trace(go.Pie(
582
+ labels=[solvent_a_name, solvent_b_name],
583
+ values=[vol_result[0], vol_result[1]],
584
+ name="体积分数",
585
+ domain=dict(x=[0.35, 0.65]),
586
+ title="体积分数",
587
+ marker_colors=[current_solvents.get(solvent_a_name, {}).get('color', '#3498db'),
588
+ current_solvents.get(solvent_b_name, {}).get('color', '#e74c3c')]
589
+ ))
590
+
591
+ if mass_result:
592
+ fig.add_trace(go.Pie(
593
+ labels=[solvent_a_name, solvent_b_name],
594
+ values=[mass_result[0], mass_result[1]],
595
+ name="质量分数",
596
+ domain=dict(x=[0.7, 1.0]),
597
+ title="质量分数",
598
+ marker_colors=[current_solvents.get(solvent_a_name, {}).get('color', '#3498db'),
599
+ current_solvents.get(solvent_b_name, {}).get('color', '#e74c3c')]
600
+ ))
601
+
602
+ fig.update_traces(textposition='inside', textinfo='percent+label')
603
+ fig.update_layout(
604
+ title_text="溶剂分数可视化",
605
+ showlegend=False,
606
+ height=400,
607
+ margin=dict(l=20, r=20, t=50, b=20)
608
+ )
609
+
610
+ st.plotly_chart(fig, use_container_width=True)
611
+
612
+ # 详细信息表格
613
+ st.markdown("---")
614
+ st.markdown(f"### {lang['detailed_info']}")
615
 
616
  col1, col2, col3 = st.columns(3)
617
 
618
  with col1:
619
+ st.markdown(f"#### {lang['solvent_params']}")
620
  df_params = pd.DataFrame({
621
  lang["solvent"]: [solvent_a_name, solvent_b_name],
622
  f"{lang['molar_mass']} (g/mol)": [M_a, M_b],
623
  f"{lang['density']} (g/cm³)": [rho_a, rho_b]
624
  })
625
+ st.dataframe(df_params, use_container_width=True)
626
 
627
  with col2:
628
+ if mole_result:
629
+ st.markdown(f"#### {lang['mole_fraction']}")
630
  df_mole = pd.DataFrame({
631
  lang["solvent"]: [solvent_a_name, solvent_b_name],
632
+ lang["mole_fraction"]: [f"{mole_result[0]:.4f}", f"{mole_result[1]:.4f}"]
633
  })
634
+ st.dataframe(df_mole, use_container_width=True)
635
+
636
+ if vol_result:
637
+ st.markdown(f"#### {lang['volume_fraction']}")
638
  df_vol = pd.DataFrame({
639
  lang["solvent"]: [solvent_a_name, solvent_b_name],
640
+ lang["volume_fraction"]: [f"{vol_result[0]:.4f}", f"{vol_result[1]:.4f}"]
641
  })
642
+ st.dataframe(df_vol, use_container_width=True)
643
 
644
  with col3:
645
+ if mass_result:
646
+ st.markdown(f"#### {lang['mass_fraction']}")
647
+ df_mass = pd.DataFrame({
648
  lang["solvent"]: [solvent_a_name, solvent_b_name],
649
+ lang["mass_fraction"]: [f"{mass_result[0]:.4f}", f"{mass_result[1]:.4f}"]
650
  })
651
+ st.dataframe(df_mass, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
652
 
653
+ # 公式说明(在可折叠容器中)
654
+ with st.expander(f"📐 {lang['calculation_formula']}", expanded=False):
655
+ formula_dict = {
656
+ lang["mode_mole_to_vol"]: {
657
+ "formula": r"\phi_A = \frac{x_A \cdot M_A / \rho_A}{x_A \cdot M_A / \rho_A + x_B \cdot M_B / \rho_B}",
658
+ "vars": "x_A, x_B: 摩尔分数; φ_A, φ_B: 体积分数; M_A, M_B: 摩尔质量 (g/mol); ρ_A, ρ_B: 密度 (g/cm³)"
659
+ },
660
+ lang["mode_vol_to_mole"]: {
661
+ "formula": r"x_A = \frac{\phi_A \cdot \rho_A / M_A}{\phi_A \cdot \rho_A / M_A + \phi_B \cdot \rho_B / M_B}",
662
+ "vars": "φ_A, φ_B: 体积分数; x_A, x_B: 摩尔分数; M_A, M_B: 摩尔质量 (g/mol); ρ_A, ρ_B: 密度 (g/cm³)"
663
+ },
664
+ lang["mode_mole_to_mass"]: {
665
+ "formula": r"w_A = \frac{x_A \cdot M_A}{x_A \cdot M_A + x_B \cdot M_B}",
666
+ "vars": "x_A, x_B: 摩尔分数; w_A, w_B: 质量分数; M_A, M_B: 摩尔质量 (g/mol)"
667
+ },
668
+ lang["mode_mass_to_mole"]: {
669
+ "formula": r"x_A = \frac{w_A / M_A}{w_A / M_A + w_B / M_B}",
670
+ "vars": "w_A, w_B: 质量分数; x_A, x_B: 摩尔分数; M_A, M_B: 摩尔质量 (g/mol)"
671
+ },
672
+ lang["mode_vol_to_mass"]: {
673
+ "formula": r"w_A = \frac{\phi_A \cdot \rho_A}{\phi_A \cdot \rho_A + \phi_B \cdot \rho_B}",
674
+ "vars": "φ_A, φ_B: 体积分数; w_A, w_B: 质量分数; ρ_A, ρ_B: 密度 (g/cm³)"
675
+ },
676
+ lang["mode_mass_to_vol"]: {
677
+ "formula": r"\phi_A = \frac{w_A / \rho_A}{w_A / \rho_A + w_B / \rho_B}",
678
+ "vars": "w_A, w_B: 质量分数; φ_A, φ_B: 体积分数; ρ_A, ρ_B: 密度 (g/cm³)"
679
+ }
680
+ }
681
+
682
+ if conversion_mode in formula_dict:
683
+ st.latex(formula_dict[conversion_mode]["formula"])
684
+ st.markdown(f"**{lang['formula_where']}** {formula_dict[conversion_mode]['vars']}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
685
 
686
  # 使用说明
687
+ with st.expander(f"📖 {lang['usage_instructions']}", expanded=False):
688
+ st.markdown(f"""
689
+ {lang["instruction_1"]}
690
+
691
+ {lang["instruction_2"]}
692
+
693
+ {lang["instruction_3"]}
694
+
695
+ {lang["instruction_4"]}
696
+ """)
697
 
698
+ # 注意事项
699
+ st.markdown(f"""
700
+ <div class="warning-box">
701
  {lang["note"]}
702
+ </div>
703
+ """, unsafe_allow_html=True)
704
+
705
+ # 页脚
706
+ st.markdown("---")
707
+ st.markdown("""
708
+ <div style="text-align: center; color: #7f8c8d; padding: 1rem;">
709
+ <small>🧪 溶剂分数转换器 | 基于理想混合理论 | Made with Streamlit</small>
710
+ </div>
711
+ """, unsafe_allow_html=True)