Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -129,6 +129,51 @@ def cluster_reps(df, labels, use):
|
|
| 129 |
reps.append(cluster_df.loc[idx]['smiles'])
|
| 130 |
return reps
|
| 131 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
# =========== Gradio 主 UI ===========
|
| 133 |
with gr.Blocks(title="Cheminformatics Platform") as demo:
|
| 134 |
gr.Markdown("# 🧪 Cheminformatics 多功能平台")
|
|
@@ -162,10 +207,16 @@ with gr.Blocks(title="Cheminformatics Platform") as demo:
|
|
| 162 |
col_sel = gr.Dropdown(['MolWt','TPSA','NumHDonors','NumHAcceptors','LogP'], label="欄位")
|
| 163 |
eda_img = gr.Image(label="描述子分布圖")
|
| 164 |
eda_btn = gr.Button("產生分布圖")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
eda_btn.click(
|
| 166 |
-
|
| 167 |
-
[file3, col_sel], eda_img
|
| 168 |
)
|
|
|
|
| 169 |
eda_sum = gr.File(label="下載EDA報表")
|
| 170 |
gr.Button("生成EDA報表", variant="primary").click(
|
| 171 |
lambda f: eda_report(load_table(f)) if f else None, file3, eda_sum
|
|
@@ -180,17 +231,20 @@ with gr.Blocks(title="Cheminformatics Platform") as demo:
|
|
| 180 |
nclus = gr.Slider(2, 8, 3, 1, label="KMeans分群數")
|
| 181 |
dr_img = gr.Image(label="降維/分群視覺化")
|
| 182 |
rep_imgs = gr.Image(label="群代表分子圖(每群1個)")
|
|
|
|
| 183 |
def dimred_and_cluster(file, fp, dr, cl, nclu):
|
| 184 |
df = load_table(file)
|
| 185 |
df = calc_features(df, [fp], [], None)
|
| 186 |
pc = apply_dim_red(df, fp, dr)
|
| 187 |
labels = KMeans(n_clusters=int(nclu), random_state=42).fit_predict(pc) if cl == 'KMeans' else DBSCAN(eps=3, min_samples=2).fit_predict(pc)
|
| 188 |
plotimg = plot_scatter(pc, labels, f"{dr}-{cl}")
|
|
|
|
| 189 |
reps = cluster_reps(df, labels, fp)
|
| 190 |
rep_img = batch_mol_imgs(reps)
|
| 191 |
-
return plotimg, rep_img
|
|
|
|
| 192 |
gr.Button("降維+分群分析", variant="primary").click(
|
| 193 |
-
dimred_and_cluster, [file4, use_fp, dr_method, cl_method, nclus], [dr_img, rep_imgs]
|
| 194 |
)
|
| 195 |
|
| 196 |
gr.Markdown("---\n> 完整工作流:1️⃣資料導入 → 2️⃣特徵/描述子/官能基 → 3️⃣EDA分析 → 4️⃣降維/分群/結構探索")
|
|
|
|
| 129 |
reps.append(cluster_df.loc[idx]['smiles'])
|
| 130 |
return reps
|
| 131 |
|
| 132 |
+
# 圖像自動說明函數
|
| 133 |
+
# 針對描述子分布圖的簡易解釋
|
| 134 |
+
def explain_desc_dist(df, desc):
|
| 135 |
+
if df is None or desc not in df.columns:
|
| 136 |
+
return "請先上傳檔案並選擇描述子。"
|
| 137 |
+
n = df.shape[0]
|
| 138 |
+
mean = df[desc].mean()
|
| 139 |
+
std = df[desc].std()
|
| 140 |
+
minv = df[desc].min()
|
| 141 |
+
maxv = df[desc].max()
|
| 142 |
+
msg = (
|
| 143 |
+
f"這張圖顯示目前資料集裡「{desc}」這個特徵的分布情況。\n\n"
|
| 144 |
+
f"總共有 {n} 筆資料。數值大多集中在平均值 {mean:.2f} 左右,標準差是 {std:.2f}。\n"
|
| 145 |
+
f"最低值 {minv:.2f},最高值 {maxv:.2f}。圖中高峰的位置就是資料最集中的範圍。\n"
|
| 146 |
+
"這樣的分布圖可以幫助你判斷資料是不是有極端值,或是大多數分子都屬於哪個範圍。\n\n"
|
| 147 |
+
"【應用案例】\n"
|
| 148 |
+
"比方說,如果你正在開發一款新藥或新材料,可以藉由分布圖觀察目標分子的分子量、極性(TPSA)是否和現有產品類似。"
|
| 149 |
+
"如果發現有極端高或低的分子量,可能要特別注意這些分子在後續應用上的行為,例如溶解度、吸收性等。\n"
|
| 150 |
+
"這樣的分析常被用於藥物篩選(藥物發現)、高分子材料設計,甚至協助判斷是否有「資料異常」需要清理。"
|
| 151 |
+
)
|
| 152 |
+
return msg
|
| 153 |
+
|
| 154 |
+
# 針對降維與分群圖的簡易解釋
|
| 155 |
+
def explain_dimred(pc, labels, dr, cl):
|
| 156 |
+
n = pc.shape[0]
|
| 157 |
+
n_cls = len(np.unique(labels))
|
| 158 |
+
label_cnt = {int(lbl): sum(labels==lbl) for lbl in np.unique(labels)}
|
| 159 |
+
msg = (
|
| 160 |
+
f"這張圖是把分子資料用 {dr} 方法做降維,再用 {cl} 方法分群得到的。\n\n"
|
| 161 |
+
f"每個點代表一個分子,不同顏色表示不同的群組。這次總共分成 {n_cls} 群。\n"
|
| 162 |
+
f"每群的分子數量分別是:{label_cnt}\n"
|
| 163 |
+
"如果看到有明顯分群,代表這些分子之間可能有某些共通的特徵。\n"
|
| 164 |
+
"點跟點之間越近,代表它們在特徵上也越像。如果有單獨一兩個點很遠,那可能就是所謂的離群值(和其他分子差異較大)。\n\n"
|
| 165 |
+
"【應用案例】\n"
|
| 166 |
+
"假設你是一位藥物化學家,可以利用這張圖來判斷哪些分子屬於同一類型(例如同一類藥效分子),快速發現群內外的差異。"
|
| 167 |
+
"如果你是在開發新材料,可以找出和現有材料組成最相近或最不一樣的分子,有助於找出潛力新材料。\n"
|
| 168 |
+
"此外,如果發現某個群組特別小或特別大,也可以針對這些群組進行更細緻的分析,例如針對特殊族群做後續的結構設計。"
|
| 169 |
+
)
|
| 170 |
+
return msg
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
|
| 177 |
# =========== Gradio 主 UI ===========
|
| 178 |
with gr.Blocks(title="Cheminformatics Platform") as demo:
|
| 179 |
gr.Markdown("# 🧪 Cheminformatics 多功能平台")
|
|
|
|
| 207 |
col_sel = gr.Dropdown(['MolWt','TPSA','NumHDonors','NumHAcceptors','LogP'], label="欄位")
|
| 208 |
eda_img = gr.Image(label="描述子分布圖")
|
| 209 |
eda_btn = gr.Button("產生分布圖")
|
| 210 |
+
def show_eda_img_with_explain(f, c):
|
| 211 |
+
df = calc_features(load_table(f), ['ecfp4'], [c], None)
|
| 212 |
+
img = plot_desc_dist(df, c)
|
| 213 |
+
exp = explain_desc_dist(df, c)
|
| 214 |
+
return img, exp
|
| 215 |
+
|
| 216 |
eda_btn.click(
|
| 217 |
+
show_eda_img_with_explain, [file3, col_sel], [eda_img, eda_desc]
|
|
|
|
| 218 |
)
|
| 219 |
+
|
| 220 |
eda_sum = gr.File(label="下載EDA報表")
|
| 221 |
gr.Button("生成EDA報表", variant="primary").click(
|
| 222 |
lambda f: eda_report(load_table(f)) if f else None, file3, eda_sum
|
|
|
|
| 231 |
nclus = gr.Slider(2, 8, 3, 1, label="KMeans分群數")
|
| 232 |
dr_img = gr.Image(label="降維/分群視覺化")
|
| 233 |
rep_imgs = gr.Image(label="群代表分子圖(每群1個)")
|
| 234 |
+
|
| 235 |
def dimred_and_cluster(file, fp, dr, cl, nclu):
|
| 236 |
df = load_table(file)
|
| 237 |
df = calc_features(df, [fp], [], None)
|
| 238 |
pc = apply_dim_red(df, fp, dr)
|
| 239 |
labels = KMeans(n_clusters=int(nclu), random_state=42).fit_predict(pc) if cl == 'KMeans' else DBSCAN(eps=3, min_samples=2).fit_predict(pc)
|
| 240 |
plotimg = plot_scatter(pc, labels, f"{dr}-{cl}")
|
| 241 |
+
exp = explain_dimred(pc, labels, dr, cl)
|
| 242 |
reps = cluster_reps(df, labels, fp)
|
| 243 |
rep_img = batch_mol_imgs(reps)
|
| 244 |
+
return plotimg, exp, rep_img
|
| 245 |
+
|
| 246 |
gr.Button("降維+分群分析", variant="primary").click(
|
| 247 |
+
dimred_and_cluster, [file4, use_fp, dr_method, cl_method, nclus], [dr_img, dr_desc, rep_imgs]
|
| 248 |
)
|
| 249 |
|
| 250 |
gr.Markdown("---\n> 完整工作流:1️⃣資料導入 → 2️⃣特徵/描述子/官能基 → 3️⃣EDA分析 → 4️⃣降維/分群/結構探索")
|