Spaces:
Sleeping
Sleeping
Gilmullin Almaz
commited on
Commit
·
59ff193
1
Parent(s):
2fec28f
Refactor route handling to replace ReducedRouteCGR with SB-CGR across multiple modules, enhancing clarity and consistency in clustering and visualization processes.
Browse files- app.py +107 -109
- synplan/chem/reaction_routes/clustering.py +23 -23
- synplan/chem/reaction_routes/route_cgr.py +3 -3
- synplan/utils/visualisation.py +19 -19
app.py
CHANGED
|
@@ -26,6 +26,7 @@ from synplan.utils.visualisation import (
|
|
| 26 |
generate_results_html,
|
| 27 |
html_top_routes_cluster,
|
| 28 |
get_route_svg,
|
|
|
|
| 29 |
)
|
| 30 |
from synplan.utils.config import TreeConfig, PolicyNetworkConfig
|
| 31 |
from synplan.utils.loading import load_reaction_rules, load_building_blocks
|
|
@@ -169,8 +170,10 @@ def initialize_app():
|
|
| 169 |
st.session_state.num_clusters_setting = 10
|
| 170 |
if "route_cgrs_dict" not in st.session_state:
|
| 171 |
st.session_state.route_cgrs_dict = None
|
| 172 |
-
if "
|
| 173 |
-
st.session_state.
|
|
|
|
|
|
|
| 174 |
|
| 175 |
# Subclustering state
|
| 176 |
if "subclustering_done" not in st.session_state:
|
|
@@ -439,7 +442,8 @@ def setup_planning_options():
|
|
| 439 |
st.session_state.reactions_dict = None
|
| 440 |
st.session_state.subclusters = None
|
| 441 |
st.session_state.route_cgrs_dict = None
|
| 442 |
-
st.session_state.
|
|
|
|
| 443 |
active_smile_code = st.session_state.get(
|
| 444 |
"ketcher", DEFAULT_MOL
|
| 445 |
) # Get current SMILES
|
|
@@ -520,8 +524,6 @@ def setup_planning_options():
|
|
| 520 |
|
| 521 |
if error is not None:
|
| 522 |
st.error(f"An error occurred during planning: {error}")
|
| 523 |
-
# else:
|
| 524 |
-
# st.rerun()
|
| 525 |
|
| 526 |
|
| 527 |
def display_planning_results():
|
|
@@ -564,6 +566,7 @@ def display_planning_results():
|
|
| 564 |
num_steps = len(tree.synthesis_route(node_id))
|
| 565 |
route_score = round(tree.route_score(node_id), 3)
|
| 566 |
svg = get_route_svg(tree, node_id)
|
|
|
|
| 567 |
if svg:
|
| 568 |
st.image(
|
| 569 |
svg,
|
|
@@ -622,15 +625,6 @@ def download_planning_results():
|
|
| 622 |
):
|
| 623 |
res = st.session_state.res
|
| 624 |
tree = st.session_state.tree
|
| 625 |
-
# This section is usually placed within a column in the original script
|
| 626 |
-
# We'll assume it's called after display_planning_results and can use a new column or area.
|
| 627 |
-
# For proper layout, this should be integrated with display_planning_results' columns.
|
| 628 |
-
# For now, creating a placeholder or separate section for downloads:
|
| 629 |
-
# st.subheader("Downloads") # This might be redundant if called within a layout context.
|
| 630 |
-
|
| 631 |
-
# The original code places downloads in the second column of planning results.
|
| 632 |
-
# To replicate, we'd need to pass the column object or call this within that context.
|
| 633 |
-
# Simulating this by just creating the download links:
|
| 634 |
try:
|
| 635 |
html_body = generate_results_html(tree, html_path=None, extended=True)
|
| 636 |
dl_html = download_button(
|
|
@@ -675,7 +669,7 @@ def setup_clustering():
|
|
| 675 |
st.session_state.reactions_dict = None
|
| 676 |
st.session_state.subclusters = None
|
| 677 |
st.session_state.route_cgrs_dict = None
|
| 678 |
-
st.session_state.
|
| 679 |
|
| 680 |
with st.spinner("Performing clustering..."):
|
| 681 |
error = None
|
|
@@ -687,19 +681,22 @@ def setup_clustering():
|
|
| 687 |
|
| 688 |
st.write("Calculating RoutesCGRs...")
|
| 689 |
route_cgrs_dict = compose_all_route_cgrs(current_tree)
|
| 690 |
-
st.write("Processing
|
| 691 |
-
|
|
|
|
| 692 |
|
| 693 |
results = cluster_routes(
|
| 694 |
-
|
| 695 |
-
)
|
| 696 |
results = dict(sorted(results.items(), key=lambda x: float(x[0])))
|
| 697 |
|
| 698 |
st.session_state.clusters = results
|
| 699 |
st.session_state.route_cgrs_dict = route_cgrs_dict
|
| 700 |
-
st.session_state.
|
| 701 |
st.write("Extracting reactions...")
|
| 702 |
-
|
|
|
|
|
|
|
| 703 |
|
| 704 |
if (
|
| 705 |
st.session_state.clusters is not None
|
|
@@ -713,9 +710,8 @@ def setup_clustering():
|
|
| 713 |
st.error("Clustering failed or returned empty results.")
|
| 714 |
st.session_state.clustering_done = False
|
| 715 |
|
| 716 |
-
del results #
|
| 717 |
gc.collect()
|
| 718 |
-
# st.rerun()
|
| 719 |
except Exception as e:
|
| 720 |
error = e
|
| 721 |
st.error(f"An error occurred during clustering: {e}")
|
|
@@ -723,8 +719,6 @@ def setup_clustering():
|
|
| 723 |
|
| 724 |
if error is not None:
|
| 725 |
st.error(f"An error occurred during planning: {error}")
|
| 726 |
-
# else:
|
| 727 |
-
# st.rerun()
|
| 728 |
|
| 729 |
|
| 730 |
def display_clustering_results():
|
|
@@ -765,16 +759,17 @@ def display_clustering_results():
|
|
| 765 |
num_steps = len(tree.synthesis_route(node_id))
|
| 766 |
route_score = round(tree.route_score(node_id), 3)
|
| 767 |
svg = get_route_svg(tree, node_id)
|
| 768 |
-
|
| 769 |
-
|
| 770 |
-
|
| 771 |
-
|
| 772 |
-
|
| 773 |
-
|
| 774 |
-
|
|
|
|
| 775 |
col1, col2 = st.columns([0.2, 0.8])
|
| 776 |
with col1:
|
| 777 |
-
st.image(
|
| 778 |
with col2:
|
| 779 |
st.image(
|
| 780 |
svg,
|
|
@@ -786,11 +781,11 @@ def display_clustering_results():
|
|
| 786 |
caption=f"Route {node_id}; {num_steps} steps; Route score: {route_score}",
|
| 787 |
)
|
| 788 |
st.warning(
|
| 789 |
-
f"
|
| 790 |
)
|
| 791 |
else:
|
| 792 |
st.warning(
|
| 793 |
-
f"Could not generate SVG for route {node_id} or its
|
| 794 |
)
|
| 795 |
except Exception as e:
|
| 796 |
st.error(
|
|
@@ -816,17 +811,18 @@ def display_clustering_results():
|
|
| 816 |
try:
|
| 817 |
num_steps = len(tree.synthesis_route(node_id))
|
| 818 |
route_score = round(tree.route_score(node_id), 3)
|
| 819 |
-
svg = get_route_svg(tree, node_id)
|
| 820 |
-
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
|
| 825 |
-
|
| 826 |
-
|
|
|
|
| 827 |
col1, col2 = st.columns([0.2, 0.8])
|
| 828 |
with col1:
|
| 829 |
-
st.image(
|
| 830 |
with col2:
|
| 831 |
st.image(
|
| 832 |
svg,
|
|
@@ -838,11 +834,11 @@ def display_clustering_results():
|
|
| 838 |
caption=f"Route {node_id}; {num_steps} steps; Route score: {route_score}",
|
| 839 |
)
|
| 840 |
st.warning(
|
| 841 |
-
f"
|
| 842 |
)
|
| 843 |
else:
|
| 844 |
st.warning(
|
| 845 |
-
f"Could not generate SVG for route {node_id} or its
|
| 846 |
)
|
| 847 |
except Exception as e:
|
| 848 |
st.error(
|
|
@@ -855,8 +851,8 @@ def download_clustering_results():
|
|
| 855 |
if st.session_state.get("clustering_done", False):
|
| 856 |
tree_for_html = st.session_state.get("tree")
|
| 857 |
clusters_for_html = st.session_state.get("clusters")
|
| 858 |
-
|
| 859 |
-
"
|
| 860 |
) # This was used instead of reactions_dict in the original for report
|
| 861 |
|
| 862 |
if not tree_for_html:
|
|
@@ -865,7 +861,7 @@ def download_clustering_results():
|
|
| 865 |
if not clusters_for_html:
|
| 866 |
st.warning("Cluster data not found. Cannot generate cluster reports.")
|
| 867 |
return
|
| 868 |
-
#
|
| 869 |
|
| 870 |
st.subheader("Cluster Reports") # Changed subheader in original
|
| 871 |
st.write("Generate downloadable HTML reports for each cluster:")
|
|
@@ -884,7 +880,7 @@ def download_clustering_results():
|
|
| 884 |
tree_for_html,
|
| 885 |
clusters_for_html, # Pass the whole dict
|
| 886 |
str(cluster_idx), # Pass the key of the cluster
|
| 887 |
-
|
| 888 |
aam=False,
|
| 889 |
)
|
| 890 |
st.download_button(
|
|
@@ -911,7 +907,7 @@ def download_clustering_results():
|
|
| 911 |
tree_for_html,
|
| 912 |
clusters_for_html,
|
| 913 |
str(group_index),
|
| 914 |
-
|
| 915 |
aam=False,
|
| 916 |
)
|
| 917 |
st.download_button(
|
|
@@ -936,7 +932,7 @@ def download_clustering_results():
|
|
| 936 |
tree_for_html,
|
| 937 |
clusters_for_html,
|
| 938 |
str(idx),
|
| 939 |
-
|
| 940 |
aam=False,
|
| 941 |
)
|
| 942 |
filename = f"cluster_{idx}_{st.session_state.target_smiles}.html"
|
|
@@ -969,19 +965,19 @@ def setup_subclustering():
|
|
| 969 |
error = None
|
| 970 |
try:
|
| 971 |
clusters_for_sub = st.session_state.get("clusters")
|
| 972 |
-
|
| 973 |
-
"
|
| 974 |
)
|
| 975 |
route_cgrs_dict_for_sub = st.session_state.get("route_cgrs_dict")
|
| 976 |
|
| 977 |
if (
|
| 978 |
clusters_for_sub
|
| 979 |
-
and
|
| 980 |
and route_cgrs_dict_for_sub
|
| 981 |
): # Ensure all are present
|
| 982 |
all_subgroups = subcluster_all_clusters(
|
| 983 |
clusters_for_sub,
|
| 984 |
-
|
| 985 |
route_cgrs_dict_for_sub,
|
| 986 |
)
|
| 987 |
st.session_state.subclusters = all_subgroups
|
|
@@ -993,8 +989,8 @@ def setup_subclustering():
|
|
| 993 |
missing = []
|
| 994 |
if not clusters_for_sub:
|
| 995 |
missing.append("clusters")
|
| 996 |
-
if not
|
| 997 |
-
missing.append("
|
| 998 |
if not route_cgrs_dict_for_sub:
|
| 999 |
missing.append("RouteCGRs dictionary")
|
| 1000 |
st.error(
|
|
@@ -1061,17 +1057,17 @@ def display_subclustering_results():
|
|
| 1061 |
current_subcluster_data = sub[user_input_cluster_num_display][
|
| 1062 |
selected_subcluster_idx
|
| 1063 |
]
|
| 1064 |
-
if "
|
| 1065 |
-
|
| 1066 |
-
"
|
| 1067 |
]
|
| 1068 |
-
|
| 1069 |
st.image(
|
| 1070 |
-
|
| 1071 |
-
caption=f"
|
| 1072 |
)
|
| 1073 |
else:
|
| 1074 |
-
st.warning("
|
| 1075 |
else:
|
| 1076 |
st.warning(
|
| 1077 |
f"Selected cluster {user_input_cluster_num_display} not found in subclustering results."
|
|
@@ -1126,48 +1122,50 @@ def display_subclustering_results():
|
|
| 1126 |
st.warning(f"Could not depict synthon reaction: {e_depict}")
|
| 1127 |
else:
|
| 1128 |
st.info("No synthon reaction data for this subcluster.")
|
| 1129 |
-
|
| 1130 |
-
|
| 1131 |
-
|
| 1132 |
-
|
| 1133 |
-
|
| 1134 |
-
|
| 1135 |
-
|
| 1136 |
-
|
| 1137 |
-
|
| 1138 |
-
|
| 1139 |
-
|
| 1140 |
-
|
| 1141 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1142 |
)
|
| 1143 |
-
except Exception as e:
|
| 1144 |
-
st.error(
|
| 1145 |
-
f"Error displaying route {route_id} in subcluster: {e}"
|
| 1146 |
-
)
|
| 1147 |
|
| 1148 |
-
|
| 1149 |
-
|
| 1150 |
-
|
| 1151 |
-
|
| 1152 |
-
|
| 1153 |
-
|
| 1154 |
-
|
| 1155 |
-
|
| 1156 |
-
)
|
| 1157 |
-
svg_sub = get_route_svg(tree, route_id)
|
| 1158 |
-
if svg_sub:
|
| 1159 |
-
st.image(
|
| 1160 |
-
svg_sub,
|
| 1161 |
-
caption=f"Route {route_id}; Score: {route_score_sub}",
|
| 1162 |
)
|
| 1163 |
-
|
| 1164 |
-
st.
|
| 1165 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1166 |
)
|
| 1167 |
-
except Exception as e:
|
| 1168 |
-
st.error(
|
| 1169 |
-
f"Error displaying route {route_id} in subcluster (expanded): {e}"
|
| 1170 |
-
)
|
| 1171 |
else:
|
| 1172 |
st.info("Select a valid cluster and subcluster index to see details.")
|
| 1173 |
|
|
@@ -1182,16 +1180,16 @@ def download_subclustering_results():
|
|
| 1182 |
|
| 1183 |
sub = st.session_state.get("subclusters")
|
| 1184 |
tree = st.session_state.get("tree")
|
| 1185 |
-
|
| 1186 |
-
"
|
| 1187 |
) # Used by routes_subclustering_report
|
| 1188 |
|
| 1189 |
user_input_cluster_num_display = st.session_state.subcluster_num_select_key
|
| 1190 |
selected_subcluster_idx = st.session_state.subcluster_index_select_key
|
| 1191 |
|
| 1192 |
-
if not tree or not sub or not
|
| 1193 |
st.warning(
|
| 1194 |
-
"Missing data for subclustering report generation (tree, subclusters, or
|
| 1195 |
)
|
| 1196 |
return
|
| 1197 |
|
|
@@ -1226,7 +1224,7 @@ def download_subclustering_results():
|
|
| 1226 |
processed_subcluster_data, # Pass the specific post-processed subcluster data
|
| 1227 |
user_input_cluster_num_display,
|
| 1228 |
selected_subcluster_idx,
|
| 1229 |
-
|
| 1230 |
if_lg_group=True, # This parameter was in the original call
|
| 1231 |
)
|
| 1232 |
st.download_button(
|
|
@@ -1259,7 +1257,7 @@ def implement_restart():
|
|
| 1259 |
"reactions_dict",
|
| 1260 |
"num_clusters_setting",
|
| 1261 |
"route_cgrs_dict",
|
| 1262 |
-
"
|
| 1263 |
"subclustering_done",
|
| 1264 |
"subclusters", # "sub" was renamed
|
| 1265 |
"clusters_downloaded",
|
|
|
|
| 26 |
generate_results_html,
|
| 27 |
html_top_routes_cluster,
|
| 28 |
get_route_svg,
|
| 29 |
+
get_route_svg_from_json
|
| 30 |
)
|
| 31 |
from synplan.utils.config import TreeConfig, PolicyNetworkConfig
|
| 32 |
from synplan.utils.loading import load_reaction_rules, load_building_blocks
|
|
|
|
| 170 |
st.session_state.num_clusters_setting = 10
|
| 171 |
if "route_cgrs_dict" not in st.session_state:
|
| 172 |
st.session_state.route_cgrs_dict = None
|
| 173 |
+
if "sb_cgrs_dict" not in st.session_state:
|
| 174 |
+
st.session_state.sb_cgrs_dict = None
|
| 175 |
+
if "route_json" not in st.session_state:
|
| 176 |
+
st.session_state.route_json = None
|
| 177 |
|
| 178 |
# Subclustering state
|
| 179 |
if "subclustering_done" not in st.session_state:
|
|
|
|
| 442 |
st.session_state.reactions_dict = None
|
| 443 |
st.session_state.subclusters = None
|
| 444 |
st.session_state.route_cgrs_dict = None
|
| 445 |
+
st.session_state.sb_cgrs_dict = None
|
| 446 |
+
st.session_state.route_json = None
|
| 447 |
active_smile_code = st.session_state.get(
|
| 448 |
"ketcher", DEFAULT_MOL
|
| 449 |
) # Get current SMILES
|
|
|
|
| 524 |
|
| 525 |
if error is not None:
|
| 526 |
st.error(f"An error occurred during planning: {error}")
|
|
|
|
|
|
|
| 527 |
|
| 528 |
|
| 529 |
def display_planning_results():
|
|
|
|
| 566 |
num_steps = len(tree.synthesis_route(node_id))
|
| 567 |
route_score = round(tree.route_score(node_id), 3)
|
| 568 |
svg = get_route_svg(tree, node_id)
|
| 569 |
+
# svg = get_route_svg_from_json(st.session_state.route_json, node_id)
|
| 570 |
if svg:
|
| 571 |
st.image(
|
| 572 |
svg,
|
|
|
|
| 625 |
):
|
| 626 |
res = st.session_state.res
|
| 627 |
tree = st.session_state.tree
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 628 |
try:
|
| 629 |
html_body = generate_results_html(tree, html_path=None, extended=True)
|
| 630 |
dl_html = download_button(
|
|
|
|
| 669 |
st.session_state.reactions_dict = None
|
| 670 |
st.session_state.subclusters = None
|
| 671 |
st.session_state.route_cgrs_dict = None
|
| 672 |
+
st.session_state.sb_cgrs_dict = None
|
| 673 |
|
| 674 |
with st.spinner("Performing clustering..."):
|
| 675 |
error = None
|
|
|
|
| 681 |
|
| 682 |
st.write("Calculating RoutesCGRs...")
|
| 683 |
route_cgrs_dict = compose_all_route_cgrs(current_tree)
|
| 684 |
+
st.write("Processing SB-CGRs...")
|
| 685 |
+
sb_cgrs_dict = compose_all_sb_cgrs(route_cgrs_dict)
|
| 686 |
+
# route_json = make_json(extract_reactions(current_tree))
|
| 687 |
|
| 688 |
results = cluster_routes(
|
| 689 |
+
sb_cgrs_dict, use_strat=False
|
| 690 |
+
)
|
| 691 |
results = dict(sorted(results.items(), key=lambda x: float(x[0])))
|
| 692 |
|
| 693 |
st.session_state.clusters = results
|
| 694 |
st.session_state.route_cgrs_dict = route_cgrs_dict
|
| 695 |
+
st.session_state.sb_cgrs_dict = sb_cgrs_dict
|
| 696 |
st.write("Extracting reactions...")
|
| 697 |
+
reactions_dict = extract_reactions(current_tree)
|
| 698 |
+
st.session_state.reactions_dict = reactions_dict
|
| 699 |
+
# st.session_state.route_json = make_json(reactions_dict)
|
| 700 |
|
| 701 |
if (
|
| 702 |
st.session_state.clusters is not None
|
|
|
|
| 710 |
st.error("Clustering failed or returned empty results.")
|
| 711 |
st.session_state.clustering_done = False
|
| 712 |
|
| 713 |
+
del results # sb_cgrs_dict are stored
|
| 714 |
gc.collect()
|
|
|
|
| 715 |
except Exception as e:
|
| 716 |
error = e
|
| 717 |
st.error(f"An error occurred during clustering: {e}")
|
|
|
|
| 719 |
|
| 720 |
if error is not None:
|
| 721 |
st.error(f"An error occurred during planning: {error}")
|
|
|
|
|
|
|
| 722 |
|
| 723 |
|
| 724 |
def display_clustering_results():
|
|
|
|
| 759 |
num_steps = len(tree.synthesis_route(node_id))
|
| 760 |
route_score = round(tree.route_score(node_id), 3)
|
| 761 |
svg = get_route_svg(tree, node_id)
|
| 762 |
+
# svg = get_route_svg_from_json(st.session_state.route_json, node_id)
|
| 763 |
+
sb_cgr = group_data.get("sb_cgr") # Safely get sb_cgr
|
| 764 |
+
sb_cgr_svg = None
|
| 765 |
+
if sb_cgr:
|
| 766 |
+
sb_cgr.clean2d()
|
| 767 |
+
sb_cgr_svg = cgr_display(sb_cgr)
|
| 768 |
+
|
| 769 |
+
if svg and sb_cgr_svg:
|
| 770 |
col1, col2 = st.columns([0.2, 0.8])
|
| 771 |
with col1:
|
| 772 |
+
st.image(sb_cgr_svg, caption="SB-CGR")
|
| 773 |
with col2:
|
| 774 |
st.image(
|
| 775 |
svg,
|
|
|
|
| 781 |
caption=f"Route {node_id}; {num_steps} steps; Route score: {route_score}",
|
| 782 |
)
|
| 783 |
st.warning(
|
| 784 |
+
f"SB-CGR could not be displayed for cluster {cluster_num}."
|
| 785 |
)
|
| 786 |
else:
|
| 787 |
st.warning(
|
| 788 |
+
f"Could not generate SVG for route {node_id} or its SB-CGR."
|
| 789 |
)
|
| 790 |
except Exception as e:
|
| 791 |
st.error(
|
|
|
|
| 811 |
try:
|
| 812 |
num_steps = len(tree.synthesis_route(node_id))
|
| 813 |
route_score = round(tree.route_score(node_id), 3)
|
| 814 |
+
# svg = get_route_svg(tree, node_id)
|
| 815 |
+
svg = get_route_svg_from_json(st.session_state.route_json, node_id)
|
| 816 |
+
sb_cgr = group_data.get("sb_cgr")
|
| 817 |
+
sb_cgr_svg = None
|
| 818 |
+
if sb_cgr:
|
| 819 |
+
sb_cgr.clean2d()
|
| 820 |
+
sb_cgr_svg = cgr_display(sb_cgr)
|
| 821 |
+
|
| 822 |
+
if svg and sb_cgr_svg:
|
| 823 |
col1, col2 = st.columns([0.2, 0.8])
|
| 824 |
with col1:
|
| 825 |
+
st.image(sb_cgr_svg, caption="SB-CGR")
|
| 826 |
with col2:
|
| 827 |
st.image(
|
| 828 |
svg,
|
|
|
|
| 834 |
caption=f"Route {node_id}; {num_steps} steps; Route score: {route_score}",
|
| 835 |
)
|
| 836 |
st.warning(
|
| 837 |
+
f"SB-CGR could not be displayed for cluster {cluster_num}."
|
| 838 |
)
|
| 839 |
else:
|
| 840 |
st.warning(
|
| 841 |
+
f"Could not generate SVG for route {node_id} or its SB-CGR."
|
| 842 |
)
|
| 843 |
except Exception as e:
|
| 844 |
st.error(
|
|
|
|
| 851 |
if st.session_state.get("clustering_done", False):
|
| 852 |
tree_for_html = st.session_state.get("tree")
|
| 853 |
clusters_for_html = st.session_state.get("clusters")
|
| 854 |
+
sb_cgrs_for_html = st.session_state.get(
|
| 855 |
+
"sb_cgrs_dict"
|
| 856 |
) # This was used instead of reactions_dict in the original for report
|
| 857 |
|
| 858 |
if not tree_for_html:
|
|
|
|
| 861 |
if not clusters_for_html:
|
| 862 |
st.warning("Cluster data not found. Cannot generate cluster reports.")
|
| 863 |
return
|
| 864 |
+
# sb_cgrs_for_html is optional for routes_clustering_report if not essential
|
| 865 |
|
| 866 |
st.subheader("Cluster Reports") # Changed subheader in original
|
| 867 |
st.write("Generate downloadable HTML reports for each cluster:")
|
|
|
|
| 880 |
tree_for_html,
|
| 881 |
clusters_for_html, # Pass the whole dict
|
| 882 |
str(cluster_idx), # Pass the key of the cluster
|
| 883 |
+
sb_cgrs_for_html, # Pass the sb_cgrs dict
|
| 884 |
aam=False,
|
| 885 |
)
|
| 886 |
st.download_button(
|
|
|
|
| 907 |
tree_for_html,
|
| 908 |
clusters_for_html,
|
| 909 |
str(group_index),
|
| 910 |
+
sb_cgrs_for_html,
|
| 911 |
aam=False,
|
| 912 |
)
|
| 913 |
st.download_button(
|
|
|
|
| 932 |
tree_for_html,
|
| 933 |
clusters_for_html,
|
| 934 |
str(idx),
|
| 935 |
+
sb_cgrs_for_html,
|
| 936 |
aam=False,
|
| 937 |
)
|
| 938 |
filename = f"cluster_{idx}_{st.session_state.target_smiles}.html"
|
|
|
|
| 965 |
error = None
|
| 966 |
try:
|
| 967 |
clusters_for_sub = st.session_state.get("clusters")
|
| 968 |
+
sb_cgrs_dict_for_sub = st.session_state.get(
|
| 969 |
+
"sb_cgrs_dict"
|
| 970 |
)
|
| 971 |
route_cgrs_dict_for_sub = st.session_state.get("route_cgrs_dict")
|
| 972 |
|
| 973 |
if (
|
| 974 |
clusters_for_sub
|
| 975 |
+
and sb_cgrs_dict_for_sub
|
| 976 |
and route_cgrs_dict_for_sub
|
| 977 |
): # Ensure all are present
|
| 978 |
all_subgroups = subcluster_all_clusters(
|
| 979 |
clusters_for_sub,
|
| 980 |
+
sb_cgrs_dict_for_sub,
|
| 981 |
route_cgrs_dict_for_sub,
|
| 982 |
)
|
| 983 |
st.session_state.subclusters = all_subgroups
|
|
|
|
| 989 |
missing = []
|
| 990 |
if not clusters_for_sub:
|
| 991 |
missing.append("clusters")
|
| 992 |
+
if not sb_cgrs_dict_for_sub:
|
| 993 |
+
missing.append("SB-CGRs dictionary")
|
| 994 |
if not route_cgrs_dict_for_sub:
|
| 995 |
missing.append("RouteCGRs dictionary")
|
| 996 |
st.error(
|
|
|
|
| 1057 |
current_subcluster_data = sub[user_input_cluster_num_display][
|
| 1058 |
selected_subcluster_idx
|
| 1059 |
]
|
| 1060 |
+
if "sb_cgr" in current_subcluster_data:
|
| 1061 |
+
cluster_sb_cgr_display = current_subcluster_data[
|
| 1062 |
+
"sb_cgr"
|
| 1063 |
]
|
| 1064 |
+
cluster_sb_cgr_display.clean2d()
|
| 1065 |
st.image(
|
| 1066 |
+
cluster_sb_cgr_display.depict(),
|
| 1067 |
+
caption=f"SB-CGR of parent Cluster {user_input_cluster_num_display}",
|
| 1068 |
)
|
| 1069 |
else:
|
| 1070 |
+
st.warning("SB-CGR for this subcluster not found.")
|
| 1071 |
else:
|
| 1072 |
st.warning(
|
| 1073 |
f"Selected cluster {user_input_cluster_num_display} not found in subclustering results."
|
|
|
|
| 1122 |
st.warning(f"Could not depict synthon reaction: {e_depict}")
|
| 1123 |
else:
|
| 1124 |
st.info("No synthon reaction data for this subcluster.")
|
| 1125 |
+
with st.container(height=300):
|
| 1126 |
+
for route_id in routes_to_display_direct:
|
| 1127 |
+
try:
|
| 1128 |
+
route_score_sub = round(tree.route_score(route_id), 3)
|
| 1129 |
+
# svg_sub = get_route_svg(tree, route_id)
|
| 1130 |
+
svg = get_route_svg_from_json(st.session_state.route_json, route_id)
|
| 1131 |
+
if svg_sub:
|
| 1132 |
+
st.image(
|
| 1133 |
+
svg_sub,
|
| 1134 |
+
caption=f"Route {route_id}; Score: {route_score_sub}",
|
| 1135 |
+
)
|
| 1136 |
+
else:
|
| 1137 |
+
st.warning(
|
| 1138 |
+
f"Could not generate SVG for route {route_id}."
|
| 1139 |
+
)
|
| 1140 |
+
except Exception as e:
|
| 1141 |
+
st.error(
|
| 1142 |
+
f"Error displaying route {route_id} in subcluster: {e}"
|
| 1143 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1144 |
|
| 1145 |
+
if remaining_routes_sub:
|
| 1146 |
+
with st.expander(
|
| 1147 |
+
f"... and {len(remaining_routes_sub)} more routes in this subcluster"
|
| 1148 |
+
):
|
| 1149 |
+
for route_id in remaining_routes_sub:
|
| 1150 |
+
try:
|
| 1151 |
+
route_score_sub = round(
|
| 1152 |
+
tree.route_score(route_id), 3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1153 |
)
|
| 1154 |
+
# svg_sub = get_route_svg(tree, route_id)
|
| 1155 |
+
svg_sub = get_route_svg_from_json(st.session_state.route_json, route_id)
|
| 1156 |
+
if svg_sub:
|
| 1157 |
+
st.image(
|
| 1158 |
+
svg_sub,
|
| 1159 |
+
caption=f"Route {route_id}; Score: {route_score_sub}",
|
| 1160 |
+
)
|
| 1161 |
+
else:
|
| 1162 |
+
st.warning(
|
| 1163 |
+
f"Could not generate SVG for route {route_id}."
|
| 1164 |
+
)
|
| 1165 |
+
except Exception as e:
|
| 1166 |
+
st.error(
|
| 1167 |
+
f"Error displaying route {route_id} in subcluster (expanded): {e}"
|
| 1168 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1169 |
else:
|
| 1170 |
st.info("Select a valid cluster and subcluster index to see details.")
|
| 1171 |
|
|
|
|
| 1180 |
|
| 1181 |
sub = st.session_state.get("subclusters")
|
| 1182 |
tree = st.session_state.get("tree")
|
| 1183 |
+
sb_cgrs_for_report = st.session_state.get(
|
| 1184 |
+
"sb_cgrs_dict"
|
| 1185 |
) # Used by routes_subclustering_report
|
| 1186 |
|
| 1187 |
user_input_cluster_num_display = st.session_state.subcluster_num_select_key
|
| 1188 |
selected_subcluster_idx = st.session_state.subcluster_index_select_key
|
| 1189 |
|
| 1190 |
+
if not tree or not sub or not sb_cgrs_for_report:
|
| 1191 |
st.warning(
|
| 1192 |
+
"Missing data for subclustering report generation (tree, subclusters, or SB-CGRs)."
|
| 1193 |
)
|
| 1194 |
return
|
| 1195 |
|
|
|
|
| 1224 |
processed_subcluster_data, # Pass the specific post-processed subcluster data
|
| 1225 |
user_input_cluster_num_display,
|
| 1226 |
selected_subcluster_idx,
|
| 1227 |
+
sb_cgrs_for_report, # Pass the whole sb_cgrs dict
|
| 1228 |
if_lg_group=True, # This parameter was in the original call
|
| 1229 |
)
|
| 1230 |
st.download_button(
|
|
|
|
| 1257 |
"reactions_dict",
|
| 1258 |
"num_clusters_setting",
|
| 1259 |
"route_cgrs_dict",
|
| 1260 |
+
"sb_cgrs_dict",
|
| 1261 |
"subclustering_done",
|
| 1262 |
"subclusters", # "sub" was renamed
|
| 1263 |
"clusters_downloaded",
|
synplan/chem/reaction_routes/clustering.py
CHANGED
|
@@ -57,7 +57,7 @@ def run_cluster_cli(
|
|
| 57 |
# Compose condensed graph representations
|
| 58 |
route_cgrs = compose_all_route_cgrs(routes_dict)
|
| 59 |
click.echo(f"Generating RouteCGR")
|
| 60 |
-
reduced_cgrs =
|
| 61 |
click.echo(f"Generating ReducedRouteCGR")
|
| 62 |
|
| 63 |
# Perform clustering
|
|
@@ -129,7 +129,7 @@ def cluster_route_from_csv(routes_file: str):
|
|
| 129 |
"""
|
| 130 |
routes_dict = read_routes_csv(routes_file)
|
| 131 |
route_cgrs_dict = compose_all_route_cgrs(routes_dict)
|
| 132 |
-
reduced_route_cgrs_dict =
|
| 133 |
clusters = cluster_routes(reduced_route_cgrs_dict, use_strat=False)
|
| 134 |
return clusters
|
| 135 |
|
|
@@ -157,7 +157,7 @@ def cluster_route_from_json(routes_file: str):
|
|
| 157 |
routes_json = read_routes_json(routes_file)
|
| 158 |
routes_dict = make_dict(routes_json)
|
| 159 |
route_cgrs_dict = compose_all_route_cgrs(routes_dict)
|
| 160 |
-
reduced_route_cgrs_dict =
|
| 161 |
clusters = cluster_routes(reduced_route_cgrs_dict, use_strat=False)
|
| 162 |
return clusters
|
| 163 |
|
|
@@ -196,34 +196,34 @@ def extract_strat_bonds(target_cgr: CGRContainer):
|
|
| 196 |
return sorted(result)
|
| 197 |
|
| 198 |
|
| 199 |
-
def cluster_routes(
|
| 200 |
"""
|
| 201 |
Cluster routes objects based on their strategic bonds
|
| 202 |
or CGRContainer object signature (not avoid mapping)
|
| 203 |
|
| 204 |
Args:
|
| 205 |
-
|
| 206 |
|
| 207 |
Returns:
|
| 208 |
Dictionary with groups keyed by '{length}.{index}' containing
|
| 209 |
-
'
|
| 210 |
"""
|
| 211 |
temp_groups = defaultdict(
|
| 212 |
-
lambda: {"node_ids": [], "
|
| 213 |
)
|
| 214 |
|
| 215 |
# 1. Initial grouping based on the content of strategic bonds
|
| 216 |
-
for node_id,
|
| 217 |
-
strat_bonds_list = extract_strat_bonds(
|
| 218 |
if use_strat == True:
|
| 219 |
group_key = tuple(strat_bonds_list)
|
| 220 |
else:
|
| 221 |
-
group_key = str(
|
| 222 |
|
| 223 |
if not temp_groups[group_key]["node_ids"]: # First time seeing this group
|
| 224 |
temp_groups[group_key][
|
| 225 |
-
"
|
| 226 |
-
] =
|
| 227 |
temp_groups[group_key][
|
| 228 |
"strat_bonds"
|
| 229 |
] = strat_bonds_list # Store the actual list
|
|
@@ -437,7 +437,7 @@ class SubclusterError(Exception):
|
|
| 437 |
"""Raised when subcluster_one_cluster cannot complete successfully."""
|
| 438 |
|
| 439 |
|
| 440 |
-
def subcluster_one_cluster(group,
|
| 441 |
"""
|
| 442 |
Generate synthon data for each route in a single cluster.
|
| 443 |
|
|
@@ -449,7 +449,7 @@ def subcluster_one_cluster(group, r_route_cgrs_dict, route_cgrs_dict):
|
|
| 449 |
----------
|
| 450 |
group : dict
|
| 451 |
Must include `'node_ids'`, a list of node identifiers.
|
| 452 |
-
|
| 453 |
Maps node IDs to their ReducedRouteCGR.
|
| 454 |
route_cgrs_dict : dict
|
| 455 |
Maps node IDs to their RouteCGR.
|
|
@@ -458,7 +458,7 @@ def subcluster_one_cluster(group, r_route_cgrs_dict, route_cgrs_dict):
|
|
| 458 |
-------
|
| 459 |
dict or None
|
| 460 |
If successful, returns a dict mapping each `node_id` to a tuple:
|
| 461 |
-
`(
|
| 462 |
Or raises SubclusterError on any failure: if any step (X replacement or reaction
|
| 463 |
parsing) fails for a node.
|
| 464 |
|
|
@@ -472,7 +472,7 @@ def subcluster_one_cluster(group, r_route_cgrs_dict, route_cgrs_dict):
|
|
| 472 |
|
| 473 |
result = {}
|
| 474 |
for node_id in node_ids:
|
| 475 |
-
|
| 476 |
route_cgr = route_cgrs_dict[node_id]
|
| 477 |
|
| 478 |
# 1) Replace leaving groups in RouteCGR
|
|
@@ -502,7 +502,7 @@ def subcluster_one_cluster(group, r_route_cgrs_dict, route_cgrs_dict):
|
|
| 502 |
) from e
|
| 503 |
|
| 504 |
result[node_id] = (
|
| 505 |
-
|
| 506 |
ReactionContainer(reactants=old_reactants, products=[target_mol]),
|
| 507 |
synthon_cgr,
|
| 508 |
new_rxn,
|
|
@@ -521,7 +521,7 @@ def group_nodes_by_synthon_detail(data_dict: dict):
|
|
| 521 |
data_dict: Dictionary {node_id: [synthon_cgr, synthon_reaction, node_data, ...]}.
|
| 522 |
|
| 523 |
Returns:
|
| 524 |
-
Dictionary {group_index: {'
|
| 525 |
'nodes_data': {node_id1: node_data1, ...}}}.
|
| 526 |
"""
|
| 527 |
temp_groups = defaultdict(list)
|
|
@@ -553,7 +553,7 @@ def group_nodes_by_synthon_detail(data_dict: dict):
|
|
| 553 |
sorted_temp_groups = sorted(temp_groups.items(), key=lambda item: item[1])
|
| 554 |
for group_key, node_ids in sorted_temp_groups:
|
| 555 |
|
| 556 |
-
|
| 557 |
nodes_data_dict = {}
|
| 558 |
|
| 559 |
# Iterate through the node IDs belonging to this group
|
|
@@ -568,7 +568,7 @@ def group_nodes_by_synthon_detail(data_dict: dict):
|
|
| 568 |
nodes_data_dict[node_id] = node_specific_data # Add to the sub-dictionary
|
| 569 |
|
| 570 |
final_grouped_results[group_index] = {
|
| 571 |
-
"
|
| 572 |
"unlabeled_reaction": unlabeled_reaction,
|
| 573 |
"synthon_cgr": synthon_cgr,
|
| 574 |
"synthon_reaction": synthon_reaction,
|
|
@@ -580,7 +580,7 @@ def group_nodes_by_synthon_detail(data_dict: dict):
|
|
| 580 |
return final_grouped_results
|
| 581 |
|
| 582 |
|
| 583 |
-
def subcluster_all_clusters(groups,
|
| 584 |
"""
|
| 585 |
Subdivide each reaction cluster into detailed synthon-based subgroups.
|
| 586 |
|
|
@@ -591,7 +591,7 @@ def subcluster_all_clusters(groups, r_route_cgrs_dict, route_cgrs_dict):
|
|
| 591 |
----------
|
| 592 |
groups : dict
|
| 593 |
Mapping of cluster indices to cluster data.
|
| 594 |
-
|
| 595 |
Dictionary of ReducedRoteCGRs
|
| 596 |
route_cgrs_dict : dict
|
| 597 |
Dictionary of RoteCGRs
|
|
@@ -605,7 +605,7 @@ def subcluster_all_clusters(groups, r_route_cgrs_dict, route_cgrs_dict):
|
|
| 605 |
all_subgroups = {}
|
| 606 |
for group_index, group in groups.items():
|
| 607 |
group_synthons = subcluster_one_cluster(
|
| 608 |
-
group,
|
| 609 |
)
|
| 610 |
if group_synthons is None:
|
| 611 |
return None
|
|
|
|
| 57 |
# Compose condensed graph representations
|
| 58 |
route_cgrs = compose_all_route_cgrs(routes_dict)
|
| 59 |
click.echo(f"Generating RouteCGR")
|
| 60 |
+
reduced_cgrs = compose_all_sb_cgrs(route_cgrs)
|
| 61 |
click.echo(f"Generating ReducedRouteCGR")
|
| 62 |
|
| 63 |
# Perform clustering
|
|
|
|
| 129 |
"""
|
| 130 |
routes_dict = read_routes_csv(routes_file)
|
| 131 |
route_cgrs_dict = compose_all_route_cgrs(routes_dict)
|
| 132 |
+
reduced_route_cgrs_dict = compose_all_sb_cgrs(route_cgrs_dict)
|
| 133 |
clusters = cluster_routes(reduced_route_cgrs_dict, use_strat=False)
|
| 134 |
return clusters
|
| 135 |
|
|
|
|
| 157 |
routes_json = read_routes_json(routes_file)
|
| 158 |
routes_dict = make_dict(routes_json)
|
| 159 |
route_cgrs_dict = compose_all_route_cgrs(routes_dict)
|
| 160 |
+
reduced_route_cgrs_dict = compose_all_sb_cgrs(route_cgrs_dict)
|
| 161 |
clusters = cluster_routes(reduced_route_cgrs_dict, use_strat=False)
|
| 162 |
return clusters
|
| 163 |
|
|
|
|
| 196 |
return sorted(result)
|
| 197 |
|
| 198 |
|
| 199 |
+
def cluster_routes(sb_cgrs: dict, use_strat=False):
|
| 200 |
"""
|
| 201 |
Cluster routes objects based on their strategic bonds
|
| 202 |
or CGRContainer object signature (not avoid mapping)
|
| 203 |
|
| 204 |
Args:
|
| 205 |
+
sb_cgrs: Dictionary mapping node_id to sb_cgr objects.
|
| 206 |
|
| 207 |
Returns:
|
| 208 |
Dictionary with groups keyed by '{length}.{index}' containing
|
| 209 |
+
'sb_cgr', 'node_ids', and 'strat_bonds'.
|
| 210 |
"""
|
| 211 |
temp_groups = defaultdict(
|
| 212 |
+
lambda: {"node_ids": [], "sb_cgr": None, "strat_bonds": None}
|
| 213 |
)
|
| 214 |
|
| 215 |
# 1. Initial grouping based on the content of strategic bonds
|
| 216 |
+
for node_id, sb_cgr in sb_cgrs.items():
|
| 217 |
+
strat_bonds_list = extract_strat_bonds(sb_cgr)
|
| 218 |
if use_strat == True:
|
| 219 |
group_key = tuple(strat_bonds_list)
|
| 220 |
else:
|
| 221 |
+
group_key = str(sb_cgr)
|
| 222 |
|
| 223 |
if not temp_groups[group_key]["node_ids"]: # First time seeing this group
|
| 224 |
temp_groups[group_key][
|
| 225 |
+
"sb_cgr"
|
| 226 |
+
] = sb_cgr # Store the first CGR as representative
|
| 227 |
temp_groups[group_key][
|
| 228 |
"strat_bonds"
|
| 229 |
] = strat_bonds_list # Store the actual list
|
|
|
|
| 437 |
"""Raised when subcluster_one_cluster cannot complete successfully."""
|
| 438 |
|
| 439 |
|
| 440 |
+
def subcluster_one_cluster(group, sb_cgrs_dict, route_cgrs_dict):
|
| 441 |
"""
|
| 442 |
Generate synthon data for each route in a single cluster.
|
| 443 |
|
|
|
|
| 449 |
----------
|
| 450 |
group : dict
|
| 451 |
Must include `'node_ids'`, a list of node identifiers.
|
| 452 |
+
sb_cgrs_dict : dict
|
| 453 |
Maps node IDs to their ReducedRouteCGR.
|
| 454 |
route_cgrs_dict : dict
|
| 455 |
Maps node IDs to their RouteCGR.
|
|
|
|
| 458 |
-------
|
| 459 |
dict or None
|
| 460 |
If successful, returns a dict mapping each `node_id` to a tuple:
|
| 461 |
+
`(sb_cgr, original_reaction, synthon_cgr, new_reaction, lg_groups)`.
|
| 462 |
Or raises SubclusterError on any failure: if any step (X replacement or reaction
|
| 463 |
parsing) fails for a node.
|
| 464 |
|
|
|
|
| 472 |
|
| 473 |
result = {}
|
| 474 |
for node_id in node_ids:
|
| 475 |
+
sb_cgr = sb_cgrs_dict[node_id]
|
| 476 |
route_cgr = route_cgrs_dict[node_id]
|
| 477 |
|
| 478 |
# 1) Replace leaving groups in RouteCGR
|
|
|
|
| 502 |
) from e
|
| 503 |
|
| 504 |
result[node_id] = (
|
| 505 |
+
sb_cgr,
|
| 506 |
ReactionContainer(reactants=old_reactants, products=[target_mol]),
|
| 507 |
synthon_cgr,
|
| 508 |
new_rxn,
|
|
|
|
| 521 |
data_dict: Dictionary {node_id: [synthon_cgr, synthon_reaction, node_data, ...]}.
|
| 522 |
|
| 523 |
Returns:
|
| 524 |
+
Dictionary {group_index: {'sb_cgr': ... ,'synthon_cgr': ..., 'synthon_reaction': ...,
|
| 525 |
'nodes_data': {node_id1: node_data1, ...}}}.
|
| 526 |
"""
|
| 527 |
temp_groups = defaultdict(list)
|
|
|
|
| 553 |
sorted_temp_groups = sorted(temp_groups.items(), key=lambda item: item[1])
|
| 554 |
for group_key, node_ids in sorted_temp_groups:
|
| 555 |
|
| 556 |
+
sb_cgr, unlabeled_reaction, synthon_cgr, synthon_reaction = group_key
|
| 557 |
nodes_data_dict = {}
|
| 558 |
|
| 559 |
# Iterate through the node IDs belonging to this group
|
|
|
|
| 568 |
nodes_data_dict[node_id] = node_specific_data # Add to the sub-dictionary
|
| 569 |
|
| 570 |
final_grouped_results[group_index] = {
|
| 571 |
+
"sb_cgr": sb_cgr,
|
| 572 |
"unlabeled_reaction": unlabeled_reaction,
|
| 573 |
"synthon_cgr": synthon_cgr,
|
| 574 |
"synthon_reaction": synthon_reaction,
|
|
|
|
| 580 |
return final_grouped_results
|
| 581 |
|
| 582 |
|
| 583 |
+
def subcluster_all_clusters(groups, sb_cgrs_dict, route_cgrs_dict):
|
| 584 |
"""
|
| 585 |
Subdivide each reaction cluster into detailed synthon-based subgroups.
|
| 586 |
|
|
|
|
| 591 |
----------
|
| 592 |
groups : dict
|
| 593 |
Mapping of cluster indices to cluster data.
|
| 594 |
+
sb_cgrs_dict : dict
|
| 595 |
Dictionary of ReducedRoteCGRs
|
| 596 |
route_cgrs_dict : dict
|
| 597 |
Dictionary of RoteCGRs
|
|
|
|
| 605 |
all_subgroups = {}
|
| 606 |
for group_index, group in groups.items():
|
| 607 |
group_synthons = subcluster_one_cluster(
|
| 608 |
+
group, sb_cgrs_dict, route_cgrs_dict
|
| 609 |
)
|
| 610 |
if group_synthons is None:
|
| 611 |
return None
|
synplan/chem/reaction_routes/route_cgr.py
CHANGED
|
@@ -487,7 +487,7 @@ def extract_reactions(tree: Tree, node_id=None):
|
|
| 487 |
return dict(sorted(react_dict.items()))
|
| 488 |
|
| 489 |
|
| 490 |
-
def
|
| 491 |
"""
|
| 492 |
Reduces a Routes Condensed Graph of reaction (RouteCGR) by performing the following steps:
|
| 493 |
|
|
@@ -550,7 +550,7 @@ def compose_reduced_route_cgr(route_cgr: CGRContainer):
|
|
| 550 |
return reduced_route_cgr
|
| 551 |
|
| 552 |
|
| 553 |
-
def
|
| 554 |
"""
|
| 555 |
Processes a collection (dictionary) of RouteCGRs to generate their reduced forms (ReducedRouteCGRs).
|
| 556 |
|
|
@@ -566,5 +566,5 @@ def compose_all_reduced_route_cgrs(route_cgrs_dict: dict):
|
|
| 566 |
"""
|
| 567 |
all_reduced_route_cgrs = dict()
|
| 568 |
for num, cgr in route_cgrs_dict.items():
|
| 569 |
-
all_reduced_route_cgrs[num] =
|
| 570 |
return all_reduced_route_cgrs
|
|
|
|
| 487 |
return dict(sorted(react_dict.items()))
|
| 488 |
|
| 489 |
|
| 490 |
+
def compose_sb_cgr(route_cgr: CGRContainer):
|
| 491 |
"""
|
| 492 |
Reduces a Routes Condensed Graph of reaction (RouteCGR) by performing the following steps:
|
| 493 |
|
|
|
|
| 550 |
return reduced_route_cgr
|
| 551 |
|
| 552 |
|
| 553 |
+
def compose_all_sb_cgrs(route_cgrs_dict: dict):
|
| 554 |
"""
|
| 555 |
Processes a collection (dictionary) of RouteCGRs to generate their reduced forms (ReducedRouteCGRs).
|
| 556 |
|
|
|
|
| 566 |
"""
|
| 567 |
all_reduced_route_cgrs = dict()
|
| 568 |
for num, cgr in route_cgrs_dict.items():
|
| 569 |
+
all_reduced_route_cgrs[num] = compose_sb_cgr(cgr)
|
| 570 |
return all_reduced_route_cgrs
|
synplan/utils/visualisation.py
CHANGED
|
@@ -536,7 +536,7 @@ def html_top_routes_cluster(clusters: dict, tree: Tree, target_smiles: str) -> s
|
|
| 536 |
node_id = node_ids[0]
|
| 537 |
# Get SVGs
|
| 538 |
svg = get_route_svg(tree, node_id)
|
| 539 |
-
r_cgr = group_data.get("
|
| 540 |
r_cgr_svg = None
|
| 541 |
if r_cgr:
|
| 542 |
r_cgr.clean2d()
|
|
@@ -573,7 +573,7 @@ def routes_clustering_report(
|
|
| 573 |
source: Union[Tree, dict],
|
| 574 |
clusters: dict,
|
| 575 |
group_index: str,
|
| 576 |
-
|
| 577 |
aam: bool = False,
|
| 578 |
html_path: str = None,
|
| 579 |
) -> str:
|
|
@@ -597,7 +597,7 @@ def routes_clustering_report(
|
|
| 597 |
group_index (str): The key identifying the specific cluster within the
|
| 598 |
`clusters` dictionary for which the report should be
|
| 599 |
generated.
|
| 600 |
-
|
| 601 |
ReducedRouteCGR (Retrosynthetic Graph-based Chemical
|
| 602 |
Reaction) objects. Used to display a representative
|
| 603 |
ReducedRouteCGR for the cluster.
|
|
@@ -749,18 +749,18 @@ def routes_clustering_report(
|
|
| 749 |
# --- Add ReducedRouteCGR Image ---
|
| 750 |
first_route_id = valid_routes[0] if valid_routes else None
|
| 751 |
|
| 752 |
-
if first_route_id and
|
| 753 |
try:
|
| 754 |
-
|
| 755 |
-
|
| 756 |
-
|
| 757 |
|
| 758 |
-
if
|
| 759 |
-
table += f"<tr>{td}{font_normal}Identified Strategic Bonds{font_close}<br>{
|
| 760 |
else:
|
| 761 |
table += f"<tr>{td}{font_normal}Cluster Representative ReducedRouteCGR (from Route {first_route_id}):{font_close}<br><i>Invalid SVG format retrieved.</i></td></tr>"
|
| 762 |
print(
|
| 763 |
-
f"Warning: Expected SVG for ReducedRouteCGR of node {first_route_id}, but got: {
|
| 764 |
)
|
| 765 |
except Exception as e:
|
| 766 |
table += f"<tr>{td}{font_normal}Cluster Representative ReducedRouteCGR (from Route {first_route_id}):{font_close}<br><i>Error retrieving/displaying ReducedRouteCGR: {e}</i></td></tr>"
|
|
@@ -993,7 +993,7 @@ def routes_subclustering_report(
|
|
| 993 |
subcluster: dict,
|
| 994 |
group_index: str,
|
| 995 |
cluster_num: int,
|
| 996 |
-
|
| 997 |
if_lg_group: bool = False,
|
| 998 |
aam: bool = False,
|
| 999 |
html_path: str = None,
|
|
@@ -1022,7 +1022,7 @@ def routes_subclustering_report(
|
|
| 1022 |
subcluster belongs. Used for report titling.
|
| 1023 |
cluster_num (int): The number or identifier of the subcluster within
|
| 1024 |
its main group. Used for report titling.
|
| 1025 |
-
|
| 1026 |
ReducedRouteCGR objects. Used to display a representative
|
| 1027 |
ReducedRouteCGR for the cluster.
|
| 1028 |
if_lg_group (bool, optional): If True, the leaving groups table will
|
|
@@ -1179,18 +1179,18 @@ def routes_subclustering_report(
|
|
| 1179 |
# --- Add ReducedRouteCGR Image ---
|
| 1180 |
first_route_id = valid_routes[0] if valid_routes else None
|
| 1181 |
|
| 1182 |
-
if first_route_id and
|
| 1183 |
try:
|
| 1184 |
-
|
| 1185 |
-
|
| 1186 |
-
|
| 1187 |
|
| 1188 |
-
if
|
| 1189 |
-
table += f"<tr>{td}{font_normal}Identified Strategic Bonds{font_close}<br>{
|
| 1190 |
else:
|
| 1191 |
table += f"<tr>{td}{font_normal}Cluster Representative ReducedRouteCGR (from Route {first_route_id}):{font_close}<br><i>Invalid SVG format retrieved.</i></td></tr>"
|
| 1192 |
print(
|
| 1193 |
-
f"Warning: Expected SVG for ReducedRouteCGR of node {first_route_id}, but got: {
|
| 1194 |
)
|
| 1195 |
except Exception as e:
|
| 1196 |
table += f"<tr>{td}{font_normal}Cluster Representative ReducedRouteCGR (from Route {first_route_id}):{font_close}<br><i>Error retrieving/displaying ReducedRouteCGR: {e}</i></td></tr>"
|
|
|
|
| 536 |
node_id = node_ids[0]
|
| 537 |
# Get SVGs
|
| 538 |
svg = get_route_svg(tree, node_id)
|
| 539 |
+
r_cgr = group_data.get("sb_cgr")
|
| 540 |
r_cgr_svg = None
|
| 541 |
if r_cgr:
|
| 542 |
r_cgr.clean2d()
|
|
|
|
| 573 |
source: Union[Tree, dict],
|
| 574 |
clusters: dict,
|
| 575 |
group_index: str,
|
| 576 |
+
sb_cgrs_dict: dict,
|
| 577 |
aam: bool = False,
|
| 578 |
html_path: str = None,
|
| 579 |
) -> str:
|
|
|
|
| 597 |
group_index (str): The key identifying the specific cluster within the
|
| 598 |
`clusters` dictionary for which the report should be
|
| 599 |
generated.
|
| 600 |
+
sb_cgrs_dict (dict): A dictionary mapping route IDs (integers) to
|
| 601 |
ReducedRouteCGR (Retrosynthetic Graph-based Chemical
|
| 602 |
Reaction) objects. Used to display a representative
|
| 603 |
ReducedRouteCGR for the cluster.
|
|
|
|
| 749 |
# --- Add ReducedRouteCGR Image ---
|
| 750 |
first_route_id = valid_routes[0] if valid_routes else None
|
| 751 |
|
| 752 |
+
if first_route_id and sb_cgrs_dict:
|
| 753 |
try:
|
| 754 |
+
sb_cgr = sb_cgrs_dict[first_route_id]
|
| 755 |
+
sb_cgr.clean2d()
|
| 756 |
+
sb_cgr_svg = cgr_display(sb_cgr)
|
| 757 |
|
| 758 |
+
if sb_cgr_svg.strip().startswith("<svg"):
|
| 759 |
+
table += f"<tr>{td}{font_normal}Identified Strategic Bonds{font_close}<br>{sb_cgr_svg}</td></tr>"
|
| 760 |
else:
|
| 761 |
table += f"<tr>{td}{font_normal}Cluster Representative ReducedRouteCGR (from Route {first_route_id}):{font_close}<br><i>Invalid SVG format retrieved.</i></td></tr>"
|
| 762 |
print(
|
| 763 |
+
f"Warning: Expected SVG for ReducedRouteCGR of node {first_route_id}, but got: {sb_cgr_svg[:100]}..."
|
| 764 |
)
|
| 765 |
except Exception as e:
|
| 766 |
table += f"<tr>{td}{font_normal}Cluster Representative ReducedRouteCGR (from Route {first_route_id}):{font_close}<br><i>Error retrieving/displaying ReducedRouteCGR: {e}</i></td></tr>"
|
|
|
|
| 993 |
subcluster: dict,
|
| 994 |
group_index: str,
|
| 995 |
cluster_num: int,
|
| 996 |
+
sb_cgrs_dict: dict,
|
| 997 |
if_lg_group: bool = False,
|
| 998 |
aam: bool = False,
|
| 999 |
html_path: str = None,
|
|
|
|
| 1022 |
subcluster belongs. Used for report titling.
|
| 1023 |
cluster_num (int): The number or identifier of the subcluster within
|
| 1024 |
its main group. Used for report titling.
|
| 1025 |
+
sb_cgrs_dict (dict): A dictionary mapping route IDs (integers) to
|
| 1026 |
ReducedRouteCGR objects. Used to display a representative
|
| 1027 |
ReducedRouteCGR for the cluster.
|
| 1028 |
if_lg_group (bool, optional): If True, the leaving groups table will
|
|
|
|
| 1179 |
# --- Add ReducedRouteCGR Image ---
|
| 1180 |
first_route_id = valid_routes[0] if valid_routes else None
|
| 1181 |
|
| 1182 |
+
if first_route_id and sb_cgrs_dict:
|
| 1183 |
try:
|
| 1184 |
+
sb_cgr = sb_cgrs_dict[first_route_id]
|
| 1185 |
+
sb_cgr.clean2d()
|
| 1186 |
+
sb_cgr_svg = cgr_display(sb_cgr)
|
| 1187 |
|
| 1188 |
+
if sb_cgr_svg.strip().startswith("<svg"):
|
| 1189 |
+
table += f"<tr>{td}{font_normal}Identified Strategic Bonds{font_close}<br>{sb_cgr_svg}</td></tr>"
|
| 1190 |
else:
|
| 1191 |
table += f"<tr>{td}{font_normal}Cluster Representative ReducedRouteCGR (from Route {first_route_id}):{font_close}<br><i>Invalid SVG format retrieved.</i></td></tr>"
|
| 1192 |
print(
|
| 1193 |
+
f"Warning: Expected SVG for ReducedRouteCGR of node {first_route_id}, but got: {sb_cgr_svg[:100]}..."
|
| 1194 |
)
|
| 1195 |
except Exception as e:
|
| 1196 |
table += f"<tr>{td}{font_normal}Cluster Representative ReducedRouteCGR (from Route {first_route_id}):{font_close}<br><i>Error retrieving/displaying ReducedRouteCGR: {e}</i></td></tr>"
|