From d5ebb236221dbf483b36e023ece228605f5b4fca Mon Sep 17 00:00:00 2001 From: jebus Date: Thu, 16 Oct 2025 08:17:39 +1300 Subject: [PATCH] [Fix] AppDomain Leftovers (#161) Co-authored-by: Tim Lorsbach Reviewed-on: https://git.envipath.com/enviPath/enviPy/pulls/161 --- epdb/management/commands/localize_urls.py | 17 +++++++- epdb/views.py | 51 ++++++++++++++++++++--- static/js/pps.js | 6 +-- utilities/chem.py | 6 +++ 4 files changed, 70 insertions(+), 10 deletions(-) diff --git a/epdb/management/commands/localize_urls.py b/epdb/management/commands/localize_urls.py index 91afb0a6..cc0a3726 100644 --- a/epdb/management/commands/localize_urls.py +++ b/epdb/management/commands/localize_urls.py @@ -1,8 +1,10 @@ from django.apps import apps from django.core.management.base import BaseCommand -from django.db.models import F, Value -from django.db.models.functions import Replace +from django.db.models import F, Value, TextField, JSONField +from django.db.models.functions import Replace, Cast + +from epdb.models import EnviPathModel class Command(BaseCommand): @@ -49,3 +51,14 @@ class Command(BaseCommand): obj_cls.objects.update( url=Replace(F("url"), Value(options["old"]), Value(options["new"])) ) + if issubclass(obj_cls, EnviPathModel): + obj_cls.objects.update( + kv=Cast( + Replace( + Cast(F("kv"), output_field=TextField()), + Value(options["old"]), + Value(options["new"]), + ), + output_field=JSONField(), + ) + ) diff --git a/epdb/views.py b/epdb/views.py index dd13d21d..4844d3be 100644 --- a/epdb/views.py +++ b/epdb/views.py @@ -1454,12 +1454,20 @@ def package_rule(request, package_uuid, rule_uuid): logger.info( f"Rule {current_rule.uuid} returned multiple product sets on {smiles}, picking the first one." ) - - smirks = f"{stand_smiles}>>{'.'.join(sorted(res[0]))}" + # Some Rules are touching unrelated areas which might result in ~ indicating + # any bond (-, =, #). For drawing we need a concrete bond. -> use single bond + product_smiles = [x.replace("~", "-") for x in res[0]] + smirks = f"{stand_smiles}>>{'.'.join(sorted(product_smiles))}" # Usually the functional groups are a mapping of fg -> count # As we are doing it on the fly here fake a high count to ensure that its properly highlighted - educt_functional_groups = {x: 1000 for x in current_rule.reactants_smarts} - product_functional_groups = {x: 1000 for x in current_rule.products_smarts} + + if isinstance(current_rule, SimpleAmbitRule): + educt_functional_groups = {current_rule.reactants_smarts: 1000} + product_functional_groups = {current_rule.products_smarts: 1000} + else: + educt_functional_groups = {x: 1000 for x in current_rule.reactants_smarts} + product_functional_groups = {x: 1000 for x in current_rule.products_smarts} + return HttpResponse( IndigoUtils.smirks_to_svg( smirks, @@ -1993,9 +2001,42 @@ def package_pathway_node(request, package_uuid, pathway_uuid, node_uuid): if request.method == "GET": is_image_request = request.GET.get("image") + is_highlight_request = request.GET.get("highlight", False) + is_highlight_reactivity = request.GET.get("highlightReactivity", False) if is_image_request: if is_image_request == "svg": - svg_data = current_node.as_svg + # TODO optimize this chain + if is_highlight_request: + # User functional groups covered by the model training data + fgs = {} + if current_pathway.setting: + if current_pathway.setting.model: + if current_pathway.setting.model.app_domain: + fgs = current_pathway.setting.model.app_domain.functional_groups + + svg_data = IndigoUtils.mol_to_svg( + current_node.default_node_label.smiles, functional_groups=fgs + ) + elif is_highlight_reactivity: + # Use reactant smarts to show all reaction sites + # set a high count to obtain a strong color + ad_data = current_node.get_app_domain_assessment_data() + fgs = {} + for t in ad_data.get("assessment", {}).get("transformations", []): + r = Rule.objects.get(url=t["rule"]["url"]) + + if isinstance(r, SimpleAmbitRule): + fgs[r.reactants_smarts] = 1000 + else: + for sr in r.srs: + fgs[sr.reactants_smarts] = 1000 + + svg_data = IndigoUtils.mol_to_svg( + current_node.default_node_label.smiles, functional_groups=fgs + ) + else: + svg_data = current_node.as_svg + return HttpResponse(svg_data, content_type="image/svg+xml") context = get_base_context(request) diff --git a/static/js/pps.js b/static/js/pps.js index abc92695..c0829ad1 100644 --- a/static/js/pps.js +++ b/static/js/pps.js @@ -646,8 +646,8 @@ function handleAssessmentResponse(depict_url, data) { var reactivityCentersImgSrc = null; if (data['assessment']['node'] !== undefined) { - functionalGroupsImgSrc = ""; - reactivityCentersImgSrc = "" + functionalGroupsImgSrc = ""; + reactivityCentersImgSrc = "" } else { functionalGroupsImgSrc = ""; reactivityCentersImgSrc = "" @@ -784,4 +784,4 @@ function handleAssessmentResponse(depict_url, data) { $("#appDomainAssessmentResultTable").append(res); -} \ No newline at end of file +} diff --git a/utilities/chem.py b/utilities/chem.py index 6de46147..279de26f 100644 --- a/utilities/chem.py +++ b/utilities/chem.py @@ -729,6 +729,7 @@ class IndigoUtils(object): height: int = 0, educt_functional_groups: Dict[str, int] = None, product_functional_groups: Dict[str, int] = None, + debug: bool = False, ): if educt_functional_groups is None: educt_functional_groups = {} @@ -739,6 +740,11 @@ class IndigoUtils(object): i = Indigo() renderer = IndigoRenderer(i) + if debug: + i.setOption("render-atom-ids-visible", True) + i.setOption("render-bond-ids-visible", False) + i.setOption("render-atom-bond-ids-from-one", True) + i.setOption("render-output-format", "svg") i.setOption("render-coloring", True) i.setOption("render-image-size", width, height)